[NET] NETNS: Omit sock->sk_net without CONFIG_NET_NS.
[firefly-linux-kernel-4.4.55.git] / net / ipv6 / ipv6_sockglue.c
index c11c76cab371607194acbaaaff43f1f0f3370b7b..d3d93d752e1099c43cfa1e33adfa15630463df7f 100644 (file)
@@ -107,7 +107,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                    char __user *optval, int optlen)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
-       struct net *net = sk->sk_net;
+       struct net *net = sock_net(sk);
        int val, valbool;
        int retv = -ENOPROTOOPT;
 
@@ -617,7 +617,67 @@ done:
                retv = xfrm_user_policy(sk, optname, optval, optlen);
                break;
 
+       case IPV6_ADDR_PREFERENCES:
+           {
+               unsigned int pref = 0;
+               unsigned int prefmask = ~0;
+
+               retv = -EINVAL;
+
+               /* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */
+               switch (val & (IPV6_PREFER_SRC_PUBLIC|
+                              IPV6_PREFER_SRC_TMP|
+                              IPV6_PREFER_SRC_PUBTMP_DEFAULT)) {
+               case IPV6_PREFER_SRC_PUBLIC:
+                       pref |= IPV6_PREFER_SRC_PUBLIC;
+                       break;
+               case IPV6_PREFER_SRC_TMP:
+                       pref |= IPV6_PREFER_SRC_TMP;
+                       break;
+               case IPV6_PREFER_SRC_PUBTMP_DEFAULT:
+                       break;
+               case 0:
+                       goto pref_skip_pubtmp;
+               default:
+                       goto e_inval;
+               }
+
+               prefmask &= ~(IPV6_PREFER_SRC_PUBLIC|
+                             IPV6_PREFER_SRC_TMP);
+pref_skip_pubtmp:
+
+               /* check HOME/COA conflicts */
+               switch (val & (IPV6_PREFER_SRC_HOME|IPV6_PREFER_SRC_COA)) {
+               case IPV6_PREFER_SRC_HOME:
+                       break;
+               case IPV6_PREFER_SRC_COA:
+                       pref |= IPV6_PREFER_SRC_COA;
+               case 0:
+                       goto pref_skip_coa;
+               default:
+                       goto e_inval;
+               }
+
+               prefmask &= ~IPV6_PREFER_SRC_COA;
+pref_skip_coa:
+
+               /* check CGA/NONCGA conflicts */
+               switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) {
+               case IPV6_PREFER_SRC_CGA:
+               case IPV6_PREFER_SRC_NONCGA:
+               case 0:
+                       break;
+               default:
+                       goto e_inval;
+               }
+
+               np->srcprefs = (np->srcprefs & prefmask) | pref;
+               retv = 0;
+
+               break;
+           }
        }
+
        release_sock(sk);
 
        return retv;
@@ -904,9 +964,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
                dst = sk_dst_get(sk);
                if (dst) {
                        if (val < 0)
-                               val = dst_metric(dst, RTAX_HOPLIMIT);
-                       if (val < 0)
-                               val = ipv6_get_hoplimit(dst->dev);
+                               val = ip6_dst_hoplimit(dst);
                        dst_release(dst);
                }
                if (val < 0)
@@ -934,6 +992,24 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
                val = np->sndflow;
                break;
 
+       case IPV6_ADDR_PREFERENCES:
+               val = 0;
+
+               if (np->srcprefs & IPV6_PREFER_SRC_TMP)
+                       val |= IPV6_PREFER_SRC_TMP;
+               else if (np->srcprefs & IPV6_PREFER_SRC_PUBLIC)
+                       val |= IPV6_PREFER_SRC_PUBLIC;
+               else {
+                       /* XXX: should we return system default? */
+                       val |= IPV6_PREFER_SRC_PUBTMP_DEFAULT;
+               }
+
+               if (np->srcprefs & IPV6_PREFER_SRC_COA)
+                       val |= IPV6_PREFER_SRC_COA;
+               else
+                       val |= IPV6_PREFER_SRC_HOME;
+               break;
+
        default:
                return -ENOPROTOOPT;
        }