merge Linus head tree into my drm tree and fix up conflicts
[pandora-kernel.git] / net / packet / af_packet.c
index ba99709..499ae3d 100644 (file)
  *     Michal Ostrowski        :       Module initialization cleanup.
  *         Ulises Alonso        :       Frame number limit removal and 
  *                                      packet_set_ring memory leak.
+ *             Eric Biederman  :       Allow for > 8 byte hardware addresses.
+ *                                     The convention is that longer addresses
+ *                                     will simply extend the hardware address
+ *                                     byte arrays at the end of sockaddr_ll 
+ *                                     and packet_mreq.
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
@@ -161,7 +166,17 @@ struct packet_mclist
        int                     count;
        unsigned short          type;
        unsigned short          alen;
-       unsigned char           addr[8];
+       unsigned char           addr[MAX_ADDR_LEN];
+};
+/* identical to struct packet_mreq except it has
+ * a longer address field.
+ */
+struct packet_mreq_max
+{
+       int             mr_ifindex;
+       unsigned short  mr_type;
+       unsigned short  mr_alen;
+       unsigned char   mr_address[MAX_ADDR_LEN];
 };
 #endif
 #ifdef CONFIG_PACKET_MMAP
@@ -639,8 +654,8 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
                __net_timestamp(skb);
                sock_enable_timestamp(sk);
        }
-       h->tp_sec = skb_tv_base.tv_sec + skb->tstamp.off_sec;
-       h->tp_usec = skb_tv_base.tv_usec + skb->tstamp.off_usec;
+       h->tp_sec = skb->tstamp.off_sec;
+       h->tp_usec = skb->tstamp.off_usec;
 
        sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h)));
        sll->sll_halen = 0;
@@ -716,6 +731,8 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock,
                err = -EINVAL;
                if (msg->msg_namelen < sizeof(struct sockaddr_ll))
                        goto out;
+               if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll, sll_addr)))
+                       goto out;
                ifindex = saddr->sll_ifindex;
                proto   = saddr->sll_protocol;
                addr    = saddr->sll_addr;
@@ -1045,6 +1062,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
        struct sock *sk = sock->sk;
        struct sk_buff *skb;
        int copied, err;
+       struct sockaddr_ll *sll;
 
        err = -EINVAL;
        if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT))
@@ -1056,16 +1074,6 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
                return -ENODEV;
 #endif
 
-       /*
-        *      If the address length field is there to be filled in, we fill
-        *      it in now.
-        */
-
-       if (sock->type == SOCK_PACKET)
-               msg->msg_namelen = sizeof(struct sockaddr_pkt);
-       else
-               msg->msg_namelen = sizeof(struct sockaddr_ll);
-
        /*
         *      Call the generic datagram receiver. This handles all sorts
         *      of horrible races and re-entrancy so we can forget about it
@@ -1086,6 +1094,17 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
        if(skb==NULL)
                goto out;
 
+       /*
+        *      If the address length field is there to be filled in, we fill
+        *      it in now.
+        */
+
+       sll = (struct sockaddr_ll*)skb->cb;
+       if (sock->type == SOCK_PACKET)
+               msg->msg_namelen = sizeof(struct sockaddr_pkt);
+       else
+               msg->msg_namelen = sll->sll_halen + offsetof(struct sockaddr_ll, sll_addr);
+
        /*
         *      You lose any data beyond the buffer you gave. If it worries a
         *      user program they can ask the device for its MTU anyway.
@@ -1166,7 +1185,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr,
                sll->sll_hatype = 0;    /* Bad: we have no ARPHRD_UNSPEC */
                sll->sll_halen = 0;
        }
-       *uaddr_len = sizeof(*sll);
+       *uaddr_len = offsetof(struct sockaddr_ll, sll_addr) + sll->sll_halen;
 
        return 0;
 }
@@ -1199,7 +1218,7 @@ static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, i
        }
 }
 
-static int packet_mc_add(struct sock *sk, struct packet_mreq *mreq)
+static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq)
 {
        struct packet_sock *po = pkt_sk(sk);
        struct packet_mclist *ml, *i;
@@ -1249,7 +1268,7 @@ done:
        return err;
 }
 
-static int packet_mc_drop(struct sock *sk, struct packet_mreq *mreq)
+static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq)
 {
        struct packet_mclist *ml, **mlp;
 
@@ -1315,11 +1334,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
        case PACKET_ADD_MEMBERSHIP:     
        case PACKET_DROP_MEMBERSHIP:
        {
-               struct packet_mreq mreq;
-               if (optlen<sizeof(mreq))
+               struct packet_mreq_max mreq;
+               int len = optlen;
+               memset(&mreq, 0, sizeof(mreq));
+               if (len < sizeof(struct packet_mreq))
                        return -EINVAL;
-               if (copy_from_user(&mreq,optval,sizeof(mreq)))
+               if (len > sizeof(mreq))
+                       len = sizeof(mreq);
+               if (copy_from_user(&mreq,optval,len))
                        return -EFAULT;
+               if (len < (mreq.mr_alen + offsetof(struct packet_mreq, mr_address)))
+                       return -EINVAL;
                if (optname == PACKET_ADD_MEMBERSHIP)
                        ret = packet_mc_add(sk, &mreq);
                else
@@ -1535,8 +1560,7 @@ static unsigned int packet_poll(struct file * file, struct socket *sock,
 static void packet_mm_open(struct vm_area_struct *vma)
 {
        struct file *file = vma->vm_file;
-       struct inode *inode = file->f_dentry->d_inode;
-       struct socket * sock = SOCKET_I(inode);
+       struct socket * sock = file->private_data;
        struct sock *sk = sock->sk;
        
        if (sk)
@@ -1546,8 +1570,7 @@ static void packet_mm_open(struct vm_area_struct *vma)
 static void packet_mm_close(struct vm_area_struct *vma)
 {
        struct file *file = vma->vm_file;
-       struct inode *inode = file->f_dentry->d_inode;
-       struct socket * sock = SOCKET_I(inode);
+       struct socket * sock = file->private_data;
        struct sock *sk = sock->sk;
        
        if (sk)