Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth...
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / ip_sockglue.c
index 5343d9ac510b58c4c1dd137f8b49d8a3790c193b..2fd0fba77124e3f0e3031a54e5029c918cd03358 100644 (file)
@@ -464,6 +464,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                             (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
                             (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT) |
                             (1<<IP_MINTTL) | (1<<IP_NODEFRAG))) ||
+           optname == IP_UNICAST_IF ||
            optname == IP_MULTICAST_TTL ||
            optname == IP_MULTICAST_ALL ||
            optname == IP_MULTICAST_LOOP ||
@@ -623,6 +624,35 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                        goto e_inval;
                inet->mc_loop = !!val;
                break;
+       case IP_UNICAST_IF:
+       {
+               struct net_device *dev = NULL;
+               int ifindex;
+
+               if (optlen != sizeof(int))
+                       goto e_inval;
+
+               ifindex = (__force int)ntohl((__force __be32)val);
+               if (ifindex == 0) {
+                       inet->uc_index = 0;
+                       err = 0;
+                       break;
+               }
+
+               dev = dev_get_by_index(sock_net(sk), ifindex);
+               err = -EADDRNOTAVAIL;
+               if (!dev)
+                       break;
+               dev_put(dev);
+
+               err = -EINVAL;
+               if (sk->sk_bound_dev_if)
+                       break;
+
+               inet->uc_index = ifindex;
+               err = 0;
+               break;
+       }
        case IP_MULTICAST_IF:
        {
                struct ip_mreqn mreq;
@@ -1173,6 +1203,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
        case IP_MULTICAST_LOOP:
                val = inet->mc_loop;
                break;
+       case IP_UNICAST_IF:
+               val = (__force int)htonl((__u32) inet->uc_index);
+               break;
        case IP_MULTICAST_IF:
        {
                struct in_addr addr;
@@ -1251,6 +1284,10 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
                        int hlim = inet->mc_ttl;
                        put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim);
                }
+               if (inet->cmsg_flags & IP_CMSG_TOS) {
+                       int tos = inet->rcv_tos;
+                       put_cmsg(&msg, SOL_IP, IP_TOS, sizeof(tos), &tos);
+               }
                len -= msg.msg_controllen;
                return put_user(len, optlen);
        }