patch-2.4.1 linux/net/ipx/af_ipx.c

Next file: linux/net/irda/af_irda.c
Previous file: linux/net/ipv6/netfilter/ip6table_mangle.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
@@ -61,6 +61,9 @@
  *			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
  *
  *	Protect the module by a MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT
  *	pair. Also, now usage count is managed this way
@@ -140,28 +143,23 @@
 atomic_t ipx_sock_nr;
 #endif
 
-static int ipxcfg_set_auto_create(char val)
+static void ipxcfg_set_auto_create(char val)
 {
-	if(ipxcfg_auto_create_interfaces != val)
-	{
-		if(val)
+	if (ipxcfg_auto_create_interfaces != val) {
+		if (val)
 			MOD_INC_USE_COUNT;
 		else
 			MOD_DEC_USE_COUNT;
 
 		ipxcfg_auto_create_interfaces = val;
 	}
-
-	return (0);
 }
 
-static int ipxcfg_set_auto_select(char val)
+static void ipxcfg_set_auto_select(char val)
 {
 	ipxcfg_auto_select_primary = val;
-	if(val && (ipx_primary_net == NULL))
+	if (val && !ipx_primary_net)
 		ipx_primary_net = ipx_interfaces;
-
-	return (0);
 }
 
 static int ipxcfg_get_config_data(ipx_config_data *arg)
@@ -171,7 +169,7 @@
 	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);
+	return copy_to_user(arg, &vals, sizeof(vals)) ? -EFAULT : 0;
 }
 
 /**************************************************************************\
@@ -213,22 +211,19 @@
 
 	/* Determine interface with which socket is associated */
 	intrfc = sk->protinfo.af_ipx.intrfc;
-	if(intrfc == NULL)
+	if (!intrfc)
 		return;
 
 	ipxitf_hold(intrfc);
 	spin_lock_bh(&intrfc->if_sklist_lock);
 	s = intrfc->if_sklist;
-	if(s == sk)
-	{
+	if (s == sk) {
 		intrfc->if_sklist = s->next;
 		goto out;
 	}
 
-	while(s && s->next)
-	{
-		if(s->next == sk)
-		{
+	while (s && s->next) {
+		if (s->next == sk) {
 			s->next = sk->next;
 			goto out;
 		}
@@ -264,7 +259,7 @@
 
 static void ipxitf_clear_primary_net(void)
 {
-	if(ipxcfg_auto_select_primary && (ipx_interfaces != NULL))
+	if (ipxcfg_auto_select_primary && ipx_interfaces)
 		ipx_primary_net = ipx_interfaces;
 	else
 		ipx_primary_net = NULL;
@@ -273,14 +268,14 @@
 static ipx_interface *__ipxitf_find_using_phys(struct net_device *dev,
 						unsigned short datalink)
 {
-	ipx_interface	*i;
+	ipx_interface *i;
 
-	for(i = ipx_interfaces;
-		i && ((i->if_dev != dev) || (i->if_dlink_type != datalink));
+	for (i = ipx_interfaces;
+		i && (i->if_dev != dev || i->if_dlink_type != datalink);
 		i = i->if_next)
 		;
 
-	return (i);
+	return i;
 }
 
 static ipx_interface *ipxitf_find_using_phys(struct net_device *dev,
@@ -298,12 +293,12 @@
 
 static ipx_interface *ipxitf_find_using_net(__u32 net)
 {
-	ipx_interface	*i;
+	ipx_interface *i;
 
 	spin_lock_bh(&ipx_interfaces_lock);
-	if(net)
-		for(i = ipx_interfaces; i && (i->if_netnum != net);
-			i = i->if_next)
+	if (net)
+		for (i = ipx_interfaces; i && i->if_netnum != net;
+		     i = i->if_next)
 		;
 	else
 		i = ipx_primary_net;
@@ -311,7 +306,7 @@
 		ipxitf_hold(i);
 	spin_unlock_bh(&ipx_interfaces_lock);
 
-	return (i);
+	return i;
 }
 
 /* Sockets are bound to a particular IPX interface. */
@@ -324,11 +319,10 @@
 	spin_lock_bh(&intrfc->if_sklist_lock);
 	sk->protinfo.af_ipx.intrfc = intrfc;
 	sk->next = NULL;
-	if(intrfc->if_sklist == NULL)
+	if (!intrfc->if_sklist)
 		intrfc->if_sklist = sk;
-	else
-	{
-		for (s = intrfc->if_sklist; s->next != NULL; s = s->next)
+	else {
+		for (s = intrfc->if_sklist; s->next; s = s->next)
 			;
 		s->next = sk;
 	}
@@ -337,19 +331,21 @@
 }
 
 /* caller must hold intrfc->if_sklist_lock */
-static struct sock *__ipxitf_find_socket(ipx_interface *intrfc, unsigned short port)
+static struct sock *__ipxitf_find_socket(ipx_interface *intrfc,
+					 unsigned short port)
 {
 	struct sock *s;
 
-	for(s = intrfc->if_sklist;
-		(s != NULL) && (s->protinfo.af_ipx.port != port);
-		s = s->next)
+	for (s = intrfc->if_sklist;
+	     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)
+static struct sock *ipxitf_find_socket(ipx_interface *intrfc,
+					unsigned short port)
 {
 	struct sock *s;
 
@@ -359,11 +355,10 @@
 		sock_hold(s);
 	spin_unlock_bh(&intrfc->if_sklist_lock);
 
-	return (s);
+	return s;
 }
 
 #ifdef CONFIG_IPX_INTERN
-
 static struct sock *ipxitf_find_internal_socket(ipx_interface *intrfc,
 			    unsigned char *node, unsigned short port)
 {
@@ -373,19 +368,16 @@
 	spin_lock_bh(&intrfc->if_sklist_lock);
 	s = intrfc->if_sklist;
 
-	while(s != NULL)
-	{
-		if((s->protinfo.af_ipx.port == port)
-		    && (memcmp(node, s->protinfo.af_ipx.node, IPX_NODE_LEN) == 0))
-		{
+	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);
+	return s;
 }
 #endif
 
@@ -401,8 +393,7 @@
 
 	spin_lock_bh(&intrfc->if_sklist_lock);
 	/* error sockets */
-	for(s = intrfc->if_sklist; s != NULL; )
-	{
+	for (s = intrfc->if_sklist; s; ) {
 		s->err = ENOLINK;
 		s->error_report(s);
 		s->protinfo.af_ipx.intrfc = NULL;
@@ -416,30 +407,27 @@
 	spin_unlock_bh(&intrfc->if_sklist_lock);
 
 	/* remove this interface from list */
-	if(intrfc == ipx_interfaces)
+	if (intrfc == ipx_interfaces)
 		ipx_interfaces = intrfc->if_next;
-	else
-	{
-		for(i = ipx_interfaces;
-			(i != NULL) && (i->if_next != intrfc);
-			i = i->if_next)
+	else {
+		for (i = ipx_interfaces;
+		     i && i->if_next != intrfc;
+		     i = i->if_next)
 			;
-		if((i != NULL) && (i->if_next == intrfc))
+		if (i && i->if_next == intrfc)
 			i->if_next = intrfc->if_next;
 	}
 
 	/* remove this interface from *special* networks */
-	if(intrfc == ipx_primary_net)
+	if (intrfc == ipx_primary_net)
 		ipxitf_clear_primary_net();
-	if(intrfc == ipx_internal_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;
-
-	return;
 }
 
 static void ipxitf_down(ipx_interface *intrfc)
@@ -449,36 +437,31 @@
 	spin_unlock_bh(&ipx_interfaces_lock);
 }
 
-static int ipxitf_device_event(struct notifier_block *notifier, unsigned long event, void *ptr)
+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)
+	if (event != NETDEV_DOWN)
 		return NOTIFY_DONE;
 
 	spin_lock_bh(&ipx_interfaces_lock);
-	for(i = ipx_interfaces; i != NULL;)
-	{
+	for (i = ipx_interfaces; i;) {
 		tmp = i->if_next;
-		if(i->if_dev == dev)
+		if (i->if_dev == dev)
 			__ipxitf_put(i);
 		i = tmp;
 
 	}
 	spin_unlock_bh(&ipx_interfaces_lock);
-
-	return (NOTIFY_DONE);
+	return NOTIFY_DONE;
 }
 
-static int ipxitf_def_skb_handler(struct sock *sock, struct sk_buff *skb)
+static void ipxitf_def_skb_handler(struct sock *sock, struct sk_buff *skb)
 {
-	int retval;
-
-	if((retval = sock_queue_rcv_skb(sock, skb)) < 0)
+	if (sock_queue_rcv_skb(sock, skb) < 0)
 		kfree_skb(skb);
-
-	return (retval);
 }
 
 /*
@@ -500,57 +483,50 @@
 	spin_lock_bh(&intrfc->if_sklist_lock);
 	s = intrfc->if_sklist;
 
-	while(s != NULL)
-	{
-		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) == 0)))
-		{
+	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 != 0)
-			{
+			if (copy) {
 				skb1 = skb_clone(skb, GFP_ATOMIC);
 				ret = -ENOMEM;
-				if (skb1 == NULL)
+				if (!skb1)
 					goto out;
-			}
-			else
-			{
+			} 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)
+			if (intrfc != ipx_internal_net)
 				break;
 		}
 		s = s->next;
 	}
 
 	/* skb was solely for us, and we did not make a copy, so free it. */
-	if(copy == 0)
+	if (!copy)
 		kfree_skb(skb);
 
 	ret = 0;
 out:	spin_unlock_bh(&intrfc->if_sklist_lock);
 	return ret;
 }
-
 #else
-
-static int ipxitf_demux_socket(ipx_interface *intrfc, struct sk_buff *skb, int copy)
+static 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) 
-	{
+	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,
@@ -562,48 +538,34 @@
 	 	 * VERY fast as well.
 	 	 */
 	 	int connection = 0;
+		u8 *ncphdr = (u8 *)(ipx + 1);
 
-	 	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.
-			 */
+	 	if (*ncphdr == 0x22 && *(ncphdr + 1) == 0x22)
+	  		/* The packet is a NCP request */
+			connection = (((int) *(ncphdr + 5)) << 8) |
+					(int) *(ncphdr+3);
+		else if (*ncphdr == 0x77 && *(ncphdr + 1) == 0x77)
+			/* The packet is a BURST packet */
+			connection = (((int) *(ncphdr+9)) << 8) |
+					(int) *(ncphdr+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);
+			for (sock1 = intrfc->if_sklist;
+			     sock1 &&
+			     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.
-		 */
+        if (!sock1)
+		/* 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
@@ -613,10 +575,8 @@
 	 * 0x456(Diagnostic).
 	 */
 
-	if(ipx_primary_net && (intrfc != ipx_primary_net))
-	{
-		switch(ntohs(ipx->ipx_dest.sock))
-		{
+	if (ipx_primary_net && intrfc != ipx_primary_net) {
+		switch (ntohs(ipx->ipx_dest.sock)) {
 			case 0x452:
 			case 0x453:
 			case 0x456:
@@ -637,11 +597,10 @@
 	/*
 	 * If there is nothing to do return. The kfree will cancel any charging.
 	 */
-	if(sock1 == NULL && sock2 == NULL)
-	{
-		if(!copy)
+	if (!sock1 && !sock2) {
+		if (!copy)
 			kfree_skb(skb);
-		return (0);
+		return 0;
 	}
 
 	/*
@@ -652,30 +611,30 @@
 	 * copies, we do as much as is possible.
 	 */
 
-	if(copy)
+	if (copy)
 		skb1 = skb_clone(skb, GFP_ATOMIC);
 	else
 		skb1 = skb;
 
 	ret = -ENOMEM;
-	if(skb1 == NULL)
+	if (!skb1)
 		goto out;
 
 	/* Do we need 2 SKBs? */
-	if(sock1 && sock2)
+	if (sock1 && sock2)
 		skb2 = skb_clone(skb1, GFP_ATOMIC);
 	else
 		skb2 = skb1;
 
-	if(sock1)
-		(void) ipxitf_def_skb_handler(sock1, skb1);
+	if (sock1)
+		ipxitf_def_skb_handler(sock1, skb1);
 
 	ret = -ENOMEM;
-	if(skb2 == NULL)
+	if (!skb2)
 		goto out;
 
-	if(sock2)
-		(void) ipxitf_def_skb_handler(sock2, skb2);
+	if (sock2)
+		ipxitf_def_skb_handler(sock2, skb2);
 
 	ret = 0;
 out:	if (sock1)
@@ -686,7 +645,8 @@
 }
 #endif	/* CONFIG_IPX_INTERN */
 
-static struct sk_buff *ipxitf_adjust_skbuff(ipx_interface *intrfc, struct sk_buff *skb)
+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;
@@ -694,21 +654,21 @@
 	int len;
 
 	/* Hopefully, most cases */
-	if(in_offset >= out_offset)
-		return (skb);
+	if (in_offset >= out_offset)
+		return skb;
 
 	/* Need new SKB */
 	len  = skb->len + out_offset;
 	skb2 = alloc_skb(len, GFP_ATOMIC);
-	if(skb2 != NULL)
-	{
+	if (skb2) {
 		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);
+		memcpy(skb2->cb, skb->cb, sizeof(skb->cb));
 	}
 	kfree_skb(skb);
-	return (skb2);
+	return skb2;
 }
 
 /* caller must hold a reference to intrfc */
@@ -716,6 +676,7 @@
 static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node)
 {
 	struct ipxhdr *ipx = skb->nh.ipxh;
+	struct ipx_cb *cb = (struct ipx_cb *) skb->cb;
 	struct net_device *dev = intrfc->if_dev;
 	struct datalink_proto *dl = intrfc->if_dlink;
 	char dest_node[IPX_NODE_LEN];
@@ -727,7 +688,7 @@
 	 * packet to avoid unnecessary copies.
 	 */
 	 
-	if((dl == NULL) || (dev == NULL) || (dev->flags & IFF_LOOPBACK)) 
+	if (!dl || !dev || dev->flags & IFF_LOOPBACK) 
 		send_to_wire = 0;	/* No non looped */
 
 	/*
@@ -737,30 +698,27 @@
 	 * up clones.
 	 */
 	 
-	if(ipx->ipx_dest.net == intrfc->if_netnum) 
-	{
+	if (cb->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) 
-		{
+		if (intrfc == ipx_internal_net ||
+		    !memcmp(intrfc->if_node, node, IPX_NODE_LEN)) {
 			/* Don't charge sender */
 			skb_orphan(skb);
 
 			/* Will charge receiver */
-			return (ipxitf_demux_socket(intrfc, skb, 0));
+			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)
+		if (!memcmp(ipx_broadcast_node, node, IPX_NODE_LEN)) {
+			if (!send_to_wire)
 				skb_orphan(skb);
 			ipxitf_demux_socket(intrfc, skb, send_to_wire);
-			if(!send_to_wire)
-				return (0);
+			if (!send_to_wire)
+				return 0;
 		}
 	}
 
@@ -769,36 +727,45 @@
 	 * We are still charging the sender. Which is right - the driver
 	 * free will handle this fairly.
 	 */
-	if(ipx->ipx_source.net != intrfc->if_netnum)
-	{
+	if (cb->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)
+		if (!skb)
+			return 0;
+		if (++(cb->ipx_tctrl) > ipxcfg_max_hops)
 			send_to_wire = 0;
 	}
 
-	if(!send_to_wire)
-	{
+	if (!send_to_wire) {
 		kfree_skb(skb);
-		return (0);
+		return 0;
 	}
 
 	/* Determine the appropriate hardware address */
 	addr_len = dev->addr_len;
-	if(memcmp(ipx_broadcast_node, node, IPX_NODE_LEN) == 0)
+	if (!memcmp(ipx_broadcast_node, node, IPX_NODE_LEN))
 		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);
+	if (!skb)
+		return 0;
+
+	ipx->ipx_tctrl = cb->ipx_tctrl;
+	ipx->ipx_dest.net = cb->ipx_dest_net;
+	ipx->ipx_source.net = cb->ipx_source_net;
+	/* see if we need to include the netnum in the route list */
+	if (cb->last_hop_index >= 0) {
+		u32 *last_hop = (u32 *)(((u8 *) skb->data) +
+				sizeof(struct ipxhdr) + cb->last_hop_index *
+				sizeof(u32));
+		*last_hop = intrfc->if_netnum;
+	}
 
 	/* set up data link and physical headers */
 	skb->dev = dev;
@@ -807,15 +774,14 @@
 
 	/* Send it out */
 	dev_queue_xmit(skb);
-
-	return (0);
+	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));
+	return ipxrtr_add_route(intrfc->if_netnum, intrfc, NULL);
 }
 
 static const char * ipx_frame_name(unsigned short);
@@ -824,29 +790,26 @@
 static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
 {
 	struct ipxhdr	*ipx = skb->nh.ipxh;
-	ipx_interface	*i;
+	struct ipx_cb *cb = (struct ipx_cb *) skb->cb;
 	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 */
-	{
+	if (!intrfc->if_netnum && /* net number of intrfc not known yet */
+	   cb->ipx_source_net == cb->ipx_dest_net && /* intra packet */
+	   cb->ipx_source_net) {
+		ipx_interface *i = ipxitf_find_using_net(cb->ipx_source_net);
 		/* 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
-		{
+		if (!i) {
+			intrfc->if_netnum = cb->ipx_source_net;
+			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),
+				(long unsigned int) htonl(cb->ipx_source_net),
 				ipx_device_name(i),
 				ipx_frame_name(i->if_dlink_type),
 				ipx_device_name(intrfc),
@@ -854,75 +817,63 @@
 			ipxitf_put(i);
 		}
 	}
+	
+	cb->last_hop_index = -1;
 
-	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) 
-	{
+	if (ipx->ipx_type == IPX_TYPE_PPROP && cb->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;
+		char *c = ((char *) skb->data) + sizeof(struct ipxhdr);
+  		u32 *l = (u32 *) c;
 
 		/* Dump packet if already seen this net */
-		for( ; i < ipx->ipx_tctrl; i++)
-			if(*l++ == intrfc->if_netnum)
+		for (i = 0; i < cb->ipx_tctrl; i++)
+			if (*l++ == intrfc->if_netnum)
 				break;
 
-		if(i == ipx->ipx_tctrl) 
-		{ 
+		if (i == cb->ipx_tctrl) {
 			/* < 8 hops && input itfc not in list */
-			*l = intrfc->if_netnum; /* insert recvd netnum into list */
-			ipx->ipx_tctrl++;
+ 			/* insert recvd netnum into list */
+			cb->last_hop_index = i;
+			cb->ipx_tctrl++;
 			/* xmit on all other interfaces... */
 			spin_lock_bh(&ipx_interfaces_lock);
-			for(ifcs = ipx_interfaces; ifcs != NULL; ifcs = ifcs->if_next) 
-			{
+			for (ifcs = ipx_interfaces; ifcs;
+			     ifcs = ifcs->if_next) {
 				/* Except unconfigured interfaces */
-				if(ifcs->if_netnum == 0)
+				if (!ifcs->if_netnum)
 					continue;
 					
 				/* That aren't in the list */
 				l = (__u32 *) c;
-				for(i = 0; i <= ipx->ipx_tctrl; i++)
-					if(ifcs->if_netnum == *l++)
+				for (i = 0; i <= cb->ipx_tctrl; i++)
+					if (ifcs->if_netnum == *l++)
 						break;
-				if(i - 1 == ipx->ipx_tctrl) 
-				{
-					ipx->ipx_dest.net = ifcs->if_netnum;
+				if (i - 1 == cb->ipx_tctrl) {
+					cb->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 (!cb->ipx_dest_net)
+		cb->ipx_dest_net = intrfc->if_netnum;
+	if (!cb->ipx_source_net)
+		cb->ipx_source_net = intrfc->if_netnum;
 
-	if(intrfc->if_netnum != ipx->ipx_dest.net)
-	{
+	if (intrfc->if_netnum != cb->ipx_dest_net) {
 		/* We only route point-to-point packets. */
-		if(skb->pkt_type == PACKET_HOST)
-		{
+		if (skb->pkt_type == PACKET_HOST) {
 			skb=skb_unshare(skb, GFP_ATOMIC);
-			if(skb)
+			if (skb)
 				ret = ipxrtr_route_skb(skb);
 			goto out_intrfc;
 		}
@@ -931,9 +882,8 @@
 	}
 
 	/* 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))
-	{
+	if (!memcmp(ipx_broadcast_node, ipx->ipx_dest.node, IPX_NODE_LEN) ||
+	    !memcmp(intrfc->if_node, ipx->ipx_dest.node, IPX_NODE_LEN)) {
 		ret = ipxitf_demux_socket(intrfc, skb, 0);
 		goto out_intrfc;
 	}
@@ -952,20 +902,17 @@
 
 	intrfc->if_next = NULL;
 	spin_lock_bh(&ipx_interfaces_lock);
-	if(ipx_interfaces == NULL)
+	if (!ipx_interfaces)
 		ipx_interfaces = intrfc;
-	else
-	{
-		for(i = ipx_interfaces; i->if_next != NULL; i = i->if_next)
+	else {
+		for (i = ipx_interfaces; i->if_next; i = i->if_next)
 			;
 		i->if_next = intrfc;
 	}
 	spin_unlock_bh(&ipx_interfaces_lock);
 
-	if(ipxcfg_auto_select_primary && (ipx_primary_net == NULL))
+	if (ipxcfg_auto_select_primary && !ipx_primary_net)
 		ipx_primary_net = intrfc;
-
-	return;
 }
 
 static int ipxitf_create_internal(ipx_interface_definition *idef)
@@ -974,21 +921,21 @@
 	int ret;
 
 	/* Only one primary network allowed */
-	if(ipx_primary_net != NULL)
-		return (-EEXIST);
+	if (ipx_primary_net)
+		return -EEXIST;
 
 	/* Must have a valid network number */
-	if(!idef->ipx_network)
-		return (-EADDRNOTAVAIL);
+	if (!idef->ipx_network)
+		return -EADDRNOTAVAIL;
 	intrfc = ipxitf_find_using_net(idef->ipx_network);
-	if(intrfc != NULL) {
+	if (intrfc) {
 		ipxitf_put(intrfc);
-		return (-EADDRINUSE);
+		return -EADDRINUSE;
 	}
 
-	intrfc = (ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC);
-	if(intrfc == NULL)
-		return (-EAGAIN);
+	intrfc = kmalloc(sizeof(ipx_interface),GFP_ATOMIC);
+	if (!intrfc)
+		return -EAGAIN;
 	intrfc->if_dev		= NULL;
 	intrfc->if_netnum	= idef->ipx_network;
 	intrfc->if_dlink_type 	= 0;
@@ -998,8 +945,7 @@
 	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;
+	ipx_internal_net = ipx_primary_net = intrfc;
 	spin_lock_init(&intrfc->if_sklist_lock);
 	atomic_set(&intrfc->refcnt, 1);
 	MOD_INC_USE_COUNT;
@@ -1013,22 +959,21 @@
 
 static int ipx_map_frame_type(unsigned char type)
 {
-	switch(type) 
-	{
+	switch (type) {
 		case IPX_FRAME_ETHERII:
-			return (htons(ETH_P_IPX));
+			return htons(ETH_P_IPX);
 
 		case IPX_FRAME_8022:
-			return (htons(ETH_P_802_2));
+			return htons(ETH_P_802_2);
 
 		case IPX_FRAME_SNAP:
-			return (htons(ETH_P_SNAP));
+			return htons(ETH_P_SNAP);
 
 		case IPX_FRAME_8023:
-			return (htons(ETH_P_802_3));
+			return htons(ETH_P_802_3);
 	}
 
-	return (0);
+	return 0;
 }
 
 static int ipxitf_create(ipx_interface_definition *idef)
@@ -1039,29 +984,29 @@
 	ipx_interface *intrfc;
 	int err;
 
-	if(idef->ipx_special == IPX_INTERNAL)
-		return (ipxitf_create_internal(idef));
+	if (idef->ipx_special == IPX_INTERNAL)
+		return ipxitf_create_internal(idef);
 
-	if((idef->ipx_special == IPX_PRIMARY) && (ipx_primary_net != NULL))
-		return (-EEXIST);
+	if (idef->ipx_special == IPX_PRIMARY && ipx_primary_net)
+		return -EEXIST;
 
 	intrfc = ipxitf_find_using_net(idef->ipx_network);
-	if(idef->ipx_network && intrfc != NULL) {
+	if (idef->ipx_network && intrfc) {
 		ipxitf_put(intrfc);
-		return (-EADDRINUSE);
+		return -EADDRINUSE;
 	}
 
 	if (intrfc)
 		ipxitf_put(intrfc);
 
 	dev = dev_get_by_name(idef->ipx_device);
-	if(dev == NULL)
-		return (-ENODEV);
+	if (!dev)
+		return -ENODEV;
 
-	switch(idef->ipx_dlink_type) 
-	{
+	switch (idef->ipx_dlink_type) {
 		case IPX_FRAME_TR_8022:
-			printk("IPX frame type 802.2TR is obsolete. Use 802.2 instead.\n");
+			printk(KERN_WARNING "IPX frame type 802.2TR is "
+				"obsolete Use 802.2 instead.\n");
 			/* fall through */
 
 		case IPX_FRAME_8022:
@@ -1070,14 +1015,14 @@
 			break;
 
 		case IPX_FRAME_ETHERII:
-			if (dev->type != ARPHRD_IEEE802)
-			{
+			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");
+			} else 
+				printk(KERN_WARNING "IPX frame type EtherII "
+					"over token-ring is obsolete. Use SNAP "
+					"instead.\n");
 			/* fall through */
 
 		case IPX_FRAME_SNAP:
@@ -1096,24 +1041,24 @@
 	}
 
 	err = -ENETDOWN;
-	if(!(dev->flags & IFF_UP))
+	if (!(dev->flags & IFF_UP))
 		goto out_dev;
 
 	/* Check addresses are suitable */
 	err = -EINVAL;
-	if(dev->addr_len > IPX_NODE_LEN)
+	if (dev->addr_len > IPX_NODE_LEN)
 		goto out_dev;
 
 	err = -EPROTONOSUPPORT;
-	if(datalink == NULL)
+	if (!datalink)
 		goto out_dev;
 
-	if((intrfc = ipxitf_find_using_phys(dev, dlink_type)) == NULL)
-	{
+	intrfc = ipxitf_find_using_phys(dev, dlink_type);
+	if (!intrfc) {
 		/* Ok now create */
-		intrfc = (ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC);
+		intrfc = kmalloc(sizeof(ipx_interface), GFP_ATOMIC);
 		err = -EAGAIN;
-		if(intrfc == NULL)
+		if (!intrfc)
 			goto out_dev;
 		intrfc->if_dev		= dev;
 		intrfc->if_netnum 	= idef->ipx_network;
@@ -1122,17 +1067,16 @@
 		intrfc->if_sklist 	= NULL;
 		intrfc->if_sknum 	= IPX_MIN_EPHEMERAL_SOCKET;
 		/* Setup primary if necessary */
-		if((idef->ipx_special == IPX_PRIMARY))
+		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)
-		{
+		if (!memcmp(idef->ipx_node, "\000\000\000\000\000\000",
+			    IPX_NODE_LEN)) {
 			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
+		} else
 			memcpy(intrfc->if_node, idef->ipx_node, IPX_NODE_LEN);
 		spin_lock_init(&intrfc->if_sklist_lock);
 		atomic_set(&intrfc->refcnt, 1);
@@ -1144,7 +1088,7 @@
 
 	/* If the network number is known, add a route */
 	err = 0;
-	if(!intrfc->if_netnum)
+	if (!intrfc->if_netnum)
 		goto out_intrfc;
 
 	err = ipxitf_add_local_route(intrfc);
@@ -1164,10 +1108,8 @@
 	int ret = 0;
 
 	spin_lock_bh(&ipx_interfaces_lock);
-	if(idef->ipx_special == IPX_INTERNAL) 
-	{
-		if(ipx_internal_net != NULL) 
-		{
+	if (idef->ipx_special == IPX_INTERNAL) {
+		if (ipx_internal_net) {
 			__ipxitf_put(ipx_internal_net);
 			goto out;
 		}
@@ -1176,19 +1118,19 @@
 	}
 
 	dlink_type = ipx_map_frame_type(idef->ipx_dlink_type);
-	if(dlink_type == 0) {
+	if (!dlink_type) {
 		ret = -EPROTONOSUPPORT;
 		goto out;
 	}
 
 	dev = __dev_get_by_name(idef->ipx_device);
-	if(dev == NULL) {
+	if (!dev) {
 		ret = -ENODEV;
 		goto out;
 	}
 
 	intrfc = __ipxitf_find_using_phys(dev, dlink_type);
-	if(intrfc != NULL)
+	if (intrfc)
 		__ipxitf_put(intrfc);
 	else
 		ret = -EINVAL;
@@ -1198,13 +1140,12 @@
 }
 
 static ipx_interface *ipxitf_auto_create(struct net_device *dev, 
-	unsigned short dlink_type)
+					 unsigned short dlink_type)
 {
 	struct datalink_proto *datalink = NULL;
 	ipx_interface *intrfc;
 
-	switch(htons(dlink_type)) 
-	{
+	switch (htons(dlink_type)) {
 		case ETH_P_IPX:
 			datalink = pEII_datalink;
 			break;
@@ -1222,19 +1163,18 @@
 			break;
 
 		default:
-			return (NULL);
+			return NULL;
 	}
 
-	if(dev == NULL)
-		return (NULL);
+	if (!dev)
+		return NULL;
 
 	/* Check addresses are suitable */
-	if(dev->addr_len>IPX_NODE_LEN)
-		return (NULL);
+	if (dev->addr_len > IPX_NODE_LEN)
+		return NULL;
 
-	intrfc = (ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC);
-	if(intrfc != NULL) 
-	{
+	intrfc = kmalloc(sizeof(ipx_interface), GFP_ATOMIC);
+	if (intrfc) {
 		intrfc->if_dev		= dev;
 		intrfc->if_netnum	= 0;
 		intrfc->if_dlink_type 	= dlink_type;
@@ -1253,27 +1193,25 @@
 		ipxitf_insert(intrfc);
 	}
 
-	return (intrfc);
+	return intrfc;
 }
 
 static int ipxitf_ioctl(unsigned int cmd, void *arg)
 {
 	struct ifreq ifr;
-	int err, val;
+	int err = 0, val;
 
-	switch(cmd)
-	{
-		case SIOCSIFADDR: 
-		{
+	switch (cmd) {
+		case SIOCSIFADDR: {
 			struct sockaddr_ipx *sipx;
 			ipx_interface_definition f;
 
-			if(copy_from_user(&ifr, arg, sizeof(ifr)))
-				return (-EFAULT);
+			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);
+			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));
@@ -1281,10 +1219,10 @@
 			f.ipx_dlink_type = sipx->sipx_type;
 			f.ipx_special = sipx->sipx_special;
 
-			if(sipx->sipx_action == IPX_DLTITF)
-				return (ipxitf_delete(&f));
+			if (sipx->sipx_action == IPX_DLTITF)
+				return ipxitf_delete(&f);
 			else
-				return (ipxitf_create(&f));
+				return ipxitf_create(&f);
 		}
 
 		case SIOCGIFADDR: 
@@ -1293,50 +1231,46 @@
 			ipx_interface *ipxif;
 			struct net_device *dev;
 
-			if(copy_from_user(&ifr, arg, sizeof(ifr)))
-				return (-EFAULT);
+			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);
+			if (!dev)
+				return -ENODEV;
 
 			ipxif = ipxitf_find_using_phys(dev, ipx_map_frame_type(sipx->sipx_type));
-			if(ipxif == NULL)
-				return (-EADDRNOTAVAIL);
+			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));
-			err = -EFAULT;
-			if(!copy_to_user(arg, &ifr, sizeof(ifr)))
-				err = 0;
+			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);
+			return err;
 		}
 
 		case SIOCAIPXITFCRT: 
-		{
-			err = get_user(val, (unsigned char *) arg);
-			if(err)
-				return (err);
-
-			return (ipxcfg_set_auto_create(val));
-		}
+			if (get_user(val, (unsigned char *) arg))
+				return -EFAULT;
+			ipxcfg_set_auto_create(val);
+			break;
 
 		case SIOCAIPXPRISLT: 
-		{
-			err = get_user(val, (unsigned char *) arg);
-			if(err)
-				return (err);
-
-			return (ipxcfg_set_auto_select(val));
-		}
+			if (get_user(val, (unsigned char *) arg))
+				return -EFAULT;
+			ipxcfg_set_auto_select(val);
+			break;
 
 		default:
-			return (-EINVAL);
+			return -EINVAL;
 	}
+
+	return 0;
 }
 
 /**************************************************************************\
@@ -1350,11 +1284,11 @@
 	ipx_route *r;
 
 	read_lock_bh(&ipx_routes_lock);
-	for(r = ipx_routes; (r != NULL) && (r->ir_net != net); r = r->ir_next)
+	for (r = ipx_routes; r && r->ir_net != net; r = r->ir_next)
 		;
 	read_unlock_bh(&ipx_routes_lock);
 
-	return (r);
+	return r;
 }
 
 /* caller must hold a reference to intrfc */
@@ -1365,34 +1299,30 @@
 
 	/* 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);
+	if (!rt) {
+		rt = kmalloc(sizeof(ipx_route),GFP_ATOMIC);
+		if (!rt)
+			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);
+	else if (intrfc == ipx_internal_net)
+		return -EEXIST;
 
 	rt->ir_net 	= network;
 	rt->ir_intrfc 	= intrfc;
-	if(node == NULL)
-	{
+	if (!node) {
 		memset(rt->ir_router_node, '\0', IPX_NODE_LEN);
 		rt->ir_routed = 0;
-	}
-	else
-	{
+	} else {
 		memcpy(rt->ir_router_node, node, IPX_NODE_LEN);
 		rt->ir_routed = 1;
 	}
 
-	return (0);
+	return 0;
 }
 
 static void ipxrtr_del_routes(ipx_interface *intrfc)
@@ -1400,14 +1330,11 @@
 	ipx_route **r, *tmp;
 
 	write_lock_bh(&ipx_routes_lock);
-	for(r = &ipx_routes; (tmp = *r) != NULL;)
-	{
-		if(tmp->ir_intrfc == intrfc)
-		{
+	for (r = &ipx_routes; (tmp = *r) != NULL;) {
+		if (tmp->ir_intrfc == intrfc) {
 			*r = tmp->ir_next;
 			kfree(tmp);
-		}
-		else
+		} else
 			r = &(tmp->ir_next);
 	}
 	write_unlock_bh(&ipx_routes_lock);
@@ -1420,8 +1347,8 @@
 
 	/* Find the appropriate interface */
 	intrfc = ipxitf_find_using_net(rd->ipx_router_network);
-	if(intrfc == NULL)
-		return (-ENETUNREACH);
+	if (!intrfc)
+		return -ENETUNREACH;
 	ret = ipxrtr_add_route(rd->ipx_network, intrfc, rd->ipx_router_node);
 	ipxitf_put(intrfc);
 	return ret;
@@ -1434,13 +1361,11 @@
 	int err;
 
 	write_lock_bh(&ipx_routes_lock);
-	for(r = &ipx_routes; (tmp = *r) != NULL;) 
-	{
-		if(tmp->ir_net == net) 
-		{
+	for (r = &ipx_routes; (tmp = *r) != NULL;) {
+		if (tmp->ir_net == net) {
 			/* Directly connected; can't lose route */
 			err = -EPERM;
-			if(!(tmp->ir_routed))
+			if (!tmp->ir_routed)
 				goto out;
 
 			*r = tmp->ir_next;
@@ -1461,45 +1386,38 @@
  */
  
 /* Note: We assume ipx_tctrl==0 and htons(length)==ipx_pktsize */
+/* This functions should *not* mess with packet contents */
 
-static __u16 ipx_set_checksum(struct ipxhdr *packet,int length) 
+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.)
 	 */
-
-	__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)
+	/* 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 & htons(1))
+	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)
+	if (sum >= 0x10000)
 		sum++;
 
-	return (~sum);
+	return ~sum;
 }
 
 /*
@@ -1510,80 +1428,76 @@
 	struct sk_buff *skb;
 	ipx_interface *intrfc;
 	struct ipxhdr *ipx;
+	struct ipx_cb *cb;
 	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))
-	{
+	if (!usipx->sipx_network && ipx_primary_net) {
 		usipx->sipx_network = ipx_primary_net->if_netnum;
 		intrfc = ipx_primary_net;
-	}
-	else
-	{
+	} else {
 		rt = ipxrtr_lookup(usipx->sipx_network);
-		if(rt == NULL)
-			return (-ENETUNREACH);
+		if (!rt)
+			return -ENETUNREACH;
 
 		intrfc = rt->ir_intrfc;
 	}
 
 	ipxitf_hold(intrfc);
 	ipx_offset = intrfc->if_ipx_offset;
-	size	= sizeof(struct ipxhdr) + len;
-	size 	+= ipx_offset;
+	size = sizeof(struct ipxhdr) + len + ipx_offset;
 
 	skb = sock_alloc_send_skb(sk, size, 0, noblock, &err);
-	if(skb == NULL)
+	if (!skb)
 		goto out;
 
 	skb_reserve(skb,ipx_offset);
 	skb->sk = sk;
+	cb = (struct ipx_cb *) skb->cb;
 
 	/* 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;
+	cb->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;
+	cb->last_hop_index = -1;
 
 #ifdef CONFIG_IPX_INTERN
+	cb->ipx_source_net = sk->protinfo.af_ipx.intrfc->if_netnum;
 	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)
-	{
+	err = ntohs(sk->protinfo.af_ipx.port);
+	if (err == 0x453 || err == 0x452) {
 		/* RIP/SAP special handling for mars_nwe */
-		ipx->ipx_source.net = intrfc->if_netnum;
+		cb->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;
+	} else {
+		cb->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;
+	cb->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)
-	{
+	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)
+	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));
+		ipx->ipx_checksum = ipx_cksum(ipx, len + sizeof(struct ipxhdr));
 
 	err = ipxitf_send(intrfc, skb, (rt && rt->ir_routed) ? 
 				rt->ir_router_node : ipx->ipx_dest.node);
@@ -1594,21 +1508,20 @@
 int ipxrtr_route_skb(struct sk_buff *skb)
 {
 	struct ipxhdr *ipx = skb->nh.ipxh;
-	ipx_route *r;
+	struct ipx_cb *cb = (struct ipx_cb *) skb->cb;
+	ipx_route *r = ipxrtr_lookup(cb->ipx_dest_net);
 
-	r = ipxrtr_lookup(ipx->ipx_dest.net);
-	if(r == NULL)	/* no known route */
-	{
+	if (!r) {	/* no known route */
 		kfree_skb(skb);
-		return (0);
+		return 0;
 	}
 
 	ipxitf_hold(r->ir_intrfc);
-	(void)ipxitf_send(r->ir_intrfc, skb, (r->ir_routed) ?
+	ipxitf_send(r->ir_intrfc, skb, (r->ir_routed) ?
 			r->ir_router_node : ipx->ipx_dest.node);
 	ipxitf_put(r->ir_intrfc);
 
-	return (0);
+	return 0;
 }
 
 /*
@@ -1621,23 +1534,22 @@
 	int err;
 
 	err = copy_from_user(&rt,arg,sizeof(rt));
-	if(err)
-		return (-EFAULT);
+	if (err)
+		return -EFAULT;
 
 	sg = (struct sockaddr_ipx *)&rt.rt_gateway;
 	st = (struct sockaddr_ipx *)&rt.rt_dst;
 
-	if(!(rt.rt_flags & RTF_GATEWAY))
-		return (-EINVAL);	/* Direct routes are fixed */
-	if(sg->sipx_family != AF_IPX)
-		return (-EINVAL);
-	if(st->sipx_family != AF_IPX)
-		return (-EINVAL);
+	if (!(rt.rt_flags & RTF_GATEWAY))
+		return -EINVAL;	/* Direct routes are fixed */
+	if (sg->sipx_family != AF_IPX)
+		return -EINVAL;
+	if (st->sipx_family != AF_IPX)
+		return -EINVAL;
 
-	switch(cmd)
-	{
+	switch (cmd) {
 		case SIOCDELRT:
-			return (ipxrtr_delete(st->sipx_network));
+			return ipxrtr_delete(st->sipx_network);
 
 		case SIOCADDRT:
 		{
@@ -1645,42 +1557,40 @@
 			f.ipx_network=st->sipx_network;
 			f.ipx_router_network=sg->sipx_network;
 			memcpy(f.ipx_router_node, sg->sipx_node, IPX_NODE_LEN);
-			return (ipxrtr_create(&f));
+			return ipxrtr_create(&f);
 		}
-
-		default:
-			return (-EINVAL);
 	}
+
+	return -EINVAL;
 }
 
 static const char *ipx_frame_name(unsigned short frame)
 {
-	switch(ntohs(frame)) 
-	{
+	switch (ntohs(frame)) {
 		case ETH_P_IPX:
-			return ("EtherII");
+			return "EtherII";
 
 		case ETH_P_802_2:
-			return ("802.2");
+			return "802.2";
 
 		case ETH_P_SNAP:
-			return ("SNAP");
+			return "SNAP";
 
 		case ETH_P_802_3:
-			return ("802.3");
+			return "802.3";
 
 		case ETH_P_TR_802_2:
-			return ("802.2TR");
+			return "802.2TR";
 
 		default:
-			return ("None");
+			return "None";
 	}
 }
 
 static const char *ipx_device_name(ipx_interface *intrfc)
 {
-	return (intrfc->if_internal ? "Internal" :
-		(intrfc->if_dev ? intrfc->if_dev->name : "Unknown"));
+	return intrfc->if_internal ? "Internal" :
+		intrfc->if_dev ? intrfc->if_dev->name : "Unknown";
 }
 
 /* Called from proc fs */
@@ -1700,13 +1610,12 @@
 #endif
 	strcat(buffer+len++, "\n");
 	spin_lock_bh(&ipx_interfaces_lock);
-	for(i = ipx_interfaces; i != NULL; i = i->if_next)
-	{
+	for (i = ipx_interfaces; i; i = i->if_next) {
 		len += sprintf(buffer+len, "%08lX   ", (long unsigned int)ntohl(i->if_netnum));
 		len += sprintf(buffer+len,"%02X%02X%02X%02X%02X%02X   ",
 				i->if_node[0], i->if_node[1], i->if_node[2],
 				i->if_node[3], i->if_node[4], i->if_node[5]);
-		len += sprintf(buffer+len, "%-9s", (i == ipx_primary_net) ?
+		len += sprintf(buffer+len, "%-9s", i == ipx_primary_net ?
 			"Yes" : "No");
 		len += sprintf(buffer+len, "%-11s", ipx_device_name(i));
 		len += sprintf(buffer+len, "%-9s",
@@ -1718,12 +1627,11 @@
 		/* Are we still dumping unwanted data then discard the record */
 		pos = begin + len;
 
-		if(pos < offset)
-		{
+		if (pos < offset) {
 			len   = 0;	/* Keep dumping into the buffer start */
 			begin = pos;
 		}
-		if(pos > offset + length)	/* We have dumped enough */
+		if (pos > offset + length)	/* We have dumped enough */
 			break;
 	}
 	spin_unlock_bh(&ipx_interfaces_lock);
@@ -1731,10 +1639,10 @@
 	/* The data in question runs from begin to begin+len */
 	*start = buffer + (offset - begin);	/* Start of wanted data */
 	len -= (offset - begin); /* Remove unwanted header data from length */
-	if(len > length)
+	if (len > length)
 		len = length;	/* Remove unwanted tail data from length */
 
-	return (len);
+	return len;
 }
 
 static int ipx_get_info(char *buffer, char **start, off_t offset, int length)
@@ -1755,12 +1663,10 @@
 			"State", "Uid");
 
 	spin_lock_bh(&ipx_interfaces_lock);
-	for(i = ipx_interfaces; i != NULL; i = i->if_next)
-	{
+	for (i = ipx_interfaces; i; i = i->if_next) {
 		ipxitf_hold(i);
 		spin_lock_bh(&i->if_sklist_lock);
-		for(s = i->if_sklist; s != NULL; s = s->next)
-		{
+		for (s = i->if_sklist; s; s = s->next) {
 #ifdef CONFIG_IPX_INTERN
 			len += sprintf(buffer+len,
 				       "%08lX:%02X%02X%02X%02X%02X%02X:%04X  ",
@@ -1778,10 +1684,9 @@
 				       htons(s->protinfo.af_ipx.port));
 #endif	/* CONFIG_IPX_INTERN */
 
-			if(s->state != TCP_ESTABLISHED)
+			if (s->state != TCP_ESTABLISHED)
 				len += sprintf(buffer+len, "%-28s", "Not_Connected");
-			else
-			{
+			else {
 				len += sprintf(buffer+len,
 					"%08lX:%02X%02X%02X%02X%02X%02X:%04X  ",
 					(unsigned long) htonl(s->protinfo.af_ipx.dest_addr.net),
@@ -1801,13 +1706,12 @@
 				s->state, SOCK_INODE(s->socket)->i_uid);
 
 			pos = begin + len;
-			if(pos < offset)
-			{
+			if (pos < offset) {
 				len   = 0;
 				begin = pos;
 			}
 
-			if(pos > offset + length)  /* We have dumped enough */
+			if (pos > offset + length)  /* We have dumped enough */
 				break;
 		}
 		spin_unlock_bh(&i->if_sklist_lock);
@@ -1818,10 +1722,10 @@
 	/* The data in question runs from begin to begin+len */
 	*start = buffer + (offset-begin);
 	len -= (offset - begin);
-	if(len > length)
+	if (len > length)
 		len = length;
 
-	return (len);
+	return len;
 }
 
 static int ipx_rt_get_info(char *buffer, char **start, off_t offset, int length)
@@ -1833,41 +1737,36 @@
 	len += sprintf(buffer,"%-11s%-13s%s\n",
 			"Network", "Router_Net", "Router_Node");
 	read_lock_bh(&ipx_routes_lock);
-	for(rt = ipx_routes; rt != NULL; rt = rt->ir_next)
-	{
+	for (rt = ipx_routes; rt; rt = rt->ir_next) {
 		len += sprintf(buffer+len,"%08lX   ", (long unsigned int) ntohl(rt->ir_net));
-		if(rt->ir_routed)
-		{
+		if (rt->ir_routed) {
 			len += sprintf(buffer+len,"%08lX     %02X%02X%02X%02X%02X%02X\n",
 				(long unsigned int) ntohl(rt->ir_intrfc->if_netnum),
 				rt->ir_router_node[0], rt->ir_router_node[1],
 				rt->ir_router_node[2], rt->ir_router_node[3],
 				rt->ir_router_node[4], rt->ir_router_node[5]);
-		}
-		else
-		{
+		} else {
 			len += sprintf(buffer+len, "%-13s%s\n",
 					"Directly", "Connected");
 		}
 
 		pos = begin + len;
-		if(pos < offset)
-		{
-			len   = 0;
+		if (pos < offset) {
+			len = 0;
 			begin = pos;
 		}
 
-		if(pos > offset + length)
+		if (pos > offset + length)
 			break;
 	}
 	read_unlock_bh(&ipx_routes_lock);
 
 	*start = buffer + (offset - begin);
 	len -= (offset - begin);
-	if(len > length)
+	if (len > length)
 		len = length;
 
-	return (len);
+	return len;
 }
 
 /**************************************************************************\
@@ -1877,89 +1776,80 @@
 *                                                                          *
 \**************************************************************************/
 
-static int ipx_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+static int ipx_setsockopt(struct socket *sock, int level, int optname,
+			  char *optval, int optlen)
 {
-	struct sock *sk;
-	int err, opt;
-
-	sk = sock->sk;
+	struct sock *sk = sock->sk;
+	int opt;
 
-	if(optlen != sizeof(int))
-		return (-EINVAL);
+	if (optlen != sizeof(int))
+		return -EINVAL;
 
-	err = get_user(opt, (unsigned int *)optval);
-	if(err)
-		return (err);
+	if (get_user(opt, (unsigned int *)optval))
+		return -EFAULT;
 
-	switch(level)
-	{
+	switch (level) {
 		case SOL_IPX:
-			switch(optname)
-			{
+			switch (optname) {
 				case IPX_TYPE:
 					sk->protinfo.af_ipx.type = opt;
-					return (0);
+					return 0;
 
 				default:
-					return (-ENOPROTOOPT);
+					return -ENOPROTOOPT;
 			}
 			break;
 
 		default:
-			return (-ENOPROTOOPT);
+			return -ENOPROTOOPT;
 	}
 }
 
 static int ipx_getsockopt(struct socket *sock, int level, int optname,
 	char *optval, int *optlen)
 {
-	struct sock *sk;
-	int val=0;
+	struct sock *sk = sock->sk;
+	int val = 0;
 	int len;
 
-	sk = sock->sk;
-
-	switch(level)
-	{
+	switch (level) {
 		case SOL_IPX:
-			switch(optname)
-			{
+			switch (optname) {
 				case IPX_TYPE:
 					val = sk->protinfo.af_ipx.type;
 					break;
 
 				default:
-					return (-ENOPROTOOPT);
+					return -ENOPROTOOPT;
 			}
 			break;
 
 		default:
-			return (-ENOPROTOOPT);
+			return -ENOPROTOOPT;
 	}
 
-	if(get_user(len, optlen))
-		return (-EFAULT);
+	if (get_user(len, optlen))
+		return -EFAULT;
 
 	len = min(len, sizeof(int));
-	if(put_user(len, optlen))
-		return (-EFAULT);
+	if (put_user(len, optlen))
+		return -EFAULT;
 
-	if(copy_to_user(optval, &val, len))
-		return (-EFAULT);
+	if (copy_to_user(optval, &val, len))
+		return -EFAULT;
 
-	return (0);
+	return 0;
 }
 
 static int ipx_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
 
-	switch(sock->type)
-	{
+	switch (sock->type) {
 		case SOCK_DGRAM:
 			sk = sk_alloc(PF_IPX, GFP_KERNEL, 1);
-			if(sk == NULL)
-                		return (-ENOMEM);
+			if (!sk)
+                		return -ENOMEM;
                         sock->ops = &ipx_dgram_ops;
                         break;
 
@@ -1968,12 +1858,12 @@
 			 * From this point on SPX sockets are handled
 			 * by af_spx.c and the methods replaced.
 			 */
-			if(spx_family_ops)
-				return (spx_family_ops->create(sock,protocol));
+			if (spx_family_ops)
+				return spx_family_ops->create(sock,protocol);
 			/* Fall through if SPX is not loaded */
 		case SOCK_STREAM:       /* Allow higher levels to piggyback */
 		default:
-			return (-ESOCKTNOSUPPORT);
+			return -ESOCKTNOSUPPORT;
 	}
 #ifdef IPX_REFCNT_DEBUG
         atomic_inc(&ipx_sock_nr);
@@ -1985,31 +1875,30 @@
 	sk->no_check 	= 1;		/* Checksum off by default */
 
 	MOD_INC_USE_COUNT;
-
-	return (0);
+	return 0;
 }
 
 static int ipx_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
 
-	if(sk == NULL)
-		return (0);
+	if (!sk)
+		return 0;
 
-	if(!sk->dead)
+	if (!sk->dead)
 		sk->state_change(sk);
 
 	sk->dead = 1;
 	sock->sk = NULL;
 	ipx_destroy_socket(sk);
 
-	if(sock->type == SOCK_DGRAM)
+	if (sock->type == SOCK_DGRAM)
 		MOD_DEC_USE_COUNT;
 
-	return (0);
+	return 0;
 }
 
-/* caller must hold a referente to intrfc */
+/* caller must hold a reference to intrfc */
 
 static unsigned short ipx_first_free_socketnum(ipx_interface *intrfc)
 {
@@ -2017,91 +1906,80 @@
 
 	spin_lock_bh(&intrfc->if_sklist_lock);
 
-	if(socketNum < IPX_MIN_EPHEMERAL_SOCKET)
+	if (socketNum < IPX_MIN_EPHEMERAL_SOCKET)
 		socketNum = IPX_MIN_EPHEMERAL_SOCKET;
 
-	while(__ipxitf_find_socket(intrfc, ntohs(socketNum)) != NULL)
-	{
-		if(socketNum > IPX_MAX_EPHEMERAL_SOCKET)
+	while (__ipxitf_find_socket(intrfc, ntohs(socketNum)))
+		if (socketNum > IPX_MAX_EPHEMERAL_SOCKET)
 			socketNum = IPX_MIN_EPHEMERAL_SOCKET;
 		else
 			socketNum++;
-	}
 
 	spin_unlock_bh(&intrfc->if_sklist_lock);
 	intrfc->if_sknum = socketNum;
 
-	return (ntohs(socketNum));
+	return ntohs(socketNum);
 }
 
 static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	ipx_interface *intrfc;
 	struct sockaddr_ipx *addr = (struct sockaddr_ipx *)uaddr;
 	int ret;
 
-	sk = sock->sk;
+	if (!sk->zapped)
+		return -EINVAL;
 
-	if(sk->zapped == 0)
-		return (-EINVAL);
-
-	if(addr_len != sizeof(struct sockaddr_ipx))
-		return (-EINVAL);
+	if (addr_len != sizeof(struct sockaddr_ipx))
+		return -EINVAL;
 
 	intrfc = ipxitf_find_using_net(addr->sipx_network);
-	if(intrfc == NULL)
-		return (-EADDRNOTAVAIL);
+	if (!intrfc)
+		return -EADDRNOTAVAIL;
 
-	if(addr->sipx_port == 0)
-	{
+	if (!addr->sipx_port) {
 		addr->sipx_port = ipx_first_free_socketnum(intrfc);
 		ret = -EINVAL;
-		if(addr->sipx_port == 0)
+		if (!addr->sipx_port)
 			goto out;
 	}
 
 	/* protect IPX system stuff like routing/sap */
 	ret = -EACCES;
-	if(ntohs(addr->sipx_port) < IPX_MIN_EPHEMERAL_SOCKET && !capable(CAP_NET_ADMIN))
+	if (ntohs(addr->sipx_port) < IPX_MIN_EPHEMERAL_SOCKET &&
+	    !capable(CAP_NET_ADMIN))
 		goto out;
 
 	sk->protinfo.af_ipx.port = addr->sipx_port;
 
 #ifdef CONFIG_IPX_INTERN
-	if(intrfc == ipx_internal_net)
-	{
+	if (intrfc == ipx_internal_net) {
 		/* The source address is to be set explicitly if the
 		 * socket is to be bound on the internal network. If a
 		 * node number 0 was specified, the default is used.
 		 */
 
 		ret = -EINVAL;
-		if(memcmp(addr->sipx_node,ipx_broadcast_node,IPX_NODE_LEN) == 0)
+		if (!memcmp(addr->sipx_node,ipx_broadcast_node,IPX_NODE_LEN))
 			goto out;
-		if(memcmp(addr->sipx_node, ipx_this_node, IPX_NODE_LEN) == 0)
-		{
+		if (!memcmp(addr->sipx_node, ipx_this_node, IPX_NODE_LEN))
 			memcpy(sk->protinfo.af_ipx.node, intrfc->if_node,
 			       IPX_NODE_LEN);
-		}
 		else
-		{
-			memcpy(sk->protinfo.af_ipx.node, addr->sipx_node, IPX_NODE_LEN);
-		}
+			memcpy(sk->protinfo.af_ipx.node, addr->sipx_node,
+				IPX_NODE_LEN);
 
 		ret = -EADDRINUSE;
-		if(ipxitf_find_internal_socket(intrfc,
-			sk->protinfo.af_ipx.node,
-			sk->protinfo.af_ipx.port) != NULL)
-		{
+		if (ipxitf_find_internal_socket(intrfc,
+						sk->protinfo.af_ipx.node,
+						sk->protinfo.af_ipx.port)) {
 			SOCK_DEBUG(sk,
 				"IPX: bind failed because port %X in use.\n",
 				ntohs((int)addr->sipx_port));
 			goto out;
 		}
-	}
-	else
-	{
+	} else {
 		/* Source addresses are easy. It must be our
 		 * network:node pair for an interface routed to IPX
 		 * with the ipx routing ioctl()
@@ -2111,8 +1989,7 @@
 			IPX_NODE_LEN);
 
 		ret = -EADDRINUSE;
-		if(ipxitf_find_socket(intrfc, addr->sipx_port) != NULL)
-		{
+		if (ipxitf_find_socket(intrfc, addr->sipx_port)) {
 			SOCK_DEBUG(sk,
 				"IPX: bind failed because port %X in use.\n",
 				ntohs((int)addr->sipx_port));
@@ -2126,8 +2003,7 @@
 	   an interface routed to IPX with the ipx routing ioctl() */
 
 	ret = -EADDRINUSE;
-	if(ipxitf_find_socket(intrfc, addr->sipx_port) != NULL)
-	{
+	if (ipxitf_find_socket(intrfc, addr->sipx_port)) {
 		SOCK_DEBUG(sk, "IPX: bind failed because port %X in use.\n",
 				ntohs((int)addr->sipx_port));
 		goto out;
@@ -2153,13 +2029,12 @@
 	sk->state	= TCP_CLOSE;
 	sock->state 	= SS_UNCONNECTED;
 
-	if(addr_len != sizeof(*addr))
-		return (-EINVAL);
+	if (addr_len != sizeof(*addr))
+		return -EINVAL;
 	addr = (struct sockaddr_ipx *)uaddr;
 
 	/* put the autobinding in */
-	if(sk->protinfo.af_ipx.port == 0)
-	{
+	if (!sk->protinfo.af_ipx.port) {
 		struct sockaddr_ipx uaddr;
 		int ret;
 
@@ -2167,7 +2042,7 @@
 		uaddr.sipx_network 	= 0;
 
 #ifdef CONFIG_IPX_INTERN
-		if(sk->protinfo.af_ipx.intrfc)
+		if (sk->protinfo.af_ipx.intrfc)
 			memcpy(uaddr.sipx_node, sk->protinfo.af_ipx.intrfc->if_node,IPX_NODE_LEN);
 		else
 			return -ENETDOWN;		/* Someone zonked the iface */
@@ -2175,13 +2050,15 @@
 
 		ret = ipx_bind(sock, (struct sockaddr *)&uaddr,
 				sizeof(struct sockaddr_ipx));
-		if(ret != 0)
-			return (ret);
+		if (ret)
+			return ret;
 	}
 
-        /* We can either connect to primary network or somewhere we can route to */
-	if( !(addr->sipx_network == 0 && ipx_primary_net != NULL) && ipxrtr_lookup(addr->sipx_network) == NULL)
-		return (-ENETUNREACH);
+        /* We can either connect to primary network or somewhere
+	 * we can route to */
+	if (!(!addr->sipx_network && ipx_primary_net) &&
+	    !ipxrtr_lookup(addr->sipx_network))
+		return -ENETUNREACH;
 
 	sk->protinfo.af_ipx.dest_addr.net  = addr->sipx_network;
 	sk->protinfo.af_ipx.dest_addr.sock = addr->sipx_port;
@@ -2189,41 +2066,34 @@
 		addr->sipx_node,IPX_NODE_LEN);
 	sk->protinfo.af_ipx.type = addr->sipx_type;
 
-	if(sock->type == SOCK_DGRAM )
-	{
+	if (sock->type == SOCK_DGRAM) {
 		sock->state 	= SS_CONNECTED;
 		sk->state 	= TCP_ESTABLISHED;
 	}
 
-	return (0);
+	return 0;
 }
 
 
 static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
-	int *uaddr_len, int peer)
+			int *uaddr_len, int peer)
 {
 	ipx_address *addr;
 	struct sockaddr_ipx sipx;
-	struct sock *sk;
-
-	sk = sock->sk;
+	struct sock *sk = sock->sk;
 
 	*uaddr_len = sizeof(struct sockaddr_ipx);
 
-	if(peer)
-	{
-		if(sk->state != TCP_ESTABLISHED)
-			return (-ENOTCONN);
+	if (peer) {
+		if (sk->state != TCP_ESTABLISHED)
+			return -ENOTCONN;
 
 		addr = &sk->protinfo.af_ipx.dest_addr;
 		sipx.sipx_network = addr->net;
 		memcpy(sipx.sipx_node,addr->node,IPX_NODE_LEN);
 		sipx.sipx_port = addr->sock;
-	}
-	else
-	{
-		if(sk->protinfo.af_ipx.intrfc != NULL)
-		{
+	} else {
+		if (sk->protinfo.af_ipx.intrfc) {
 			sipx.sipx_network=sk->protinfo.af_ipx.intrfc->if_netnum;
 #ifdef CONFIG_IPX_INTERN
 			memcpy(sipx.sipx_node, sk->protinfo.af_ipx.node, IPX_NODE_LEN);
@@ -2231,9 +2101,7 @@
 			memcpy(sipx.sipx_node, sk->protinfo.af_ipx.intrfc->if_node, IPX_NODE_LEN);
 #endif	/* CONFIG_IPX_INTERN */
 
-		}
-		else
-		{
+		} else {
 			sipx.sipx_network = 0;
 			memset(sipx.sipx_node, '\0', IPX_NODE_LEN);
 		}
@@ -2242,10 +2110,10 @@
 	}
 
 	sipx.sipx_family = AF_IPX;
-	sipx.sipx_type   = sk->protinfo.af_ipx.type;
+	sipx.sipx_type = sk->protinfo.af_ipx.type;
 	memcpy(uaddr,&sipx,sizeof(sipx));
 
-	return (0);
+	return 0;
 }
 
 int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
@@ -2253,97 +2121,96 @@
 	/* NULL here for pt means the packet was looped back */
 	ipx_interface *intrfc;
 	struct ipxhdr *ipx;
+	struct ipx_cb *cb;
+	u16 ipx_pktsize;
 	int ret;
-
-	ipx = skb->nh.ipxh;
-	
-	/* Too small? */
-	if(ntohs(ipx->ipx_pktsize) < sizeof(struct ipxhdr))
-		goto drop;
-
-	/* Invalid header */
-	if(ntohs(ipx->ipx_pktsize) > skb->len)
-		goto drop;
 		
 	/* Not ours */	
         if (skb->pkt_type == PACKET_OTHERHOST)
         	goto drop;
+
+	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
+		goto out;
+
+	ipx = skb->nh.ipxh;
+	ipx_pktsize = ntohs(ipx->ipx_pktsize);
+	
+	/* Too small or invalid header? */
+	if (ipx_pktsize < sizeof(struct ipxhdr) || ipx_pktsize > skb->len)
+		goto drop;
                         
-	if(ipx->ipx_checksum != IPX_NO_CHECKSUM) 
-	{
-		if(ipx_set_checksum(ipx, ntohs(ipx->ipx_pktsize)) != ipx->ipx_checksum)
-			goto drop;
-	}
+	if (ipx->ipx_checksum != IPX_NO_CHECKSUM &&
+	   ipx->ipx_checksum != ipx_cksum(ipx, ipx_pktsize))
+		goto drop;
+
+	cb = (struct ipx_cb *) skb->cb;
+	cb->ipx_tctrl = ipx->ipx_tctrl;
+	cb->ipx_dest_net = ipx->ipx_dest.net;
+	cb->ipx_source_net = ipx->ipx_source.net;
 
 	/* Determine what local ipx endpoint this is */
 	intrfc = ipxitf_find_using_phys(dev, pt->type);
-	if(intrfc == NULL)
-	{
-		if(ipxcfg_auto_create_interfaces
-		    && ntohl(ipx->ipx_dest.net) != 0L)
-		{
+	if (!intrfc) {
+		if (ipxcfg_auto_create_interfaces &&
+		   ntohl(cb->ipx_dest_net)) {
 			intrfc = ipxitf_auto_create(dev, pt->type);
 			ipxitf_hold(intrfc);
 		}
 
-		if(intrfc == NULL)	/* Not one of ours */
+		if (!intrfc)	/* Not one of ours */
 			goto drop;
 	}
 
 	ret = ipxitf_rcv(intrfc, skb);
 	ipxitf_put(intrfc);
 	return ret;
-drop:
-	kfree_skb(skb);
-	return (0);
+drop:	kfree_skb(skb);
+out:	return 0;
 }
 
 static int ipx_sendmsg(struct socket *sock, struct msghdr *msg, int len,
 	struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
-	struct sockaddr_ipx *usipx=(struct sockaddr_ipx *)msg->msg_name;
+	struct sockaddr_ipx *usipx = (struct sockaddr_ipx *)msg->msg_name;
 	struct sockaddr_ipx local_sipx;
 	int retval;
 	int flags = msg->msg_flags;
 
 	/* Socket gets bound below anyway */
-/*	if(sk->zapped)
-		return (-EIO); */	/* Socket not bound */
-	if(flags & ~MSG_DONTWAIT)
-		return (-EINVAL);
-
-	if(usipx)
-	{
-		if(sk->protinfo.af_ipx.port == 0)
-		{
+/*	if (sk->zapped)
+		return -EIO; */	/* Socket not bound */
+	if (flags & ~MSG_DONTWAIT)
+		return -EINVAL;
+
+	if (usipx) {
+		if (!sk->protinfo.af_ipx.port) {
 			struct sockaddr_ipx uaddr;
 			int ret;
 
 			uaddr.sipx_port = 0;
 			uaddr.sipx_network = 0L;
 #ifdef CONFIG_IPX_INTERN
-			if(sk->protinfo.af_ipx.intrfc)
-				memcpy(uaddr.sipx_node, sk->protinfo.af_ipx.intrfc
-						->if_node,IPX_NODE_LEN);
+			if (sk->protinfo.af_ipx.intrfc)
+				memcpy(uaddr.sipx_node,
+					sk->protinfo.af_ipx.intrfc->if_node,
+					IPX_NODE_LEN);
 			else
 				return -ENETDOWN;               /* Someone zonked the iface */
 #endif
 			ret = ipx_bind(sock, (struct sockaddr *)&uaddr,
 					sizeof(struct sockaddr_ipx));
-			if(ret != 0)
-				return (ret);
+			if (ret)
+				return ret;
 		}
 
-		if(msg->msg_namelen < sizeof(*usipx))
-			return (-EINVAL);
-		if(usipx->sipx_family != AF_IPX)
-			return (-EINVAL);
-	}
-	else
-	{
-		if(sk->state != TCP_ESTABLISHED)
-			return (-ENOTCONN);
+		if (msg->msg_namelen < sizeof(*usipx))
+			return -EINVAL;
+		if (usipx->sipx_family != AF_IPX)
+			return -EINVAL;
+	} else {
+		if (sk->state != TCP_ESTABLISHED)
+			return -ENOTCONN;
 
 		usipx=&local_sipx;
 		usipx->sipx_family 	= AF_IPX;
@@ -2353,11 +2220,12 @@
 		memcpy(usipx->sipx_node,sk->protinfo.af_ipx.dest_addr.node,IPX_NODE_LEN);
 	}
 
-	retval = ipxrtr_route_packet(sk, usipx, msg->msg_iov, len, flags&MSG_DONTWAIT);
-	if(retval < 0)
-		return (retval);
+	retval = ipxrtr_route_packet(sk, usipx, msg->msg_iov, len,
+				     flags & MSG_DONTWAIT);
+	if (retval < 0)
+		return retval;
 
-	return (len);
+	return len;
 }
 
 
@@ -2371,8 +2239,7 @@
 	int copied, err;
 
 	/* put the autobinding in */
-	if(sk->protinfo.af_ipx.port == 0)
-	{
+	if (!sk->protinfo.af_ipx.port) {
 		struct sockaddr_ipx uaddr;
 		int ret;
 
@@ -2380,7 +2247,7 @@
 		uaddr.sipx_network 	= 0;
 
 #ifdef CONFIG_IPX_INTERN
-		if(sk->protinfo.af_ipx.intrfc)
+		if (sk->protinfo.af_ipx.intrfc)
 			memcpy(uaddr.sipx_node, sk->protinfo.af_ipx.intrfc->if_node,IPX_NODE_LEN);
 		else
 			return -ENETDOWN;		/* Someone zonked the iface */
@@ -2388,47 +2255,45 @@
 
 		ret = ipx_bind(sock, (struct sockaddr *)&uaddr,
 				sizeof(struct sockaddr_ipx));
-		if(ret != 0)
-			return (ret);
+		if (ret)
+			return ret;
 	}
 	
-	if(sk->zapped)
-		return (-ENOTCONN);
+	if (sk->zapped)
+		return -ENOTCONN;
 
 	skb = skb_recv_datagram(sk,flags&~MSG_DONTWAIT,flags&MSG_DONTWAIT,&err);
-	if(!skb)
+	if (!skb)
 		goto out;
 
 	ipx 	= skb->nh.ipxh;
 	copied 	= ntohs(ipx->ipx_pktsize) - sizeof(struct ipxhdr);
-	if(copied > size)
-	{
+	if (copied > size) {
 		copied=size;
 		msg->msg_flags |= MSG_TRUNC;
 	}
 
 	err = skb_copy_datagram_iovec(skb, sizeof(struct ipxhdr), msg->msg_iov,
 					copied);
-	if(err)
+	if (err)
 		goto out_free;
 	sk->stamp = skb->stamp;
 
 	msg->msg_namelen = sizeof(*sipx);
 
-	if(sipx)
-	{
+	if (sipx) {
+		struct ipx_cb *cb = (struct ipx_cb *) skb->cb;
 		sipx->sipx_family	= AF_IPX;
 		sipx->sipx_port		= ipx->ipx_source.sock;
 		memcpy(sipx->sipx_node,ipx->ipx_source.node,IPX_NODE_LEN);
-		sipx->sipx_network	= ipx->ipx_source.net;
+		sipx->sipx_network	= cb->ipx_source_net;
 		sipx->sipx_type 	= ipx->ipx_type;
 	}
 	err = copied;
 
 out_free:
 	skb_free_datagram(sk, skb);
-out:
-	return (err);
+out:	return err;
 }
 
 
@@ -2437,40 +2302,39 @@
 	long amount = 0;
 	struct sock *sk = sock->sk;
 
-	switch(cmd)
-	{
+	switch (cmd) {
 		case TIOCOUTQ:
 			amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
-			if(amount < 0)
+			if (amount < 0)
 				amount = 0;
-			return (put_user(amount, (int *)arg));
+			return put_user(amount, (int *)arg);
 
 		case TIOCINQ:
 		{
-			struct sk_buff *skb;
+			struct sk_buff *skb = skb_peek(&sk->receive_queue);
 			/* These two are safe on a single CPU system as only user tasks fiddle here */
-			if((skb = skb_peek(&sk->receive_queue)) != NULL)
+			if (skb)
 				amount = skb->len - sizeof(struct ipxhdr);
-			return (put_user(amount, (int *)arg));
+			return put_user(amount, (int *)arg);
 		}
 
 		case SIOCADDRT:
 		case SIOCDELRT:
-			if(!capable(CAP_NET_ADMIN))
-				return (-EPERM);
-			return (ipxrtr_ioctl(cmd,(void *)arg));
+			if (!capable(CAP_NET_ADMIN))
+				return -EPERM;
+			return ipxrtr_ioctl(cmd,(void *)arg);
 
 		case SIOCSIFADDR:
 		case SIOCAIPXITFCRT:
 		case SIOCAIPXPRISLT:
-			if(!capable(CAP_NET_ADMIN))
-				return (-EPERM);
+			if (!capable(CAP_NET_ADMIN))
+				return -EPERM;
 
 		case SIOCGIFADDR:
-			return (ipxitf_ioctl(cmd,(void *)arg));
+			return ipxitf_ioctl(cmd,(void *)arg);
 
 		case SIOCIPXCFGDATA:
-			return (ipxcfg_get_config_data((void *)arg));
+			return ipxcfg_get_config_data((void *)arg);
 
 		case SIOCIPXNCPCONN:
                 {
@@ -2479,24 +2343,24 @@
 			 * handed to us in arg.
 			 */
                 	if (!capable(CAP_NET_ADMIN))
-                		return(-EPERM);
-			return get_user(sk->protinfo.af_ipx.ipx_ncp_conn, (const unsigned short *)(arg));
+                		return -EPERM;
+			return get_user(sk->protinfo.af_ipx.ipx_ncp_conn,
+					(const unsigned short *)(arg));
                 }
 
 		case SIOCGSTAMP:
 		{
 			int ret = -EINVAL;
-			if(sk)
-			{
-				if(sk->stamp.tv_sec == 0)
-					return (-ENOENT);
+			if (sk) {
+				if (!sk->stamp.tv_sec)
+					return -ENOENT;
 				ret = -EFAULT;
-				if(!copy_to_user((void *)arg, &sk->stamp,
+				if (!copy_to_user((void *)arg, &sk->stamp,
 						sizeof(struct timeval)))
 					ret = 0;
 			}
 
-			return (ret);
+			return ret;
 		}
 
 		case SIOCGIFDSTADDR:
@@ -2505,14 +2369,14 @@
 		case SIOCSIFBRDADDR:
 		case SIOCGIFNETMASK:
 		case SIOCSIFNETMASK:
-			return (-EINVAL);
+			return -EINVAL;
 
 		default:
-			return (dev_ioctl(cmd,(void *) arg));
+			return dev_ioctl(cmd,(void *) arg);
 	}
 
 	/*NOT REACHED*/
-	return (0);
+	return 0;
 }
 
 /*
@@ -2521,19 +2385,19 @@
 
 int ipx_register_spx(struct proto_ops **p, struct net_proto_family *spx)
 {
-        if(spx_family_ops!=NULL)
+        if (spx_family_ops)
                 return -EBUSY;
         cli();
         MOD_INC_USE_COUNT;
-        *p=&ipx_dgram_ops;
-        spx_family_ops=spx;
+        *p = &ipx_dgram_ops;
+        spx_family_ops = spx;
         sti();
         return 0;
 }
 
 int ipx_unregister_spx(void)
 {
-        spx_family_ops=NULL;
+        spx_family_ops = NULL;
         MOD_DEC_USE_COUNT;
         return 0;
 }
@@ -2576,7 +2440,7 @@
 	__constant_htons(ETH_P_802_3),
 	NULL,		/* All devices */
 	ipx_rcv,
-	NULL,
+	(void *) 1,	/* yap, I understand shared skbs :-) */
 	NULL,
 };
 
@@ -2585,7 +2449,7 @@
 	__constant_htons(ETH_P_IPX),
 	NULL,		/* All devices */
 	ipx_rcv,
-	NULL,
+	(void *) 1,	/* yap, I understand shared skbs :-) */
 	NULL,
 };
 
@@ -2604,12 +2468,9 @@
 static unsigned char ipx_8022_type = 0xE0;
 static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
 
-
-
-
 static int __init ipx_init(void)
 {
-	(void) sock_register(&ipx_family_ops);
+	sock_register(&ipx_family_ops);
 
 	pEII_datalink = make_EII_client();
 	dev_add_pack(&ipx_dix_packet_type);
@@ -2617,35 +2478,34 @@
 	p8023_datalink = make_8023_client();
 	dev_add_pack(&ipx_8023_packet_type);
 
-	if((p8022_datalink = register_8022_client(ipx_8022_type,ipx_rcv)) == NULL)
+	p8022_datalink = register_8022_client(ipx_8022_type,ipx_rcv);
+	if (!p8022_datalink)
 		printk(KERN_CRIT "IPX: Unable to register with 802.2\n");
 
-	if((pSNAP_datalink = register_snap_client(ipx_snap_id,ipx_rcv)) == NULL)
+	pSNAP_datalink = register_snap_client(ipx_snap_id,ipx_rcv);
+	if (!pSNAP_datalink)
 		printk(KERN_CRIT "IPX: Unable to register with SNAP\n");
 
 	register_netdevice_notifier(&ipx_dev_notifier);
-
 #ifdef CONFIG_PROC_FS
 	proc_net_create("ipx", 0, ipx_get_info);
 	proc_net_create("ipx_interface", 0, ipx_interface_get_info);
 	proc_net_create("ipx_route", 0, ipx_rt_get_info);
 #endif
-
-	printk(KERN_INFO "NET4: Linux IPX 0.42v4 for NET4.0\n");
+	printk(KERN_INFO "NET4: Linux IPX 0.43 for NET4.0\n");
 	printk(KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n");
 	printk(KERN_INFO "IPX Portions Copyright (c) 2000 Conectiva, Inc.\n");
 	return 0;
 }
+
 module_init(ipx_init);
 
 /* Higher layers need this info to prep tx pkts */
 int ipx_if_offset(unsigned long ipx_net_number)
 {
-	ipx_route *rt = NULL;
-
-	rt = ipxrtr_lookup(ipx_net_number);
+	ipx_route *rt = ipxrtr_lookup(ipx_net_number);
 
-	return (rt ? rt->ir_intrfc->if_ipx_offset : -ENETUNREACH);
+	return rt ? rt->ir_intrfc->if_ipx_offset : -ENETUNREACH;
 }
 
 /* Export symbols for higher layers */
@@ -2683,24 +2543,22 @@
 	unregister_netdevice_notifier(&ipx_dev_notifier);
 
 	unregister_snap_client(ipx_snap_id);
-	pSNAP_datalink 	= NULL;
+	pSNAP_datalink = NULL;
 
 	unregister_8022_client(ipx_8022_type);
-	p8022_datalink 	= NULL;
+	p8022_datalink = NULL;
 
 	dev_remove_pack(&ipx_8023_packet_type);
 	destroy_8023_client(p8023_datalink);
-	p8023_datalink 	= NULL;
+	p8023_datalink = NULL;
 
 	dev_remove_pack(&ipx_dix_packet_type);
 	destroy_EII_client(pEII_datalink);
-	pEII_datalink 	= NULL;
-
-	(void) sock_unregister(ipx_family_ops.family);
+	pEII_datalink = NULL;
 
-	return;
+	sock_unregister(ipx_family_ops.family);
 }
+
 module_exit(ipx_proto_finito);
 #endif /* MODULE */
-
 #endif /* CONFIG_IPX || CONFIG_IPX_MODULE */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)