wl3501_cs.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,165 行 · 第 1/4 页
C
2,165 行
} else { sig.size = pktlen + 24 + 4 - 2; pdata += 2; pktlen -= 2; if (pktlen > (254 - sizeof(struct wl3501_tx_hdr) + 6)) { tmplen = 254 - sizeof(struct wl3501_tx_hdr) + 6; pktlen -= tmplen; } else { tmplen = pktlen; pktlen = 0; } wl3501_set_to_wla(this, bf + 2 + offsetof(struct wl3501_tx_hdr, addr4), pdata, tmplen); pdata += tmplen; wl3501_get_from_wla(this, bf, &next, sizeof(next)); bf = next; } while (pktlen > 0) { if (pktlen > 254) { tmplen = 254; pktlen -= 254; } else { tmplen = pktlen; pktlen = 0; } wl3501_set_to_wla(this, bf + 2, pdata, tmplen); pdata += tmplen; wl3501_get_from_wla(this, bf, &next, sizeof(next)); bf = next; } wl3501_set_to_wla(this, sig_bf, &sig, sizeof(sig)); wl3501_esbq_req(this, &sig_bf); }out: return rc;}static int wl3501_mgmt_resync(struct wl3501_card *this){ struct wl3501_resync_req sig = { .sig_id = WL3501_SIG_RESYNC_REQ, }; return wl3501_esbq_exec(this, &sig, sizeof(sig));}static inline int wl3501_fw_bss_type(struct wl3501_card *this){ return this->net_type == IW_MODE_INFRA ? WL3501_NET_TYPE_INFRA : WL3501_NET_TYPE_ADHOC;}static inline int wl3501_fw_cap_info(struct wl3501_card *this){ return this->net_type == IW_MODE_INFRA ? WL3501_MGMT_CAPABILITY_ESS : WL3501_MGMT_CAPABILITY_IBSS;}static int wl3501_mgmt_scan(struct wl3501_card *this, u16 chan_time){ struct wl3501_scan_req sig = { .sig_id = WL3501_SIG_SCAN_REQ, .scan_type = WL3501_SCAN_TYPE_ACTIVE, .probe_delay = 0x10, .min_chan_time = chan_time, .max_chan_time = chan_time, .bss_type = wl3501_fw_bss_type(this), }; this->bss_cnt = this->join_sta_bss = 0; return wl3501_esbq_exec(this, &sig, sizeof(sig));}static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas){ struct wl3501_join_req sig = { .sig_id = WL3501_SIG_JOIN_REQ, .timeout = 10, .ds_pset = { .el = { .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, .len = 1, }, .chan = this->chan, }, }; memcpy(&sig.beacon_period, &this->bss_set[stas].beacon_period, 72); return wl3501_esbq_exec(this, &sig, sizeof(sig));}static int wl3501_mgmt_start(struct wl3501_card *this){ struct wl3501_start_req sig = { .sig_id = WL3501_SIG_START_REQ, .beacon_period = 400, .dtim_period = 1, .ds_pset = { .el = { .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, .len = 1, }, .chan = this->chan, }, .bss_basic_rset = { .el = { .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, .len = 2, }, .data_rate_labels = { [0] = IW_MGMT_RATE_LABEL_MANDATORY | IW_MGMT_RATE_LABEL_1MBIT, [1] = IW_MGMT_RATE_LABEL_MANDATORY | IW_MGMT_RATE_LABEL_2MBIT, }, }, .operational_rset = { .el = { .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, .len = 2, }, .data_rate_labels = { [0] = IW_MGMT_RATE_LABEL_MANDATORY | IW_MGMT_RATE_LABEL_1MBIT, [1] = IW_MGMT_RATE_LABEL_MANDATORY | IW_MGMT_RATE_LABEL_2MBIT, }, }, .ibss_pset = { .el = { .id = IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET, .len = 2, }, .atim_window = 10, }, .bss_type = wl3501_fw_bss_type(this), .cap_info = wl3501_fw_cap_info(this), }; iw_copy_mgmt_info_element(&sig.ssid.el, &this->essid.el); iw_copy_mgmt_info_element(&this->keep_essid.el, &this->essid.el); return wl3501_esbq_exec(this, &sig, sizeof(sig));}static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr){ u16 i = 0; int matchflag = 0; struct wl3501_scan_confirm sig; dprintk(3, "entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); if (sig.status == WL3501_STATUS_SUCCESS) { dprintk(3, "success"); if ((this->net_type == IW_MODE_INFRA && (sig.cap_info & WL3501_MGMT_CAPABILITY_ESS)) || (this->net_type == IW_MODE_ADHOC && (sig.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) || this->net_type == IW_MODE_AUTO) { if (!this->essid.el.len) matchflag = 1; else if (this->essid.el.len == 3 && !memcmp(this->essid.essid, "ANY", 3)) matchflag = 1; else if (this->essid.el.len != sig.ssid.el.len) matchflag = 0; else if (memcmp(this->essid.essid, sig.ssid.essid, this->essid.el.len)) matchflag = 0; else matchflag = 1; if (matchflag) { for (i = 0; i < this->bss_cnt; i++) { if (!memcmp(this->bss_set[i].bssid, sig.bssid, ETH_ALEN)) { matchflag = 0; break; } } } if (matchflag && (i < 20)) { memcpy(&this->bss_set[i].beacon_period, &sig.beacon_period, 73); this->bss_cnt++; this->rssi = sig.rssi; } } } else if (sig.status == WL3501_STATUS_TIMEOUT) { dprintk(3, "timeout"); this->join_sta_bss = 0; for (i = this->join_sta_bss; i < this->bss_cnt; i++) if (!wl3501_mgmt_join(this, i)) break; this->join_sta_bss = i; if (this->join_sta_bss == this->bss_cnt) { if (this->net_type == IW_MODE_INFRA) wl3501_mgmt_scan(this, 100); else { this->adhoc_times++; if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES) wl3501_mgmt_start(this); else wl3501_mgmt_scan(this, 100); } } }}/** * wl3501_block_interrupt - Mask interrupt from SUTRO * @this - card * * Mask interrupt from SUTRO. (i.e. SUTRO cannot interrupt the HOST) * Return: 1 if interrupt is originally enabled */static int wl3501_block_interrupt(struct wl3501_card *this){ u8 old = inb(this->base_addr + WL3501_NIC_GCR); u8 new = old & (~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC | WL3501_GCR_ENECINT)); wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); return old & WL3501_GCR_ENECINT;}/** * wl3501_unblock_interrupt - Enable interrupt from SUTRO * @this - card * * Enable interrupt from SUTRO. (i.e. SUTRO can interrupt the HOST) * Return: 1 if interrupt is originally enabled */static int wl3501_unblock_interrupt(struct wl3501_card *this){ u8 old = inb(this->base_addr + WL3501_NIC_GCR); u8 new = (old & ~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC)) | WL3501_GCR_ENECINT; wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); return old & WL3501_GCR_ENECINT;}/** * wl3501_receive - Receive data from Receive Queue. * * Receive data from Receive Queue. * * @this: card * @bf: address of host * @size: size of buffer. */static u16 wl3501_receive(struct wl3501_card *this, u8 *bf, u16 size){ u16 next_addr, next_addr1; u8 *data = bf + 12; size -= 12; wl3501_get_from_wla(this, this->start_seg + 2, &next_addr, sizeof(next_addr)); if (size > WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr)) { wl3501_get_from_wla(this, this->start_seg + sizeof(struct wl3501_rx_hdr), data, WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr)); size -= WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); data += WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); } else { wl3501_get_from_wla(this, this->start_seg + sizeof(struct wl3501_rx_hdr), data, size); size = 0; } while (size > 0) { if (size > WL3501_BLKSZ - 5) { wl3501_get_from_wla(this, next_addr + 5, data, WL3501_BLKSZ - 5); size -= WL3501_BLKSZ - 5; data += WL3501_BLKSZ - 5; wl3501_get_from_wla(this, next_addr + 2, &next_addr1, sizeof(next_addr1)); next_addr = next_addr1; } else { wl3501_get_from_wla(this, next_addr + 5, data, size); size = 0; } } return 0;}static void wl3501_esbq_req_free(struct wl3501_card *this){ u8 tmp; u16 addr; if (this->esbq_req_head == this->esbq_req_tail) goto out; wl3501_get_from_wla(this, this->esbq_req_tail + 3, &tmp, sizeof(tmp)); if (!(tmp & 0x80)) goto out; wl3501_get_from_wla(this, this->esbq_req_tail, &addr, sizeof(addr)); wl3501_free_tx_buffer(this, addr); this->esbq_req_tail += 4; if (this->esbq_req_tail >= this->esbq_req_end) this->esbq_req_tail = this->esbq_req_start;out: return;}static int wl3501_esbq_confirm(struct wl3501_card *this){ u8 tmp; wl3501_get_from_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); return tmp & 0x80;}static void wl3501_online(struct net_device *dev){ struct wl3501_card *this = dev->priv; printk(KERN_INFO "%s: Wireless LAN online. BSSID: " "%02X %02X %02X %02X %02X %02X\n", dev->name, this->bssid[0], this->bssid[1], this->bssid[2], this->bssid[3], this->bssid[4], this->bssid[5]); netif_wake_queue(dev);}static void wl3501_esbq_confirm_done(struct wl3501_card *this){ u8 tmp = 0; wl3501_set_to_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); this->esbq_confirm += 4; if (this->esbq_confirm >= this->esbq_confirm_end) this->esbq_confirm = this->esbq_confirm_start;}static int wl3501_mgmt_auth(struct wl3501_card *this){ struct wl3501_auth_req sig = { .sig_id = WL3501_SIG_AUTH_REQ, .type = WL3501_SYS_TYPE_OPEN, .timeout = 1000, }; dprintk(3, "entry"); memcpy(sig.mac_addr, this->bssid, ETH_ALEN); return wl3501_esbq_exec(this, &sig, sizeof(sig));}static int wl3501_mgmt_association(struct wl3501_card *this){ struct wl3501_assoc_req sig = { .sig_id = WL3501_SIG_ASSOC_REQ, .timeout = 1000, .listen_interval = 5, .cap_info = this->cap_info, }; dprintk(3, "entry"); memcpy(sig.mac_addr, this->bssid, ETH_ALEN); return wl3501_esbq_exec(this, &sig, sizeof(sig));}static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr){ struct wl3501_card *this = dev->priv; struct wl3501_join_confirm sig; dprintk(3, "entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); if (sig.status == WL3501_STATUS_SUCCESS) { if (this->net_type == IW_MODE_INFRA) { if (this->join_sta_bss < this->bss_cnt) { const int i = this->join_sta_bss; memcpy(this->bssid, this->bss_set[i].bssid, ETH_ALEN); this->chan = this->bss_set[i].ds_pset.chan; iw_copy_mgmt_info_element(&this->keep_essid.el, &this->bss_set[i].ssid.el); wl3501_mgmt_auth(this); } } else { const int i = this->join_sta_bss; memcpy(&this->bssid, &this->bss_set[i].bssid, ETH_ALEN); this->chan = this->bss_set[i].ds_pset.chan; iw_copy_mgmt_info_element(&this->keep_essid.el, &this->bss_set[i].ssid.el); wl3501_online(dev); } } else { int i; this->join_sta_bss++; for (i = this->join_sta_bss; i < this->bss_cnt; i++) if (!wl3501_mgmt_join(this, i)) break; this->join_sta_bss = i; if (this->join_sta_bss == this->bss_cnt) { if (this->net_type == IW_MODE_INFRA) wl3501_mgmt_scan(this, 100); else { this->adhoc_times++; if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES) wl3501_mgmt_start(this); else wl3501_mgmt_scan(this, 100); } } }}static inline void wl3501_alarm_interrupt(struct net_device *dev, struct wl3501_card *this){ if (this->net_type == IW_MODE_INFRA) { printk(KERN_INFO "Wireless LAN offline\n"); netif_stop_queue(dev); wl3501_mgmt_resync(this); }}static inline void wl3501_md_confirm_interrupt(struct net_device *dev, struct wl3501_card *this, u16 addr){ struct wl3501_md_confirm sig; dprintk(3, "entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); wl3501_free_tx_buffer(this, sig.data); if (netif_queue_stopped(dev)) netif_wake_queue(dev);}static inline void wl3501_md_ind_interrupt(struct net_device *dev, struct wl3501_card *this, u16 addr){ struct wl3501_md_ind sig; struct sk_buff *skb; u8 rssi, addr4[ETH_ALEN]; u16 pkt_len; wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); this->start_seg = sig.data; wl3501_get_from_wla(this, sig.data + offsetof(struct wl3501_rx_hdr, rssi), &rssi, sizeof(rssi)); this->rssi = rssi <= 63 ? (rssi * 100) / 64 : 255; wl3501_get_from_wla(this, sig.data + offsetof(struct wl3501_rx_hdr, addr4), &addr4, sizeof(addr4)); if (!(addr4[0] == 0xAA && addr4[1] == 0xAA && addr4[2] == 0x03 && addr4[4] == 0x00)) { printk(KERN_INFO "Insupported packet type!\n"); return; } pkt_len = sig.size + 12 - 24 - 4 - 6; skb = dev_alloc_skb(pkt_len + 5); if (!skb) { printk(KERN_WARNING "%s: Can't alloc a sk_buff of size %d.\n", dev->name, pkt_len); this->stats.rx_dropped++; } else { skb->dev = dev; skb_reserve(skb, 2); /* IP headers on 16 bytes boundaries */ eth_copy_and_sum(skb, (unsigned char *)&sig.daddr, 12, 0); wl3501_receive(this, skb->data, pkt_len); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, dev); dev->last_rx = jiffies; this->stats.rx_packets++; this->stats.rx_bytes += skb->len; netif_rx(skb); }}static inline void wl3501_get_confirm_interrupt(struct wl3501_card *this, u16 addr, void *sig, int size){ dprintk(3, "entry"); wl3501_get_from_wla(this, addr, &this->sig_get_confirm, sizeof(this->sig_get_confirm)); wake_up(&this->wait);}static inline void wl3501_start_confirm_interrupt(struct net_device *dev, struct wl3501_card *this, u16 addr){ struct wl3501_start_confirm sig; dprintk(3, "entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); if (sig.status == WL3501_STATUS_SUCCESS) netif_wake_queue(dev);}static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev, u16 addr){ struct wl3501_card *this = dev->priv; struct wl3501_assoc_confirm sig; dprintk(3, "entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); if (sig.status == WL3501_STATUS_SUCCESS) wl3501_online(dev);}static inline void wl3501_auth_confirm_interrupt(struct wl3501_card *this, u16 addr){ struct wl3501_auth_confirm sig; dprintk(3, "entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); if (sig.status == WL3501_STATUS_SUCCESS) wl3501_mgmt_association(this); else wl3501_mgmt_resync(this);}static inline void wl3501_rx_interrupt(struct net_device *dev){ int morepkts; u16 addr; u8 sig_id; struct wl3501_card *this = dev->priv; dprintk(3, "entry");loop: morepkts = 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?