⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ddp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *	DDP:	An implementation of the AppleTalk DDP protocol for *		Ethernet 'ELAP'. * *		Alan Cox  <Alan.Cox@linux.org> * *		With more than a little assistance from * *		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. *		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 * *		This program is free software; you can redistribute it and/or *		modify it under the terms of the GNU General Public License *		as published by the Free Software Foundation; either version *		2 of the License, or (at your option) any later version. * */#include <linux/capability.h>#include <linux/module.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>#include "../core/kmap_skb.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(atalk_sockets_lock);static inline void __atalk_insert_socket(struct sock *sk){	sk_add_node(sk, &atalk_sockets);}static inline void atalk_remove_socket(struct sock *sk){	write_lock_bh(&atalk_sockets_lock);	sk_del_node_init(sk);	write_unlock_bh(&atalk_sockets_lock);}static struct sock *atalk_search_socket(struct sockaddr_at *to,					struct atalk_iface *atif){	struct sock *s;	struct hlist_node *node;	read_lock_bh(&atalk_sockets_lock);	sk_for_each(s, node, &atalk_sockets) {		struct atalk_sock *at = at_sk(s);		if (to->sat_port != at->src_port)			continue;		if (to->sat_addr.s_net == ATADDR_ANYNET &&		    to->sat_addr.s_node == ATADDR_BCAST)			goto found;		if (to->sat_addr.s_net == at->src_net &&		    (to->sat_addr.s_node == at->src_node ||		     to->sat_addr.s_node == ATADDR_BCAST ||		     to->sat_addr.s_node == ATADDR_ANYNODE))			goto found;		/* XXXX.0 -- we got a request for this router. make sure		 * that the node is appropriately set. */		if (to->sat_addr.s_node == ATADDR_ANYNODE &&		    to->sat_addr.s_net != ATADDR_ANYNET &&		    atif->address.s_node == at->src_node) {			to->sat_addr.s_node = atif->address.s_node;			goto found;		}	}	s = NULL;found:	read_unlock_bh(&atalk_sockets_lock);	return s;}/** * 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){	struct sock *s;	struct hlist_node *node;	struct atalk_sock *at;	write_lock_bh(&atalk_sockets_lock);	sk_for_each(s, node, &atalk_sockets) {		at = at_sk(s);		if (at->src_net == sat->sat_addr.s_net &&		    at->src_node == sat->sat_addr.s_node &&		    at->src_port == sat->sat_port)			goto found;	}	s = NULL;	__atalk_insert_socket(sk); /* Wheee, it's free, assign and insert. */found:	write_unlock_bh(&atalk_sockets_lock);	return s;}static void atalk_destroy_timer(unsigned long data){	struct sock *sk = (struct sock *)data;	if (atomic_read(&sk->sk_wmem_alloc) ||	    atomic_read(&sk->sk_rmem_alloc)) {		sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME;		add_timer(&sk->sk_timer);	} else		sock_put(sk);}static inline void atalk_destroy_socket(struct sock *sk){	atalk_remove_socket(sk);	skb_queue_purge(&sk->sk_receive_queue);	if (atomic_read(&sk->sk_wmem_alloc) ||	    atomic_read(&sk->sk_rmem_alloc)) {		init_timer(&sk->sk_timer);		sk->sk_timer.expires	= jiffies + SOCK_DESTROY_TIME;		sk->sk_timer.function	= atalk_destroy_timer;		sk->sk_timer.data	= (unsigned long)sk;		add_timer(&sk->sk_timer);	} else		sock_put(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(atalk_routes_lock);struct atalk_iface *atalk_interfaces;DEFINE_RWLOCK(atalk_interfaces_lock);/* 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){	struct atalk_iface **iface = &atalk_interfaces;	struct atalk_iface *tmp;	write_lock_bh(&atalk_interfaces_lock);	while ((tmp = *iface) != NULL) {		if (tmp->dev == dev) {			*iface = tmp->next;			dev_put(dev);			kfree(tmp);			dev->atalk_ptr = NULL;		} else			iface = &tmp->next;	}	write_unlock_bh(&atalk_interfaces_lock);}static struct atalk_iface *atif_add_device(struct net_device *dev,					   struct atalk_addr *sa){	struct atalk_iface *iface = kzalloc(sizeof(*iface), GFP_KERNEL);	if (!iface)		goto out;	dev_hold(dev);	iface->dev = dev;	dev->atalk_ptr = iface;	iface->address = *sa;	iface->status = 0;	write_lock_bh(&atalk_interfaces_lock);	iface->next = atalk_interfaces;	atalk_interfaces = iface;	write_unlock_bh(&atalk_interfaces_lock);out:	return iface;}/* Perform phase 2 AARP probing on our tentative address */static int atif_probe_device(struct atalk_iface *atif){	int netrange = ntohs(atif->nets.nr_lastnet) -			ntohs(atif->nets.nr_firstnet) + 1;	int probe_net = ntohs(atif->address.s_net);	int probe_node = atif->address.s_node;	int netct, nodect;	/* Offset the network we start probing with */	if (probe_net == ATADDR_ANYNET) {		probe_net = ntohs(atif->nets.nr_firstnet);		if (netrange)			probe_net += jiffies % netrange;	}	if (probe_node == ATADDR_ANYNODE)		probe_node = jiffies & 0xFF;	/* Scan the networks */	atif->status |= ATIF_PROBE;	for (netct = 0; netct <= netrange; netct++) {		/* Sweep the available nodes from a given start */		atif->address.s_net = htons(probe_net);		for (nodect = 0; nodect < 256; nodect++) {			atif->address.s_node = (nodect + probe_node) & 0xFF;			if (atif->address.s_node > 0 &&			    atif->address.s_node < 254) {				/* Probe a proposed address */				aarp_probe_network(atif);				if (!(atif->status & ATIF_PROBE_FAIL)) {					atif->status &= ~ATIF_PROBE;					return 0;				}			}			atif->status &= ~ATIF_PROBE_FAIL;		}		probe_net++;		if (probe_net > ntohs(atif->nets.nr_lastnet))			probe_net = ntohs(atif->nets.nr_firstnet);	}	atif->status &= ~ATIF_PROBE;	return -EADDRINUSE;	/* Network is full... */}/* Perform AARP probing for a proxy address */static int atif_proxy_probe_device(struct atalk_iface *atif,				   struct atalk_addr* proxy_addr){	int netrange = ntohs(atif->nets.nr_lastnet) -			ntohs(atif->nets.nr_firstnet) + 1;	/* we probe the interface's network */	int probe_net = ntohs(atif->address.s_net);	int probe_node = ATADDR_ANYNODE;	    /* we'll take anything */	int netct, nodect;	/* Offset the network we start probing with */	if (probe_net == ATADDR_ANYNET) {		probe_net = ntohs(atif->nets.nr_firstnet);		if (netrange)			probe_net += jiffies % netrange;	}	if (probe_node == ATADDR_ANYNODE)		probe_node = jiffies & 0xFF;	/* Scan the networks */	for (netct = 0; netct <= netrange; netct++) {		/* Sweep the available nodes from a given start */		proxy_addr->s_net = htons(probe_net);		for (nodect = 0; nodect < 256; nodect++) {			proxy_addr->s_node = (nodect + probe_node) & 0xFF;			if (proxy_addr->s_node > 0 &&			    proxy_addr->s_node < 254) {				/* Tell AARP to probe a proposed address */				int ret = aarp_proxy_probe_network(atif,								    proxy_addr);				if (ret != -EADDRINUSE)					return ret;			}		}		probe_net++;		if (probe_net > ntohs(atif->nets.nr_lastnet))			probe_net = ntohs(atif->nets.nr_firstnet);	}	return -EADDRINUSE;	/* Network is full... */}struct atalk_addr *atalk_find_dev_addr(struct net_device *dev){	struct atalk_iface *iface = dev->atalk_ptr;	return iface ? &iface->address : NULL;}static struct atalk_addr *atalk_find_primary(void){	struct atalk_iface *fiface = NULL;	struct atalk_addr *retval;	struct atalk_iface *iface;	/*	 * Return a point-to-point interface only if	 * there is no non-ptp interface available.	 */	read_lock_bh(&atalk_interfaces_lock);	for (iface = atalk_interfaces; iface; iface = iface->next) {		if (!fiface && !(iface->dev->flags & IFF_LOOPBACK))			fiface = iface;		if (!(iface->dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) {			retval = &iface->address;			goto out;		}	}	if (fiface)		retval = &fiface->address;	else if (atalk_interfaces)		retval = &atalk_interfaces->address;	else		retval = NULL;out:	read_unlock_bh(&atalk_interfaces_lock);	return retval;}/* * 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){	struct atalk_iface *iface = dev->atalk_ptr;	if (!iface || iface->status & ATIF_PROBE)		goto out_err;	if (node != ATADDR_BCAST &&	    iface->address.s_node != node &&	    node != ATADDR_ANYNODE)		goto out_err;out:	return iface;out_err:	iface = NULL;	goto out;}/* Find a match for a specific network:node pair */static struct atalk_iface *atalk_find_interface(__be16 net, int node){	struct atalk_iface *iface;	read_lock_bh(&atalk_interfaces_lock);	for (iface = atalk_interfaces; iface; iface = iface->next) {		if ((node == ATADDR_BCAST ||		     node == ATADDR_ANYNODE ||		     iface->address.s_node == node) &&		    iface->address.s_net == net &&		    !(iface->status & ATIF_PROBE))			break;		/* XXXX.0 -- net.0 returns the iface associated with net */		if (node == ATADDR_ANYNODE && net != ATADDR_ANYNET &&		    ntohs(iface->nets.nr_firstnet) <= ntohs(net) &&		    ntohs(net) <= ntohs(iface->nets.nr_lastnet))			break;	}	read_unlock_bh(&atalk_interfaces_lock);	return iface;}/* * 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){	/*	 * we must search through all routes unless we find a	 * host route, because some host routes might overlap	 * network routes	 */	struct atalk_route *net_route = NULL;	struct atalk_route *r;	read_lock_bh(&atalk_routes_lock);	for (r = atalk_routes; r; r = r->next) {		if (!(r->flags & RTF_UP))			continue;		if (r->target.s_net == target->s_net) {			if (r->flags & RTF_HOST) {				/*				 * if this host route is for the target,				 * the we're done				 */				if (r->target.s_node == target->s_node)					goto out;			} else				/*				 * this route will work if there isn't a				 * direct host route, so cache it				 */				net_route = r;		}	}	/*	 * if we found a network route but not a direct host	 * route, then return it	 */	if (net_route)		r = net_route;	else if (atrtr_default.dev)		r = &atrtr_default;	else /* No route can be found */		r = NULL;out:	read_unlock_bh(&atalk_routes_lock);	return r;}/* * 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){	struct atalk_route *atr = atrtr_find(sa);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -