ipv6: fix an oops when force unload ipv6 module
[safe/jmp/linux-2.6] / net / ipv4 / raw.c
index ebb1e58..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 */
        }
@@ -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;
        }
@@ -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;
@@ -381,8 +391,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
 out:
        return 0;
 
-error_fault:
-       err = -EFAULT;
+error_free:
        kfree_skb(skb);
 error:
        IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
@@ -490,10 +499,10 @@ 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;
@@ -635,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;
@@ -682,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) {
@@ -707,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;
 }
@@ -741,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);
@@ -753,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);
@@ -762,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);
@@ -774,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);
@@ -933,10 +942,10 @@ 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",