Merge git://oss.sgi.com:8090/xfs/xfs-2.6
[linux-drm-fsl-dcu.git] / net / ipv6 / datagram.c
index 3b55b4c8e2d1814f0bfe43210491efa8497d9813..5f54dec3e2051c5fb8ecd8553d9e8d606784c637 100644 (file)
@@ -1,9 +1,9 @@
 /*
  *     common UDP/RAW code
- *     Linux INET6 implementation 
+ *     Linux INET6 implementation
  *
  *     Authors:
- *     Pedro Roque             <roque@di.fc.ul.pt>     
+ *     Pedro Roque             <roque@di.fc.ul.pt>
  *
  *     $Id: datagram.c,v 1.24 2002/02/01 22:01:04 davem Exp $
  *
@@ -55,10 +55,10 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        }
 
        if (addr_len < SIN6_LEN_RFC2133)
-               return -EINVAL;
+               return -EINVAL;
 
-       if (usin->sin6_family != AF_INET6) 
-               return -EAFNOSUPPORT;
+       if (usin->sin6_family != AF_INET6)
+               return -EAFNOSUPPORT;
 
        memset(&fl, 0, sizeof(fl));
        if (np->sndflow) {
@@ -93,14 +93,14 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                sin.sin_addr.s_addr = daddr->s6_addr32[3];
                sin.sin_port = usin->sin6_port;
 
-               err = ip4_datagram_connect(sk, 
-                                          (struct sockaddr*) &sin, 
+               err = ip4_datagram_connect(sk,
+                                          (struct sockaddr*) &sin,
                                           sizeof(sin));
 
 ipv4_connected:
                if (err)
                        goto out;
-               
+
                ipv6_addr_set(&np->daddr, 0, 0, htonl(0x0000ffff), inet->daddr);
 
                if (ipv6_addr_any(&np->saddr)) {
@@ -156,6 +156,8 @@ ipv4_connected:
        if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST))
                fl.oif = np->mcast_oif;
 
+       security_sk_classify_flow(sk, &fl);
+
        if (flowlabel) {
                if (flowlabel->opt && flowlabel->opt->srcrt) {
                        struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
@@ -176,7 +178,7 @@ ipv4_connected:
        if (final_p)
                ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-       if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+       if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0)
                goto out;
 
        /* source address lookup done in ip6_dst_lookup */
@@ -191,7 +193,12 @@ ipv4_connected:
 
        ip6_dst_store(sk, dst,
                      ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ?
-                     &np->daddr : NULL);
+                     &np->daddr : NULL,
+#ifdef CONFIG_IPV6_SUBTREES
+                     ipv6_addr_equal(&fl.fl6_src, &np->saddr) ?
+                     &np->saddr :
+#endif
+                     NULL);
 
        sk->sk_state = TCP_ESTABLISHED;
 out:
@@ -199,8 +206,8 @@ out:
        return err;
 }
 
-void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, 
-                    u16 port, u32 info, u8 *payload)
+void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
+                    __be16 port, u32 info, u8 *payload)
 {
        struct ipv6_pinfo *np  = inet6_sk(sk);
        struct icmp6hdr *icmph = (struct icmp6hdr *)skb->h.raw;
@@ -216,7 +223,7 @@ void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
        serr = SKB_EXT_ERR(skb);
        serr->ee.ee_errno = err;
        serr->ee.ee_origin = SO_EE_ORIGIN_ICMP6;
-       serr->ee.ee_type = icmph->icmp6_type; 
+       serr->ee.ee_type = icmph->icmp6_type;
        serr->ee.ee_code = icmph->icmp6_code;
        serr->ee.ee_pad = 0;
        serr->ee.ee_info = info;
@@ -252,7 +259,7 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info)
        serr = SKB_EXT_ERR(skb);
        serr->ee.ee_errno = err;
        serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
-       serr->ee.ee_type = 0; 
+       serr->ee.ee_type = 0;
        serr->ee.ee_code = 0;
        serr->ee.ee_pad = 0;
        serr->ee.ee_info = info;
@@ -267,7 +274,7 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info)
                kfree_skb(skb);
 }
 
-/* 
+/*
  *     Handle MSG_ERRQUEUE
  */
 int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
@@ -305,19 +312,19 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
        if (sin) {
                sin->sin6_family = AF_INET6;
                sin->sin6_flowinfo = 0;
-               sin->sin6_port = serr->port; 
+               sin->sin6_port = serr->port;
                sin->sin6_scope_id = 0;
                if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) {
                        ipv6_addr_copy(&sin->sin6_addr,
                          (struct in6_addr *)(skb->nh.raw + serr->addr_offset));
                        if (np->sndflow)
-                               sin->sin6_flowinfo = *(u32*)(skb->nh.raw + serr->addr_offset - 24) & IPV6_FLOWINFO_MASK;
+                               sin->sin6_flowinfo = *(__be32*)(skb->nh.raw + serr->addr_offset - 24) & IPV6_FLOWINFO_MASK;
                        if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
                                sin->sin6_scope_id = IP6CB(skb)->iif;
                } else {
                        ipv6_addr_set(&sin->sin6_addr, 0, 0,
                                      htonl(0xffff),
-                                     *(u32*)(skb->nh.raw + serr->addr_offset));
+                                     *(__be32*)(skb->nh.raw + serr->addr_offset));
                }
        }
 
@@ -363,7 +370,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
                spin_unlock_bh(&sk->sk_error_queue.lock);
        }
 
-out_free_skb:  
+out_free_skb:
        kfree_skb(skb);
 out:
        return err;
@@ -390,12 +397,12 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
        }
 
        if (np->rxopt.bits.rxtclass) {
-               int tclass = (ntohl(*(u32 *)skb->nh.ipv6h) >> 20) & 0xff;
+               int tclass = (ntohl(*(__be32 *)skb->nh.ipv6h) >> 20) & 0xff;
                put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass);
        }
 
-       if (np->rxopt.bits.rxflow && (*(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) {
-               u32 flowinfo = *(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK;
+       if (np->rxopt.bits.rxflow && (*(__be32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) {
+               __be32 flowinfo = *(__be32*)skb->nh.raw & IPV6_FLOWINFO_MASK;
                put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo);
        }
 
@@ -412,7 +419,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
                 * report extension headers (except for HbH)
                 * in order.
                 *
-                * Also note that IPV6_RECVRTHDRDSTOPTS is NOT 
+                * Also note that IPV6_RECVRTHDRDSTOPTS is NOT
                 * (and WILL NOT be) defined because
                 * IPV6_RECVDSTOPTS is more generic. --yoshfuji
                 */
@@ -505,15 +512,15 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
                        continue;
 
                switch (cmsg->cmsg_type) {
-               case IPV6_PKTINFO:
-               case IPV6_2292PKTINFO:
-                       if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) {
+               case IPV6_PKTINFO:
+               case IPV6_2292PKTINFO:
+                       if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) {
                                err = -EINVAL;
                                goto exit_f;
                        }
 
                        src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
-                       
+
                        if (src_info->ipi6_ifindex) {
                                if (fl->oif && src_info->ipi6_ifindex != fl->oif)
                                        return -EINVAL;
@@ -524,7 +531,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
 
                        if (addr_type == IPV6_ADDR_ANY)
                                break;
-                       
+
                        if (addr_type & IPV6_ADDR_LINKLOCAL) {
                                if (!src_info->ipi6_ifindex)
                                        return -EINVAL;
@@ -547,23 +554,23 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
                        break;
 
                case IPV6_FLOWINFO:
-                        if (cmsg->cmsg_len < CMSG_LEN(4)) {
+                       if (cmsg->cmsg_len < CMSG_LEN(4)) {
                                err = -EINVAL;
                                goto exit_f;
                        }
 
                        if (fl->fl6_flowlabel&IPV6_FLOWINFO_MASK) {
-                               if ((fl->fl6_flowlabel^*(u32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) {
+                               if ((fl->fl6_flowlabel^*(__be32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) {
                                        err = -EINVAL;
                                        goto exit_f;
                                }
                        }
-                       fl->fl6_flowlabel = IPV6_FLOWINFO_MASK & *(u32 *)CMSG_DATA(cmsg);
+                       fl->fl6_flowlabel = IPV6_FLOWINFO_MASK & *(__be32 *)CMSG_DATA(cmsg);
                        break;
 
                case IPV6_2292HOPOPTS:
                case IPV6_HOPOPTS:
-                        if (opt->hopopt || cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
+                       if (opt->hopopt || cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
                                err = -EINVAL;
                                goto exit_f;
                        }
@@ -583,7 +590,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
                        break;
 
                case IPV6_2292DSTOPTS:
-                        if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
+                       if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
                                err = -EINVAL;
                                goto exit_f;
                        }
@@ -634,24 +641,27 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
 
                case IPV6_2292RTHDR:
                case IPV6_RTHDR:
-                        if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_rt_hdr))) {
+                       if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_rt_hdr))) {
                                err = -EINVAL;
                                goto exit_f;
                        }
 
                        rthdr = (struct ipv6_rt_hdr *)CMSG_DATA(cmsg);
 
-                       /*
-                        *      TYPE 0
-                        */
-                       if (rthdr->type) {
+                       switch (rthdr->type) {
+                       case IPV6_SRCRT_TYPE_0:
+#ifdef CONFIG_IPV6_MIP6
+                       case IPV6_SRCRT_TYPE_2:
+#endif
+                               break;
+                       default:
                                err = -EINVAL;
                                goto exit_f;
                        }
 
                        len = ((rthdr->hdrlen + 1) << 3);
 
-                        if (cmsg->cmsg_len < CMSG_LEN(len)) {
+                       if (cmsg->cmsg_len < CMSG_LEN(len)) {
                                err = -EINVAL;
                                goto exit_f;
                        }
@@ -706,7 +716,7 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
                    }
                default:
                        LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n",
-                                      cmsg->cmsg_type);
+                                      cmsg->cmsg_type);
                        err = -EINVAL;
                        break;
                };