Merge remote branch 'wireless-next/master' into ath6kl-next
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / udp.c
index fe141052a1beaf5c85376cfed0740c348c019dce..eaca73644e7965e5405b6e61f362a3be3e0d2e2f 100644 (file)
 #include <net/checksum.h>
 #include <net/xfrm.h>
 #include <trace/events/udp.h>
+#include <linux/static_key.h>
 #include "udp_impl.h"
 
 struct udp_table udp_table __read_mostly;
@@ -206,7 +207,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
 
        if (!snum) {
                int low, high, remaining;
-               unsigned rand;
+               unsigned int rand;
                unsigned short first, last;
                DECLARE_BITMAP(bitmap, PORTS_PER_CHAIN);
 
@@ -846,7 +847,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
         *      Get and verify the address.
         */
        if (msg->msg_name) {
-               struct sockaddr_in * usin = (struct sockaddr_in *)msg->msg_name;
+               struct sockaddr_in *usin = (struct sockaddr_in *)msg->msg_name;
                if (msg->msg_namelen < sizeof(*usin))
                        return -EINVAL;
                if (usin->sin_family != AF_INET) {
@@ -1379,6 +1380,14 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 
 }
 
+static struct static_key udp_encap_needed __read_mostly;
+void udp_encap_enable(void)
+{
+       if (!static_key_enabled(&udp_encap_needed))
+               static_key_slow_inc(&udp_encap_needed);
+}
+EXPORT_SYMBOL(udp_encap_enable);
+
 /* returns:
  *  -1: error
  *   0: success
@@ -1400,7 +1409,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
                goto drop;
        nf_reset(skb);
 
-       if (up->encap_type) {
+       if (static_key_false(&udp_encap_needed) && up->encap_type) {
                int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
 
                /*
@@ -1470,7 +1479,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
                goto drop;
 
 
-       if (sk_rcvqueues_full(sk, skb))
+       if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf))
                goto drop;
 
        rc = 0;
@@ -1479,7 +1488,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
        bh_lock_sock(sk);
        if (!sock_owned_by_user(sk))
                rc = __udp_queue_rcv_skb(sk, skb);
-       else if (sk_add_backlog(sk, skb)) {
+       else if (sk_add_backlog(sk, skb, sk->sk_rcvbuf)) {
                bh_unlock_sock(sk);
                goto drop;
        }
@@ -1760,6 +1769,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
                        /* FALLTHROUGH */
                case UDP_ENCAP_L2TPINUDP:
                        up->encap_type = val;
+                       udp_encap_enable();
                        break;
                default:
                        err = -ENOPROTOOPT;
@@ -2163,9 +2173,15 @@ void udp4_proc_exit(void)
 static __initdata unsigned long uhash_entries;
 static int __init set_uhash_entries(char *str)
 {
+       ssize_t ret;
+
        if (!str)
                return 0;
-       uhash_entries = simple_strtoul(str, &str, 0);
+
+       ret = kstrtoul(str, 0, &uhash_entries);
+       if (ret)
+               return 0;
+
        if (uhash_entries && uhash_entries < UDP_HTABLE_SIZE_MIN)
                uhash_entries = UDP_HTABLE_SIZE_MIN;
        return 1;
@@ -2176,26 +2192,16 @@ void __init udp_table_init(struct udp_table *table, const char *name)
 {
        unsigned int i;
 
-       if (!CONFIG_BASE_SMALL)
-               table->hash = alloc_large_system_hash(name,
-                       2 * sizeof(struct udp_hslot),
-                       uhash_entries,
-                       21, /* one slot per 2 MB */
-                       0,
-                       &table->log,
-                       &table->mask,
-                       64 * 1024);
-       /*
-        * Make sure hash table has the minimum size
-        */
-       if (CONFIG_BASE_SMALL || table->mask < UDP_HTABLE_SIZE_MIN - 1) {
-               table->hash = kmalloc(UDP_HTABLE_SIZE_MIN *
-                                     2 * sizeof(struct udp_hslot), GFP_KERNEL);
-               if (!table->hash)
-                       panic(name);
-               table->log = ilog2(UDP_HTABLE_SIZE_MIN);
-               table->mask = UDP_HTABLE_SIZE_MIN - 1;
-       }
+       table->hash = alloc_large_system_hash(name,
+                                             2 * sizeof(struct udp_hslot),
+                                             uhash_entries,
+                                             21, /* one slot per 2 MB */
+                                             0,
+                                             &table->log,
+                                             &table->mask,
+                                             UDP_HTABLE_SIZE_MIN,
+                                             64 * 1024);
+
        table->hash2 = table->hash + (table->mask + 1);
        for (i = 0; i <= table->mask; i++) {
                INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i);