Merge tag 'v3.10.76' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / ipv6 / ndisc.c
index 2712ab22a174087c09cc705e1f6adec2bd601154..42c40b119c8995e47366722db891b679e9d2c50f 100644 (file)
@@ -372,14 +372,11 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
        int tlen = dev->needed_tailroom;
        struct sock *sk = dev_net(dev)->ipv6.ndisc_sk;
        struct sk_buff *skb;
-       int err;
 
-       skb = sock_alloc_send_skb(sk,
-                                 hlen + sizeof(struct ipv6hdr) + len + tlen,
-                                 1, &err);
+       skb = alloc_skb(hlen + sizeof(struct ipv6hdr) + len + tlen, GFP_ATOMIC);
        if (!skb) {
-               ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb, err=%d\n",
-                         __func__, err);
+               ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb\n",
+                         __func__);
                return NULL;
        }
 
@@ -389,6 +386,11 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
        skb_reserve(skb, hlen + sizeof(struct ipv6hdr));
        skb_reset_transport_header(skb);
 
+       /* Manually assign socket ownership as we avoid calling
+        * sock_alloc_send_pskb() to bypass wmem buffer limits
+        */
+       skb_set_owner_w(skb, sk);
+
        return skb;
 }
 
@@ -1191,7 +1193,14 @@ static void ndisc_router_discovery(struct sk_buff *skb)
        if (rt)
                rt6_set_expires(rt, jiffies + (HZ * lifetime));
        if (ra_msg->icmph.icmp6_hop_limit) {
-               in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
+               /* Only set hop_limit on the interface if it is higher than
+                * the current hop_limit.
+                */
+               if (in6_dev->cnf.hop_limit < ra_msg->icmph.icmp6_hop_limit) {
+                       in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
+               } else {
+                       ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than current\n");
+               }
                if (rt)
                        dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
                                       ra_msg->icmph.icmp6_hop_limit);
@@ -1323,12 +1332,35 @@ skip_routeinfo:
                }
        }
 
+#ifdef CONFIG_MTK_DHCPV6C_WIFI
+       if (in6_dev->if_flags & IF_RA_OTHERCONF){
+               printk(KERN_INFO "[mtk_net][ipv6]receive RA with o bit!\n");
+               in6_dev->cnf.ra_info_flag = 1;
+       } 
+       if(in6_dev->if_flags & IF_RA_MANAGED){
+               printk(KERN_INFO "[mtk_net][ipv6]receive RA with m bit!\n");
+               in6_dev->cnf.ra_info_flag = 2;
+       }
+       if(in6_dev->cnf.ra_info_flag == 0){
+               printk(KERN_INFO "[mtk_net][ipv6]receive RA neither O nor M bit is set!\n");
+               in6_dev->cnf.ra_info_flag = 4;
+       }
+#endif
+
        if (ndopts.nd_useropts) {
                struct nd_opt_hdr *p;
                for (p = ndopts.nd_useropts;
                     p;
                     p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
                        ndisc_ra_useropt(skb, p);
+#ifdef CONFIG_MTK_DHCPV6C_WIFI
+                       /* only clear ra_info_flag when O bit is set */
+                       if (p->nd_opt_type == ND_OPT_RDNSS &&
+                                       in6_dev->if_flags & IF_RA_OTHERCONF) {
+                               printk(KERN_INFO "[mtk_net][ipv6]RDNSS, ignore RA with o bit!\n");
+                               in6_dev->cnf.ra_info_flag = 0;
+                       } 
+#endif
                }
        }
 
@@ -1493,7 +1525,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
         */
 
        if (ha)
-               ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, ha);
+               ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha);
 
        /*
         *      build redirect option and copy skb over to the new packet.
@@ -1540,7 +1572,7 @@ int ndisc_rcv(struct sk_buff *skb)
        }
 
        memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
-
+       
        switch (msg->icmph.icmp6_type) {
        case NDISC_NEIGHBOUR_SOLICITATION:
                ndisc_recv_ns(skb);