]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - net/ipv4/ip_sockglue.c
Merge branches 'pm-core', 'pm-qos', 'pm-domains' and 'pm-opp'
[linux.git] / net / ipv4 / ip_sockglue.c
index b8a2d63d1fb82f5084a0d98911b8110816dee963..900011709e3b8e4807daaa6bf537c3871a7d9306 100644 (file)
@@ -44,7 +44,7 @@
 #include <net/ip_fib.h>
 
 #include <linux/errqueue.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 /*
  *     SOL_IP control messages.
@@ -97,6 +97,17 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
        put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data);
 }
 
+static void ip_cmsg_recv_fragsize(struct msghdr *msg, struct sk_buff *skb)
+{
+       int val;
+
+       if (IPCB(skb)->frag_max_size == 0)
+               return;
+
+       val = IPCB(skb)->frag_max_size;
+       put_cmsg(msg, SOL_IP, IP_RECVFRAGSIZE, sizeof(val), &val);
+}
+
 static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
                                  int tlen, int offset)
 {
@@ -137,7 +148,7 @@ static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)
        const struct iphdr *iph = ip_hdr(skb);
        __be16 *ports = (__be16 *)skb_transport_header(skb);
 
-       if (skb_transport_offset(skb) + 4 > skb->len)
+       if (skb_transport_offset(skb) + 4 > (int)skb->len)
                return;
 
        /* All current transport protocols have the port numbers in the
@@ -153,10 +164,10 @@ static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)
        put_cmsg(msg, SOL_IP, IP_ORIGDSTADDR, sizeof(sin), &sin);
 }
 
-void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb,
-                        int tlen, int offset)
+void ip_cmsg_recv_offset(struct msghdr *msg, struct sock *sk,
+                        struct sk_buff *skb, int tlen, int offset)
 {
-       struct inet_sock *inet = inet_sk(skb->sk);
+       struct inet_sock *inet = inet_sk(sk);
        unsigned int flags = inet->cmsg_flags;
 
        /* Ordered by supposed usage frequency */
@@ -218,6 +229,9 @@ void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb,
 
        if (flags & IP_CMSG_CHECKSUM)
                ip_cmsg_recv_checksum(msg, skb, tlen, offset);
+
+       if (flags & IP_CMSG_RECVFRAGSIZE)
+               ip_cmsg_recv_fragsize(msg, skb);
 }
 EXPORT_SYMBOL(ip_cmsg_recv_offset);
 
@@ -614,6 +628,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
        case IP_MULTICAST_LOOP:
        case IP_RECVORIGDSTADDR:
        case IP_CHECKSUM:
+       case IP_RECVFRAGSIZE:
                if (optlen >= sizeof(int)) {
                        if (get_user(val, (int __user *) optval))
                                return -EFAULT;
@@ -726,6 +741,14 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                        }
                }
                break;
+       case IP_RECVFRAGSIZE:
+               if (sk->sk_type != SOCK_RAW && sk->sk_type != SOCK_DGRAM)
+                       goto e_inval;
+               if (val)
+                       inet->cmsg_flags |= IP_CMSG_RECVFRAGSIZE;
+               else
+                       inet->cmsg_flags &= ~IP_CMSG_RECVFRAGSIZE;
+               break;
        case IP_TOS:    /* This sets both TOS and Precedence */
                if (sk->sk_type == SOCK_STREAM) {
                        val &= ~INET_ECN_MASK;
@@ -1202,14 +1225,27 @@ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb)
                 * which has interface index (iif) as the first member of the
                 * underlying inet{6}_skb_parm struct. This code then overlays
                 * PKTINFO_SKB_CB and in_pktinfo also has iif as the first
-                * element so the iif is picked up from the prior IPCB
+                * element so the iif is picked up from the prior IPCB. If iif
+                * is the loopback interface, then return the sending interface
+                * (e.g., process binds socket to eth0 for Tx which is
+                * redirected to loopback in the rtable/dst).
                 */
+               if (pktinfo->ipi_ifindex == LOOPBACK_IFINDEX)
+                       pktinfo->ipi_ifindex = inet_iif(skb);
+
                pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb);
        } else {
                pktinfo->ipi_ifindex = 0;
                pktinfo->ipi_spec_dst.s_addr = 0;
        }
-       skb_dst_drop(skb);
+       /* We need to keep the dst for __ip_options_echo()
+        * We could restrict the test to opt.ts_needtime || opt.srr,
+        * but the following is good enough as IP options are not often used.
+        */
+       if (unlikely(IPCB(skb)->opt.optlen))
+               skb_dst_force(skb);
+       else
+               skb_dst_drop(skb);
 }
 
 int ip_setsockopt(struct sock *sk, int level,
@@ -1357,6 +1393,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
        case IP_CHECKSUM:
                val = (inet->cmsg_flags & IP_CMSG_CHECKSUM) != 0;
                break;
+       case IP_RECVFRAGSIZE:
+               val = (inet->cmsg_flags & IP_CMSG_RECVFRAGSIZE) != 0;
+               break;
        case IP_TOS:
                val = inet->tos;
                break;