gre: fix netns vs proto registration ordering
[safe/jmp/linux-2.6] / net / ipv4 / raw.c
index 7f39ea4..ce154b4 100644 (file)
@@ -87,7 +87,7 @@ void raw_hash_sk(struct sock *sk)
        struct raw_hashinfo *h = sk->sk_prot->h.raw_hash;
        struct hlist_head *head;
 
-       head = &h->ht[inet_sk(sk)->num & (RAW_HTABLE_SIZE - 1)];
+       head = &h->ht[inet_sk(sk)->inet_num & (RAW_HTABLE_SIZE - 1)];
 
        write_lock_bh(&h->lock);
        sk_add_node(sk, head);
@@ -115,9 +115,9 @@ static struct sock *__raw_v4_lookup(struct net *net, struct sock *sk,
        sk_for_each_from(sk, node) {
                struct inet_sock *inet = inet_sk(sk);
 
-               if (net_eq(sock_net(sk), net) && inet->num == num       &&
-                   !(inet->daddr && inet->daddr != raddr)              &&
-                   !(inet->rcv_saddr && inet->rcv_saddr != laddr)      &&
+               if (net_eq(sock_net(sk), net) && inet->inet_num == num  &&
+                   !(inet->inet_daddr && inet->inet_daddr != raddr)    &&
+                   !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) &&
                    !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif))
                        goto found; /* gotcha */
        }
@@ -247,7 +247,7 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info)
        }
 
        if (inet->recverr) {
-               struct iphdr *iph = (struct iphdr*)skb->data;
+               struct iphdr *iph = (struct iphdr *)skb->data;
                u8 *payload = skb->data + (iph->ihl << 2);
 
                if (inet->hdrincl)
@@ -292,7 +292,6 @@ static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
        /* Charge it to the socket. */
 
        if (sock_queue_rcv_skb(sk, skb) < 0) {
-               atomic_inc(&sk->sk_drops);
                kfree_skb(skb);
                return NET_RX_DROP;
        }
@@ -327,7 +326,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
        int err;
 
        if (length > rt->u.dst.dev->mtu) {
-               ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->dport,
+               ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport,
                               rt->u.dst.dev->mtu);
                return -EMSGSIZE;
        }
@@ -343,7 +342,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
 
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
-       skb->dst = dst_clone(&rt->u.dst);
+       skb_dst_set(skb, dst_clone(&rt->u.dst));
 
        skb_reset_network_header(skb);
        iph = ip_hdr(skb);
@@ -352,13 +351,24 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
        skb->ip_summed = CHECKSUM_NONE;
 
        skb->transport_header = skb->network_header;
-       err = memcpy_fromiovecend((void *)iph, from, 0, length);
-       if (err)
-               goto error_fault;
+       err = -EFAULT;
+       if (memcpy_fromiovecend((void *)iph, from, 0, length))
+               goto error_free;
 
-       /* We don't modify invalid header */
        iphlen = iph->ihl * 4;
-       if (iphlen >= sizeof(*iph) && iphlen <= length) {
+
+       /*
+        * We don't want to modify the ip header, but we do need to
+        * be sure that it won't cause problems later along the network
+        * stack.  Specifically we want to make sure that iph->ihl is a
+        * sane value.  If ihl points beyond the length of the buffer passed
+        * in, reject the frame as invalid
+        */
+       err = -EINVAL;
+       if (iphlen > length)
+               goto error_free;
+
+       if (iphlen >= sizeof(*iph)) {
                if (!iph->saddr)
                        iph->saddr = rt->rt_src;
                iph->check   = 0;
@@ -375,17 +385,18 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
        err = NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
                      dst_output);
        if (err > 0)
-               err = inet->recverr ? net_xmit_errno(err) : 0;
+               err = net_xmit_errno(err);
        if (err)
                goto error;
 out:
        return 0;
 
-error_fault:
-       err = -EFAULT;
+error_free:
        kfree_skb(skb);
 error:
-       IP_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+       IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
+       if (err == -ENOBUFS && !inet->recverr)
+               err = 0;
        return err;
 }
 
@@ -465,7 +476,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
         */
 
        if (msg->msg_namelen) {
-               struct sockaddr_in *usin = (struct sockaddr_in*)msg->msg_name;
+               struct sockaddr_in *usin = (struct sockaddr_in *)msg->msg_name;
                err = -EINVAL;
                if (msg->msg_namelen < sizeof(*usin))
                        goto out;
@@ -488,11 +499,12 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                err = -EDESTADDRREQ;
                if (sk->sk_state != TCP_ESTABLISHED)
                        goto out;
-               daddr = inet->daddr;
+               daddr = inet->inet_daddr;
        }
 
-       ipc.addr = inet->saddr;
+       ipc.addr = inet->inet_saddr;
        ipc.opt = NULL;
+       ipc.shtx.flags = 0;
        ipc.oif = sk->sk_bound_dev_if;
 
        if (msg->msg_controllen) {
@@ -572,11 +584,14 @@ back_from_confirm:
                        ipc.addr = rt->rt_dst;
                lock_sock(sk);
                err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, len, 0,
-                                       &ipc, rt, msg->msg_flags);
+                                       &ipc, &rt, msg->msg_flags);
                if (err)
                        ip_flush_pending_frames(sk);
-               else if (!(msg->msg_flags & MSG_MORE))
+               else if (!(msg->msg_flags & MSG_MORE)) {
                        err = ip_push_pending_frames(sk);
+                       if (err == -ENOBUFS && !inet->recverr)
+                               err = 0;
+               }
                release_sock(sk);
        }
 done:
@@ -629,9 +644,9 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL &&
            chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST)
                goto out;
-       inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr;
+       inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr;
        if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
-               inet->saddr = 0;  /* Use device */
+               inet->inet_saddr = 0;  /* Use device */
        sk_dst_reset(sk);
        ret = 0;
 out:   return ret;
@@ -676,7 +691,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        if (err)
                goto done;
 
-       sock_recv_timestamp(msg, sk, skb);
+       sock_recv_ts_and_drops(msg, sk, skb);
 
        /* Copy the address. */
        if (sin) {
@@ -701,7 +716,7 @@ static int raw_init(struct sock *sk)
 {
        struct raw_sock *rp = raw_sk(sk);
 
-       if (inet_sk(sk)->num == IPPROTO_ICMP)
+       if (inet_sk(sk)->inet_num == IPPROTO_ICMP)
                memset(&rp->filter, 0, sizeof(rp->filter));
        return 0;
 }
@@ -735,10 +750,10 @@ out:      return ret;
 }
 
 static int do_raw_setsockopt(struct sock *sk, int level, int optname,
-                         char __user *optval, int optlen)
+                         char __user *optval, unsigned int optlen)
 {
        if (optname == ICMP_FILTER) {
-               if (inet_sk(sk)->num != IPPROTO_ICMP)
+               if (inet_sk(sk)->inet_num != IPPROTO_ICMP)
                        return -EOPNOTSUPP;
                else
                        return raw_seticmpfilter(sk, optval, optlen);
@@ -747,7 +762,7 @@ static int do_raw_setsockopt(struct sock *sk, int level, int optname,
 }
 
 static int raw_setsockopt(struct sock *sk, int level, int optname,
-                         char __user *optval, int optlen)
+                         char __user *optval, unsigned int optlen)
 {
        if (level != SOL_RAW)
                return ip_setsockopt(sk, level, optname, optval, optlen);
@@ -756,7 +771,7 @@ static int raw_setsockopt(struct sock *sk, int level, int optname,
 
 #ifdef CONFIG_COMPAT
 static int compat_raw_setsockopt(struct sock *sk, int level, int optname,
-                                char __user *optval, int optlen)
+                                char __user *optval, unsigned int optlen)
 {
        if (level != SOL_RAW)
                return compat_ip_setsockopt(sk, level, optname, optval, optlen);
@@ -768,7 +783,7 @@ static int do_raw_getsockopt(struct sock *sk, int level, int optname,
                          char __user *optval, int __user *optlen)
 {
        if (optname == ICMP_FILTER) {
-               if (inet_sk(sk)->num != IPPROTO_ICMP)
+               if (inet_sk(sk)->inet_num != IPPROTO_ICMP)
                        return -EOPNOTSUPP;
                else
                        return raw_geticmpfilter(sk, optval, optlen);
@@ -798,7 +813,8 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
        switch (cmd) {
                case SIOCOUTQ: {
-                       int amount = atomic_read(&sk->sk_wmem_alloc);
+                       int amount = sk_wmem_alloc_get(sk);
+
                        return put_user(amount, (int __user *)arg);
                }
                case SIOCINQ: {
@@ -851,7 +867,7 @@ struct proto raw_prot = {
 static struct sock *raw_get_first(struct seq_file *seq)
 {
        struct sock *sk;
-       struct raw_iter_statestate = raw_seq_private(seq);
+       struct raw_iter_state *state = raw_seq_private(seq);
 
        for (state->bucket = 0; state->bucket < RAW_HTABLE_SIZE;
                        ++state->bucket) {
@@ -868,7 +884,7 @@ found:
 
 static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk)
 {
-       struct raw_iter_statestate = raw_seq_private(seq);
+       struct raw_iter_state *state = raw_seq_private(seq);
 
        do {
                sk = sk_next(sk);
@@ -926,16 +942,16 @@ EXPORT_SYMBOL_GPL(raw_seq_stop);
 static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
 {
        struct inet_sock *inet = inet_sk(sp);
-       __be32 dest = inet->daddr,
-              src = inet->rcv_saddr;
+       __be32 dest = inet->inet_daddr,
+              src = inet->inet_rcv_saddr;
        __u16 destp = 0,
-             srcp  = inet->num;
+             srcp  = inet->inet_num;
 
        seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
                " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
                i, src, srcp, dest, destp, sp->sk_state,
-               atomic_read(&sp->sk_wmem_alloc),
-               atomic_read(&sp->sk_rmem_alloc),
+               sk_wmem_alloc_get(sp),
+               sk_rmem_alloc_get(sp),
                0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
                atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
 }