These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / ipv4 / raw.c
index 561cd4b..7113bae 100644 (file)
@@ -406,13 +406,16 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
                        ip_select_ident(net, skb, NULL);
 
                iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+               skb->transport_header += iphlen;
+               if (iph->protocol == IPPROTO_ICMP &&
+                   length >= iphlen + sizeof(struct icmphdr))
+                       icmp_out_count(net, ((struct icmphdr *)
+                               skb_transport_header(skb))->type);
        }
-       if (iph->protocol == IPPROTO_ICMP)
-               icmp_out_count(net, ((struct icmphdr *)
-                       skb_transport_header(skb))->type);
 
-       err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, sk, skb,
-                     NULL, rt->dst.dev, dst_output_sk);
+       err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT,
+                     net, sk, skb, NULL, rt->dst.dev,
+                     dst_output);
        if (err > 0)
                err = net_xmit_errno(err);
        if (err)
@@ -483,6 +486,7 @@ static int raw_getfrag(void *from, char *to, int offset, int len, int odd,
 static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 {
        struct inet_sock *inet = inet_sk(sk);
+       struct net *net = sock_net(sk);
        struct ipcm_cookie ipc;
        struct rtable *rt = NULL;
        struct flowi4 fl4;
@@ -542,9 +546,11 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        ipc.oif = sk->sk_bound_dev_if;
 
        if (msg->msg_controllen) {
-               err = ip_cmsg_send(sock_net(sk), msg, &ipc, false);
-               if (err)
+               err = ip_cmsg_send(net, msg, &ipc, false);
+               if (unlikely(err)) {
+                       kfree(ipc.opt);
                        goto out;
+               }
                if (ipc.opt)
                        free = 1;
        }
@@ -597,6 +603,12 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
                            (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0),
                           daddr, saddr, 0, 0);
 
+       if (!saddr && ipc.oif) {
+               err = l3mdev_get_saddr(net, ipc.oif, &fl4);
+               if (err < 0)
+                       goto done;
+       }
+
        if (!inet->hdrincl) {
                rfv.msg = msg;
                rfv.hlen = 0;
@@ -607,7 +619,7 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        }
 
        security_sk_classify_flow(sk, flowi4_to_flowi(&fl4));
-       rt = ip_route_output_flow(sock_net(sk), &fl4, sk);
+       rt = ip_route_output_flow(net, &fl4, sk);
        if (IS_ERR(rt)) {
                err = PTR_ERR(rt);
                rt = NULL;