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>
This commit is contained in:
Родитель
1edd3a5553
Коммит
7698d6977a
|
@ -44,6 +44,7 @@
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/ethtool.h>
|
#include <linux/ethtool.h>
|
||||||
|
#include <linux/ieee80211.h>
|
||||||
|
|
||||||
#include <pcmcia/cs_types.h>
|
#include <pcmcia/cs_types.h>
|
||||||
#include <pcmcia/cs.h>
|
#include <pcmcia/cs.h>
|
||||||
|
@ -1003,7 +1004,7 @@ static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigne
|
||||||
/* Copy LLC header to card buffer */
|
/* Copy LLC header to card buffer */
|
||||||
memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc));
|
memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc));
|
||||||
memcpy_toio( ((void __iomem *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2);
|
memcpy_toio( ((void __iomem *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2);
|
||||||
if ((proto == 0xf380) || (proto == 0x3781)) {
|
if (proto == htons(ETH_P_AARP) || proto == htons(ETH_P_IPX)) {
|
||||||
/* This is the selective translation table, only 2 entries */
|
/* This is the selective translation table, only 2 entries */
|
||||||
writeb(0xf8, &((struct snaphdr_t __iomem *)ptx->var)->org[3]);
|
writeb(0xf8, &((struct snaphdr_t __iomem *)ptx->var)->org[3]);
|
||||||
}
|
}
|
||||||
|
@ -1014,7 +1015,7 @@ static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigne
|
||||||
}
|
}
|
||||||
else { /* already 802 type, and proto is length */
|
else { /* already 802 type, and proto is length */
|
||||||
DEBUG(3,"ray_cs translate_frame 802\n");
|
DEBUG(3,"ray_cs translate_frame 802\n");
|
||||||
if (proto == 0xffff) { /* evil netware IPX 802.3 without LLC */
|
if (proto == htons(0xffff)) { /* evil netware IPX 802.3 without LLC */
|
||||||
DEBUG(3,"ray_cs translate_frame evil IPX\n");
|
DEBUG(3,"ray_cs translate_frame evil IPX\n");
|
||||||
memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN);
|
memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN);
|
||||||
return 0 - ETH_HLEN;
|
return 0 - ETH_HLEN;
|
||||||
|
@ -1780,19 +1781,19 @@ static struct net_device_stats *ray_get_stats(struct net_device *dev)
|
||||||
}
|
}
|
||||||
if (readb(&p->mrx_overflow_for_host))
|
if (readb(&p->mrx_overflow_for_host))
|
||||||
{
|
{
|
||||||
local->stats.rx_over_errors += ntohs(readb(&p->mrx_overflow));
|
local->stats.rx_over_errors += swab16(readw(&p->mrx_overflow));
|
||||||
writeb(0,&p->mrx_overflow);
|
writeb(0,&p->mrx_overflow);
|
||||||
writeb(0,&p->mrx_overflow_for_host);
|
writeb(0,&p->mrx_overflow_for_host);
|
||||||
}
|
}
|
||||||
if (readb(&p->mrx_checksum_error_for_host))
|
if (readb(&p->mrx_checksum_error_for_host))
|
||||||
{
|
{
|
||||||
local->stats.rx_crc_errors += ntohs(readb(&p->mrx_checksum_error));
|
local->stats.rx_crc_errors += swab16(readw(&p->mrx_checksum_error));
|
||||||
writeb(0,&p->mrx_checksum_error);
|
writeb(0,&p->mrx_checksum_error);
|
||||||
writeb(0,&p->mrx_checksum_error_for_host);
|
writeb(0,&p->mrx_checksum_error_for_host);
|
||||||
}
|
}
|
||||||
if (readb(&p->rx_hec_error_for_host))
|
if (readb(&p->rx_hec_error_for_host))
|
||||||
{
|
{
|
||||||
local->stats.rx_frame_errors += ntohs(readb(&p->rx_hec_error));
|
local->stats.rx_frame_errors += swab16(readw(&p->rx_hec_error));
|
||||||
writeb(0,&p->rx_hec_error);
|
writeb(0,&p->rx_hec_error);
|
||||||
writeb(0,&p->rx_hec_error_for_host);
|
writeb(0,&p->rx_hec_error_for_host);
|
||||||
}
|
}
|
||||||
|
@ -2316,32 +2317,17 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned i
|
||||||
static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
|
static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
|
||||||
{
|
{
|
||||||
snaphdr_t *psnap = (snaphdr_t *)(skb->data + RX_MAC_HEADER_LENGTH);
|
snaphdr_t *psnap = (snaphdr_t *)(skb->data + RX_MAC_HEADER_LENGTH);
|
||||||
struct mac_header *pmac = (struct mac_header *)skb->data;
|
struct ieee80211_hdr *pmac = (struct ieee80211_hdr *)skb->data;
|
||||||
unsigned short type = *(unsigned short *)psnap->ethertype;
|
__be16 type = *(__be16 *)psnap->ethertype;
|
||||||
unsigned int xsap = *(unsigned int *)psnap & 0x00ffffff;
|
|
||||||
unsigned int org = (*(unsigned int *)psnap->org) & 0x00ffffff;
|
|
||||||
int delta;
|
int delta;
|
||||||
struct ethhdr *peth;
|
struct ethhdr *peth;
|
||||||
UCHAR srcaddr[ADDRLEN];
|
UCHAR srcaddr[ADDRLEN];
|
||||||
UCHAR destaddr[ADDRLEN];
|
UCHAR destaddr[ADDRLEN];
|
||||||
|
static UCHAR org_bridge[3] = {0, 0, 0xf8};
|
||||||
|
static UCHAR org_1042[3] = {0, 0, 0};
|
||||||
|
|
||||||
if (pmac->frame_ctl_2 & FC2_FROM_DS) {
|
memcpy(destaddr, ieee80211_get_DA(pmac), ADDRLEN);
|
||||||
if (pmac->frame_ctl_2 & FC2_TO_DS) { /* AP to AP */
|
memcpy(srcaddr, ieee80211_get_SA(pmac), ADDRLEN);
|
||||||
memcpy(destaddr, pmac->addr_3, ADDRLEN);
|
|
||||||
memcpy(srcaddr, ((unsigned char *)pmac->addr_3) + ADDRLEN, ADDRLEN);
|
|
||||||
} else { /* AP to terminal */
|
|
||||||
memcpy(destaddr, pmac->addr_1, ADDRLEN);
|
|
||||||
memcpy(srcaddr, pmac->addr_3, ADDRLEN);
|
|
||||||
}
|
|
||||||
} else { /* Terminal to AP */
|
|
||||||
if (pmac->frame_ctl_2 & FC2_TO_DS) {
|
|
||||||
memcpy(destaddr, pmac->addr_3, ADDRLEN);
|
|
||||||
memcpy(srcaddr, pmac->addr_2, ADDRLEN);
|
|
||||||
} else { /* Adhoc */
|
|
||||||
memcpy(destaddr, pmac->addr_1, ADDRLEN);
|
|
||||||
memcpy(srcaddr, pmac->addr_2, ADDRLEN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef PCMCIA_DEBUG
|
#ifdef PCMCIA_DEBUG
|
||||||
if (pc_debug > 3) {
|
if (pc_debug > 3) {
|
||||||
|
@ -2349,33 +2335,34 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
|
||||||
printk(KERN_DEBUG "skb->data before untranslate");
|
printk(KERN_DEBUG "skb->data before untranslate");
|
||||||
for (i=0;i<64;i++)
|
for (i=0;i<64;i++)
|
||||||
printk("%02x ",skb->data[i]);
|
printk("%02x ",skb->data[i]);
|
||||||
printk("\n" KERN_DEBUG "type = %08x, xsap = %08x, org = %08x\n",
|
printk("\n" KERN_DEBUG "type = %08x, xsap = %02x%02x%02x, org = %02x02x02x\n",
|
||||||
type,xsap,org);
|
ntohs(type),
|
||||||
|
psnap->dsap, psnap->ssap, psnap->ctrl,
|
||||||
|
psnap->org[0], psnap->org[1], psnap->org[2]);
|
||||||
printk(KERN_DEBUG "untranslate skb->data = %p\n",skb->data);
|
printk(KERN_DEBUG "untranslate skb->data = %p\n",skb->data);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( xsap != SNAP_ID) {
|
if (psnap->dsap != 0xaa || psnap->ssap != 0xaa || psnap->ctrl != 3) {
|
||||||
/* not a snap type so leave it alone */
|
/* not a snap type so leave it alone */
|
||||||
DEBUG(3,"ray_cs untranslate NOT SNAP %x\n", *(unsigned int *)psnap & 0x00ffffff);
|
DEBUG(3,"ray_cs untranslate NOT SNAP %02x %02x %02x\n",
|
||||||
|
psnap->dsap, psnap->ssap, psnap->ctrl);
|
||||||
|
|
||||||
delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
|
delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
|
||||||
peth = (struct ethhdr *)(skb->data + delta);
|
peth = (struct ethhdr *)(skb->data + delta);
|
||||||
peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH);
|
peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH);
|
||||||
}
|
}
|
||||||
else { /* Its a SNAP */
|
else { /* Its a SNAP */
|
||||||
if (org == BRIDGE_ENCAP) { /* EtherII and nuke the LLC */
|
if (memcmp(psnap->org, org_bridge, 3) == 0) { /* EtherII and nuke the LLC */
|
||||||
DEBUG(3,"ray_cs untranslate Bridge encap\n");
|
DEBUG(3,"ray_cs untranslate Bridge encap\n");
|
||||||
delta = RX_MAC_HEADER_LENGTH
|
delta = RX_MAC_HEADER_LENGTH
|
||||||
+ sizeof(struct snaphdr_t) - ETH_HLEN;
|
+ sizeof(struct snaphdr_t) - ETH_HLEN;
|
||||||
peth = (struct ethhdr *)(skb->data + delta);
|
peth = (struct ethhdr *)(skb->data + delta);
|
||||||
peth->h_proto = type;
|
peth->h_proto = type;
|
||||||
}
|
} else if (memcmp(psnap->org, org_1042, 3) == 0) {
|
||||||
else {
|
switch (ntohs(type)) {
|
||||||
if (org == RFC1042_ENCAP) {
|
case ETH_P_IPX:
|
||||||
switch (type) {
|
case ETH_P_AARP:
|
||||||
case RAY_IPX_TYPE:
|
|
||||||
case APPLEARP_TYPE:
|
|
||||||
DEBUG(3,"ray_cs untranslate RFC IPX/AARP\n");
|
DEBUG(3,"ray_cs untranslate RFC IPX/AARP\n");
|
||||||
delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
|
delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
|
||||||
peth = (struct ethhdr *)(skb->data + delta);
|
peth = (struct ethhdr *)(skb->data + delta);
|
||||||
|
@ -2389,14 +2376,12 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
|
||||||
peth->h_proto = type;
|
peth->h_proto = type;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
printk("ray_cs untranslate very confused by packet\n");
|
printk("ray_cs untranslate very confused by packet\n");
|
||||||
delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
|
delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
|
||||||
peth = (struct ethhdr *)(skb->data + delta);
|
peth = (struct ethhdr *)(skb->data + delta);
|
||||||
peth->h_proto = type;
|
peth->h_proto = type;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* TBD reserve skb_reserve(skb, delta); */
|
/* TBD reserve skb_reserve(skb, delta); */
|
||||||
skb_pull(skb, delta);
|
skb_pull(skb, delta);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче