ipv6,mcast: always hold idev->lock before mca_lock
[linux-3.10.git] / net / ipv6 / datagram.c
index 33be363..4b56cbb 100644 (file)
@@ -124,7 +124,7 @@ ipv4_connected:
                goto out;
        }
 
-       if (addr_type&IPV6_ADDR_LINKLOCAL) {
+       if (__ipv6_addr_needs_scope_id(addr_type)) {
                if (addr_len >= sizeof(struct sockaddr_in6) &&
                    usin->sin6_scope_id) {
                        if (sk->sk_bound_dev_if &&
@@ -355,18 +355,19 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
                sin->sin6_family = AF_INET6;
                sin->sin6_flowinfo = 0;
                sin->sin6_port = serr->port;
-               sin->sin6_scope_id = 0;
                if (skb->protocol == htons(ETH_P_IPV6)) {
                        const struct ipv6hdr *ip6h = container_of((struct in6_addr *)(nh + serr->addr_offset),
                                                                  struct ipv6hdr, daddr);
                        sin->sin6_addr = ip6h->daddr;
                        if (np->sndflow)
                                sin->sin6_flowinfo = ip6_flowinfo(ip6h);
-                       if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
-                               sin->sin6_scope_id = IP6CB(skb)->iif;
+                       sin->sin6_scope_id =
+                               ipv6_iface_scope_id(&sin->sin6_addr,
+                                                   IP6CB(skb)->iif);
                } else {
                        ipv6_addr_set_v4mapped(*(__be32 *)(nh + serr->addr_offset),
                                               &sin->sin6_addr);
+                       sin->sin6_scope_id = 0;
                }
        }
 
@@ -376,18 +377,19 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
        if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) {
                sin->sin6_family = AF_INET6;
                sin->sin6_flowinfo = 0;
-               sin->sin6_scope_id = 0;
                if (skb->protocol == htons(ETH_P_IPV6)) {
                        sin->sin6_addr = ipv6_hdr(skb)->saddr;
                        if (np->rxopt.all)
-                               datagram_recv_ctl(sk, msg, skb);
-                       if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
-                               sin->sin6_scope_id = IP6CB(skb)->iif;
+                               ip6_datagram_recv_ctl(sk, msg, skb);
+                       sin->sin6_scope_id =
+                               ipv6_iface_scope_id(&sin->sin6_addr,
+                                                   IP6CB(skb)->iif);
                } else {
                        struct inet_sock *inet = inet_sk(sk);
 
                        ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
                                               &sin->sin6_addr);
+                       sin->sin6_scope_id = 0;
                        if (inet->cmsg_flags)
                                ip_cmsg_recv(msg, skb);
                }
@@ -468,7 +470,8 @@ out:
 }
 
 
-int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
+int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
+                         struct sk_buff *skb)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct inet6_skb_parm *opt = IP6CB(skb);
@@ -591,18 +594,21 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
                        sin6.sin6_addr = ipv6_hdr(skb)->daddr;
                        sin6.sin6_port = ports[1];
                        sin6.sin6_flowinfo = 0;
-                       sin6.sin6_scope_id = 0;
+                       sin6.sin6_scope_id =
+                               ipv6_iface_scope_id(&ipv6_hdr(skb)->daddr,
+                                                   opt->iif);
 
                        put_cmsg(msg, SOL_IPV6, IPV6_ORIGDSTADDR, sizeof(sin6), &sin6);
                }
        }
        return 0;
 }
+EXPORT_SYMBOL_GPL(ip6_datagram_recv_ctl);
 
-int datagram_send_ctl(struct net *net, struct sock *sk,
-                     struct msghdr *msg, struct flowi6 *fl6,
-                     struct ipv6_txoptions *opt,
-                     int *hlimit, int *tclass, int *dontfrag)
+int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+                         struct msghdr *msg, struct flowi6 *fl6,
+                         struct ipv6_txoptions *opt,
+                         int *hlimit, int *tclass, int *dontfrag)
 {
        struct in6_pktinfo *src_info;
        struct cmsghdr *cmsg;
@@ -872,4 +878,4 @@ int datagram_send_ctl(struct net *net, struct sock *sk,
 exit_f:
        return err;
 }
-EXPORT_SYMBOL_GPL(datagram_send_ctl);
+EXPORT_SYMBOL_GPL(ip6_datagram_send_ctl);