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 + -
显示快捷键?