diff options
Diffstat (limited to 'net/core/utils.c')
| -rw-r--r-- | net/core/utils.c | 59 |
1 files changed, 43 insertions, 16 deletions
diff --git a/net/core/utils.c b/net/core/utils.c index 3c7f5b51b97..eed34338736 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -339,24 +339,51 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb, } EXPORT_SYMBOL(inet_proto_csum_replace16); -int mac_pton(const char *s, u8 *mac) +struct __net_random_once_work { + struct work_struct work; + struct static_key *key; +}; + +static void __net_random_once_deferred(struct work_struct *w) { - int i; + struct __net_random_once_work *work = + container_of(w, struct __net_random_once_work, work); + BUG_ON(!static_key_enabled(work->key)); + static_key_slow_dec(work->key); + kfree(work); +} - /* XX:XX:XX:XX:XX:XX */ - if (strlen(s) < 3 * ETH_ALEN - 1) - return 0; +static void __net_random_once_disable_jump(struct static_key *key) +{ + struct __net_random_once_work *w; - /* Don't dirty result unless string is valid MAC. */ - for (i = 0; i < ETH_ALEN; i++) { - if (!isxdigit(s[i * 3]) || !isxdigit(s[i * 3 + 1])) - return 0; - if (i != ETH_ALEN - 1 && s[i * 3 + 2] != ':') - return 0; - } - for (i = 0; i < ETH_ALEN; i++) { - mac[i] = (hex_to_bin(s[i * 3]) << 4) | hex_to_bin(s[i * 3 + 1]); + w = kmalloc(sizeof(*w), GFP_ATOMIC); + if (!w) + return; + + INIT_WORK(&w->work, __net_random_once_deferred); + w->key = key; + schedule_work(&w->work); +} + +bool __net_get_random_once(void *buf, int nbytes, bool *done, + struct static_key *once_key) +{ + static DEFINE_SPINLOCK(lock); + unsigned long flags; + + spin_lock_irqsave(&lock, flags); + if (*done) { + spin_unlock_irqrestore(&lock, flags); + return false; } - return 1; + + get_random_bytes(buf, nbytes); + *done = true; + spin_unlock_irqrestore(&lock, flags); + + __net_random_once_disable_jump(once_key); + + return true; } -EXPORT_SYMBOL(mac_pton); +EXPORT_SYMBOL(__net_get_random_once); |
