[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>

authored by Al Viro and committed by David S. Miller 02e60370 4833ed09

+22 -15
+2 -2
include/net/ipx.h
··· 26 #define IPX_MAX_PPROP_HOPS 8 27 28 struct ipxhdr { 29 - __u16 ipx_checksum __attribute__ ((packed)); 30 - #define IPX_NO_CHECKSUM 0xFFFF 31 __be16 ipx_pktsize __attribute__ ((packed)); 32 __u8 ipx_tctrl; 33 __u8 ipx_type;
··· 26 #define IPX_MAX_PPROP_HOPS 8 27 28 struct ipxhdr { 29 + __be16 ipx_checksum __attribute__ ((packed)); 30 + #define IPX_NO_CHECKSUM __constant_htons(0xFFFF) 31 __be16 ipx_pktsize __attribute__ ((packed)); 32 __u8 ipx_tctrl; 33 __u8 ipx_type;
+18 -11
net/ipx/af_ipx.c
··· 1234 /* Note: We assume ipx_tctrl==0 and htons(length)==ipx_pktsize */ 1235 /* This functions should *not* mess with packet contents */ 1236 1237 - __u16 ipx_cksum(struct ipxhdr *packet, int length) 1238 { 1239 /* 1240 * NOTE: sum is a net byte order quantity, which optimizes the 1241 * loop. This only works on big and little endian machines. (I 1242 * don't know of a machine that isn't.) 1243 */ 1244 - /* start at ipx_dest - We skip the checksum field and start with 1245 - * ipx_type before the loop, not considering ipx_tctrl in the calc */ 1246 - __u16 *p = (__u16 *)&packet->ipx_dest; 1247 - __u32 i = (length >> 1) - 1; /* Number of complete words */ 1248 - __u32 sum = packet->ipx_type << sizeof(packet->ipx_tctrl); 1249 1250 - /* Loop through all complete words except the checksum field, 1251 - * ipx_type (accounted above) and ipx_tctrl (not used in the cksum) */ 1252 - while (--i) 1253 sum += *p++; 1254 1255 /* Add on the last part word if it exists */ 1256 if (packet->ipx_pktsize & htons(1)) 1257 - sum += ntohs(0xff00) & *p; 1258 1259 /* Do final fixup */ 1260 sum = (sum & 0xffff) + (sum >> 16); ··· 1263 if (sum >= 0x10000) 1264 sum++; 1265 1266 - return ~sum; 1267 } 1268 1269 const char *ipx_frame_name(__be16 frame)
··· 1234 /* Note: We assume ipx_tctrl==0 and htons(length)==ipx_pktsize */ 1235 /* This functions should *not* mess with packet contents */ 1236 1237 + __be16 ipx_cksum(struct ipxhdr *packet, int length) 1238 { 1239 /* 1240 * NOTE: sum is a net byte order quantity, which optimizes the 1241 * loop. This only works on big and little endian machines. (I 1242 * don't know of a machine that isn't.) 1243 */ 1244 + /* handle the first 3 words separately; checksum should be skipped 1245 + * and ipx_tctrl masked out */ 1246 + __u16 *p = (__u16 *)packet; 1247 + __u32 sum = p[1] + (p[2] & (__force u16)htons(0x00ff)); 1248 + __u32 i = (length >> 1) - 3; /* Number of remaining complete words */ 1249 1250 + /* Loop through them */ 1251 + p += 3; 1252 + while (i--) 1253 sum += *p++; 1254 1255 /* Add on the last part word if it exists */ 1256 if (packet->ipx_pktsize & htons(1)) 1257 + sum += (__force u16)htons(0xff00) & *p; 1258 1259 /* Do final fixup */ 1260 sum = (sum & 0xffff) + (sum >> 16); ··· 1263 if (sum >= 0x10000) 1264 sum++; 1265 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; 1274 } 1275 1276 const char *ipx_frame_name(__be16 frame)
+2 -2
net/ipx/ipx_route.c
··· 19 20 extern struct ipx_interface *ipx_internal_net; 21 22 - extern __u16 ipx_cksum(struct ipxhdr *packet, int length); 23 extern struct ipx_interface *ipxitf_find_using_net(__be32 net); 24 extern int ipxitf_demux_socket(struct ipx_interface *intrfc, 25 struct sk_buff *skb, int copy); ··· 238 239 /* Apply checksum. Not allowed on 802.3 links. */ 240 if (sk->sk_no_check || intrfc->if_dlink_type == htons(IPX_FRAME_8023)) 241 - ipx->ipx_checksum = 0xFFFF; 242 else 243 ipx->ipx_checksum = ipx_cksum(ipx, len + sizeof(struct ipxhdr)); 244
··· 19 20 extern struct ipx_interface *ipx_internal_net; 21 22 + extern __be16 ipx_cksum(struct ipxhdr *packet, int length); 23 extern struct ipx_interface *ipxitf_find_using_net(__be32 net); 24 extern int ipxitf_demux_socket(struct ipx_interface *intrfc, 25 struct sk_buff *skb, int copy); ··· 238 239 /* Apply checksum. Not allowed on 802.3 links. */ 240 if (sk->sk_no_check || intrfc->if_dlink_type == htons(IPX_FRAME_8023)) 241 + ipx->ipx_checksum = htons(0xFFFF); 242 else 243 ipx->ipx_checksum = ipx_cksum(ipx, len + sizeof(struct ipxhdr)); 244