diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2007-12-29 04:55:50 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:08:55 -0500 |
commit | 7698d6977a62bbc6ed3b9d0d0230f2213a3b2f9d (patch) | |
tree | e7ea75cdb6ec548e3c31a71f26410e9d1892d512 | |
parent | 1edd3a555304a266e76bbc6cbe04f446fdd7940b (diff) |
ray_cs fixes
bugs galore:
* 0xf380 instead of htons(ETH_P_AARP), etc. Works only on l-e.
* back in 2.3.20 driver got readb() and friends instead of
direct dereferencing of iomem. Somebody got too enthusiatic and replaced
ntohs(p->mrx_overflow)
with
ntohs(read(&p->mrx_overflow)
without noticing that (a) the sucker is 16bit and (b) that expression can't possibly
be portable anyway (hell, on l-e it's always less than 256, on b-e it's always a
multiple of 256). Proper fix is
swab16(readw(&p->mrx_overflow)
taking into account the conversion done by readw() itself. That crap happened
in several places; the same fix applies.
* untranslate() assumes little-endian almost everywhere, except for
the code checking for IPX/AARP packets; there we forgot ntohs(), so that part
only works on big-endian.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ray_cs.c | 67 |
1 files changed, 26 insertions, 41 deletions
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index f87fe10059ae..8ba28a515d4a 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/ioport.h> | 44 | #include <linux/ioport.h> |
45 | #include <linux/skbuff.h> | 45 | #include <linux/skbuff.h> |
46 | #include <linux/ethtool.h> | 46 | #include <linux/ethtool.h> |
47 | #include <linux/ieee80211.h> | ||
47 | 48 | ||
48 | #include <pcmcia/cs_types.h> | 49 | #include <pcmcia/cs_types.h> |
49 | #include <pcmcia/cs.h> | 50 | #include <pcmcia/cs.h> |
@@ -1003,7 +1004,7 @@ static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigne | |||
1003 | /* Copy LLC header to card buffer */ | 1004 | /* Copy LLC header to card buffer */ |
1004 | memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc)); | 1005 | memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc)); |
1005 | memcpy_toio( ((void __iomem *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2); | 1006 | memcpy_toio( ((void __iomem *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2); |
1006 | if ((proto == 0xf380) || (proto == 0x3781)) { | 1007 | if (proto == htons(ETH_P_AARP) || proto == htons(ETH_P_IPX)) { |
1007 | /* This is the selective translation table, only 2 entries */ | 1008 | /* This is the selective translation table, only 2 entries */ |
1008 | writeb(0xf8, &((struct snaphdr_t __iomem *)ptx->var)->org[3]); | 1009 | writeb(0xf8, &((struct snaphdr_t __iomem *)ptx->var)->org[3]); |
1009 | } | 1010 | } |
@@ -1014,7 +1015,7 @@ static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigne | |||
1014 | } | 1015 | } |
1015 | else { /* already 802 type, and proto is length */ | 1016 | else { /* already 802 type, and proto is length */ |
1016 | DEBUG(3,"ray_cs translate_frame 802\n"); | 1017 | DEBUG(3,"ray_cs translate_frame 802\n"); |
1017 | if (proto == 0xffff) { /* evil netware IPX 802.3 without LLC */ | 1018 | if (proto == htons(0xffff)) { /* evil netware IPX 802.3 without LLC */ |
1018 | DEBUG(3,"ray_cs translate_frame evil IPX\n"); | 1019 | DEBUG(3,"ray_cs translate_frame evil IPX\n"); |
1019 | memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); | 1020 | memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); |
1020 | return 0 - ETH_HLEN; | 1021 | return 0 - ETH_HLEN; |
@@ -1780,19 +1781,19 @@ static struct net_device_stats *ray_get_stats(struct net_device *dev) | |||
1780 | } | 1781 | } |
1781 | if (readb(&p->mrx_overflow_for_host)) | 1782 | if (readb(&p->mrx_overflow_for_host)) |
1782 | { | 1783 | { |
1783 | local->stats.rx_over_errors += ntohs(readb(&p->mrx_overflow)); | 1784 | local->stats.rx_over_errors += swab16(readw(&p->mrx_overflow)); |
1784 | writeb(0,&p->mrx_overflow); | 1785 | writeb(0,&p->mrx_overflow); |
1785 | writeb(0,&p->mrx_overflow_for_host); | 1786 | writeb(0,&p->mrx_overflow_for_host); |
1786 | } | 1787 | } |
1787 | if (readb(&p->mrx_checksum_error_for_host)) | 1788 | if (readb(&p->mrx_checksum_error_for_host)) |
1788 | { | 1789 | { |
1789 | local->stats.rx_crc_errors += ntohs(readb(&p->mrx_checksum_error)); | 1790 | local->stats.rx_crc_errors += swab16(readw(&p->mrx_checksum_error)); |
1790 | writeb(0,&p->mrx_checksum_error); | 1791 | writeb(0,&p->mrx_checksum_error); |
1791 | writeb(0,&p->mrx_checksum_error_for_host); | 1792 | writeb(0,&p->mrx_checksum_error_for_host); |
1792 | } | 1793 | } |
1793 | if (readb(&p->rx_hec_error_for_host)) | 1794 | if (readb(&p->rx_hec_error_for_host)) |
1794 | { | 1795 | { |
1795 | local->stats.rx_frame_errors += ntohs(readb(&p->rx_hec_error)); | 1796 | local->stats.rx_frame_errors += swab16(readw(&p->rx_hec_error)); |
1796 | writeb(0,&p->rx_hec_error); | 1797 | writeb(0,&p->rx_hec_error); |
1797 | writeb(0,&p->rx_hec_error_for_host); | 1798 | writeb(0,&p->rx_hec_error_for_host); |
1798 | } | 1799 | } |
@@ -2316,32 +2317,17 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned i | |||
2316 | static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) | 2317 | static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) |
2317 | { | 2318 | { |
2318 | snaphdr_t *psnap = (snaphdr_t *)(skb->data + RX_MAC_HEADER_LENGTH); | 2319 | snaphdr_t *psnap = (snaphdr_t *)(skb->data + RX_MAC_HEADER_LENGTH); |
2319 | struct mac_header *pmac = (struct mac_header *)skb->data; | 2320 | struct ieee80211_hdr *pmac = (struct ieee80211_hdr *)skb->data; |
2320 | unsigned short type = *(unsigned short *)psnap->ethertype; | 2321 | __be16 type = *(__be16 *)psnap->ethertype; |
2321 | unsigned int xsap = *(unsigned int *)psnap & 0x00ffffff; | ||
2322 | unsigned int org = (*(unsigned int *)psnap->org) & 0x00ffffff; | ||
2323 | int delta; | 2322 | int delta; |
2324 | struct ethhdr *peth; | 2323 | struct ethhdr *peth; |
2325 | UCHAR srcaddr[ADDRLEN]; | 2324 | UCHAR srcaddr[ADDRLEN]; |
2326 | UCHAR destaddr[ADDRLEN]; | 2325 | UCHAR destaddr[ADDRLEN]; |
2326 | static UCHAR org_bridge[3] = {0, 0, 0xf8}; | ||
2327 | static UCHAR org_1042[3] = {0, 0, 0}; | ||
2327 | 2328 | ||
2328 | if (pmac->frame_ctl_2 & FC2_FROM_DS) { | 2329 | memcpy(destaddr, ieee80211_get_DA(pmac), ADDRLEN); |
2329 | if (pmac->frame_ctl_2 & FC2_TO_DS) { /* AP to AP */ | 2330 | memcpy(srcaddr, ieee80211_get_SA(pmac), ADDRLEN); |
2330 | memcpy(destaddr, pmac->addr_3, ADDRLEN); | ||
2331 | memcpy(srcaddr, ((unsigned char *)pmac->addr_3) + ADDRLEN, ADDRLEN); | ||
2332 | } else { /* AP to terminal */ | ||
2333 | memcpy(destaddr, pmac->addr_1, ADDRLEN); | ||
2334 | memcpy(srcaddr, pmac->addr_3, ADDRLEN); | ||
2335 | } | ||
2336 | } else { /* Terminal to AP */ | ||
2337 | if (pmac->frame_ctl_2 & FC2_TO_DS) { | ||
2338 | memcpy(destaddr, pmac->addr_3, ADDRLEN); | ||
2339 | memcpy(srcaddr, pmac->addr_2, ADDRLEN); | ||
2340 | } else { /* Adhoc */ | ||
2341 | memcpy(destaddr, pmac->addr_1, ADDRLEN); | ||
2342 | memcpy(srcaddr, pmac->addr_2, ADDRLEN); | ||
2343 | } | ||
2344 | } | ||
2345 | 2331 | ||
2346 | #ifdef PCMCIA_DEBUG | 2332 | #ifdef PCMCIA_DEBUG |
2347 | if (pc_debug > 3) { | 2333 | if (pc_debug > 3) { |
@@ -2349,33 +2335,34 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) | |||
2349 | printk(KERN_DEBUG "skb->data before untranslate"); | 2335 | printk(KERN_DEBUG "skb->data before untranslate"); |
2350 | for (i=0;i<64;i++) | 2336 | for (i=0;i<64;i++) |
2351 | printk("%02x ",skb->data[i]); | 2337 | printk("%02x ",skb->data[i]); |
2352 | printk("\n" KERN_DEBUG "type = %08x, xsap = %08x, org = %08x\n", | 2338 | printk("\n" KERN_DEBUG "type = %08x, xsap = %02x%02x%02x, org = %02x02x02x\n", |
2353 | type,xsap,org); | 2339 | ntohs(type), |
2340 | psnap->dsap, psnap->ssap, psnap->ctrl, | ||
2341 | psnap->org[0], psnap->org[1], psnap->org[2]); | ||
2354 | printk(KERN_DEBUG "untranslate skb->data = %p\n",skb->data); | 2342 | printk(KERN_DEBUG "untranslate skb->data = %p\n",skb->data); |
2355 | } | 2343 | } |
2356 | #endif | 2344 | #endif |
2357 | 2345 | ||
2358 | if ( xsap != SNAP_ID) { | 2346 | if (psnap->dsap != 0xaa || psnap->ssap != 0xaa || psnap->ctrl != 3) { |
2359 | /* not a snap type so leave it alone */ | 2347 | /* not a snap type so leave it alone */ |
2360 | DEBUG(3,"ray_cs untranslate NOT SNAP %x\n", *(unsigned int *)psnap & 0x00ffffff); | 2348 | DEBUG(3,"ray_cs untranslate NOT SNAP %02x %02x %02x\n", |
2349 | psnap->dsap, psnap->ssap, psnap->ctrl); | ||
2361 | 2350 | ||
2362 | delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; | 2351 | delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; |
2363 | peth = (struct ethhdr *)(skb->data + delta); | 2352 | peth = (struct ethhdr *)(skb->data + delta); |
2364 | peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH); | 2353 | peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH); |
2365 | } | 2354 | } |
2366 | else { /* Its a SNAP */ | 2355 | else { /* Its a SNAP */ |
2367 | if (org == BRIDGE_ENCAP) { /* EtherII and nuke the LLC */ | 2356 | if (memcmp(psnap->org, org_bridge, 3) == 0) { /* EtherII and nuke the LLC */ |
2368 | DEBUG(3,"ray_cs untranslate Bridge encap\n"); | 2357 | DEBUG(3,"ray_cs untranslate Bridge encap\n"); |
2369 | delta = RX_MAC_HEADER_LENGTH | 2358 | delta = RX_MAC_HEADER_LENGTH |
2370 | + sizeof(struct snaphdr_t) - ETH_HLEN; | 2359 | + sizeof(struct snaphdr_t) - ETH_HLEN; |
2371 | peth = (struct ethhdr *)(skb->data + delta); | 2360 | peth = (struct ethhdr *)(skb->data + delta); |
2372 | peth->h_proto = type; | 2361 | peth->h_proto = type; |
2373 | } | 2362 | } else if (memcmp(psnap->org, org_1042, 3) == 0) { |
2374 | else { | 2363 | switch (ntohs(type)) { |
2375 | if (org == RFC1042_ENCAP) { | 2364 | case ETH_P_IPX: |
2376 | switch (type) { | 2365 | case ETH_P_AARP: |
2377 | case RAY_IPX_TYPE: | ||
2378 | case APPLEARP_TYPE: | ||
2379 | DEBUG(3,"ray_cs untranslate RFC IPX/AARP\n"); | 2366 | DEBUG(3,"ray_cs untranslate RFC IPX/AARP\n"); |
2380 | delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; | 2367 | delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; |
2381 | peth = (struct ethhdr *)(skb->data + delta); | 2368 | peth = (struct ethhdr *)(skb->data + delta); |
@@ -2389,14 +2376,12 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) | |||
2389 | peth->h_proto = type; | 2376 | peth->h_proto = type; |
2390 | break; | 2377 | break; |
2391 | } | 2378 | } |
2392 | } | 2379 | } else { |
2393 | else { | ||
2394 | printk("ray_cs untranslate very confused by packet\n"); | 2380 | printk("ray_cs untranslate very confused by packet\n"); |
2395 | delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; | 2381 | delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; |
2396 | peth = (struct ethhdr *)(skb->data + delta); | 2382 | peth = (struct ethhdr *)(skb->data + delta); |
2397 | peth->h_proto = type; | 2383 | peth->h_proto = type; |
2398 | } | 2384 | } |
2399 | } | ||
2400 | } | 2385 | } |
2401 | /* TBD reserve skb_reserve(skb, delta); */ | 2386 | /* TBD reserve skb_reserve(skb, delta); */ |
2402 | skb_pull(skb, delta); | 2387 | skb_pull(skb, delta); |