aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/net.h25
-rw-r--r--net/core/utils.c48
2 files changed, 73 insertions, 0 deletions
diff --git a/include/linux/net.h b/include/linux/net.h
index ca9ec8540905..a489705f6fa3 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -239,6 +239,31 @@ do { \
239#define net_random() prandom_u32() 239#define net_random() prandom_u32()
240#define net_srandom(seed) prandom_seed((__force u32)(seed)) 240#define net_srandom(seed) prandom_seed((__force u32)(seed))
241 241
242bool __net_get_random_once(void *buf, int nbytes, bool *done,
243 struct static_key *done_key);
244
245#ifdef HAVE_JUMP_LABEL
246#define ___NET_RANDOM_STATIC_KEY_INIT ((struct static_key) \
247 { .enabled = ATOMIC_INIT(0), .entries = (void *)1 })
248#else /* !HAVE_JUMP_LABEL */
249#define ___NET_RANDOM_STATIC_KEY_INIT STATIC_KEY_INIT_FALSE
250#endif /* HAVE_JUMP_LABEL */
251
252/* BE CAREFUL: this function is not interrupt safe */
253#define net_get_random_once(buf, nbytes) \
254 ({ \
255 bool ___ret = false; \
256 static bool ___done = false; \
257 static struct static_key ___done_key = \
258 ___NET_RANDOM_STATIC_KEY_INIT; \
259 if (!static_key_true(&___done_key)) \
260 ___ret = __net_get_random_once(buf, \
261 nbytes, \
262 &___done, \
263 &___done_key); \
264 ___ret; \
265 })
266
242int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, 267int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
243 size_t num, size_t len); 268 size_t num, size_t len);
244int kernel_recvmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, 269int kernel_recvmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
diff --git a/net/core/utils.c b/net/core/utils.c
index aa88e23fc87a..bf09371e19b1 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -338,3 +338,51 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
338 csum_unfold(*sum))); 338 csum_unfold(*sum)));
339} 339}
340EXPORT_SYMBOL(inet_proto_csum_replace16); 340EXPORT_SYMBOL(inet_proto_csum_replace16);
341
342struct __net_random_once_work {
343 struct work_struct work;
344 struct static_key *key;
345};
346
347static void __net_random_once_deferred(struct work_struct *w)
348{
349 struct __net_random_once_work *work =
350 container_of(w, struct __net_random_once_work, work);
351 if (!static_key_enabled(work->key))
352 static_key_slow_inc(work->key);
353 kfree(work);
354}
355
356static void __net_random_once_disable_jump(struct static_key *key)
357{
358 struct __net_random_once_work *w;
359
360 w = kmalloc(sizeof(*w), GFP_ATOMIC);
361 if (!w)
362 return;
363
364 INIT_WORK(&w->work, __net_random_once_deferred);
365 w->key = key;
366 schedule_work(&w->work);
367}
368
369bool __net_get_random_once(void *buf, int nbytes, bool *done,
370 struct static_key *done_key)
371{
372 static DEFINE_SPINLOCK(lock);
373
374 spin_lock_bh(&lock);
375 if (*done) {
376 spin_unlock_bh(&lock);
377 return false;
378 }
379
380 get_random_bytes(buf, nbytes);
381 *done = true;
382 spin_unlock_bh(&lock);
383
384 __net_random_once_disable_jump(done_key);
385
386 return true;
387}
388EXPORT_SYMBOL(__net_get_random_once);