aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2007-12-29 04:55:50 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:08:55 -0500
commit7698d6977a62bbc6ed3b9d0d0230f2213a3b2f9d (patch)
treee7ea75cdb6ec548e3c31a71f26410e9d1892d512
parent1edd3a555304a266e76bbc6cbe04f446fdd7940b (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.c67
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
2316static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) 2317static 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);