📄 orinoco.c
字号:
dev->name); /* Perform an emergency shutdown */ clear_bit(DLDWD_STATE_DOIRQ, &priv->state); hermes_set_irqmask(hw, 0); break; } evstat = hermes_read_regn(hw, EVSTAT); DEBUG(3, "__dldwd_interrupt(): count=%d EVSTAT=0x%04x inten=0x%04x\n", count, evstat, hw->inten); events = evstat & hw->inten; if (! events) { if (netif_queue_stopped(dev)) { /* There seems to be a firmware bug which sometimes causes the card to give an interrupt with no event set, when there sould be a Tx completed event. */ DEBUG(3, "%s: Interrupt with no event (ALLOCFID=0x%04x)\n", dev->name, (int)hermes_read_regn(hw, ALLOCFID)); events = HERMES_EV_TX | HERMES_EV_ALLOC; } else /* Nothing's happening, we're done */ break; } /* Check the card hasn't been removed */ if (! hermes_present(hw)) { DEBUG(0, "dldwd_interrupt(): card removed\n"); break; } if (events & HERMES_EV_TICK) __dldwd_ev_tick(priv, hw); if (events & HERMES_EV_WTERR) __dldwd_ev_wterr(priv, hw); if (events & HERMES_EV_INFDROP) __dldwd_ev_infdrop(priv, hw); if (events & HERMES_EV_INFO) __dldwd_ev_info(priv, hw); if (events & HERMES_EV_RX) __dldwd_ev_rx(priv, hw); if (events & HERMES_EV_TXEXC) __dldwd_ev_txexc(priv, hw); if (events & HERMES_EV_TX) __dldwd_ev_tx(priv, hw); if (events & HERMES_EV_ALLOC) __dldwd_ev_alloc(priv, hw); hermes_write_regn(hw, EVACK, events); } clear_bit(DLDWD_STATE_INIRQ, &priv->state);}static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw){ printk(KERN_DEBUG "%s: TICK\n", priv->ndev.name);}static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw){ /* This seems to happen a fair bit under load, but ignoring it seems to work fine...*/ DEBUG(1, "%s: MAC controller error (WTERR). Ignoring.\n", priv->ndev.name);}static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw){ printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev.name);}static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw){ DEBUG(3, "%s: Information frame received.\n", priv->ndev.name); /* We don't actually do anything about it - we assume the MAC controller can deal with it */}static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw){ struct net_device *dev = &priv->ndev; struct net_device_stats *stats = &priv->stats; struct iw_statistics *wstats = &priv->wstats; struct sk_buff *skb = NULL; uint16_t rxfid, status; int length, data_len, data_off; char *p; struct dldwd_frame_hdr hdr; struct ethhdr *eh; int err; rxfid = hermes_read_regn(hw, RXFID); DEBUG(3, "__dldwd_ev_rx(): RXFID=0x%04x\n", rxfid); /* We read in the entire frame header here. This isn't really necessary, since we ignore most of it, but it's conceptually simpler. We can tune this later if necessary. */ err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), rxfid, 0); if (err) { printk(KERN_ERR "%s: error %d reading frame header. " "Frame dropped.\n", dev->name, err); stats->rx_errors++; goto drop; } status = le16_to_cpu(hdr.desc.status); if (status & HERMES_RXSTAT_ERR) { if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_BADCRC) { stats->rx_crc_errors++; DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name); show_rx_frame(&hdr); } else if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_UNDECRYPTABLE) { wstats->discard.code++; printk(KERN_WARNING "%s: Undecryptable frame on Rx. Frame dropped.\n", dev->name); } else { wstats->discard.misc++; printk("%s: Unknown Rx error (0x%x). Frame dropped.\n", dev->name, status & HERMES_RXSTAT_ERR); } stats->rx_errors++; goto drop; } length = le16_to_cpu(hdr.p80211.data_len); /* Yes, you heard right, that's le16. 802.2 and 802.3 are big-endian, but 802.11 is little-endian believe it or not. */ /* Correct. 802.3 is big-endian byte order and little endian bit * order, whereas 802.11 is little endian for both byte and bit * order. That's specified in the 802.11 spec. - Jean II */ /* Sanity check */ if (length > MAX_FRAME_SIZE) { printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", dev->name, length); stats->rx_length_errors++; stats->rx_errors++; goto drop; } /* We need space for the packet data itself, plus an ethernet header, plus 2 bytes so we can align the IP header on a 32bit boundary, plus 1 byte so we can read in odd length packets from the card, which has an IO granularity of 16 bits */ skb = dev_alloc_skb(length+ETH_HLEN+2+1); if (!skb) { printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", dev->name); stats->rx_dropped++; goto drop; } skb_reserve(skb, 2); /* This way the IP header is aligned */ /* Handle decapsulation * In most cases, the firmware tell us about SNAP frames. * For some reason, the SNAP frames sent by LinkSys APs * are not properly recognised by most firmwares. * So, check ourselves (note : only 3 bytes out of 6). */ if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || (!memcmp(&hdr.p8022, &encaps_hdr, 3))) { /* These indicate a SNAP within 802.2 LLC within 802.11 frame which we'll need to de-encapsulate to the original EthernetII frame. IEEE and ISO OSI have a lot to answer for. */ /* Remove SNAP header, reconstruct EthernetII frame */ data_len = length - ENCAPS_OVERHEAD; data_off = sizeof(hdr); eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); memcpy(eh, &hdr.p8023, sizeof(hdr.p8023)); eh->h_proto = hdr.ethertype; } else { /* All other cases indicate a genuine 802.3 frame. * No decapsulation needed */ /* Otherwise, we just throw the whole thing in, * and hope the protocol layer can deal with it * as 802.3 */ data_len = length; data_off = P8023_OFFSET; } p = skb_put(skb, data_len); if (hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len), rxfid, data_off) != 0) { printk(KERN_WARNING "%s: Error reading packet data\n", dev->name); stats->rx_errors++; goto drop; } dev->last_rx = jiffies; skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; /* Process the wireless stats if needed */ dldwd_stat_gather(dev, skb, &hdr); /* Pass the packet to the networking stack */ netif_rx(skb); stats->rx_packets++; stats->rx_bytes += length; return; drop: if (skb) dev_kfree_skb_irq(skb); return;}static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw){ struct net_device *dev = &priv->ndev; struct net_device_stats *stats = &priv->stats; printk(KERN_WARNING "%s: Tx error!\n", dev->name); netif_wake_queue(dev); stats->tx_errors++;}static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw){ struct net_device *dev = &priv->ndev; struct net_device_stats *stats = &priv->stats; DEBUG(3, "%s: Transmit completed\n", dev->name); stats->tx_packets++; netif_wake_queue(dev);}static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw){ uint16_t allocfid; allocfid = hermes_read_regn(hw, ALLOCFID); DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, allocfid); /* For some reason we don't seem to get transmit completed events properly */ if (allocfid == priv->txfid) __dldwd_ev_tx(priv, hw);/* hermes_write_regn(hw, ALLOCFID, 0); */}static void determine_firmware(struct net_device *dev){ dldwd_priv_t *priv = dev->priv; hermes_t *hw = &priv->hw; int err; uint32_t firmver; char *vendor_str; /* Get the firmware version */ err = hermes_read_staidentity(hw, USER_BAP, &priv->firmware_info); if (err) { printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n", dev->name, err); memset(&priv->firmware_info, 0, sizeof(priv->firmware_info)); } firmver = ((uint32_t)priv->firmware_info.major << 16) | priv->firmware_info.minor; DEBUG(2, "%s: firmver = 0x%X\n", dev->name, firmver); /* Determine capabilities from the firmware version */ switch (priv->firmware_info.vendor) { case 0x1: /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, * ELSA, Melco, HP, IBM, Dell 1150 cards */ vendor_str = "Lucent"; /* Lucent MAC : 00:60:1D:* & 00:02:2D:* */ priv->firmware_type = FIRMWARE_TYPE_LUCENT; priv->tx_rate_ctrl = 0x3; /* 11 Mb/s auto */ priv->need_card_reset = 0; priv->broken_reset = 0; priv->broken_allocate = 0; priv->has_port3 = 1; /* Still works in 7.28 */ priv->has_ibss = (firmver >= 0x60006); priv->has_ibss_any = (firmver >= 0x60010); priv->has_wep = (firmver >= 0x40020); priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell Gold cards from the others? */ priv->has_mwo = (firmver >= 0x60000); priv->has_pm = (firmver >= 0x40020); priv->has_preamble = 0; /* Tested with Lucent firmware : * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II * Tested CableTron firmware : 4.32 => Anton */ break; case 0x2: vendor_str = "Generic Prism II"; /* Some D-Link cards report vendor 0x02... */ priv->firmware_type = FIRMWARE_TYPE_PRISM2; priv->tx_rate_ctrl = 0xF; /* 11 Mb/s auto */ priv->need_card_reset = 0; priv->broken_reset = 0; priv->broken_allocate = 0; priv->has_port3 = 1; priv->has_ibss = (firmver >= 0x00007); /* FIXME */ priv->has_wep = (firmver >= 0x00007); /* FIXME */ priv->has_big_wep = 0; priv->has_mwo = 0; priv->has_pm = (firmver >= 0x00007); /* FIXME */ priv->has_preamble = 0; /* Tim Hurley -> D-Link card, vendor 02, firmware 0.08 */ /* Special case for Symbol cards */ if(firmver == 0x10001) { /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ vendor_str = "Symbol"; /* Intel MAC : 00:02:B3:* */ /* 3Com MAC : 00:50:DA:* */ /* FIXME : we need to get Symbol firmware revision. * I tried to use SYMBOL_***ARY_VER, but it didn't * returned anything proper... */ priv->firmware_type = FIRMWARE_TYPE_SYMBOL; priv->tx_rate_ctrl = 0xF; /* 11 Mb/s auto */ priv->need_card_reset = 1; priv->broken_reset = 0; priv->broken_allocate = 1; priv->has_port3 = 1; priv->has_ibss = 1; /* FIXME */ priv->has_wep = 1; /* FIXME */ priv->has_big_wep = 1; /* RID_SYMBOL_KEY_LENGTH */ priv->has_mwo = 0; priv->has_pm = 1; /* FIXME */ priv->has_preamble = 0; /* FIXME */ /* Tested with Intel firmware : v15 => Jean II */ } break; case 0x3: vendor_str = "Samsung"; /* To check - Should cover Samsung & Compaq */ priv->firmware_type = FIRMWARE_TYPE_PRISM2; priv->tx_rate_ctrl = 0xF; /* 11 Mb/s auto */ priv->need_card_reset = 0; priv->broken_reset = 0; priv->broken_allocate = 0; priv->has_port3 = 1; priv->has_ibss = 0; /* FIXME: available in later firmwares */ priv->has_wep = (firmver >= 0x20000); /* FIXME */ priv->has_big_wep = 0; /* FIXME */ priv->has_mwo = 0; priv->has_pm = (firmver >= 0x20000); /* FIXME */ priv->has_preamble = 0; break; case 0x6: /* D-Link DWL 650, ... */ vendor_str = "LinkSys/D-Link"; /* D-Link MAC : 00:40:05:* */ priv->firmware_type = FIRMWARE_TYPE_PRISM2; priv->tx_rate_ctrl = 0xF; /* 11 Mb/s auto */ priv->need_card_reset = 0; priv->broken_reset = 0; priv->broken_allocate = 0; priv->has_port3 = 1; priv->has_ibss = (firmver >= 0x00007); /* FIXME */ priv->has_wep = (firmver >= 0x00007); /* FIXME */ priv->has_big_wep = 0; priv->has_mwo = 0; priv->has_pm = (firmver >= 0x00007); /* FIXME */ priv->has_preamble = 0; /* Tested with D-Link firmware 0.07 => Jean II */ /* Note : with 0.07, IBSS to a Lucent card seem flaky */ break; default: vendor_str = "UNKNOWN"; priv->firmware_type = 0; priv->tx_rate_ctrl = 0x3; /* Hum... */ priv->need_card_reset = 0; priv->broken_reset = 0; priv->broken_allocate = 0; priv->has_port3 = 0; priv->has_ibss = 0; priv->has_wep = 0; priv->has_big_wep = 0; priv->has_mwo = 0; priv->has_pm = 0; priv->has_preamble = 0; } if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) priv->ibss_port = 4; else if ( (priv->firmware_type == FIRMWARE_TYPE_PRISM2) && (firmver >= 0x00008) ) priv->ibss_port = 0; else priv->ibss_port = 1; printk(KERN_DEBUG "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n", dev->name, priv->firmware_info.id, priv->firmware_info.vendor, vendor_str, priv->firmware_info.major, priv->firmware_info.minor);}/* * struct net_device methods */intdldwd_init(struct net_device *dev){ dldwd_priv_t *priv = dev->priv; hermes_t *hw = &priv->hw; int err = 0; hermes_id_t nickbuf; uint16_t reclen; int len; TRACE_ENTER("dldwd"); dldwd_lock(priv); /* Do standard firmware reset */ err = hermes_reset(hw); if (err != 0) { printk(KERN_ERR "%s: failed to reset hardware (err = %d)\n", dev->name, err); goto out; } determine_firmware(dev); if (priv->has_port3) printk(KERN_DEBUG "%s: Ad-hoc demo mode supported.\n", dev->name); if (priv->has_ibss) printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported.\n", dev->name); if (priv->has_wep) { printk(KERN_DEBUG "%s: WEP supported, ", dev->name); if (priv->has_big_wep) printk("\"128\"-bit key.\n"); else printk("40-bit key.\n"); } /* Get the MAC address */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_MACADDR, ETH_ALEN, NULL, dev->dev_addr); if (err) { printk(KERN_WARNING "%s: failed to read MAC address!\n", dev->name); goto out; } printk(KERN_DEBUG "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); /* Get the station name */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, sizeof(nickbuf), &reclen, &nickbuf);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -