📄 orinoco.c
字号:
} break; default: DEBUG(1, "%s: Unknown information frame received (type %04x).\n", priv->ndev.name, le16_to_cpu(info.type)); /* We don't actually do anything about it */ break; }}static void __orinoco_ev_rx(struct orinoco_private *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; u16 rxfid, status; int length, data_len, data_off; char *p; struct orinoco_rxframe_hdr hdr; struct ethhdr *eh; int err; rxfid = hermes_read_regn(hw, RXFID); DEBUG(3, "__orinoco_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); } 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. */ /* 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); err = hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len), rxfid, data_off); if (err) { if (err == -EIO) DEBUG(1, "%s: EIO reading frame header.\n", dev->name); else printk(KERN_ERR "%s: error %d reading frame header. " "Frame dropped.\n", dev->name, err); 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 */ orinoco_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 __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw){ struct net_device *dev = &priv->ndev; struct net_device_stats *stats = &priv->stats; u16 fid = hermes_read_regn(hw, TXCOMPLFID); struct hermes_tx_descriptor desc; int err = 0; if (fid == DUMMY_FID) return; /* Nothing's really happened */ err = hermes_bap_pread(hw, USER_BAP, &desc, sizeof(desc), fid, 0); if (err) { printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " "(FID=%04X error %d)\n", dev->name, fid, err); } else { printk(KERN_INFO "%s: Tx error, status %d (FID=%04X)\n", dev->name, le16_to_cpu(desc.status), fid); } stats->tx_errors++; netif_wake_queue(dev); hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);}static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw){ struct net_device *dev = &priv->ndev; struct net_device_stats *stats = &priv->stats;/* u16 fid = hermes_read_regn(hw, TXCOMPLFID); */ /* We don't generally use the Tx event (to cut down on interrupts) - we do the transmit complet processing once the transmit buffer is reclaimed in __orinoco_ev_alloc() , hence nothing here *//* DEBUG(2, "%s: Transmit completed (FID=%04X)\n", priv->ndev.name, fid); */ stats->tx_packets++; netif_wake_queue(dev); hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);}static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw){ struct net_device *dev = &priv->ndev; u16 fid = hermes_read_regn(hw, ALLOCFID); DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, fid); /* We don't generally request Tx complete events to cut down on the number of interrupts, so we do trasmit complete processing here, which happens once the firmware is done with the transmit buffer */ if (fid != priv->txfid) { if (fid != DUMMY_FID) printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", dev->name, fid); return; } hermes_write_regn(hw, ALLOCFID, DUMMY_FID);}static void determine_firmware(struct net_device *dev){ struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err; struct sta_id { u16 id, vendor, major, minor; } __attribute__ ((packed)) sta_id; u32 firmver; /* Get the firmware version */ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id); if (err) { printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n", dev->name, err); memset(&sta_id, 0, sizeof(sta_id)); } le16_to_cpus(&sta_id.id); le16_to_cpus(&sta_id.vendor); le16_to_cpus(&sta_id.major); le16_to_cpus(&sta_id.minor); firmver = ((u32)sta_id.major << 16) | sta_id.minor; printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n", dev->name, sta_id.id, sta_id.vendor, sta_id.major, sta_id.minor); /* Determine capabilities from the firmware version */ if (sta_id.vendor == 1) { /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ printk(KERN_DEBUG "%s: Looks like a Lucent/Agere firmware " "version %d.%02d\n", dev->name, sta_id.major, sta_id.minor); priv->firmware_type = FIRMWARE_TYPE_AGERE; priv->need_card_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); /* Don't work in 7.52 ? */ priv->has_preamble = 0; priv->ibss_port = 1; /* Tested with Agere firmware : * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II * Tested CableTron firmware : 4.32 => Anton */ } else if ((sta_id.vendor == 2) && ((firmver == 0x10001) || (firmver == 0x20001))) { /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */ /* Intel MAC : 00:02:B3:* */ /* 3Com MAC : 00:50:DA:* */ char tmp[SYMBOL_MAX_VER_LEN+1]; memset(tmp, 0, sizeof(tmp)); /* Get the Symbol firmware version */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SECONDARYVERSION_SYMBOL, SYMBOL_MAX_VER_LEN, NULL, &tmp); if (err) { printk(KERN_WARNING "%s: Error %d reading Symbol firmware info. Wildly guessing capabilities...\n", dev->name, err); firmver = 0; tmp[0] = '\0'; } else { /* The firmware revision is a string, the format is * something like : "V2.20-01". * Quick and dirty parsing... - Jean II */ firmver = ((tmp[1] - '0') << 16) | ((tmp[3] - '0') << 12) | ((tmp[4] - '0') << 8) | ((tmp[6] - '0') << 4) | (tmp[7] - '0'); tmp[SYMBOL_MAX_VER_LEN] = '\0'; } printk(KERN_DEBUG "%s: Looks like a Symbol firmware " "version [%s] (parsing to %X)\n", dev->name, tmp, firmver); priv->firmware_type = FIRMWARE_TYPE_SYMBOL; priv->need_card_reset = 1; priv->broken_allocate = 1; priv->has_port3 = 1; priv->has_ibss = (firmver >= 0x20000); priv->has_wep = (firmver >= 0x15012); priv->has_big_wep = (firmver >= 0x20000); priv->has_mwo = 0; priv->has_pm = (firmver >= 0x20000) && (firmver < 0x22000); priv->has_preamble = (firmver >= 0x20000); priv->ibss_port = 4; /* Tested with Intel firmware : 0x20015 => Jean II */ /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ } else { /* D-Link, Linksys, Adtron, ZoomAir, and many others... * Samsung, Compaq 100/200 and Proxim are slightly * different and less well tested */ /* D-Link MAC : 00:40:05:* */ /* Addtron MAC : 00:90:D1:* */ printk(KERN_DEBUG "%s: Looks like an Intersil firmware " "version %d.%02d\n", dev->name, sta_id.major, sta_id.minor); priv->firmware_type = FIRMWARE_TYPE_INTERSIL; priv->need_card_reset = 0; priv->broken_allocate = 0; priv->has_port3 = 1; priv->has_ibss = (firmver >= 0x00007); /* FIXME */ priv->has_wep = (firmver >= 0x00008); priv->has_big_wep = priv->has_wep; priv->has_mwo = 0; priv->has_pm = (firmver >= 0x00007); priv->has_preamble = 0; if (firmver >= 0x00008) priv->ibss_port = 0; else { printk(KERN_NOTICE "%s: Intersil firmware earlier " "than v0.08 - several features not supported\n", dev->name); priv->ibss_port = 1; } }}/* * struct net_device methods */intorinoco_init(struct net_device *dev){ struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err = 0; struct hermes_idstring nickbuf; u16 reclen; int len; TRACE_ENTER("orinoco"); orinoco_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("104-bit key\n"); else printk("40-bit key\n"); } /* Get the MAC address */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR, 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_CNFOWNNAME, sizeof(nickbuf), &reclen, &nickbuf); if (err) { printk(KERN_ERR "%s: failed to read station name\n", dev->name); goto out; } if (nickbuf.len) len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len)); else len = min(IW_ESSID_MAX_SIZE, 2 * reclen); memcpy(priv->nick, &nickbuf.val, len); priv->nick[len] = '\0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -