// SPDX-License-Identifier: GPL-2.0-or-later /* * DDP: An implementation of the AppleTalk DDP protocol for * Ethernet 'ELAP'. * * Alan Cox <[email protected]> * * With more than a little assistance from * * Wesley Craig <[email protected]> * * Fixes: * Neil Horman : Added missing device ioctls * Michael Callahan : Made routing work * Wesley Craig : Fix probing to listen to a * passed node id. * Alan Cox : Added send/recvmsg support * Alan Cox : Moved at. to protinfo in * socket. * Alan Cox : Added firewall hooks. * Alan Cox : Supports new ARPHRD_LOOPBACK * Christer Weinigel : Routing and /proc fixes. * Bradford Johnson : LocalTalk. * Tom Dyas : Module support. * Alan Cox : Hooks for PPP (based on the * LocalTalk hook). * Alan Cox : Posix bits * Alan Cox/Mike Freeman : Possible fix to NBP problems * Bradford Johnson : IP-over-DDP (experimental) * Jay Schulist : Moved IP-over-DDP to its own * driver file. (ipddp.c & ipddp.h) * Jay Schulist : Made work as module with * AppleTalk drivers, cleaned it. * Rob Newberry : Added proxy AARP and AARP * procfs, moved probing to AARP * module. * Adrian Sun/ * Michael Zuelsdorff : fix for net.0 packets. don't * allow illegal ether/tokentalk * port assignment. we lose a * valid localtalk port as a * result. * Arnaldo C. de Melo : Cleanup, in preparation for * shared skb support 8) * Arnaldo C. de Melo : Move proc stuff to atalk_proc.c, * use seq_file */ #include <linux/capability.h> #include <linux/module.h> #include <linux/if_arp.h> #include <linux/termios.h> /* For TIOCOUTQ/INQ */ #include <linux/compat.h> #include <linux/slab.h> #include <net/datalink.h> #include <net/psnap.h> #include <net/sock.h> #include <net/tcp_states.h> #include <net/route.h> #include <net/compat.h> #include <linux/atalk.h> #include <linux/highmem.h> struct datalink_proto *ddp_dl, *aarp_dl; static const struct proto_ops atalk_dgram_ops; /**************************************************************************\ * * * Handlers for the socket list. * * * \**************************************************************************/ HLIST_HEAD(atalk_sockets); DEFINE_RWLOCK(…); static inline void __atalk_insert_socket(struct sock *sk) { … } static inline void atalk_remove_socket(struct sock *sk) { … } static struct sock *atalk_search_socket(struct sockaddr_at *to, struct atalk_iface *atif) { … } /** * atalk_find_or_insert_socket - Try to find a socket matching ADDR * @sk: socket to insert in the list if it is not there already * @sat: address to search for * * Try to find a socket matching ADDR in the socket list, if found then return * it. If not, insert SK into the socket list. * * This entire operation must execute atomically. */ static struct sock *atalk_find_or_insert_socket(struct sock *sk, struct sockaddr_at *sat) { … } static void atalk_destroy_timer(struct timer_list *t) { … } static inline void atalk_destroy_socket(struct sock *sk) { … } /**************************************************************************\ * * * Routing tables for the AppleTalk socket layer. * * * \**************************************************************************/ /* Anti-deadlock ordering is atalk_routes_lock --> iface_lock -DaveM */ struct atalk_route *atalk_routes; DEFINE_RWLOCK(…); struct atalk_iface *atalk_interfaces; DEFINE_RWLOCK(…); /* For probing devices or in a routerless network */ struct atalk_route atrtr_default; /* AppleTalk interface control */ /* * Drop a device. Doesn't drop any of its routes - that is the caller's * problem. Called when we down the interface or delete the address. */ static void atif_drop_device(struct net_device *dev) { … } static struct atalk_iface *atif_add_device(struct net_device *dev, struct atalk_addr *sa) { … } /* Perform phase 2 AARP probing on our tentative address */ static int atif_probe_device(struct atalk_iface *atif) { … } /* Perform AARP probing for a proxy address */ static int atif_proxy_probe_device(struct atalk_iface *atif, struct atalk_addr *proxy_addr) { … } struct atalk_addr *atalk_find_dev_addr(struct net_device *dev) { … } static struct atalk_addr *atalk_find_primary(void) { … } /* * Find a match for 'any network' - ie any of our interfaces with that * node number will do just nicely. */ static struct atalk_iface *atalk_find_anynet(int node, struct net_device *dev) { … } /* Find a match for a specific network:node pair */ static struct atalk_iface *atalk_find_interface(__be16 net, int node) { … } /* * Find a route for an AppleTalk packet. This ought to get cached in * the socket (later on...). We know about host routes and the fact * that a route must be direct to broadcast. */ static struct atalk_route *atrtr_find(struct atalk_addr *target) { … } /* * Given an AppleTalk network, find the device to use. This can be * a simple lookup. */ struct net_device *atrtr_get_dev(struct atalk_addr *sa) { … } /* Set up a default router */ static void atrtr_set_default(struct net_device *dev) { … } /* * Add a router. Basically make sure it looks valid and stuff the * entry in the list. While it uses netranges we always set them to one * entry to work like netatalk. */ static int atrtr_create(struct rtentry *r, struct net_device *devhint) { … } /* Delete a route. Find it and discard it */ static int atrtr_delete(struct atalk_addr *addr) { … } /* * Called when a device is downed. Just throw away any routes * via it. */ static void atrtr_device_down(struct net_device *dev) { … } /* Actually down the interface */ static inline void atalk_dev_down(struct net_device *dev) { … } /* * A device event has occurred. Watch for devices going down and * delete our use of them (iface and route). */ static int ddp_device_event(struct notifier_block *this, unsigned long event, void *ptr) { … } /* ioctl calls. Shouldn't even need touching */ /* Device configuration ioctl calls */ static int atif_ioctl(int cmd, void __user *arg) { … } static int atrtr_ioctl_addrt(struct rtentry *rt) { … } /* Routing ioctl() calls */ static int atrtr_ioctl(unsigned int cmd, void __user *arg) { … } /**************************************************************************\ * * * Handling for system calls applied via the various interfaces to an * * AppleTalk socket object. * * * \**************************************************************************/ /* * Checksum: This is 'optional'. It's quite likely also a good * candidate for assembler hackery 8) */ static unsigned long atalk_sum_partial(const unsigned char *data, int len, unsigned long sum) { … } /* Checksum skb data -- similar to skb_checksum */ static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset, int len, unsigned long sum) { … } static __be16 atalk_checksum(const struct sk_buff *skb, int len) { … } static struct proto ddp_proto = …; /* * Create a socket. Initialise the socket, blank the addresses * set the state. */ static int atalk_create(struct net *net, struct socket *sock, int protocol, int kern) { … } /* Free a socket. No work needed */ static int atalk_release(struct socket *sock) { … } /** * atalk_pick_and_bind_port - Pick a source port when one is not given * @sk: socket to insert into the tables * @sat: address to search for * * Pick a source port when one is not given. If we can find a suitable free * one, we insert the socket into the tables using it. * * This whole operation must be atomic. */ static int atalk_pick_and_bind_port(struct sock *sk, struct sockaddr_at *sat) { … } static int atalk_autobind(struct sock *sk) { … } /* Set the address 'our end' of the connection */ static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { … } /* Set the address we talk to */ static int atalk_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) { … } /* * Find the name of an AppleTalk socket. Just copy the right * fields into the sockaddr. */ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr, int peer) { … } static int atalk_route_packet(struct sk_buff *skb, struct net_device *dev, struct ddpehdr *ddp, __u16 len_hops, int origlen) { … } /** * atalk_rcv - Receive a packet (in skb) from device dev * @skb: packet received * @dev: network device where the packet comes from * @pt: packet type * @orig_dev: the original receive net device * * Receive a packet (in skb) from device dev. This has come from the SNAP * decoder, and on entry skb->transport_header is the DDP header, skb->len * is the DDP header, skb->len is the DDP length. The physical headers * have been extracted. PPP should probably pass frames marked as for this * layer. [ie ARPHRD_ETHERTALK] */ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { … } /* * Receive a LocalTalk frame. We make some demands on the caller here. * Caller must provide enough headroom on the packet to pull the short * header and append a long one. */ static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { … } static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) { … } static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, int flags) { … } /* * AppleTalk ioctl calls. */ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { … } #ifdef CONFIG_COMPAT static int atalk_compat_routing_ioctl(struct sock *sk, unsigned int cmd, struct compat_rtentry __user *ur) { … } static int atalk_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { … } #endif /* CONFIG_COMPAT */ static const struct net_proto_family atalk_family_ops = …; static const struct proto_ops atalk_dgram_ops = …; static struct notifier_block ddp_notifier = …; static struct packet_type ltalk_packet_type __read_mostly = …; static struct packet_type ppptalk_packet_type __read_mostly = …; static unsigned char ddp_snap_id[] = …; /* Export symbols for use by drivers when AppleTalk is a module */ EXPORT_SYMBOL(…); EXPORT_SYMBOL(…); /* Called by proto.c on kernel start up */ static int __init atalk_init(void) { … } module_init(…) …; /* * No explicit module reference count manipulation is needed in the * protocol. Socket layer sets module reference count for us * and interfaces reference counting is done * by the network device layer. * * Ergo, before the AppleTalk module can be removed, all AppleTalk * sockets should be closed from user space. */ static void __exit atalk_exit(void) { … } module_exit(atalk_exit); MODULE_LICENSE(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_ALIAS_NETPROTO(…);