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

📄 af_ipx.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *	Implements an IPX socket layer. * *	This code is derived from work by *		Ross Biro	: 	Writing the original IP stack *		Fred Van Kempen :	Tidying up the TCP/IP * *	Many thanks go to Keith Baker, Institute For Industrial Information *	Technology Ltd, Swansea University for allowing me to work on this *	in my own time even though it was in some ways related to commercial *	work I am currently employed to do there. * *	All the material in this file is subject to the Gnu license version 2. *	Neither Alan Cox nor the Swansea University Computer Society admit  *	liability nor provide warranty for any of this software. This material *	is provided as is and at no charge. * *	Revision 0.21:	Uses the new generic socket option code. *	Revision 0.22:	Gcc clean ups and drop out device registration. Use the *			new multi-protocol edition of hard_header *	Revision 0.23:  IPX /proc by Mark Evans. Adding a route will *     			will overwrite any existing route to the same network. *	Revision 0.24:	Supports new /proc with no 4K limit *	Revision 0.25:	Add ephemeral sockets, passive local network *			identification, support for local net 0 and *			multiple datalinks <Greg Page> *	Revision 0.26:  Device drop kills IPX routes via it. (needed for module) *	Revision 0.27:  Autobind <Mark Evans> *	Revision 0.28:  Small fix for multiple local networks <Thomas Winder> *	Revision 0.29:  Assorted major errors removed <Mark Evans> *			Small correction to promisc mode error fix <Alan Cox> *			Asynchronous I/O support. Changed to use notifiers *			and the newer packet_type stuff. Assorted major *			fixes <Alejandro Liu> *	Revision 0.30:	Moved to net/ipx/...	<Alan Cox> *			Don't set address length on recvfrom that errors. *			Incorrect verify_area. *	Revision 0.31:	New sk_buffs. This still needs a lot of  *			testing. <Alan Cox> *	Revision 0.32:  Using sock_alloc_send_skb, firewall hooks. <Alan Cox> *			Supports sendmsg/recvmsg *	Revision 0.33:	Internal network support, routing changes, uses a *			protocol private area for ipx data. *	Revision 0.34:	Module support. <Jim Freeman> *	Revision 0.35:  Checksum support. <Neil Turton>, hooked in by <Alan Cox> *			Handles WIN95 discovery packets <Volker Lendecke> *	Revision 0.36:	Internal bump up for 2.1 *	Revision 0.37:	Began adding POSIXisms. *	Revision 0.38:  Asynchronous socket stuff made current. *	Revision 0.39:  SPX interfaces *	Revision 0.40:  Tiny SIOCGSTAMP fix (chris@cybernet.co.nz) *      Revision 0.41:  802.2TR removed (p.norton@computer.org) *			Fixed connecting to primary net, *			Automatic binding on send & receive, *			Martijn van Oosterhout <kleptogimp@geocities.com> *	Revision 042:   Multithreading - use spinlocks and refcounting to *			protect some structures: ipx_interface sock list, list *			of ipx interfaces, etc.  *			Bugfixes - do refcounting on net_devices, check function *			results, etc. Thanks to davem and freitag for *			suggestions and guidance. *			Arnaldo Carvalho de Melo <acme@conectiva.com.br>, *			November, 2000 *	Revision 043:	Shared SKBs, don't mangle packets, some cleanups *			Arnaldo Carvalho de Melo <acme@conectiva.com.br>, *			December, 2000 *	Revision 044:	Call ipxitf_hold on NETDEV_UP (acme) *	Revision 045:	fix PPROP routing bug (acme) *	Revision 046:	Further fixes to PPROP, ipxitf_create_internal was *			doing an unneeded MOD_INC_USE_COUNT, implement *			sysctl for ipx_pprop_broacasting, fix the ipx sysctl *			handling, making it dynamic, some cleanups, thanks to *			Petr Vandrovec for review and good suggestions. (acme) *	Revision 047:	Cleanups, CodingStyle changes, move the ncp connection *			hack out of line (acme) * *	Protect the module by a MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT *	pair. Also, now usage count is managed this way *	-Count one if the auto_interface mode is on *      -Count one per configured interface * *	Jacques Gelinas (jacques@solucorp.qc.ca) * * * 	Portions Copyright (c) 1995 Caldera, Inc. <greg@caldera.com> *	Neither Greg Page nor Caldera, Inc. admit liability nor provide *	warranty for any of this software. This material is provided *	"AS-IS" and at no charge. */#include <linux/config.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/in.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/sockios.h>#include <linux/net.h>#include <linux/netdevice.h>#include <net/ipx.h>#include <linux/inet.h>#include <linux/route.h>#include <net/sock.h>#include <asm/uaccess.h>#include <asm/system.h>#include <linux/fcntl.h>#include <linux/mm.h>#include <linux/termios.h>	/* For TIOCOUTQ/INQ */#include <linux/interrupt.h>#include <net/p8022.h>#include <net/psnap.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <linux/init.h>#include <linux/if_arp.h>#ifdef CONFIG_SYSCTLextern void ipx_register_sysctl(void);extern void ipx_unregister_sysctl(void);#else#define ipx_register_sysctl()#define ipx_unregister_sysctl()#endif/* Configuration Variables */static unsigned char ipxcfg_max_hops = 16;static char ipxcfg_auto_select_primary;static char ipxcfg_auto_create_interfaces;int sysctl_ipx_pprop_broadcasting = 1;/* Global Variables */static struct datalink_proto *p8022_datalink;static struct datalink_proto *pEII_datalink;static struct datalink_proto *p8023_datalink;static struct datalink_proto *pSNAP_datalink;static struct proto_ops ipx_dgram_ops;static struct net_proto_family *spx_family_ops;static ipx_route *ipx_routes;static rwlock_t ipx_routes_lock = RW_LOCK_UNLOCKED;static ipx_interface *ipx_interfaces;static spinlock_t ipx_interfaces_lock = SPIN_LOCK_UNLOCKED;static ipx_interface *ipx_primary_net;static ipx_interface *ipx_internal_net;#define IPX_SKB_CB(__skb) ((struct ipx_cb *)&((__skb)->cb[0]))#undef IPX_REFCNT_DEBUG#ifdef IPX_REFCNT_DEBUGatomic_t ipx_sock_nr;#endifstatic void ipxcfg_set_auto_create(char val){	if (ipxcfg_auto_create_interfaces != val) {		if (val)			MOD_INC_USE_COUNT;		else			MOD_DEC_USE_COUNT;		ipxcfg_auto_create_interfaces = val;	}}static void ipxcfg_set_auto_select(char val){	ipxcfg_auto_select_primary = val;	if (val && !ipx_primary_net)		ipx_primary_net = ipx_interfaces;}static int ipxcfg_get_config_data(ipx_config_data *arg){	ipx_config_data	vals;	vals.ipxcfg_auto_create_interfaces = ipxcfg_auto_create_interfaces;	vals.ipxcfg_auto_select_primary	   = ipxcfg_auto_select_primary;	return copy_to_user(arg, &vals, sizeof(vals)) ? -EFAULT : 0;}/* Handlers for the socket list. */static inline void ipxitf_hold(ipx_interface *intrfc){	atomic_inc(&intrfc->refcnt);}static void ipxitf_down(ipx_interface *intrfc);static inline void ipxitf_put(ipx_interface *intrfc){	if (atomic_dec_and_test(&intrfc->refcnt))		ipxitf_down(intrfc);}static void __ipxitf_down(ipx_interface *intrfc);static inline void __ipxitf_put(ipx_interface *intrfc){	if (atomic_dec_and_test(&intrfc->refcnt))		__ipxitf_down(intrfc);}/* * Note: Sockets may not be removed _during_ an interrupt or inet_bh * handler using this technique. They can be added although we do not * use this facility. */void ipx_remove_socket(struct sock *sk){	struct sock *s;	ipx_interface *intrfc;	/* Determine interface with which socket is associated */	intrfc = sk->protinfo.af_ipx.intrfc;	if (!intrfc)		goto out;	ipxitf_hold(intrfc);	spin_lock_bh(&intrfc->if_sklist_lock);	s = intrfc->if_sklist;	if (s == sk) {		intrfc->if_sklist = s->next;		goto out_unlock;	}	while (s && s->next) {		if (s->next == sk) {			s->next = sk->next;			goto out_unlock;		}		s = s->next;	}out_unlock:	spin_unlock_bh(&intrfc->if_sklist_lock);	sock_put(sk);	ipxitf_put(intrfc);out:	return;}static void ipx_destroy_socket(struct sock *sk){	ipx_remove_socket(sk);	skb_queue_purge(&sk->receive_queue);#ifdef IPX_REFCNT_DEBUG        atomic_dec(&ipx_sock_nr);        printk(KERN_DEBUG "IPX socket %p released, %d are still alive\n", sk,			atomic_read(&ipx_sock_nr));	if (atomic_read(&sk->refcnt) != 1)		printk(KERN_DEBUG "Destruction sock ipx %p delayed, cnt=%d\n",				sk, atomic_read(&sk->refcnt));#endif	sock_put(sk);}/*  * The following code is used to support IPX Interfaces (IPXITF).  An * IPX interface is defined by a physical device and a frame type. */static ipx_route * ipxrtr_lookup(__u32);/* ipxitf_clear_primary_net has to be called with ipx_interfaces_lock held */static void ipxitf_clear_primary_net(void){	ipx_primary_net = ipxcfg_auto_select_primary ? ipx_interfaces : NULL;}static ipx_interface *__ipxitf_find_using_phys(struct net_device *dev,						unsigned short datalink){	ipx_interface *i = ipx_interfaces;	while (i && (i->if_dev != dev || i->if_dlink_type != datalink))		i = i->if_next;	return i;}static ipx_interface *ipxitf_find_using_phys(struct net_device *dev,						unsigned short datalink){	ipx_interface *i;	spin_lock_bh(&ipx_interfaces_lock);	i = __ipxitf_find_using_phys(dev, datalink);	if (i)		ipxitf_hold(i);	spin_unlock_bh(&ipx_interfaces_lock);	return i;}static ipx_interface *ipxitf_find_using_net(__u32 net){	ipx_interface *i;	spin_lock_bh(&ipx_interfaces_lock);	if (net)		for (i = ipx_interfaces; i && i->if_netnum != net;		     i = i->if_next)		;	else		i = ipx_primary_net;	if (i)		ipxitf_hold(i);	spin_unlock_bh(&ipx_interfaces_lock);	return i;}/* Sockets are bound to a particular IPX interface. */static void ipxitf_insert_socket(ipx_interface *intrfc, struct sock *sk){	ipxitf_hold(intrfc);	sock_hold(sk);	spin_lock_bh(&intrfc->if_sklist_lock);	sk->protinfo.af_ipx.intrfc = intrfc;	sk->next = NULL;	if (!intrfc->if_sklist)		intrfc->if_sklist = sk;	else {		struct sock *s = intrfc->if_sklist;		while (s->next)			s = s->next;		s->next = sk;	}	spin_unlock_bh(&intrfc->if_sklist_lock);	ipxitf_put(intrfc);}/* caller must hold intrfc->if_sklist_lock */static struct sock *__ipxitf_find_socket(ipx_interface *intrfc,					 unsigned short port){	struct sock *s = intrfc->if_sklist;	while (s && s->protinfo.af_ipx.port != port)	     s = s->next;	return s;}/* caller must hold a reference to intrfc */static struct sock *ipxitf_find_socket(ipx_interface *intrfc,					unsigned short port){	struct sock *s;	spin_lock_bh(&intrfc->if_sklist_lock);	s = __ipxitf_find_socket(intrfc, port);	if (s)		sock_hold(s);	spin_unlock_bh(&intrfc->if_sklist_lock);	return s;}#ifdef CONFIG_IPX_INTERNstatic struct sock *ipxitf_find_internal_socket(ipx_interface *intrfc,			    unsigned char *node, unsigned short port){	struct sock *s;	ipxitf_hold(intrfc);	spin_lock_bh(&intrfc->if_sklist_lock);	s = intrfc->if_sklist;	while (s) {		if (s->protinfo.af_ipx.port == port &&		    !memcmp(node, s->protinfo.af_ipx.node, IPX_NODE_LEN))			break;		s = s->next;	}	spin_unlock_bh(&intrfc->if_sklist_lock);	ipxitf_put(intrfc);	return s;}#endifstatic void ipxrtr_del_routes(ipx_interface *);static void __ipxitf_down(ipx_interface *intrfc){	struct sock *s, *t;	/* Delete all routes associated with this interface */	ipxrtr_del_routes(intrfc);	spin_lock_bh(&intrfc->if_sklist_lock);	/* error sockets */	for (s = intrfc->if_sklist; s;) {		s->err = ENOLINK;		s->error_report(s);		s->protinfo.af_ipx.intrfc = NULL;		s->protinfo.af_ipx.port	  = 0;		s->zapped = 1;	/* Indicates it is no longer bound */		t = s;		s = s->next;		t->next = NULL;	}	intrfc->if_sklist = NULL;	spin_unlock_bh(&intrfc->if_sklist_lock);	/* remove this interface from list */	if (intrfc == ipx_interfaces)		ipx_interfaces = intrfc->if_next;	else {		ipx_interface *i = ipx_interfaces;		while (i && i->if_next != intrfc)		     i = i->if_next;		if (i && i->if_next == intrfc)			i->if_next = intrfc->if_next;	}	/* remove this interface from *special* networks */	if (intrfc == ipx_primary_net)		ipxitf_clear_primary_net();	if (intrfc == ipx_internal_net)		ipx_internal_net = NULL;	if (intrfc->if_dev)		dev_put(intrfc->if_dev);	kfree(intrfc);	MOD_DEC_USE_COUNT;}static void ipxitf_down(ipx_interface *intrfc){	spin_lock_bh(&ipx_interfaces_lock);	__ipxitf_down(intrfc);	spin_unlock_bh(&ipx_interfaces_lock);}static int ipxitf_device_event(struct notifier_block *notifier,				unsigned long event, void *ptr){	struct net_device *dev = ptr;	ipx_interface *i, *tmp;	if (event != NETDEV_DOWN && event != NETDEV_UP)		goto out;	spin_lock_bh(&ipx_interfaces_lock);	for (i = ipx_interfaces; i;) {		tmp = i->if_next;		if (i->if_dev == dev) {			if (event == NETDEV_UP)				ipxitf_hold(i);			else				__ipxitf_put(i);		}		i = tmp;	}	spin_unlock_bh(&ipx_interfaces_lock);out:	return NOTIFY_DONE;}static void ipxitf_def_skb_handler(struct sock *sock, struct sk_buff *skb){	if (sock_queue_rcv_skb(sock, skb) < 0)		kfree_skb(skb);}/* * On input skb->sk is NULL. Nobody is charged for the memory. *//* caller must hold a reference to intrfc */#ifdef CONFIG_IPX_INTERNstatic int ipxitf_demux_socket(ipx_interface *intrfc, struct sk_buff *skb,				int copy){	struct ipxhdr *ipx = skb->nh.ipxh;	int is_broadcast = !memcmp(ipx->ipx_dest.node, ipx_broadcast_node,				   IPX_NODE_LEN);	struct sock *s;	int ret;	spin_lock_bh(&intrfc->if_sklist_lock);	s = intrfc->if_sklist;	while (s) {		if (s->protinfo.af_ipx.port == ipx->ipx_dest.sock &&		    (is_broadcast || !memcmp(ipx->ipx_dest.node,					     s->protinfo.af_ipx.node,					     IPX_NODE_LEN))) {			/* We found a socket to which to send */			struct sk_buff *skb1;			if (copy) {				skb1 = skb_clone(skb, GFP_ATOMIC);				ret = -ENOMEM;				if (!skb1)					goto out;			} else {				skb1 = skb;				copy = 1; /* skb may only be used once */			}			ipxitf_def_skb_handler(s, skb1);			/* On an external interface, one socket can listen */			if (intrfc != ipx_internal_net)

⌨️ 快捷键说明

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