]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/ipv6/raw.c
[NET]: Make all initialized struct seq_operations const.
[net-next-2.6.git] / net / ipv6 / raw.c
index 1f8f6275a7e4f08018a2d6715b32f17115b98ed7..e27383d855dedfeffc1855ec906ea2522c8344e2 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/sockios.h>
-#include <linux/sched.h>
 #include <linux/net.h>
 #include <linux/in6.h>
 #include <linux/netdevice.h>
@@ -50,7 +49,7 @@
 #include <net/udp.h>
 #include <net/inet_common.h>
 #include <net/tcp_states.h>
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
 #include <net/mip6.h>
 #endif
 
@@ -138,6 +137,28 @@ static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
        return 0;
 }
 
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
+static int (*mh_filter)(struct sock *sock, struct sk_buff *skb);
+
+int rawv6_mh_filter_register(int (*filter)(struct sock *sock,
+                                          struct sk_buff *skb))
+{
+       rcu_assign_pointer(mh_filter, filter);
+       return 0;
+}
+EXPORT_SYMBOL(rawv6_mh_filter_register);
+
+int rawv6_mh_filter_unregister(int (*filter)(struct sock *sock,
+                                            struct sk_buff *skb))
+{
+       rcu_assign_pointer(mh_filter, NULL);
+       synchronize_rcu();
+       return 0;
+}
+EXPORT_SYMBOL(rawv6_mh_filter_unregister);
+
+#endif
+
 /*
  *     demultiplex raw sockets.
  *     (should consider queueing the skb in the sock receive_queue
@@ -153,7 +174,7 @@ int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
        int delivered = 0;
        __u8 hash;
 
-       saddr = &skb->nh.ipv6h->saddr;
+       saddr = &ipv6_hdr(skb)->saddr;
        daddr = saddr + 1;
 
        hash = nexthdr & (MAX_INET_PROTOS - 1);
@@ -179,16 +200,22 @@ int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
                case IPPROTO_ICMPV6:
                        filtered = icmpv6_filter(sk, skb);
                        break;
-#ifdef CONFIG_IPV6_MIP6
+
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
                case IPPROTO_MH:
+               {
                        /* XXX: To validate MH only once for each packet,
                         * this is placed here. It should be after checking
                         * xfrm policy, however it doesn't. The checking xfrm
                         * policy is placed in rawv6_rcv() because it is
                         * required for each socket.
                         */
-                       filtered = mip6_mh_filter(sk, skb);
+                       int (*filter)(struct sock *sock, struct sk_buff *skb);
+
+                       filter = rcu_dereference(mh_filter);
+                       filtered = filter ? filter(sk, skb) : 0;
                        break;
+               }
 #endif
                default:
                        filtered = 0;
@@ -362,17 +389,18 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb)
                skb->ip_summed = CHECKSUM_UNNECESSARY;
 
        if (skb->ip_summed == CHECKSUM_COMPLETE) {
-               skb_postpull_rcsum(skb, skb->nh.raw,
-                                  skb->h.raw - skb->nh.raw);
-               if (!csum_ipv6_magic(&skb->nh.ipv6h->saddr,
-                                    &skb->nh.ipv6h->daddr,
+               skb_postpull_rcsum(skb, skb_network_header(skb),
+                                  skb_network_header_len(skb));
+               if (!csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+                                    &ipv6_hdr(skb)->daddr,
                                     skb->len, inet->num, skb->csum))
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
        }
-       if (skb->ip_summed != CHECKSUM_UNNECESSARY)
-               skb->csum = ~csum_unfold(csum_ipv6_magic(&skb->nh.ipv6h->saddr,
-                                            &skb->nh.ipv6h->daddr,
-                                            skb->len, inet->num, 0));
+       if (!skb_csum_unnecessary(skb))
+               skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+                                                        &ipv6_hdr(skb)->daddr,
+                                                        skb->len,
+                                                        inet->num, 0));
 
        if (inet->hdrincl) {
                if (skb_checksum_complete(skb)) {
@@ -421,7 +449,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
                msg->msg_flags |= MSG_TRUNC;
        }
 
-       if (skb->ip_summed==CHECKSUM_UNNECESSARY) {
+       if (skb_csum_unnecessary(skb)) {
                err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
        } else if (msg->msg_flags&MSG_TRUNC) {
                if (__skb_checksum_complete(skb))
@@ -439,7 +467,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
        if (sin6) {
                sin6->sin6_family = AF_INET6;
                sin6->sin6_port = 0;
-               ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr);
+               ipv6_addr_copy(&sin6->sin6_addr, &ipv6_hdr(skb)->saddr);
                sin6->sin6_flowinfo = 0;
                sin6->sin6_scope_id = 0;
                if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
@@ -489,7 +517,8 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl,
                goto out;
 
        offset = rp->offset;
-       total_len = inet_sk(sk)->cork.length - (skb->nh.raw - skb->data);
+       total_len = inet_sk(sk)->cork.length - (skb_network_header(skb) -
+                                               skb->data);
        if (offset >= total_len - 1) {
                err = -EINVAL;
                ip6_flush_pending_frames(sk);
@@ -512,7 +541,7 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl,
                        if (csum_skb)
                                continue;
 
-                       len = skb->len - (skb->h.raw - skb->data);
+                       len = skb->len - skb_transport_offset(skb);
                        if (offset >= len) {
                                offset -= len;
                                continue;
@@ -524,7 +553,7 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl,
                skb = csum_skb;
        }
 
-       offset += skb->h.raw - skb->data;
+       offset += skb_transport_offset(skb);
        if (skb_copy_bits(skb, offset, &csum, 2))
                BUG();
 
@@ -576,11 +605,13 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
        skb->priority = sk->sk_priority;
        skb->dst = dst_clone(&rt->u.dst);
 
-       skb->nh.ipv6h = iph = (struct ipv6hdr *)skb_put(skb, length);
+       skb_put(skb, length);
+       skb_reset_network_header(skb);
+       iph = ipv6_hdr(skb);
 
        skb->ip_summed = CHECKSUM_NONE;
 
-       skb->h.raw = skb->nh.raw;
+       skb->transport_header = skb->network_header;
        err = memcpy_fromiovecend((void *)iph, from, 0, length);
        if (err)
                goto error_fault;
@@ -608,9 +639,7 @@ static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
        struct iovec *iov;
        u8 __user *type = NULL;
        u8 __user *code = NULL;
-#ifdef CONFIG_IPV6_MIP6
        u8 len = 0;
-#endif
        int probed = 0;
        int i;
 
@@ -643,7 +672,6 @@ static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
                                probed = 1;
                        }
                        break;
-#ifdef CONFIG_IPV6_MIP6
                case IPPROTO_MH:
                        if (iov->iov_base && iov->iov_len < 1)
                                break;
@@ -657,7 +685,6 @@ static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
                                len += iov->iov_len;
 
                        break;
-#endif
                default:
                        probed = 1;
                        break;
@@ -688,9 +715,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
        int err;
 
        /* Rough check on arithmetic overflow,
-          better check is made in ip6_build_xmit
+          better check is made in ip6_append_data().
         */
-       if (len < 0)
+       if (len > INT_MAX)
                return -EMSGSIZE;
 
        /* Mirror BSD error message compatibility */
@@ -815,8 +842,12 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
        if (final_p)
                ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-       if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0)
-               goto out;
+       if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) {
+               if (err == -EREMOTE)
+                       err = ip6_dst_blackhole(sk, &dst, &fl);
+               if (err < 0)
+                       goto out;
+       }
 
        if (hlimit < 0) {
                if (ipv6_addr_is_multicast(&fl.fl6_dst))
@@ -879,7 +910,7 @@ static int rawv6_seticmpfilter(struct sock *sk, int level, int optname,
                return 0;
        default:
                return -ENOPROTOOPT;
-       };
+       }
 
        return 0;
 }
@@ -904,7 +935,7 @@ static int rawv6_geticmpfilter(struct sock *sk, int level, int optname,
                return 0;
        default:
                return -ENOPROTOOPT;
-       };
+       }
 
        return 0;
 }
@@ -958,7 +989,8 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
                default:
                        return ipv6_setsockopt(sk, level, optname, optval,
                                               optlen);
-       };
+       }
+
        return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
 }
 
@@ -979,7 +1011,7 @@ static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname,
        default:
                return compat_ipv6_setsockopt(sk, level, optname,
                                              optval, optlen);
-       };
+       }
        return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
 }
 #endif
@@ -1032,7 +1064,8 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname,
                default:
                        return ipv6_getsockopt(sk, level, optname, optval,
                                               optlen);
-       };
+       }
+
        return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
 }
 
@@ -1053,7 +1086,7 @@ static int compat_rawv6_getsockopt(struct sock *sk, int level, int optname,
        default:
                return compat_ipv6_getsockopt(sk, level, optname,
                                              optval, optlen);
-       };
+       }
        return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
 }
 #endif
@@ -1074,7 +1107,7 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg)
                        spin_lock_bh(&sk->sk_receive_queue.lock);
                        skb = skb_peek(&sk->sk_receive_queue);
                        if (skb != NULL)
-                               amount = skb->tail - skb->h.raw;
+                               amount = skb->tail - skb->transport_header;
                        spin_unlock_bh(&sk->sk_receive_queue.lock);
                        return put_user(amount, (int __user *)arg);
                }
@@ -1247,7 +1280,7 @@ static int raw6_seq_show(struct seq_file *seq, void *v)
        return 0;
 }
 
-static struct seq_operations raw6_seq_ops = {
+static const struct seq_operations raw6_seq_ops = {
        .start =        raw6_seq_start,
        .next =         raw6_seq_next,
        .stop =         raw6_seq_stop,