aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2006-11-03 03:28:23 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-11-05 17:11:25 -0500
commit02e60370d4dac83f22d5ae75d5512bcb9a3f24b7 (patch)
tree3952d784c9d7c061a5ff7c0e23277783f10e55d2
parent4833ed094097323f5f219820f6ebdc8dd66f501f (diff)
[IPX]: Annotate and fix IPX checksum
Calculation of IPX checksum got buggered about 2.4.0. The old variant mangled the packet; that got fixed, but calculation itself got buggered. Restored the correct logics, fixed a subtle breakage we used to have even back then: if the sum is 0 mod 0xffff, we want to return 0, not 0xffff. The latter has special meaning for IPX (cheksum disabled). Observation (and obvious fix) nicked from history of FreeBSD ipx_cksum.c... Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/ipx.h4
-rw-r--r--net/ipx/af_ipx.c31
-rw-r--r--net/ipx/ipx_route.c4
3 files changed, 23 insertions, 16 deletions
diff --git a/include/net/ipx.h b/include/net/ipx.h
index 4a423d2695ba..c6b2ee610866 100644
--- a/include/net/ipx.h
+++ b/include/net/ipx.h
@@ -26,8 +26,8 @@ struct ipx_address {
26#define IPX_MAX_PPROP_HOPS 8 26#define IPX_MAX_PPROP_HOPS 8
27 27
28struct ipxhdr { 28struct ipxhdr {
29 __u16 ipx_checksum __attribute__ ((packed)); 29 __be16 ipx_checksum __attribute__ ((packed));
30#define IPX_NO_CHECKSUM 0xFFFF 30#define IPX_NO_CHECKSUM __constant_htons(0xFFFF)
31 __be16 ipx_pktsize __attribute__ ((packed)); 31 __be16 ipx_pktsize __attribute__ ((packed));
32 __u8 ipx_tctrl; 32 __u8 ipx_tctrl;
33 __u8 ipx_type; 33 __u8 ipx_type;
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index c272a38af325..76c661566dfd 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -1234,27 +1234,27 @@ static int ipxitf_ioctl(unsigned int cmd, void __user *arg)
1234/* Note: We assume ipx_tctrl==0 and htons(length)==ipx_pktsize */ 1234/* Note: We assume ipx_tctrl==0 and htons(length)==ipx_pktsize */
1235/* This functions should *not* mess with packet contents */ 1235/* This functions should *not* mess with packet contents */
1236 1236
1237__u16 ipx_cksum(struct ipxhdr *packet, int length) 1237__be16 ipx_cksum(struct ipxhdr *packet, int length)
1238{ 1238{
1239 /* 1239 /*
1240 * NOTE: sum is a net byte order quantity, which optimizes the 1240 * NOTE: sum is a net byte order quantity, which optimizes the
1241 * loop. This only works on big and little endian machines. (I 1241 * loop. This only works on big and little endian machines. (I
1242 * don't know of a machine that isn't.) 1242 * don't know of a machine that isn't.)
1243 */ 1243 */
1244 /* start at ipx_dest - We skip the checksum field and start with 1244 /* handle the first 3 words separately; checksum should be skipped
1245 * ipx_type before the loop, not considering ipx_tctrl in the calc */ 1245 * and ipx_tctrl masked out */
1246 __u16 *p = (__u16 *)&packet->ipx_dest; 1246 __u16 *p = (__u16 *)packet;
1247 __u32 i = (length >> 1) - 1; /* Number of complete words */ 1247 __u32 sum = p[1] + (p[2] & (__force u16)htons(0x00ff));
1248 __u32 sum = packet->ipx_type << sizeof(packet->ipx_tctrl); 1248 __u32 i = (length >> 1) - 3; /* Number of remaining complete words */
1249 1249
1250 /* Loop through all complete words except the checksum field, 1250 /* Loop through them */
1251 * ipx_type (accounted above) and ipx_tctrl (not used in the cksum) */ 1251 p += 3;
1252 while (--i) 1252 while (i--)
1253 sum += *p++; 1253 sum += *p++;
1254 1254
1255 /* Add on the last part word if it exists */ 1255 /* Add on the last part word if it exists */
1256 if (packet->ipx_pktsize & htons(1)) 1256 if (packet->ipx_pktsize & htons(1))
1257 sum += ntohs(0xff00) & *p; 1257 sum += (__force u16)htons(0xff00) & *p;
1258 1258
1259 /* Do final fixup */ 1259 /* Do final fixup */
1260 sum = (sum & 0xffff) + (sum >> 16); 1260 sum = (sum & 0xffff) + (sum >> 16);
@@ -1263,7 +1263,14 @@ __u16 ipx_cksum(struct ipxhdr *packet, int length)
1263 if (sum >= 0x10000) 1263 if (sum >= 0x10000)
1264 sum++; 1264 sum++;
1265 1265
1266 return ~sum; 1266 /*
1267 * Leave 0 alone; we don't want 0xffff here. Note that we can't get
1268 * here with 0x10000, so this check is the same as ((__u16)sum)
1269 */
1270 if (sum)
1271 sum = ~sum;
1272
1273 return (__force __be16)sum;
1267} 1274}
1268 1275
1269const char *ipx_frame_name(__be16 frame) 1276const char *ipx_frame_name(__be16 frame)
diff --git a/net/ipx/ipx_route.c b/net/ipx/ipx_route.c
index 8bfaefaf8841..68560ee0d797 100644
--- a/net/ipx/ipx_route.c
+++ b/net/ipx/ipx_route.c
@@ -19,7 +19,7 @@ DEFINE_RWLOCK(ipx_routes_lock);
19 19
20extern struct ipx_interface *ipx_internal_net; 20extern struct ipx_interface *ipx_internal_net;
21 21
22extern __u16 ipx_cksum(struct ipxhdr *packet, int length); 22extern __be16 ipx_cksum(struct ipxhdr *packet, int length);
23extern struct ipx_interface *ipxitf_find_using_net(__be32 net); 23extern struct ipx_interface *ipxitf_find_using_net(__be32 net);
24extern int ipxitf_demux_socket(struct ipx_interface *intrfc, 24extern int ipxitf_demux_socket(struct ipx_interface *intrfc,
25 struct sk_buff *skb, int copy); 25 struct sk_buff *skb, int copy);
@@ -238,7 +238,7 @@ int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
238 238
239 /* Apply checksum. Not allowed on 802.3 links. */ 239 /* Apply checksum. Not allowed on 802.3 links. */
240 if (sk->sk_no_check || intrfc->if_dlink_type == htons(IPX_FRAME_8023)) 240 if (sk->sk_no_check || intrfc->if_dlink_type == htons(IPX_FRAME_8023))
241 ipx->ipx_checksum = 0xFFFF; 241 ipx->ipx_checksum = htons(0xFFFF);
242 else 242 else
243 ipx->ipx_checksum = ipx_cksum(ipx, len + sizeof(struct ipxhdr)); 243 ipx->ipx_checksum = ipx_cksum(ipx, len + sizeof(struct ipxhdr));
244 244