[IA64] SGI Altix : fix a force_interrupt bug on altix
[safe/jmp/linux-2.6] / net / ipv4 / raw.c
index 165a4d8..c6d7152 100644 (file)
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
  */
-#include <linux/config.h> 
+
+#include <linux/types.h>
 #include <asm/atomic.h>
 #include <asm/byteorder.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
-#include <linux/types.h>
 #include <linux/stddef.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
@@ -96,14 +95,14 @@ static void raw_v4_hash(struct sock *sk)
 
 static void raw_v4_unhash(struct sock *sk)
 {
-       write_lock_bh(&raw_v4_lock);
+       write_lock_bh(&raw_v4_lock);
        if (sk_del_node_init(sk))
                sock_prot_dec_use(sk->sk_prot);
        write_unlock_bh(&raw_v4_lock);
 }
 
 struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num,
-                            unsigned long raddr, unsigned long laddr,
+                            __be32 raddr, __be32 laddr,
                             int dif)
 {
        struct hlist_node *node;
@@ -133,7 +132,7 @@ static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb)
        if (!pskb_may_pull(skb, sizeof(struct icmphdr)))
                return 1;
 
-       type = skb->h.icmph->type;
+       type = icmp_hdr(skb)->type;
        if (type < 32) {
                __u32 data = raw_sk(sk)->filter.data;
 
@@ -185,8 +184,8 @@ out:
 void raw_err (struct sock *sk, struct sk_buff *skb, u32 info)
 {
        struct inet_sock *inet = inet_sk(sk);
-       int type = skb->h.icmph->type;
-       int code = skb->h.icmph->code;
+       const int type = icmp_hdr(skb)->type;
+       const int code = icmp_hdr(skb)->code;
        int err = 0;
        int harderr = 0;
 
@@ -239,7 +238,7 @@ void raw_err (struct sock *sk, struct sk_buff *skb, u32 info)
 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) {
                /* FIXME: increment a raw drops counter here */
                kfree_skb(skb);
@@ -257,14 +256,14 @@ int raw_rcv(struct sock *sk, struct sk_buff *skb)
        }
        nf_reset(skb);
 
-       skb_push(skb, skb->data - skb->nh.raw);
+       skb_push(skb, skb->data - skb_network_header(skb));
 
        raw_rcv_skb(sk, skb);
        return 0;
 }
 
 static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
-                       struct rtable *rt, 
+                       struct rtable *rt,
                        unsigned int flags)
 {
        struct inet_sock *inet = inet_sk(sk);
@@ -286,17 +285,19 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
        skb = sock_alloc_send_skb(sk, length+hh_len+15,
                                  flags&MSG_DONTWAIT, &err);
        if (skb == NULL)
-               goto error; 
+               goto error;
        skb_reserve(skb, hh_len);
 
        skb->priority = sk->sk_priority;
        skb->dst = dst_clone(&rt->u.dst);
 
-       skb->nh.iph = iph = (struct iphdr *)skb_put(skb, length);
+       skb_reset_network_header(skb);
+       iph = ip_hdr(skb);
+       skb_put(skb, length);
 
        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;
@@ -327,10 +328,10 @@ error_fault:
        kfree_skb(skb);
 error:
        IP_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
-       return err; 
+       return err;
 }
 
-static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
+static int raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
 {
        struct iovec *iov;
        u8 __user *type = NULL;
@@ -339,7 +340,7 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
        unsigned int i;
 
        if (!msg->msg_iov)
-               return;
+               return 0;
 
        for (i = 0; i < msg->msg_iovlen; i++) {
                iov = &msg->msg_iov[i];
@@ -361,8 +362,9 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
                                code = iov->iov_base;
 
                        if (type && code) {
-                               get_user(fl->fl_icmp_type, type);
-                               get_user(fl->fl_icmp_code, code);
+                               if (get_user(fl->fl_icmp_type, type) ||
+                                   get_user(fl->fl_icmp_code, code))
+                                       return -EFAULT;
                                probed = 1;
                        }
                        break;
@@ -373,6 +375,7 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
                if (probed)
                        break;
        }
+       return 0;
 }
 
 static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
@@ -382,8 +385,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        struct ipcm_cookie ipc;
        struct rtable *rt = NULL;
        int free = 0;
-       u32 daddr;
-       u32 saddr;
+       __be32 daddr;
+       __be32 saddr;
        u8  tos;
        int err;
 
@@ -398,9 +401,9 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        err = -EOPNOTSUPP;
        if (msg->msg_flags & MSG_OOB)   /* Mirror BSD error message */
                goto out;               /* compatibility */
-                        
+
        /*
-        *      Get and verify the address. 
+        *      Get and verify the address.
         */
 
        if (msg->msg_namelen) {
@@ -425,7 +428,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                 */
        } else {
                err = -EDESTADDRREQ;
-               if (sk->sk_state != TCP_ESTABLISHED) 
+               if (sk->sk_state != TCP_ESTABLISHED)
                        goto out;
                daddr = inet->daddr;
        }
@@ -479,12 +482,16 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                                                .saddr = saddr,
                                                .tos = tos } },
                                    .proto = inet->hdrincl ? IPPROTO_RAW :
-                                                            sk->sk_protocol,
+                                                            sk->sk_protocol,
                                  };
-               if (!inet->hdrincl)
-                       raw_probe_proto_opt(&fl, msg);
+               if (!inet->hdrincl) {
+                       err = raw_probe_proto_opt(&fl, msg);
+                       if (err)
+                               goto done;
+               }
 
-               err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));
+               security_sk_classify_flow(sk, &fl);
+               err = ip_route_output_flow(&rt, &fl, sk, 1);
        }
        if (err)
                goto done;
@@ -498,9 +505,9 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 back_from_confirm:
 
        if (inet->hdrincl)
-               err = raw_send_hdrinc(sk, msg->msg_iov, len, 
+               err = raw_send_hdrinc(sk, msg->msg_iov, len,
                                        rt, msg->msg_flags);
-       
+
         else {
                if (!ipc.addr)
                        ipc.addr = rt->rt_dst;
@@ -533,7 +540,7 @@ do_confirm:
 
 static void raw_close(struct sock *sk, long timeout)
 {
-        /*
+       /*
         * Raw sockets may have direct kernel refereneces. Kill them.
         */
        ip_ra_control(sk, 0, NULL);
@@ -608,7 +615,8 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        /* Copy the address. */
        if (sin) {
                sin->sin_family = AF_INET;
-               sin->sin_addr.s_addr = skb->nh.iph->saddr;
+               sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
+               sin->sin_port = 0;
                memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
        }
        if (inet->cmsg_flags)
@@ -660,12 +668,9 @@ static int raw_geticmpfilter(struct sock *sk, char __user *optval, int __user *o
 out:   return ret;
 }
 
-static int raw_setsockopt(struct sock *sk, int level, int optname, 
+static int do_raw_setsockopt(struct sock *sk, int level, int optname,
                          char __user *optval, int optlen)
 {
-       if (level != SOL_RAW)
-               return ip_setsockopt(sk, level, optname, optval, optlen);
-
        if (optname == ICMP_FILTER) {
                if (inet_sk(sk)->num != IPPROTO_ICMP)
                        return -EOPNOTSUPP;
@@ -675,12 +680,27 @@ static int raw_setsockopt(struct sock *sk, int level, int optname,
        return -ENOPROTOOPT;
 }
 
-static int raw_getsockopt(struct sock *sk, int level, int optname, 
-                         char __user *optval, int __user *optlen)
+static int raw_setsockopt(struct sock *sk, int level, int optname,
+                         char __user *optval, int optlen)
 {
        if (level != SOL_RAW)
-               return ip_getsockopt(sk, level, optname, optval, optlen);
+               return ip_setsockopt(sk, level, optname, optval, optlen);
+       return do_raw_setsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+static int compat_raw_setsockopt(struct sock *sk, int level, int optname,
+                                char __user *optval, int optlen)
+{
+       if (level != SOL_RAW)
+               return compat_ip_setsockopt(sk, level, optname, optval, optlen);
+       return do_raw_setsockopt(sk, level, optname, optval, optlen);
+}
+#endif
 
+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)
                        return -EOPNOTSUPP;
@@ -690,6 +710,24 @@ static int raw_getsockopt(struct sock *sk, int level, int optname,
        return -ENOPROTOOPT;
 }
 
+static int raw_getsockopt(struct sock *sk, int level, int optname,
+                         char __user *optval, int __user *optlen)
+{
+       if (level != SOL_RAW)
+               return ip_getsockopt(sk, level, optname, optval, optlen);
+       return do_raw_getsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+static int compat_raw_getsockopt(struct sock *sk, int level, int optname,
+                                char __user *optval, int __user *optlen)
+{
+       if (level != SOL_RAW)
+               return compat_ip_getsockopt(sk, level, optname, optval, optlen);
+       return do_raw_getsockopt(sk, level, optname, optval, optlen);
+}
+#endif
+
 static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
        switch (cmd) {
@@ -719,22 +757,26 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
 }
 
 struct proto raw_prot = {
-       .name =         "RAW",
-       .owner =        THIS_MODULE,
-       .close =        raw_close,
-       .connect =      ip4_datagram_connect,
-       .disconnect =   udp_disconnect,
-       .ioctl =        raw_ioctl,
-       .init =         raw_init,
-       .setsockopt =   raw_setsockopt,
-       .getsockopt =   raw_getsockopt,
-       .sendmsg =      raw_sendmsg,
-       .recvmsg =      raw_recvmsg,
-       .bind =         raw_bind,
-       .backlog_rcv =  raw_rcv_skb,
-       .hash =         raw_v4_hash,
-       .unhash =       raw_v4_unhash,
-       .obj_size =     sizeof(struct raw_sock),
+       .name              = "RAW",
+       .owner             = THIS_MODULE,
+       .close             = raw_close,
+       .connect           = ip4_datagram_connect,
+       .disconnect        = udp_disconnect,
+       .ioctl             = raw_ioctl,
+       .init              = raw_init,
+       .setsockopt        = raw_setsockopt,
+       .getsockopt        = raw_getsockopt,
+       .sendmsg           = raw_sendmsg,
+       .recvmsg           = raw_recvmsg,
+       .bind              = raw_bind,
+       .backlog_rcv       = raw_rcv_skb,
+       .hash              = raw_v4_hash,
+       .unhash            = raw_v4_unhash,
+       .obj_size          = sizeof(struct raw_sock),
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_raw_setsockopt,
+       .compat_getsockopt = compat_raw_getsockopt,
+#endif
 };
 
 #ifdef CONFIG_PROC_FS
@@ -814,14 +856,14 @@ static void raw_seq_stop(struct seq_file *seq, void *v)
 static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i)
 {
        struct inet_sock *inet = inet_sk(sp);
-       unsigned int dest = inet->daddr,
-                    src = inet->rcv_saddr;
+       __be32 dest = inet->daddr,
+              src = inet->rcv_saddr;
        __u16 destp = 0,
              srcp  = inet->num;
 
        sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
                " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p",
-               i, src, srcp, dest, destp, sp->sk_state, 
+               i, src, srcp, dest, destp, sp->sk_state,
                atomic_read(&sp->sk_wmem_alloc),
                atomic_read(&sp->sk_rmem_alloc),
                0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
@@ -847,7 +889,7 @@ static int raw_seq_show(struct seq_file *seq, void *v)
        return 0;
 }
 
-static struct seq_operations raw_seq_ops = {
+static const struct seq_operations raw_seq_ops = {
        .start = raw_seq_start,
        .next  = raw_seq_next,
        .stop  = raw_seq_stop,
@@ -858,8 +900,9 @@ static int raw_seq_open(struct inode *inode, struct file *file)
 {
        struct seq_file *seq;
        int rc = -ENOMEM;
-       struct raw_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+       struct raw_iter_state *s;
 
+       s = kzalloc(sizeof(*s), GFP_KERNEL);
        if (!s)
                goto out;
        rc = seq_open(file, &raw_seq_ops);
@@ -868,7 +911,6 @@ static int raw_seq_open(struct inode *inode, struct file *file)
 
        seq = file->private_data;
        seq->private = s;
-       memset(s, 0, sizeof(*s));
 out:
        return rc;
 out_kfree:
@@ -876,7 +918,7 @@ out_kfree:
        goto out;
 }
 
-static struct file_operations raw_seq_fops = {
+static const struct file_operations raw_seq_fops = {
        .owner   = THIS_MODULE,
        .open    = raw_seq_open,
        .read    = seq_read,