mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
[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>
This commit is contained in:
parent
4833ed0940
commit
02e60370d4
3 changed files with 22 additions and 15 deletions
|
@ -26,8 +26,8 @@ struct ipx_address {
|
|||
#define IPX_MAX_PPROP_HOPS 8
|
||||
|
||||
struct ipxhdr {
|
||||
__u16 ipx_checksum __attribute__ ((packed));
|
||||
#define IPX_NO_CHECKSUM 0xFFFF
|
||||
__be16 ipx_checksum __attribute__ ((packed));
|
||||
#define IPX_NO_CHECKSUM __constant_htons(0xFFFF)
|
||||
__be16 ipx_pktsize __attribute__ ((packed));
|
||||
__u8 ipx_tctrl;
|
||||
__u8 ipx_type;
|
||||
|
|
|
@ -1234,27 +1234,27 @@ static int ipxitf_ioctl(unsigned int cmd, void __user *arg)
|
|||
/* Note: We assume ipx_tctrl==0 and htons(length)==ipx_pktsize */
|
||||
/* This functions should *not* mess with packet contents */
|
||||
|
||||
__u16 ipx_cksum(struct ipxhdr *packet, int length)
|
||||
__be16 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.)
|
||||
*/
|
||||
/* 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);
|
||||
/* handle the first 3 words separately; checksum should be skipped
|
||||
* and ipx_tctrl masked out */
|
||||
__u16 *p = (__u16 *)packet;
|
||||
__u32 sum = p[1] + (p[2] & (__force u16)htons(0x00ff));
|
||||
__u32 i = (length >> 1) - 3; /* Number of remaining complete words */
|
||||
|
||||
/* Loop through all complete words except the checksum field,
|
||||
* ipx_type (accounted above) and ipx_tctrl (not used in the cksum) */
|
||||
while (--i)
|
||||
/* Loop through them */
|
||||
p += 3;
|
||||
while (i--)
|
||||
sum += *p++;
|
||||
|
||||
/* Add on the last part word if it exists */
|
||||
if (packet->ipx_pktsize & htons(1))
|
||||
sum += ntohs(0xff00) & *p;
|
||||
sum += (__force u16)htons(0xff00) & *p;
|
||||
|
||||
/* Do final fixup */
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
|
@ -1263,7 +1263,14 @@ __u16 ipx_cksum(struct ipxhdr *packet, int length)
|
|||
if (sum >= 0x10000)
|
||||
sum++;
|
||||
|
||||
return ~sum;
|
||||
/*
|
||||
* Leave 0 alone; we don't want 0xffff here. Note that we can't get
|
||||
* here with 0x10000, so this check is the same as ((__u16)sum)
|
||||
*/
|
||||
if (sum)
|
||||
sum = ~sum;
|
||||
|
||||
return (__force __be16)sum;
|
||||
}
|
||||
|
||||
const char *ipx_frame_name(__be16 frame)
|
||||
|
|
|
@ -19,7 +19,7 @@ DEFINE_RWLOCK(ipx_routes_lock);
|
|||
|
||||
extern struct ipx_interface *ipx_internal_net;
|
||||
|
||||
extern __u16 ipx_cksum(struct ipxhdr *packet, int length);
|
||||
extern __be16 ipx_cksum(struct ipxhdr *packet, int length);
|
||||
extern struct ipx_interface *ipxitf_find_using_net(__be32 net);
|
||||
extern int ipxitf_demux_socket(struct ipx_interface *intrfc,
|
||||
struct sk_buff *skb, int copy);
|
||||
|
@ -238,7 +238,7 @@ int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
|
|||
|
||||
/* Apply checksum. Not allowed on 802.3 links. */
|
||||
if (sk->sk_no_check || intrfc->if_dlink_type == htons(IPX_FRAME_8023))
|
||||
ipx->ipx_checksum = 0xFFFF;
|
||||
ipx->ipx_checksum = htons(0xFFFF);
|
||||
else
|
||||
ipx->ipx_checksum = ipx_cksum(ipx, len + sizeof(struct ipxhdr));
|
||||
|
||||
|
|
Loading…
Reference in a new issue