X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fappletalk%2Fddp.c;h=96dc6bb52d14aecd00cff0e8f37bed950d6b557f;hb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;hp=af571e3e319796a0b86e95f2ec0c1ff36c0616c1;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index af571e3e3..96dc6bb52 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -9,6 +9,7 @@ * Wesley Craig * * Fixes: + * Neil Horman : Added missing device ioctls * Michael Callahan : Made routing work * Wesley Craig : Fix probing to listen to a * passed node id. @@ -50,29 +51,19 @@ * */ -#include +#include #include -#include #include #include /* For TIOCOUTQ/INQ */ #include #include #include +#include #include #include -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);