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

📄 af_ipx.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
			datalink 	= pSNAP_datalink;			break;		case IPX_FRAME_8023:			dlink_type 	= htons(ETH_P_802_3);			datalink 	= p8023_datalink;			break;		case IPX_FRAME_NONE:		default:			break;	}	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;	err = -EPROTONOSUPPORT;	if(datalink == NULL)		goto out_dev;	if((intrfc = ipxitf_find_using_phys(dev, dlink_type)) == NULL)	{		/* Ok now create */		intrfc = (ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC);		err = -EAGAIN;		if(intrfc == NULL)			goto out_dev;		intrfc->if_dev		= dev;		intrfc->if_netnum 	= idef->ipx_network;		intrfc->if_dlink_type 	= dlink_type;		intrfc->if_dlink 	= datalink;		intrfc->if_sklist 	= NULL;		intrfc->if_sknum 	= IPX_MIN_EPHEMERAL_SOCKET;		/* Setup primary if necessary */		if((idef->ipx_special == IPX_PRIMARY))			ipx_primary_net = intrfc;		intrfc->if_internal 	= 0;		intrfc->if_ipx_offset 	= dev->hard_header_len + datalink->header_length;		if(memcmp(idef->ipx_node, "\000\000\000\000\000\000", IPX_NODE_LEN) == 0)		{			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);		}		else			memcpy(intrfc->if_node, idef->ipx_node, IPX_NODE_LEN);		spin_lock_init(&intrfc->if_sklist_lock);		atomic_set(&intrfc->refcnt, 1);		MOD_INC_USE_COUNT;		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);	return err;out_dev:	dev_put(dev);	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 != NULL) 		{			__ipxitf_put(ipx_internal_net);			goto out;		}		ret = -ENOENT;		goto out;	}	dlink_type = ipx_map_frame_type(idef->ipx_dlink_type);	if(dlink_type == 0) {		ret = -EPROTONOSUPPORT;		goto out;	}	dev = __dev_get_by_name(idef->ipx_device);	if(dev == NULL) {		ret = -ENODEV;		goto out;	}	intrfc = __ipxitf_find_using_phys(dev, dlink_type);	if(intrfc != NULL)		__ipxitf_put(intrfc);	else		ret = -EINVAL;out:	spin_unlock_bh(&ipx_interfaces_lock);	return ret;}static ipx_interface *ipxitf_auto_create(struct net_device *dev, 	unsigned short dlink_type){	struct datalink_proto *datalink = NULL;	ipx_interface *intrfc;	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:			return (NULL);	}	if(dev == NULL)		return (NULL);	/* Check addresses are suitable */	if(dev->addr_len>IPX_NODE_LEN)		return (NULL);	intrfc = (ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC);	if(intrfc != NULL) 	{		intrfc->if_dev		= dev;		intrfc->if_netnum	= 0;		intrfc->if_dlink_type 	= dlink_type;		intrfc->if_dlink 	= datalink;		intrfc->if_sklist 	= NULL;		intrfc->if_internal 	= 0;		intrfc->if_sknum 	= IPX_MIN_EPHEMERAL_SOCKET;		intrfc->if_ipx_offset 	= dev->hard_header_len +						datalink->header_length;		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);		MOD_INC_USE_COUNT;		ipxitf_insert(intrfc);	}	return (intrfc);}static int ipxitf_ioctl(unsigned int cmd, void *arg){	struct ifreq ifr;	int err, 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: 		{			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 == NULL)				return (-EADDRNOTAVAIL);			sipx->sipx_family	= AF_IPX;			sipx->sipx_network	= ipxif->if_netnum;			memcpy(sipx->sipx_node, ipxif->if_node, sizeof(sipx->sipx_node));			err = -EFAULT;			if(!copy_to_user(arg, &ifr, sizeof(ifr)))				err = 0;			ipxitf_put(ipxif);			return (err);		}		case SIOCAIPXITFCRT: 		{			err = get_user(val, (unsigned char *) arg);			if(err)				return (err);			return (ipxcfg_set_auto_create(val));		}		case SIOCAIPXPRISLT: 		{			err = get_user(val, (unsigned char *) arg);			if(err)				return (err);			return (ipxcfg_set_auto_select(val));		}		default:			return (-EINVAL);	}}/**************************************************************************\*                                                                          ** Routing tables for the IPX socket layer.                                 **                                                                          *\**************************************************************************/static ipx_route *ipxrtr_lookup(__u32 net){	ipx_route *r;	read_lock_bh(&ipx_routes_lock);	for(r = ipx_routes; (r != NULL) && (r->ir_net != net); r = r->ir_next)		;	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;	/* Get a route structure; either existing or create */	rt = ipxrtr_lookup(network);	if(rt == NULL) 	{		rt = (ipx_route *)kmalloc(sizeof(ipx_route),GFP_ATOMIC);		if(rt == NULL)			return (-EAGAIN);		write_lock_bh(&ipx_routes_lock);		rt->ir_next	= ipx_routes;		ipx_routes	= rt;		write_unlock_bh(&ipx_routes_lock);	}	else if(intrfc == ipx_internal_net)		return (-EEXIST);	rt->ir_net 	= network;	rt->ir_intrfc 	= intrfc;	if(node == NULL)	{		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;	}	return (0);}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;			kfree(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;	/* Find the appropriate interface */	intrfc = ipxitf_find_using_net(rd->ipx_router_network);	if(intrfc == NULL)		return (-ENETUNREACH);	ret = ipxrtr_add_route(rd->ipx_network, intrfc, rd->ipx_router_node);	ipxitf_put(intrfc);	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;			kfree(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 */static __u16 ipx_set_checksum(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.)	 */	__u32 sum = 0;	/* Pointer to second word - We skip the checksum field */	__u16 *p = (__u16 *)&packet->ipx_pktsize;	/* Number of complete words */	__u32 i = length >> 1;	char hops = packet->ipx_tctrl;	/* Hop count excluded from checksum calc */	packet->ipx_tctrl = 0;	/* Loop through all complete words except the checksum field */	while(--i)		sum += *p++;	/* Add on the last part word if it exists */	if(packet->ipx_pktsize & htons(1))		sum += ntohs(0xff00) & *p;	packet->ipx_tctrl = hops;	/* 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 != NULL))	{		usipx->sipx_network = ipx_primary_net->if_netnum;		intrfc = ipx_primary_net;	}	else	{		rt = ipxrtr_lookup(usipx->sipx_network);		if(rt == NULL)			return (-ENETUNREACH);		intrfc = rt->ir_intrfc;	}	ipxitf_hold(intrfc);	ipx_offset = intrfc->if_ipx_offset;	size	= sizeof(struct ipxhdr) + len;	size 	+= ipx_offset;	skb = sock_alloc_send_skb(sk, size, 0, noblock, &err);	if(skb == NULL)		goto out;	skb_reserve(skb,ipx_offset);	skb->sk = sk;	/* Fill in IPX header */	ipx = (struct ipxhdr *)skb_put(skb, sizeof(struct ipxhdr));	ipx->ipx_pktsize= htons(len + sizeof(struct ipxhdr));	ipx->ipx_tctrl 	= 0;	ipx->ipx_type 	= usipx->sipx_type;	skb->h.raw 	= (void *)skb->nh.ipxh = ipx;	ipx->ipx_source.net = sk->protinfo.af_ipx.intrfc->if_netnum;#ifdef CONFIG_IPX_INTERN	memcpy(ipx->ipx_source.node, sk->protinfo.af_ipx.node, IPX_NODE_LEN);#else	if((err = ntohs(sk->protinfo.af_ipx.port)) == 0x453 || err == 0x452)	{		/* RIP/SAP special handling for mars_nwe */		ipx->ipx_source.net = intrfc->if_netnum;		memcpy(ipx->ipx_source.node, intrfc->if_node, IPX_NODE_LEN);	}	else	{		ipx->ipx_source.net = sk->protinfo.af_ipx.intrfc->if_netnum;		memcpy(ipx->ipx_source.node, sk->protinfo.af_ipx.intrfc->if_node, IPX_NODE_LEN);	}#endif	/* CONFIG_IPX_INTERN */	ipx->ipx_source.sock 	= sk->protinfo.af_ipx.port;	ipx->ipx_dest.net	= usipx->sipx_network;	memcpy(ipx->ipx_dest.node,usipx->sipx_node,IPX_NODE_LEN);	ipx->ipx_dest.sock	= usipx->sipx_port;	err = memcpy_fromiovec(skb_put(skb,len),iov,len);	if(err)	{		kfree_skb(skb);		goto out;	}		/* Apply checksum. Not allowed on 802.3 links. */	if(sk->no_check || intrfc->if_dlink_type == IPX_FRAME_8023)		ipx->ipx_checksum=0xFFFF;	else		ipx->ipx_checksum = ipx_set_checksum(ipx, len + sizeof(struct ipxhdr));	err = ipxitf_send(intrfc, skb, (rt && rt->ir_routed) ? 				rt->ir_router_node : ipx->ipx_dest.node);out:	ipxitf_put(intrfc);	return err;}	int ipxrtr_route_skb(struct sk_buff *skb){	struct ipxhdr *ipx = skb->nh.ipxh;	ipx_route *r;	r = ipxrtr_lookup(ipx->ipx_dest.net);	if(r == NULL)	/* no known route */	{		kfree_skb(skb);		return (0);	}	ipxitf_hold(r->ir_intrfc);	(void)ipxitf_send(r->ir_intrfc, skb, (r->ir_routed) ?			r->ir_router_node : ipx->ipx_dest.node);	ipxitf_put(r->ir_intrfc);	return (0);}/* * We use a normal struct rtentry for route handling */static int ipxrtr_ioctl(unsigned int cmd, void *arg){	struct rtentry rt;	/* Use these to behave like 'other' stacks */	struct sockaddr_ipx *sg,*st;	int err;	err = copy_from_user(&rt,arg,sizeof(rt));	if(err)		return (-EFAULT);

⌨️ 快捷键说明

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