Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / net / appletalk / ddp.c
index af571e3..96dc6bb 100644 (file)
@@ -9,6 +9,7 @@
  *             Wesley Craig <netatalk@umich.edu>
  *
  *     Fixes:
+ *             Neil Horman             :       Added missing device ioctls
  *             Michael Callahan        :       Made routing work
  *             Wesley Craig            :       Fix probing to listen to a
  *                                             passed node id.
  * 
  */
 
-#include <linux/config.h>
+#include <linux/capability.h>
 #include <linux/module.h>
-#include <linux/tcp.h>
 #include <linux/if_arp.h>
 #include <linux/termios.h>     /* For TIOCOUTQ/INQ */
 #include <net/datalink.h>
 #include <net/psnap.h>
 #include <net/sock.h>
+#include <net/tcp_states.h>
 #include <net/route.h>
 #include <linux/atalk.h>
 
-extern void aarp_cleanup_module(void);
-
-extern void aarp_probe_network(struct atalk_iface *atif);
-extern int  aarp_proxy_probe_network(struct atalk_iface *atif,
-                                    struct atalk_addr *sa);
-extern void aarp_proxy_remove(struct net_device *dev, struct atalk_addr *sa);
-
-extern void atalk_register_sysctl(void);
-extern void atalk_unregister_sysctl(void);
-
 struct datalink_proto *ddp_dl, *aarp_dl;
-static struct proto_ops atalk_dgram_ops;
+static const struct proto_ops atalk_dgram_ops;
 
 /**************************************************************************\
 *                                                                          *
@@ -81,20 +72,13 @@ static struct proto_ops atalk_dgram_ops;
 \**************************************************************************/
 
 HLIST_HEAD(atalk_sockets);
-rwlock_t atalk_sockets_lock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(atalk_sockets_lock);
 
 static inline void __atalk_insert_socket(struct sock *sk)
 {
        sk_add_node(sk, &atalk_sockets);
 }
 
-static inline void atalk_insert_socket(struct sock *sk)
-{
-       write_lock_bh(&atalk_sockets_lock);
-       __atalk_insert_socket(sk);
-       write_unlock_bh(&atalk_sockets_lock);
-}
-
 static inline void atalk_remove_socket(struct sock *sk)
 {
        write_lock_bh(&atalk_sockets_lock);
@@ -116,8 +100,7 @@ static struct sock *atalk_search_socket(struct sockaddr_at *to,
                        continue;
 
                if (to->sat_addr.s_net == ATADDR_ANYNET &&
-                   to->sat_addr.s_node == ATADDR_BCAST &&
-                   at->src_net == atif->address.s_net)
+                   to->sat_addr.s_node == ATADDR_BCAST)
                        goto found;
 
                if (to->sat_addr.s_net == at->src_net &&
@@ -210,10 +193,10 @@ static inline void atalk_destroy_socket(struct sock *sk)
 
 /* Anti-deadlock ordering is atalk_routes_lock --> iface_lock -DaveM */
 struct atalk_route *atalk_routes;
-rwlock_t atalk_routes_lock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(atalk_routes_lock);
 
 struct atalk_iface *atalk_interfaces;
-rwlock_t atalk_interfaces_lock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(atalk_interfaces_lock);
 
 /* For probing devices or in a routerless network */
 struct atalk_route atrtr_default;
@@ -244,12 +227,11 @@ static void atif_drop_device(struct net_device *dev)
 static struct atalk_iface *atif_add_device(struct net_device *dev,
                                           struct atalk_addr *sa)
 {
-       struct atalk_iface *iface = kmalloc(sizeof(*iface), GFP_KERNEL);
+       struct atalk_iface *iface = kzalloc(sizeof(*iface), GFP_KERNEL);
 
        if (!iface)
                goto out;
 
-       memset(iface, 0, sizeof(*iface));
        dev_hold(dev);
        iface->dev = dev;
        dev->atalk_ptr = iface;
@@ -417,7 +399,7 @@ out_err:
 }
 
 /* Find a match for a specific network:node pair */
-static struct atalk_iface *atalk_find_interface(int net, int node)
+static struct atalk_iface *atalk_find_interface(__be16 net, int node)
 {
        struct atalk_iface *iface;
 
@@ -576,12 +558,11 @@ static int atrtr_create(struct rtentry *r, struct net_device *devhint)
        }
 
        if (!rt) {
-               rt = kmalloc(sizeof(*rt), GFP_ATOMIC);
+               rt = kzalloc(sizeof(*rt), GFP_ATOMIC);
 
                retval = -ENOBUFS;
                if (!rt)
-                       goto out;
-               memset(rt, 0, sizeof(*rt));
+                       goto out_unlock;
 
                rt->next = atalk_routes;
                atalk_routes = rt;
@@ -589,6 +570,7 @@ static int atrtr_create(struct rtentry *r, struct net_device *devhint)
 
        /* Fill in the routing entry */
        rt->target  = ta->sat_addr;
+       dev_hold(devhint);
        rt->dev     = devhint;
        rt->flags   = r->rt_flags;
        rt->gateway = ga->sat_addr;
@@ -629,7 +611,7 @@ out:
  * Called when a device is downed. Just throw away any routes
  * via it.
  */
-void atrtr_device_down(struct net_device *dev)
+static void atrtr_device_down(struct net_device *dev)
 {
        struct atalk_route **r = &atalk_routes;
        struct atalk_route *tmp;
@@ -673,7 +655,7 @@ static int ddp_device_event(struct notifier_block *this, unsigned long event,
 
 /* ioctl calls. Shouldn't even need touching */
 /* Device configuration ioctl calls */
-static int atif_ioctl(int cmd, void *arg)
+static int atif_ioctl(int cmd, void __user *arg)
 {
        static char aarp_mcast[6] = { 0x09, 0x00, 0x00, 0xFF, 0xFF, 0xFF };
        struct ifreq atreq;
@@ -892,7 +874,7 @@ static int atif_ioctl(int cmd, void *arg)
 }
 
 /* Routing ioctl() calls */
-static int atrtr_ioctl(unsigned int cmd, void *arg)
+static int atrtr_ioctl(unsigned int cmd, void __user *arg)
 {
        struct rtentry rt;
 
@@ -908,12 +890,12 @@ static int atrtr_ioctl(unsigned int cmd, void *arg)
 
                case SIOCADDRT: {
                        struct net_device *dev = NULL;
-                       /*
-                        * FIXME: the name of the device is still in user
-                        * space, isn't it?
-                        */
                        if (rt.rt_dev) {
-                               dev = __dev_get_by_name(rt.rt_dev);
+                               char name[IFNAMSIZ];
+                               if (copy_from_user(name, rt.rt_dev, IFNAMSIZ-1))
+                                       return -EFAULT;
+                               name[IFNAMSIZ-1] = '\0';
+                               dev = __dev_get_by_name(name);
                                if (!dev)
                                        return -ENODEV;
                        }                       
@@ -1031,6 +1013,12 @@ static unsigned short atalk_checksum(const struct sk_buff *skb, int len)
        return sum ? htons((unsigned short)sum) : 0xFFFF;
 }
 
+static struct proto ddp_proto = {
+       .name     = "DDP",
+       .owner    = THIS_MODULE,
+       .obj_size = sizeof(struct atalk_sock),
+};
+
 /*
  * Create a socket. Initialise the socket, blank the addresses
  * set the state.
@@ -1038,7 +1026,6 @@ static unsigned short atalk_checksum(const struct sk_buff *skb, int len)
 static int atalk_create(struct socket *sock, int protocol)
 {
        struct sock *sk;
-       struct atalk_sock *at;
        int rc = -ESOCKTNOSUPPORT;
 
        /*
@@ -1048,25 +1035,17 @@ static int atalk_create(struct socket *sock, int protocol)
        if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)
                goto out;
        rc = -ENOMEM;
-       sk = sk_alloc(PF_APPLETALK, GFP_KERNEL, 1, NULL);
+       sk = sk_alloc(PF_APPLETALK, GFP_KERNEL, &ddp_proto, 1);
        if (!sk)
                goto out;
-       at = sk->sk_protinfo = kmalloc(sizeof(*at), GFP_KERNEL);
-       if (!at)
-               goto outsk;
-       memset(at, 0, sizeof(*at));
        rc = 0;
        sock->ops = &atalk_dgram_ops;
        sock_init_data(sock, sk);
-       sk_set_owner(sk, THIS_MODULE);
 
        /* Checksums on by default */
-       sk->sk_zapped = 1;
+       sock_set_flag(sk, SOCK_ZAPPED);
 out:
        return rc;
-outsk:
-       sk_free(sk);
-       goto out;
 }
 
 /* Free a socket. No work needed */
@@ -1143,7 +1122,7 @@ static int atalk_autobind(struct sock *sk)
 
        n = atalk_pick_and_bind_port(sk, &sat);
        if (!n)
-               sk->sk_zapped = 0;
+               sock_reset_flag(sk, SOCK_ZAPPED);
 out:
        return n;
 }
@@ -1155,7 +1134,8 @@ static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        struct sock *sk = sock->sk;
        struct atalk_sock *at = at_sk(sk);
 
-       if (!sk->sk_zapped || addr_len != sizeof(struct sockaddr_at))
+       if (!sock_flag(sk, SOCK_ZAPPED) ||
+           addr_len != sizeof(struct sockaddr_at))
                return -EINVAL;
 
        if (addr->sat_family != AF_APPLETALK)
@@ -1190,7 +1170,7 @@ static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                        return -EADDRINUSE;
        }
 
-       sk->sk_zapped = 0;
+       sock_reset_flag(sk, SOCK_ZAPPED);
        return 0;
 }
 
@@ -1225,7 +1205,7 @@ static int atalk_connect(struct socket *sock, struct sockaddr *uaddr,
 #endif                 
        }
 
-       if (sk->sk_zapped)
+       if (sock_flag(sk, SOCK_ZAPPED))
                if (atalk_autobind(sk) < 0)
                        return -EBUSY;
 
@@ -1252,7 +1232,7 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
        struct sock *sk = sock->sk;
        struct atalk_sock *at = at_sk(sk);
 
-       if (sk->sk_zapped)
+       if (sock_flag(sk, SOCK_ZAPPED))
                if (atalk_autobind(sk) < 0)
                        return -ENOBUFS;
 
@@ -1407,7 +1387,7 @@ free_it:
  *     [ie ARPHRD_ETHERTALK]
  */
 static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
-                    struct packet_type *pt)
+                    struct packet_type *pt, struct net_device *orig_dev)
 {
        struct ddpehdr *ddp;
        struct sock *sock;
@@ -1460,8 +1440,10 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
        else
                atif = atalk_find_interface(ddp->deh_dnet, ddp->deh_dnode);
 
-       /* Not ours, so we route the packet via the correct AppleTalk iface */
        if (!atif) {
+               /* Not ours, so we route the packet via the correct
+                * AppleTalk iface
+                */
                atalk_route_packet(skb, dev, ddp, &ddphv, origlen);
                goto out;
        }
@@ -1499,7 +1481,7 @@ freeit:
  * header and append a long one.
  */
 static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev,
-                       struct packet_type *pt)
+                    struct packet_type *pt, struct net_device *orig_dev)
 {
        /* Expand any short form frames */
        if (skb->mac.raw[2] == 1) {
@@ -1545,7 +1527,7 @@ static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev,
        }
        skb->h.raw = skb->data;
 
-       return atalk_rcv(skb, dev, pt);
+       return atalk_rcv(skb, dev, pt, orig_dev);
 freeit:
        kfree_skb(skb);
        return 0;
@@ -1567,14 +1549,14 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
        struct atalk_route *rt;
        int err;
 
-       if (flags & ~MSG_DONTWAIT)
+       if (flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
                return -EINVAL;
 
        if (len > DDP_MAXSZ)
                return -EMSGSIZE;
 
        if (usat) {
-               if (sk->sk_zapped)
+               if (sock_flag(sk, SOCK_ZAPPED))
                        if (atalk_autobind(sk) < 0)
                                return -EBUSY;
 
@@ -1609,9 +1591,6 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
 
        if (usat->sat_addr.s_net || usat->sat_addr.s_node == ATADDR_ANYNODE) {
                rt = atrtr_find(&usat->sat_addr);
-               if (!rt)
-                       return -ENETUNREACH;
-
                dev = rt->dev;
        } else {
                struct atalk_addr at_hint;
@@ -1620,11 +1599,12 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
                at_hint.s_net  = at->src_net;
 
                rt = atrtr_find(&at_hint);
-               if (!rt)
-                       return -ENETUNREACH;
-
                dev = rt->dev;
        }
+       if (!rt)
+               return -ENETUNREACH;
+
+       dev = rt->dev;
 
        SOCK_DEBUG(sk, "SK %p: Size needed %d, device %s\n",
                        sk, size, dev->name);
@@ -1694,6 +1674,20 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
                SOCK_DEBUG(sk, "SK %p: Loop back.\n", sk);
                /* loop back */
                skb_orphan(skb);
+               if (ddp->deh_dnode == ATADDR_BCAST) {
+                       struct atalk_addr at_lo;
+
+                       at_lo.s_node = 0;
+                       at_lo.s_net  = 0;
+
+                       rt = atrtr_find(&at_lo);
+                       if (!rt) {
+                               kfree_skb(skb);
+                               return -ENETUNREACH;
+                       }
+                       dev = rt->dev;
+                       skb->dev = dev;
+               }
                ddp_dl->request(ddp_dl, skb, dev->dev_addr);
        } else {
                SOCK_DEBUG(sk, "SK %p: send out.\n", sk);
@@ -1767,8 +1761,9 @@ static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
  */
 static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
-       int rc = -EINVAL;
+       int rc = -ENOIOCTLCMD;
        struct sock *sk = sock->sk;
+       void __user *argp = (void __user *)arg;
 
        switch (cmd) {
                /* Protocol layer */
@@ -1778,7 +1773,7 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 
                        if (amount < 0)
                                amount = 0;
-                       rc = put_user(amount, (int *)arg);
+                       rc = put_user(amount, (int __user *)argp);
                        break;
                }
                case TIOCINQ: {
@@ -1791,18 +1786,18 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 
                        if (skb)
                                amount = skb->len - sizeof(struct ddpehdr);
-                       rc = put_user(amount, (int *)arg);
+                       rc = put_user(amount, (int __user *)argp);
                        break;
                }
                case SIOCGSTAMP:
-                       rc = sock_get_timestamp(sk, (struct timeval *)arg);
+                       rc = sock_get_timestamp(sk, argp);
                        break;
                /* Routing */
                case SIOCADDRT:
                case SIOCDELRT:
                        rc = -EPERM;
                        if (capable(CAP_NET_ADMIN))
-                               rc = atrtr_ioctl(cmd, (void *)arg);
+                               rc = atrtr_ioctl(cmd, argp);
                        break;
                /* Interface */
                case SIOCGIFADDR:
@@ -1813,36 +1808,37 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                case SIOCSARP:          /* proxy AARP */
                case SIOCDARP:          /* proxy AARP */
                        rtnl_lock();
-                       rc = atif_ioctl(cmd, (void *)arg);
+                       rc = atif_ioctl(cmd, argp);
                        rtnl_unlock();
                        break;
-               /* Physical layer ioctl calls */
-               case SIOCSIFLINK:
-               case SIOCGIFHWADDR:
-               case SIOCSIFHWADDR:
-               case SIOCGIFFLAGS:
-               case SIOCSIFFLAGS:
-               case SIOCGIFMTU:
-               case SIOCGIFCONF:
-               case SIOCADDMULTI:
-               case SIOCDELMULTI:
-               case SIOCGIFCOUNT:
-               case SIOCGIFINDEX:
-               case SIOCGIFNAME:
-                       rc = dev_ioctl(cmd, (void *)arg);
-                       break;
        }
 
        return rc;
 }
 
+
+#ifdef CONFIG_COMPAT
+static int atalk_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       /*
+        * All Appletalk ioctls except SIOCATALKDIFADDR are standard.  And
+        * SIOCATALKDIFADDR is handled by upper layer as well, so there is
+        * nothing to do.  Eventually SIOCATALKDIFADDR should be moved
+        * here so there is no generic SIOCPROTOPRIVATE translation in the
+        * system.
+        */
+       return -ENOIOCTLCMD;
+}
+#endif
+
+
 static struct net_proto_family atalk_family_ops = {
        .family         = PF_APPLETALK,
        .create         = atalk_create,
        .owner          = THIS_MODULE,
 };
 
-static struct proto_ops SOCKOPS_WRAPPED(atalk_dgram_ops) = {
+static const struct proto_ops SOCKOPS_WRAPPED(atalk_dgram_ops) = {
        .family         = PF_APPLETALK,
        .owner          = THIS_MODULE,
        .release        = atalk_release,
@@ -1853,6 +1849,9 @@ static struct proto_ops SOCKOPS_WRAPPED(atalk_dgram_ops) = {
        .getname        = atalk_getname,
        .poll           = datagram_poll,
        .ioctl          = atalk_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = atalk_compat_ioctl,
+#endif
        .listen         = sock_no_listen,
        .shutdown       = sock_no_shutdown,
        .setsockopt     = sock_no_setsockopt,
@@ -1870,12 +1869,12 @@ static struct notifier_block ddp_notifier = {
        .notifier_call  = ddp_device_event,
 };
 
-struct packet_type ltalk_packet_type = {
+static struct packet_type ltalk_packet_type = {
        .type           = __constant_htons(ETH_P_LOCALTALK),
        .func           = ltalk_rcv,
 };
 
-struct packet_type ppptalk_packet_type = {
+static struct packet_type ppptalk_packet_type = {
        .type           = __constant_htons(ETH_P_PPPTALK),
        .func           = atalk_rcv,
 };
@@ -1893,6 +1892,11 @@ static char atalk_err_snap[] __initdata =
 /* Called by proto.c on kernel start up */
 static int __init atalk_init(void)
 {
+       int rc = proto_register(&ddp_proto, 0);
+
+       if (rc != 0)
+               goto out;
+
        (void)sock_register(&atalk_family_ops);
        ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv);
        if (!ddp_dl)
@@ -1905,7 +1909,8 @@ static int __init atalk_init(void)
        aarp_proto_init();
        atalk_proc_init();
        atalk_register_sysctl();
-       return 0;
+out:
+       return rc;
 }
 module_init(atalk_init);
 
@@ -1930,6 +1935,7 @@ static void __exit atalk_exit(void)
        dev_remove_pack(&ppptalk_packet_type);
        unregister_snap_client(ddp_dl);
        sock_unregister(PF_APPLETALK);
+       proto_unregister(&ddp_proto);
 }
 module_exit(atalk_exit);