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

📄 af_ipx.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
#elsestatic int ipxitf_demux_socket(ipx_interface *intrfc, struct sk_buff *skb, int copy){	struct ipxhdr *ipx = skb->nh.ipxh;	struct sock *sock1 = NULL, *sock2 = NULL;	struct sk_buff *skb1 = NULL, *skb2 = NULL;	int ret;	if (intrfc == ipx_primary_net && ntohs(ipx->ipx_dest.sock) == 0x451) 	{		/* 	 	 * The packet's target is a NCP connection handler. We want to	 	 * hand it to the correct socket directly within the kernel,	 	 * so that the mars_nwe packet distribution process	 	 * does not have to do it. Here we only care about NCP and	 	 * BURST packets.	 	 * You might call this a hack, but believe me, you do not	 	 * want a complete NCP layer in the kernel, and this is	 	 * VERY fast as well.	 	 */	 	int connection = 0;	 	if (*((char*)(ipx+1)) == 0x22 &&  *((char*)(ipx+1)+1) == 0x22) 		{	  		/*			 * The packet is a NCP request			 */			connection = ( ((int) *((char*)(ipx+1)+5)) << 8 )		 	       | (int) *((char*)(ipx+1)+3);		} 		else if (*((char*)(ipx+1))== 0x77 &&  *((char*)(ipx+1)+1) == 0x77) 		{			/*			 * The packet is a BURST packet			 */			connection = ( ((int) *((char*)(ipx+1)+9)) << 8 )		 	       | (int) *((char*)(ipx+1)+8);		}        	if (connection) 		{			/*			 * Now we have to look for a special NCP connection handling			 * socket. Only these sockets have ipx_ncp_conn != 0, set			 * by SIOCIPXNCPCONN.			 */			spin_lock_bh(&intrfc->if_sklist_lock);			for (sock1=intrfc->if_sklist;				(sock1 != NULL) &&				(sock1->protinfo.af_ipx.ipx_ncp_conn != connection);					sock1=sock1->next);			if (sock1)				sock_hold(sock1);			spin_unlock_bh(&intrfc->if_sklist_lock);		}        }        if (sock1 == NULL) 	{		/* No special socket found, forward the packet the		 * normal way.		 */		sock1 = ipxitf_find_socket(intrfc, ipx->ipx_dest.sock);	}	/*	 * We need to check if there is a primary net and if	 * this is addressed to one of the *SPECIAL* sockets because	 * these need to be propagated to the primary net.	 * The *SPECIAL* socket list contains: 0x452(SAP), 0x453(RIP) and	 * 0x456(Diagnostic).	 */	if(ipx_primary_net && (intrfc != ipx_primary_net))	{		switch(ntohs(ipx->ipx_dest.sock))		{			case 0x452:			case 0x453:			case 0x456:				/*				 * The appropriate thing to do here is to				 * dup the packet and route to the primary net				 * interface via ipxitf_send; however, we'll 				 * cheat and just demux it here.				 */				sock2 = ipxitf_find_socket(ipx_primary_net,					ipx->ipx_dest.sock);				break;			default:				break;		}	}	/*	 * If there is nothing to do return. The kfree will cancel any charging.	 */	if(sock1 == NULL && sock2 == NULL)	{		if(!copy)			kfree_skb(skb);		return (0);	}	/*	 * This next segment of code is a little awkward, but it sets it up	 * so that the appropriate number of copies of the SKB are made and	 * that skb1 and skb2 point to it (them) so that it (they) can be	 * demuxed to sock1 and/or sock2.  If we are unable to make enough	 * copies, we do as much as is possible.	 */	if(copy)		skb1 = skb_clone(skb, GFP_ATOMIC);	else		skb1 = skb;	ret = -ENOMEM;	if(skb1 == NULL)		goto out;	/* Do we need 2 SKBs? */	if(sock1 && sock2)		skb2 = skb_clone(skb1, GFP_ATOMIC);	else		skb2 = skb1;	if(sock1)		(void) ipxitf_def_skb_handler(sock1, skb1);	ret = -ENOMEM;	if(skb2 == NULL)		goto out;	if(sock2)		(void) ipxitf_def_skb_handler(sock2, skb2);	ret = 0;out:	if (sock1)		sock_put(sock1);	if (sock2)		sock_put(sock2);	return ret;}#endif	/* CONFIG_IPX_INTERN */static struct sk_buff *ipxitf_adjust_skbuff(ipx_interface *intrfc, struct sk_buff *skb){	struct sk_buff *skb2;	int in_offset = skb->h.raw - skb->head;	int out_offset = intrfc->if_ipx_offset;	int len;	/* Hopefully, most cases */	if(in_offset >= out_offset)		return (skb);	/* Need new SKB */	len  = skb->len + out_offset;	skb2 = alloc_skb(len, GFP_ATOMIC);	if(skb2 != NULL)	{		skb_reserve(skb2, out_offset);		skb2->nh.raw =		skb2->h.raw = skb_put(skb2,skb->len);		memcpy(skb2->h.raw, skb->h.raw, skb->len);	}	kfree_skb(skb);	return (skb2);}/* caller must hold a reference to intrfc */static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node){	struct ipxhdr *ipx = skb->nh.ipxh;	struct net_device *dev = intrfc->if_dev;	struct datalink_proto *dl = intrfc->if_dlink;	char dest_node[IPX_NODE_LEN];	int send_to_wire = 1;	int addr_len;		/* 	 * We need to know how many skbuffs it will take to send out this	 * packet to avoid unnecessary copies.	 */	 	if((dl == NULL) || (dev == NULL) || (dev->flags & IFF_LOOPBACK)) 		send_to_wire = 0;	/* No non looped */	/*	 * See if this should be demuxed to sockets on this interface 	 *	 * We want to ensure the original was eaten or that we only use	 * up clones.	 */	 	if(ipx->ipx_dest.net == intrfc->if_netnum) 	{		/*		 * To our own node, loop and free the original.		 * The internal net will receive on all node address.		 */		if((intrfc == ipx_internal_net)		    || memcmp(intrfc->if_node, node, IPX_NODE_LEN) == 0) 		{			/* Don't charge sender */			skb_orphan(skb);			/* Will charge receiver */			return (ipxitf_demux_socket(intrfc, skb, 0));		}		/* Broadcast, loop and possibly keep to send on. */		if(memcmp(ipx_broadcast_node, node, IPX_NODE_LEN) == 0)		{			if(!send_to_wire)				skb_orphan(skb);			ipxitf_demux_socket(intrfc, skb, send_to_wire);			if(!send_to_wire)				return (0);		}	}	/*	 * If the originating net is not equal to our net; this is routed	 * We are still charging the sender. Which is right - the driver	 * free will handle this fairly.	 */	if(ipx->ipx_source.net != intrfc->if_netnum)	{		/*		 * Unshare the buffer before modifying the count in		 * case its a flood or tcpdump		 */		skb = skb_unshare(skb, GFP_ATOMIC);		if(!skb)			return (0);		if(++(ipx->ipx_tctrl) > ipxcfg_max_hops)			send_to_wire = 0;	}	if(!send_to_wire)	{		kfree_skb(skb);		return (0);	}	/* Determine the appropriate hardware address */	addr_len = dev->addr_len;	if(memcmp(ipx_broadcast_node, node, IPX_NODE_LEN) == 0)		memcpy(dest_node, dev->broadcast, addr_len);	else		memcpy(dest_node, &(node[IPX_NODE_LEN-addr_len]), addr_len);	/* Make any compensation for differing physical/data link size */	skb = ipxitf_adjust_skbuff(intrfc, skb);	if(skb == NULL)		return (0);	/* set up data link and physical headers */	skb->dev = dev;	skb->protocol = htons(ETH_P_IPX);	dl->datalink_header(dl, skb, dest_node);	/* Send it out */	dev_queue_xmit(skb);	return (0);}static int ipxrtr_add_route(__u32, ipx_interface *, unsigned char *);static int ipxitf_add_local_route(ipx_interface *intrfc){	return (ipxrtr_add_route(intrfc->if_netnum, intrfc, NULL));}static const char * ipx_frame_name(unsigned short);static const char * ipx_device_name(ipx_interface *);static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb){	struct ipxhdr	*ipx = skb->nh.ipxh;	ipx_interface	*i;	int ret = 0;	ipxitf_hold(intrfc);	/* See if we should update our network number */	if(!intrfc->if_netnum  /* net number of intrfc not known yet (== 0) */		&& (ipx->ipx_source.net == ipx->ipx_dest.net) /* intra packet */		&& ipx->ipx_source.net)  /* source net number of packet != 0 */	{		/* NB: NetWare servers lie about their hop count so we		 * dropped the test based on it.  This is the best way		 * to determine this is a 0 hop count packet.		 */		if((i=ipxitf_find_using_net(ipx->ipx_source.net)) == NULL)		{			intrfc->if_netnum = ipx->ipx_source.net;			(void) ipxitf_add_local_route(intrfc);		}		else		{			printk(KERN_WARNING "IPX: Network number collision %lx\n        %s %s and %s %s\n",				(long unsigned int) htonl(ipx->ipx_source.net),				ipx_device_name(i),				ipx_frame_name(i->if_dlink_type),				ipx_device_name(intrfc),				ipx_frame_name(intrfc->if_dlink_type));			ipxitf_put(i);		}	}	if(ipx->ipx_type == IPX_TYPE_PPROP		&& ipx->ipx_tctrl < 8 		&& skb->pkt_type != PACKET_OTHERHOST		   /* header + 8 network numbers */ 		&& ntohs(ipx->ipx_pktsize) >= sizeof(struct ipxhdr) + 8 * 4) 	{		int i;        	ipx_interface *ifcs;		struct sk_buff *skb2;  		__u32 *l;		char *c;				c = (char *) skb->data;		c += sizeof(struct ipxhdr);		l = (__u32 *) c;		i = 0;		/* Dump packet if already seen this net */		for( ; i < ipx->ipx_tctrl; i++)			if(*l++ == intrfc->if_netnum)				break;		if(i == ipx->ipx_tctrl) 		{ 			/* < 8 hops && input itfc not in list */			*l = intrfc->if_netnum; /* insert recvd netnum into list */			ipx->ipx_tctrl++;			/* xmit on all other interfaces... */			spin_lock_bh(&ipx_interfaces_lock);			for(ifcs = ipx_interfaces; ifcs != NULL; ifcs = ifcs->if_next) 			{				/* Except unconfigured interfaces */				if(ifcs->if_netnum == 0)					continue;									/* That aren't in the list */				l = (__u32 *) c;				for(i = 0; i <= ipx->ipx_tctrl; i++)					if(ifcs->if_netnum == *l++)						break;				if(i - 1 == ipx->ipx_tctrl) 				{					ipx->ipx_dest.net = ifcs->if_netnum;					skb2=skb_clone(skb, GFP_ATOMIC);					if (skb2)						ipxrtr_route_skb(skb2);				}			}			spin_unlock_bh(&ipx_interfaces_lock);			/* Reset network number in packet */			ipx->ipx_dest.net = intrfc->if_netnum;		}	}	if(!ipx->ipx_dest.net)		ipx->ipx_dest.net = intrfc->if_netnum;	if(!ipx->ipx_source.net)		ipx->ipx_source.net = intrfc->if_netnum;	if(intrfc->if_netnum != ipx->ipx_dest.net)	{		/* We only route point-to-point packets. */		if(skb->pkt_type == PACKET_HOST)		{			skb=skb_unshare(skb, GFP_ATOMIC);			if(skb)				ret = ipxrtr_route_skb(skb);			goto out_intrfc;		}		goto out_free_skb;	}	/* see if we should keep it */	if((memcmp(ipx_broadcast_node, ipx->ipx_dest.node, IPX_NODE_LEN) == 0)		|| (memcmp(intrfc->if_node, ipx->ipx_dest.node, IPX_NODE_LEN) == 0))	{		ret = ipxitf_demux_socket(intrfc, skb, 0);		goto out_intrfc;	}	/* we couldn't pawn it off so unload it */out_free_skb:	kfree_skb(skb);out_intrfc:	ipxitf_put(intrfc);	return ret;}static void ipxitf_insert(ipx_interface *intrfc){	ipx_interface *i;	intrfc->if_next = NULL;	spin_lock_bh(&ipx_interfaces_lock);	if(ipx_interfaces == NULL)		ipx_interfaces = intrfc;	else	{		for(i = ipx_interfaces; i->if_next != NULL; i = i->if_next)			;		i->if_next = intrfc;	}	spin_unlock_bh(&ipx_interfaces_lock);	if(ipxcfg_auto_select_primary && (ipx_primary_net == NULL))		ipx_primary_net = intrfc;	return;}static int ipxitf_create_internal(ipx_interface_definition *idef){	ipx_interface *intrfc;	int ret;	/* Only one primary network allowed */	if(ipx_primary_net != NULL)		return (-EEXIST);	/* Must have a valid network number */	if(!idef->ipx_network)		return (-EADDRNOTAVAIL);	intrfc = ipxitf_find_using_net(idef->ipx_network);	if(intrfc != NULL) {		ipxitf_put(intrfc);		return (-EADDRINUSE);	}	intrfc = (ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC);	if(intrfc == NULL)		return (-EAGAIN);	intrfc->if_dev		= NULL;	intrfc->if_netnum	= idef->ipx_network;	intrfc->if_dlink_type 	= 0;	intrfc->if_dlink 	= NULL;	intrfc->if_sklist 	= NULL;	intrfc->if_internal 	= 1;	intrfc->if_ipx_offset 	= 0;	intrfc->if_sknum 	= IPX_MIN_EPHEMERAL_SOCKET;	memcpy((char *)&(intrfc->if_node), idef->ipx_node, IPX_NODE_LEN);	ipx_internal_net 	= intrfc;	ipx_primary_net 	= intrfc;	spin_lock_init(&intrfc->if_sklist_lock);	atomic_set(&intrfc->refcnt, 1);	MOD_INC_USE_COUNT;	ipxitf_hold(intrfc);	ipxitf_insert(intrfc);	ret = ipxitf_add_local_route(intrfc);	ipxitf_put(intrfc);	return ret;}static int ipx_map_frame_type(unsigned char type){	switch(type) 	{		case IPX_FRAME_ETHERII:			return (htons(ETH_P_IPX));		case IPX_FRAME_8022:			return (htons(ETH_P_802_2));		case IPX_FRAME_SNAP:			return (htons(ETH_P_SNAP));		case IPX_FRAME_8023:			return (htons(ETH_P_802_3));	}	return (0);}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)		return (ipxitf_create_internal(idef));	if((idef->ipx_special == IPX_PRIMARY) && (ipx_primary_net != NULL))		return (-EEXIST);	intrfc = ipxitf_find_using_net(idef->ipx_network);	if(idef->ipx_network && intrfc != NULL) {		ipxitf_put(intrfc);		return (-EADDRINUSE);	}	if (intrfc)		ipxitf_put(intrfc);	dev = dev_get_by_name(idef->ipx_device);	if(dev == NULL)		return (-ENODEV);	switch(idef->ipx_dlink_type) 	{		case IPX_FRAME_TR_8022:			printk("IPX frame type 802.2TR is obsolete. Use 802.2 instead.\n");			/* fall through */		case IPX_FRAME_8022:			dlink_type 	= htons(ETH_P_802_2);			datalink 	= p8022_datalink;			break;		case IPX_FRAME_ETHERII:			if (dev->type != ARPHRD_IEEE802)			{				dlink_type 	= htons(ETH_P_IPX);				datalink 	= pEII_datalink;				break;			}			else 				printk("IPX frame type EtherII over token-ring is obsolete. Use SNAP instead.\n");			/* fall through */		case IPX_FRAME_SNAP:			dlink_type 	= htons(ETH_P_SNAP);

⌨️ 快捷键说明

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