[PATCH] Update my email address from jkmaline@cc.hut.fi to j@w1.fi
[powerpc.git] / drivers / net / tun.c
index de8da6d..a2c6caa 100644 (file)
 /*
  *  Changes:
  *
+ *  Brian Braunstein <linuxkernel@bristyle.com> 2007/03/23
+ *    Fixed hw address handling.  Now net_device.dev_addr is kept consistent
+ *    with tun.dev_addr when the address is set by this module.
+ *
  *  Mike Kershaw <dragorn@kismetwireless.net> 2005/08/14
  *    Add TUNSETLINK ioctl to set the link encapsulation
  *
@@ -196,7 +200,10 @@ static void tun_net_init(struct net_device *dev)
                dev->set_multicast_list = tun_net_mclist;
 
                ether_setup(dev);
-               random_ether_addr(dev->dev_addr);
+
+               /* random address already created for us by tun_set_iff, use it */
+               memcpy(dev->dev_addr, tun->dev_addr, min(sizeof(tun->dev_addr), sizeof(dev->dev_addr)) );
+
                dev->tx_queue_len = TUN_READQ_SIZE;  /* We prefer our own queue length */
                break;
        }
@@ -254,11 +261,11 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv,
                return -EFAULT;
        }
 
-       skb->dev = tun->dev;
        switch (tun->flags & TUN_TYPE_MASK) {
        case TUN_TUN_DEV:
-               skb->mac.raw = skb->data;
+               skb_reset_mac_header(skb);
                skb->protocol = pi.proto;
+               skb->dev = tun->dev;
                break;
        case TUN_TAP_DEV:
                skb->protocol = eth_type_trans(skb, tun->dev);
@@ -288,11 +295,10 @@ static inline size_t iov_total(const struct iovec *iv, unsigned long count)
        return len;
 }
 
-/* Writev */
-static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv,
-                             unsigned long count, loff_t *pos)
+static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv,
+                             unsigned long count, loff_t pos)
 {
-       struct tun_struct *tun = file->private_data;
+       struct tun_struct *tun = iocb->ki_filp->private_data;
 
        if (!tun)
                return -EBADFD;
@@ -302,14 +308,6 @@ static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv,
        return tun_get_user(tun, (struct iovec *) iv, iov_total(iv, count));
 }
 
-/* Write */
-static ssize_t tun_chr_write(struct file * file, const char __user * buf,
-                            size_t count, loff_t *pos)
-{
-       struct iovec iv = { (void __user *) buf, count };
-       return tun_chr_writev(file, &iv, 1, pos);
-}
-
 /* Put packet to the user space buffer */
 static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
                                       struct sk_buff *skb,
@@ -343,10 +341,10 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
        return total;
 }
 
-/* Readv */
-static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
-                           unsigned long count, loff_t *pos)
+static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
+                           unsigned long count, loff_t pos)
 {
+       struct file *file = iocb->ki_filp;
        struct tun_struct *tun = file->private_data;
        DECLARE_WAITQUEUE(wait, current);
        struct sk_buff *skb;
@@ -395,8 +393,8 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
                 *   - we are multicast promiscous.
                 *   - we belong to the multicast group.
                 */
-               memcpy(addr, skb->data,
-                      min_t(size_t, sizeof addr, skb->len));
+               skb_copy_from_linear_data(skb, addr, min_t(size_t, sizeof addr,
+                                                                  skb->len));
                bit_nr = ether_crc(sizeof addr, addr) >> 26;
                if ((tun->if_flags & IFF_PROMISC) ||
                                memcmp(addr, tun->dev_addr, sizeof addr) == 0 ||
@@ -426,14 +424,6 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
        return ret;
 }
 
-/* Read */
-static ssize_t tun_chr_read(struct file * file, char __user * buf,
-                           size_t count, loff_t *pos)
-{
-       struct iovec iv = { buf, count };
-       return tun_chr_readv(file, &iv, 1, pos);
-}
-
 static void tun_setup(struct net_device *dev)
 {
        struct tun_struct *tun = netdev_priv(dev);
@@ -653,6 +643,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file,
                return 0;
 
        case SIOCGIFHWADDR:
+               /* Note: the actual net device's address may be different */
                memcpy(ifr.ifr_hwaddr.sa_data, tun->dev_addr,
                                min(sizeof ifr.ifr_hwaddr.sa_data, sizeof tun->dev_addr));
                if (copy_to_user( argp, &ifr, sizeof ifr))
@@ -660,16 +651,24 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file,
                return 0;
 
        case SIOCSIFHWADDR:
-               /** Set the character device's hardware address. This is used when
-                * filtering packets being sent from the network device to the character
-                * device. */
-               memcpy(tun->dev_addr, ifr.ifr_hwaddr.sa_data,
-                               min(sizeof ifr.ifr_hwaddr.sa_data, sizeof tun->dev_addr));
-               DBG(KERN_DEBUG "%s: set hardware address: %x:%x:%x:%x:%x:%x\n",
-                               tun->dev->name,
-                               tun->dev_addr[0], tun->dev_addr[1], tun->dev_addr[2],
-                               tun->dev_addr[3], tun->dev_addr[4], tun->dev_addr[5]);
-               return 0;
+       {
+               /* try to set the actual net device's hw address */
+               int ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr);
+
+               if (ret == 0) {
+                       /** Set the character device's hardware address. This is used when
+                        * filtering packets being sent from the network device to the character
+                        * device. */
+                       memcpy(tun->dev_addr, ifr.ifr_hwaddr.sa_data,
+                                       min(sizeof ifr.ifr_hwaddr.sa_data, sizeof tun->dev_addr));
+                       DBG(KERN_DEBUG "%s: set hardware address: %x:%x:%x:%x:%x:%x\n",
+                                       tun->dev->name,
+                                       tun->dev_addr[0], tun->dev_addr[1], tun->dev_addr[2],
+                                       tun->dev_addr[3], tun->dev_addr[4], tun->dev_addr[5]);
+               }
+
+               return  ret;
+       }
 
        case SIOCADDMULTI:
                /** Add the specified group to the character device's multicast filter
@@ -714,7 +713,7 @@ static int tun_chr_fasync(int fd, struct file *file, int on)
                return ret;
 
        if (on) {
-               ret = f_setown(file, current->pid, 0);
+               ret = __f_setown(file, task_pid(current), PIDTYPE_PID, 0);
                if (ret)
                        return ret;
                tun->flags |= TUN_FASYNC;
@@ -761,13 +760,13 @@ static int tun_chr_close(struct inode *inode, struct file *file)
        return 0;
 }
 
-static struct file_operations tun_fops = {
+static const struct file_operations tun_fops = {
        .owner  = THIS_MODULE,
        .llseek = no_llseek,
-       .read   = tun_chr_read,
-       .readv  = tun_chr_readv,
-       .write  = tun_chr_write,
-       .writev = tun_chr_writev,
+       .read  = do_sync_read,
+       .aio_read  = tun_chr_aio_read,
+       .write = do_sync_write,
+       .aio_write = tun_chr_aio_write,
        .poll   = tun_chr_poll,
        .ioctl  = tun_chr_ioctl,
        .open   = tun_chr_open,