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

📄 af_ipx.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (!intrfc)		goto out;	memcpy((char *)&(intrfc->if_node), idef->ipx_node, IPX_NODE_LEN);	ipx_internal_net = ipx_primary_net = intrfc;	ipxitf_hold(intrfc);	ipxitf_insert(intrfc);	ret = ipxitf_add_local_route(intrfc);	ipxitf_put(intrfc);out:	return ret;}static int ipx_map_frame_type(unsigned char type){	int ret = 0;	switch (type) {		case IPX_FRAME_ETHERII:			ret = __constant_htons(ETH_P_IPX);			break;		case IPX_FRAME_8022:			ret = __constant_htons(ETH_P_802_2);			break;		case IPX_FRAME_SNAP:			ret = __constant_htons(ETH_P_SNAP);			break;		case IPX_FRAME_8023:			ret = __constant_htons(ETH_P_802_3);			break;	}	return ret;}static int ipxitf_create(ipx_interface_definition *idef){	struct net_device *dev;	unsigned short dlink_type = 0;	struct datalink_proto *datalink = NULL;	ipx_interface *intrfc;	int err;	if (idef->ipx_special == IPX_INTERNAL) {		err = ipxitf_create_internal(idef);		goto out;	}	err = -EEXIST;	if (idef->ipx_special == IPX_PRIMARY && ipx_primary_net)		goto out;	intrfc = ipxitf_find_using_net(idef->ipx_network);	err = -EADDRINUSE;	if (idef->ipx_network && intrfc) {		ipxitf_put(intrfc);		goto out;	}	if (intrfc)		ipxitf_put(intrfc);	dev = dev_get_by_name(idef->ipx_device);	err = -ENODEV;	if (!dev)		goto out;	switch (idef->ipx_dlink_type) {		case IPX_FRAME_TR_8022:			printk(KERN_WARNING "IPX frame type 802.2TR is "				"obsolete Use 802.2 instead.\n");			/* fall through */		case IPX_FRAME_8022:			dlink_type 	= __constant_htons(ETH_P_802_2);			datalink 	= p8022_datalink;			break;		case IPX_FRAME_ETHERII:			if (dev->type != ARPHRD_IEEE802) {				dlink_type 	= __constant_htons(ETH_P_IPX);				datalink 	= pEII_datalink;				break;			} else 				printk(KERN_WARNING "IPX frame type EtherII "					"over token-ring is obsolete. Use SNAP "					"instead.\n");			/* fall through */		case IPX_FRAME_SNAP:			dlink_type 	= __constant_htons(ETH_P_SNAP);			datalink 	= pSNAP_datalink;			break;		case IPX_FRAME_8023:			dlink_type 	= __constant_htons(ETH_P_802_3);			datalink 	= p8023_datalink;			break;		case IPX_FRAME_NONE:		default:			err = -EPROTONOSUPPORT;			goto out_dev;	}	err = -ENETDOWN;	if (!(dev->flags & IFF_UP))		goto out_dev;	/* Check addresses are suitable */	err = -EINVAL;	if (dev->addr_len > IPX_NODE_LEN)		goto out_dev;	intrfc = ipxitf_find_using_phys(dev, dlink_type);	if (!intrfc) {		/* Ok now create */		intrfc = ipxitf_alloc(dev, idef->ipx_network, dlink_type,				      datalink, 0, dev->hard_header_len +					datalink->header_length);		err = -EAGAIN;		if (!intrfc)			goto out_dev;		/* Setup primary if necessary */		if (idef->ipx_special == IPX_PRIMARY)			ipx_primary_net = intrfc;		if (!memcmp(idef->ipx_node, "\000\000\000\000\000\000",			    IPX_NODE_LEN)) {			memset(intrfc->if_node, 0, IPX_NODE_LEN);			memcpy(intrfc->if_node + IPX_NODE_LEN - dev->addr_len,				dev->dev_addr, dev->addr_len);		} else			memcpy(intrfc->if_node, idef->ipx_node, IPX_NODE_LEN);		ipxitf_hold(intrfc);		ipxitf_insert(intrfc);	}	/* If the network number is known, add a route */	err = 0;	if (!intrfc->if_netnum)		goto out_intrfc;	err = ipxitf_add_local_route(intrfc);out_intrfc:	ipxitf_put(intrfc);	goto out;out_dev:	dev_put(dev);out:	return err;}static int ipxitf_delete(ipx_interface_definition *idef){	struct net_device *dev = NULL;	unsigned short dlink_type = 0;	ipx_interface *intrfc;	int ret = 0;	spin_lock_bh(&ipx_interfaces_lock);	if (idef->ipx_special == IPX_INTERNAL) {		if (ipx_internal_net) {			__ipxitf_put(ipx_internal_net);			goto out;		}		ret = -ENOENT;		goto out;	}	dlink_type = ipx_map_frame_type(idef->ipx_dlink_type);	ret = -EPROTONOSUPPORT;	if (!dlink_type)		goto out;	dev = __dev_get_by_name(idef->ipx_device);	ret = -ENODEV;	if (!dev)		goto out;	intrfc = __ipxitf_find_using_phys(dev, dlink_type);	ret = -EINVAL;	if (!intrfc)		goto out;	__ipxitf_put(intrfc);	ret = 0;out:	spin_unlock_bh(&ipx_interfaces_lock);	return ret;}static ipx_interface *ipxitf_auto_create(struct net_device *dev, 					 unsigned short dlink_type){	ipx_interface *intrfc = NULL;	struct datalink_proto *datalink;	if (!dev)		goto out;	/* Check addresses are suitable */	if (dev->addr_len > IPX_NODE_LEN)		goto out;	switch (htons(dlink_type)) {		case ETH_P_IPX:			datalink = pEII_datalink;			break;		case ETH_P_802_2:			datalink = p8022_datalink;			break;		case ETH_P_SNAP:			datalink = pSNAP_datalink;			break;		case ETH_P_802_3:			datalink = p8023_datalink;			break;		default:			goto out;	}	intrfc = ipxitf_alloc(dev, 0, dlink_type, datalink, 0,				dev->hard_header_len + datalink->header_length);	if (intrfc) {		memset(intrfc->if_node, 0, IPX_NODE_LEN);		memcpy((char *)&(intrfc->if_node[IPX_NODE_LEN-dev->addr_len]),			dev->dev_addr, dev->addr_len);		spin_lock_init(&intrfc->if_sklist_lock);		atomic_set(&intrfc->refcnt, 1);		ipxitf_insert(intrfc);		dev_hold(dev);	}out:	return intrfc;}static int ipxitf_ioctl(unsigned int cmd, void *arg){	struct ifreq ifr;	int val;	switch (cmd) {		case SIOCSIFADDR: {			struct sockaddr_ipx *sipx;			ipx_interface_definition f;			if (copy_from_user(&ifr, arg, sizeof(ifr)))				return -EFAULT;			sipx = (struct sockaddr_ipx *)&ifr.ifr_addr;			if (sipx->sipx_family != AF_IPX)				return -EINVAL;			f.ipx_network = sipx->sipx_network;			memcpy(f.ipx_device, ifr.ifr_name,				sizeof(f.ipx_device));			memcpy(f.ipx_node, sipx->sipx_node, IPX_NODE_LEN);			f.ipx_dlink_type = sipx->sipx_type;			f.ipx_special = sipx->sipx_special;			if (sipx->sipx_action == IPX_DLTITF)				return ipxitf_delete(&f);			else				return ipxitf_create(&f);		}		case SIOCGIFADDR: {			int err = 0;			struct sockaddr_ipx *sipx;			ipx_interface *ipxif;			struct net_device *dev;			if (copy_from_user(&ifr, arg, sizeof(ifr)))				return -EFAULT;			sipx = (struct sockaddr_ipx *)&ifr.ifr_addr;			dev = __dev_get_by_name(ifr.ifr_name);			if (!dev)				return -ENODEV;			ipxif = ipxitf_find_using_phys(dev, ipx_map_frame_type(sipx->sipx_type));			if (!ipxif)				return -EADDRNOTAVAIL;			sipx->sipx_family	= AF_IPX;			sipx->sipx_network	= ipxif->if_netnum;			memcpy(sipx->sipx_node, ipxif->if_node,				sizeof(sipx->sipx_node));			if (copy_to_user(arg, &ifr, sizeof(ifr)))				err = -EFAULT;			ipxitf_put(ipxif);			return err;		}		case SIOCAIPXITFCRT: 			if (get_user(val, (unsigned char *) arg))				return -EFAULT;			ipxcfg_set_auto_create(val);			break;		case SIOCAIPXPRISLT: 			if (get_user(val, (unsigned char *) arg))				return -EFAULT;			ipxcfg_set_auto_select(val);			break;		default:			return -EINVAL;	}	return 0;}/* Routing tables for the IPX socket layer. */static inline void ipxrtr_hold(ipx_route *rt){	atomic_inc(&rt->refcnt);}static inline void ipxrtr_put(ipx_route *rt){	if (atomic_dec_and_test(&rt->refcnt))		kfree(rt);}static ipx_route *ipxrtr_lookup(__u32 net){	ipx_route *r;	read_lock_bh(&ipx_routes_lock);	for (r = ipx_routes; r && r->ir_net != net; r = r->ir_next)		;	if (r)		ipxrtr_hold(r);	read_unlock_bh(&ipx_routes_lock);	return r;}/* caller must hold a reference to intrfc */static int ipxrtr_add_route(__u32 network, ipx_interface *intrfc,				unsigned char *node){	ipx_route *rt;	int ret;	/* Get a route structure; either existing or create */	rt = ipxrtr_lookup(network);	if (!rt) {		rt = kmalloc(sizeof(ipx_route), GFP_ATOMIC);		ret = -EAGAIN;		if (!rt)			goto out;		atomic_set(&rt->refcnt, 1);		ipxrtr_hold(rt);		write_lock_bh(&ipx_routes_lock);		rt->ir_next	= ipx_routes;		ipx_routes	= rt;		write_unlock_bh(&ipx_routes_lock);	} else {		ret = -EEXIST;		if (intrfc == ipx_internal_net)			goto out_put;	}	rt->ir_net 	= network;	rt->ir_intrfc 	= intrfc;	if (!node) {		memset(rt->ir_router_node, '\0', IPX_NODE_LEN);		rt->ir_routed = 0;	} else {		memcpy(rt->ir_router_node, node, IPX_NODE_LEN);		rt->ir_routed = 1;	}	ret = 0;out_put:	ipxrtr_put(rt);out:	return ret;}static void ipxrtr_del_routes(ipx_interface *intrfc){	ipx_route **r, *tmp;	write_lock_bh(&ipx_routes_lock);	for (r = &ipx_routes; (tmp = *r) != NULL;) {		if (tmp->ir_intrfc == intrfc) {			*r = tmp->ir_next;			ipxrtr_put(tmp);		} else			r = &(tmp->ir_next);	}	write_unlock_bh(&ipx_routes_lock);}static int ipxrtr_create(ipx_route_definition *rd){	ipx_interface *intrfc;	int ret = -ENETUNREACH;	/* Find the appropriate interface */	intrfc = ipxitf_find_using_net(rd->ipx_router_network);	if (!intrfc)		goto out;	ret = ipxrtr_add_route(rd->ipx_network, intrfc, rd->ipx_router_node);	ipxitf_put(intrfc);out:	return ret;}static int ipxrtr_delete(long net){	ipx_route **r;	ipx_route *tmp;	int err;	write_lock_bh(&ipx_routes_lock);	for (r = &ipx_routes; (tmp = *r) != NULL;) {		if (tmp->ir_net == net) {			/* Directly connected; can't lose route */			err = -EPERM;			if (!tmp->ir_routed)				goto out;			*r = tmp->ir_next;			ipxrtr_put(tmp);			err = 0;			goto out;		}		r = &(tmp->ir_next);	}	err = -ENOENT;out:	write_unlock_bh(&ipx_routes_lock);	return err;}/* *	Checksum routine for IPX */ /* Note: We assume ipx_tctrl==0 and htons(length)==ipx_pktsize *//* This functions should *not* mess with packet contents */static __u16 ipx_cksum(struct ipxhdr *packet, int length) {	/* 	 *	NOTE: sum is a net byte order quantity, which optimizes the 	 *	loop. This only works on big and little endian machines. (I	 *	don't know of a machine that isn't.)	 */	/* start at ipx_dest - We skip the checksum field and start with	 * ipx_type before the loop, not considering ipx_tctrl in the calc */	__u16 *p = (__u16 *)&packet->ipx_dest;	__u32 i = (length >> 1) - 1; /* Number of complete words */	__u32 sum = packet->ipx_type << sizeof(packet->ipx_tctrl); 	/* Loop through all complete words except the checksum field,	 * ipx_type (accounted above) and ipx_tctrl (not used in the cksum) */	while (--i)		sum += *p++;	/* Add on the last part word if it exists */	if (packet->ipx_pktsize & __constant_htons(1))		sum += ntohs(0xff00) & *p;	/* Do final fixup */	sum = (sum & 0xffff) + (sum >> 16);	/* It's a pity there's no concept of carry in C */	if (sum >= 0x10000)		sum++;	return ~sum;}/* * Route an outgoing frame from a socket. */static int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,				struct iovec *iov, int len, int noblock){	struct sk_buff *skb;	ipx_interface *intrfc;	struct ipxhdr *ipx;	int size;	int ipx_offset;	ipx_route *rt = NULL;	int err;	/* Find the appropriate interface on which to send packet */	if (!usipx->sipx_network && ipx_primary_net) {		usipx->sipx_network = ipx_primary_net->if_netnum;		intrfc = ipx_primary_net;	} else {		rt = ipxrtr_lookup(usipx->sipx_network);		err = -ENETUNREACH;		if (!rt)			goto out;		intrfc = rt->ir_intrfc;	}	ipxitf_hold(intrfc);	ipx_offset = intrfc->if_ipx_offset;	size = sizeof(struct ipxhdr) + len + ipx_offset;	skb = sock_alloc_send_skb(sk, size, noblock, &err);	if (!skb)		goto out_put;	skb_reserve(skb, ipx_offset);

⌨️ 快捷键说明

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