⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 zd_mac.c

📁 zd1211无线网卡驱动源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* zd_mac.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/wireless.h>#include <linux/usb.h>#include <linux/jiffies.h>#include <net/ieee80211_radiotap.h>#include "zd_def.h"#include "zd_chip.h"#include "zd_mac.h"#include "zd_ieee80211.h"#include "zd_netdev.h"#include "zd_rf.h"#include "zd_util.h"static void ieee_init(struct ieee80211_device *ieee);static void softmac_init(struct ieee80211softmac_device *sm);int zd_mac_init(struct zd_mac *mac,	        struct net_device *netdev,	        struct usb_interface *intf){	struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev);	memset(mac, 0, sizeof(*mac));	spin_lock_init(&mac->lock);	mac->netdev = netdev;	ieee_init(ieee);	softmac_init(ieee80211_priv(netdev));	zd_chip_init(&mac->chip, netdev, intf);	return 0;}static int reset_channel(struct zd_mac *mac){	int r;	unsigned long flags;	const struct channel_range *range;	spin_lock_irqsave(&mac->lock, flags);	range = zd_channel_range(mac->regdomain);	if (!range->start) {		r = -EINVAL;		goto out;	}	mac->requested_channel = range->start;	r = 0;out:	spin_unlock_irqrestore(&mac->lock, flags);	return r;}int zd_mac_init_hw(struct zd_mac *mac, u8 device_type){	int r;	struct zd_chip *chip = &mac->chip;	u8 addr[ETH_ALEN];	u8 default_regdomain;	r = zd_chip_enable_int(chip);	if (r)		goto out;	r = zd_chip_init_hw(chip, device_type);	if (r)		goto disable_int;	zd_get_e2p_mac_addr(chip, addr);	r = zd_write_mac_addr(chip, addr);	if (r)		goto disable_int;	ZD_ASSERT(!irqs_disabled());	spin_lock_irq(&mac->lock);	memcpy(mac->netdev->dev_addr, addr, ETH_ALEN);	spin_unlock_irq(&mac->lock);	r = zd_read_regdomain(chip, &default_regdomain);	if (r)		goto disable_int;	if (!zd_regdomain_supported(default_regdomain)) {		dev_dbg_f(zd_mac_dev(mac),			  "Regulatory Domain %#04x is not supported.\n",		          default_regdomain);		r = -EINVAL;		goto disable_int;	}	spin_lock_irq(&mac->lock);	mac->regdomain = mac->default_regdomain = default_regdomain;	spin_unlock_irq(&mac->lock);	r = reset_channel(mac);	if (r)		goto disable_int;	/* We must inform the device that we are doing encryption/decryption in	 * software at the moment. */	r = zd_set_encryption_type(chip, ENC_SNIFFER);	if (r)		goto disable_int;	r = zd_geo_init(zd_mac_to_ieee80211(mac), mac->regdomain);	if (r)		goto disable_int;	r = 0;disable_int:	zd_chip_disable_int(chip);out:	return r;}void zd_mac_clear(struct zd_mac *mac){	/* Aquire the lock. */	spin_lock(&mac->lock);	spin_unlock(&mac->lock);	zd_chip_clear(&mac->chip);	memset(mac, 0, sizeof(*mac));}static int reset_mode(struct zd_mac *mac){	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);	struct zd_ioreq32 ioreqs[3] = {		{ CR_RX_FILTER, STA_RX_FILTER },		{ CR_SNIFFER_ON, 0U },	};	if (ieee->iw_mode == IW_MODE_MONITOR) {		ioreqs[0].value = 0xffffffff;		ioreqs[1].value = 0x1;		ioreqs[2].value = ENC_SNIFFER;	}	return zd_iowrite32a(&mac->chip, ioreqs, 3);}int zd_mac_open(struct net_device *netdev){	struct zd_mac *mac = zd_netdev_mac(netdev);	struct zd_chip *chip = &mac->chip;	int r;	r = zd_chip_enable_int(chip);	if (r < 0)		goto out;	r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G);	if (r < 0)		goto disable_int;	r = reset_mode(mac);	if (r)		goto disable_int;	r = zd_chip_switch_radio_on(chip);	if (r < 0)		goto disable_int;	r = zd_chip_set_channel(chip, mac->requested_channel);	if (r < 0)		goto disable_radio;	r = zd_chip_enable_rx(chip);	if (r < 0)		goto disable_radio;	r = zd_chip_enable_hwint(chip);	if (r < 0)		goto disable_rx;	ieee80211softmac_start(netdev);	return 0;disable_rx:	zd_chip_disable_rx(chip);disable_radio:	zd_chip_switch_radio_off(chip);disable_int:	zd_chip_disable_int(chip);out:	return r;}int zd_mac_stop(struct net_device *netdev){	struct zd_mac *mac = zd_netdev_mac(netdev);	struct zd_chip *chip = &mac->chip;	netif_stop_queue(netdev);	/*	 * The order here deliberately is a little different from the open()	 * method, since we need to make sure there is no opportunity for RX	 * frames to be processed by softmac after we have stopped it.	 */	zd_chip_disable_rx(chip);	ieee80211softmac_stop(netdev);	zd_chip_disable_hwint(chip);	zd_chip_switch_radio_off(chip);	zd_chip_disable_int(chip);	return 0;}int zd_mac_set_mac_address(struct net_device *netdev, void *p){	int r;	unsigned long flags;	struct sockaddr *addr = p;	struct zd_mac *mac = zd_netdev_mac(netdev);	struct zd_chip *chip = &mac->chip;	if (!is_valid_ether_addr(addr->sa_data))		return -EADDRNOTAVAIL;	dev_dbg_f(zd_mac_dev(mac),		  "Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data));	r = zd_write_mac_addr(chip, addr->sa_data);	if (r)		return r;	spin_lock_irqsave(&mac->lock, flags);	memcpy(netdev->dev_addr, addr->sa_data, ETH_ALEN);	spin_unlock_irqrestore(&mac->lock, flags);	return 0;}int zd_mac_set_regdomain(struct zd_mac *mac, u8 regdomain){	int r;	u8 channel;	ZD_ASSERT(!irqs_disabled());	spin_lock_irq(&mac->lock);	if (regdomain == 0) {		regdomain = mac->default_regdomain;	}	if (!zd_regdomain_supported(regdomain)) {		spin_unlock_irq(&mac->lock);		return -EINVAL;	}	mac->regdomain = regdomain;	channel = mac->requested_channel;	spin_unlock_irq(&mac->lock);	r = zd_geo_init(zd_mac_to_ieee80211(mac), regdomain);	if (r)		return r;	if (!zd_regdomain_supports_channel(regdomain, channel)) {		r = reset_channel(mac);		if (r)			return r;	}	return 0;}u8 zd_mac_get_regdomain(struct zd_mac *mac){	unsigned long flags;	u8 regdomain;	spin_lock_irqsave(&mac->lock, flags);	regdomain = mac->regdomain;	spin_unlock_irqrestore(&mac->lock, flags);	return regdomain;}static void set_channel(struct net_device *netdev, u8 channel){	struct zd_mac *mac = zd_netdev_mac(netdev);	dev_dbg_f(zd_mac_dev(mac), "channel %d\n", channel);	zd_chip_set_channel(&mac->chip, channel);}/* TODO: Should not work in Managed mode. */int zd_mac_request_channel(struct zd_mac *mac, u8 channel){	unsigned long lock_flags;	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);	if (ieee->iw_mode == IW_MODE_INFRA)		return -EPERM;	spin_lock_irqsave(&mac->lock, lock_flags);	if (!zd_regdomain_supports_channel(mac->regdomain, channel)) {		spin_unlock_irqrestore(&mac->lock, lock_flags);		return -EINVAL;	}	mac->requested_channel = channel;	spin_unlock_irqrestore(&mac->lock, lock_flags);	if (netif_running(mac->netdev))		return zd_chip_set_channel(&mac->chip, channel);	else		return 0;}int zd_mac_get_channel(struct zd_mac *mac, u8 *channel, u8 *flags){	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);	*channel = zd_chip_get_channel(&mac->chip);	if (ieee->iw_mode != IW_MODE_INFRA) {		spin_lock_irq(&mac->lock);		*flags = *channel == mac->requested_channel ?			MAC_FIXED_CHANNEL : 0;		spin_unlock(&mac->lock);	} else {		*flags = 0;	}	dev_dbg_f(zd_mac_dev(mac), "channel %u flags %u\n", *channel, *flags);	return 0;}/* If wrong rate is given, we are falling back to the slowest rate: 1MBit/s */static u8 cs_typed_rate(u8 cs_rate){	static const u8 typed_rates[16] = {		[ZD_CS_CCK_RATE_1M]	= ZD_CS_CCK|ZD_CS_CCK_RATE_1M,		[ZD_CS_CCK_RATE_2M]	= ZD_CS_CCK|ZD_CS_CCK_RATE_2M,		[ZD_CS_CCK_RATE_5_5M]	= ZD_CS_CCK|ZD_CS_CCK_RATE_5_5M,		[ZD_CS_CCK_RATE_11M]	= ZD_CS_CCK|ZD_CS_CCK_RATE_11M,		[ZD_OFDM_RATE_6M]	= ZD_CS_OFDM|ZD_OFDM_RATE_6M,		[ZD_OFDM_RATE_9M]	= ZD_CS_OFDM|ZD_OFDM_RATE_9M,		[ZD_OFDM_RATE_12M]	= ZD_CS_OFDM|ZD_OFDM_RATE_12M,		[ZD_OFDM_RATE_18M]	= ZD_CS_OFDM|ZD_OFDM_RATE_18M,		[ZD_OFDM_RATE_24M]	= ZD_CS_OFDM|ZD_OFDM_RATE_24M,		[ZD_OFDM_RATE_36M]	= ZD_CS_OFDM|ZD_OFDM_RATE_36M,		[ZD_OFDM_RATE_48M]	= ZD_CS_OFDM|ZD_OFDM_RATE_48M,		[ZD_OFDM_RATE_54M]	= ZD_CS_OFDM|ZD_OFDM_RATE_54M,	};	ZD_ASSERT(ZD_CS_RATE_MASK == 0x0f);	return typed_rates[cs_rate & ZD_CS_RATE_MASK];}/* Fallback to lowest rate, if rate is unknown. */static u8 rate_to_cs_rate(u8 rate){	switch (rate) {	case IEEE80211_CCK_RATE_2MB:		return ZD_CS_CCK_RATE_2M;	case IEEE80211_CCK_RATE_5MB:		return ZD_CS_CCK_RATE_5_5M;	case IEEE80211_CCK_RATE_11MB:		return ZD_CS_CCK_RATE_11M;	case IEEE80211_OFDM_RATE_6MB:		return ZD_OFDM_RATE_6M;	case IEEE80211_OFDM_RATE_9MB:		return ZD_OFDM_RATE_9M;	case IEEE80211_OFDM_RATE_12MB:		return ZD_OFDM_RATE_12M;	case IEEE80211_OFDM_RATE_18MB:		return ZD_OFDM_RATE_18M;	case IEEE80211_OFDM_RATE_24MB:		return ZD_OFDM_RATE_24M;	case IEEE80211_OFDM_RATE_36MB:		return ZD_OFDM_RATE_36M;	case IEEE80211_OFDM_RATE_48MB:		return ZD_OFDM_RATE_48M;	case IEEE80211_OFDM_RATE_54MB:		return ZD_OFDM_RATE_54M;	}	return ZD_CS_CCK_RATE_1M;}int zd_mac_set_mode(struct zd_mac *mac, u32 mode){	struct ieee80211_device *ieee;	switch (mode) {	case IW_MODE_AUTO:	case IW_MODE_ADHOC:	case IW_MODE_INFRA:		mac->netdev->type = ARPHRD_ETHER;		break;	case IW_MODE_MONITOR:		mac->netdev->type = ARPHRD_IEEE80211_RADIOTAP;		break;	default:		dev_dbg_f(zd_mac_dev(mac), "wrong mode %u\n", mode);		return -EINVAL;	}	ieee = zd_mac_to_ieee80211(mac);	ZD_ASSERT(!irqs_disabled());	spin_lock_irq(&ieee->lock);	ieee->iw_mode = mode;	spin_unlock_irq(&ieee->lock);	if (netif_running(mac->netdev))		return reset_mode(mac);	return 0;}int zd_mac_get_mode(struct zd_mac *mac, u32 *mode){	unsigned long flags;	struct ieee80211_device *ieee;	ieee = zd_mac_to_ieee80211(mac);	spin_lock_irqsave(&ieee->lock, flags);	*mode = ieee->iw_mode;	spin_unlock_irqrestore(&ieee->lock, flags);	return 0;}int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range){	int i;	const struct channel_range *channel_range;	u8 regdomain;	memset(range, 0, sizeof(*range));	/* FIXME: Not so important and depends on the mode. For 802.11g	 * usually this value is used. It seems to be that Bit/s number is	 * given here.	 */	range->throughput = 27 * 1000 * 1000;	range->max_qual.qual = 100;	range->max_qual.level = 100;	/* FIXME: Needs still to be tuned. */	range->avg_qual.qual = 71;	range->avg_qual.level = 80;	/* FIXME: depends on standard? */	range->min_rts = 256;	range->max_rts = 2346;	range->min_frag = MIN_FRAG_THRESHOLD;	range->max_frag = MAX_FRAG_THRESHOLD;	range->max_encoding_tokens = WEP_KEYS;	range->num_encoding_sizes = 2;	range->encoding_size[0] = 5;	range->encoding_size[1] = WEP_KEY_LEN;	range->we_version_compiled = WIRELESS_EXT;	range->we_version_source = 20;	ZD_ASSERT(!irqs_disabled());	spin_lock_irq(&mac->lock);	regdomain = mac->regdomain;	spin_unlock_irq(&mac->lock);	channel_range = zd_channel_range(regdomain);	range->num_channels = channel_range->end - channel_range->start;	range->old_num_channels = range->num_channels;	range->num_frequency = range->num_channels;	range->old_num_frequency = range->num_frequency;	for (i = 0; i < range->num_frequency; i++) {		struct iw_freq *freq = &range->freq[i];		freq->i = channel_range->start + i;		zd_channel_to_freq(freq, freq->i);	}	return 0;}static int zd_calc_tx_length_us(u8 *service, u8 cs_rate, u16 tx_length){	static const u8 rate_divisor[] = {		[ZD_CS_CCK_RATE_1M]	=  1,		[ZD_CS_CCK_RATE_2M]	=  2,		[ZD_CS_CCK_RATE_5_5M]	= 11, /* bits must be doubled */		[ZD_CS_CCK_RATE_11M]	= 11,		[ZD_OFDM_RATE_6M]	=  6,		[ZD_OFDM_RATE_9M]	=  9,		[ZD_OFDM_RATE_12M]	= 12,		[ZD_OFDM_RATE_18M]	= 18,		[ZD_OFDM_RATE_24M]	= 24,		[ZD_OFDM_RATE_36M]	= 36,		[ZD_OFDM_RATE_48M]	= 48,		[ZD_OFDM_RATE_54M]	= 54,	};	u32 bits = (u32)tx_length * 8;	u32 divisor;	divisor = rate_divisor[cs_rate];	if (divisor == 0)		return -EINVAL;	switch (cs_rate) {	case ZD_CS_CCK_RATE_5_5M:		bits = (2*bits) + 10; /* round up to the next integer */		break;	case ZD_CS_CCK_RATE_11M:		if (service) {			u32 t = bits % 11;			*service &= ~ZD_PLCP_SERVICE_LENGTH_EXTENSION;			if (0 < t && t <= 3) {				*service |= ZD_PLCP_SERVICE_LENGTH_EXTENSION;			}		}		bits += 10; /* round up to the next integer */		break;	}	return bits/divisor;}enum {	R2M_SHORT_PREAMBLE = 0x01,	R2M_11A		   = 0x02,};static u8 cs_rate_to_modulation(u8 cs_rate, int flags){	u8 modulation;	modulation = cs_typed_rate(cs_rate);	if (flags & R2M_SHORT_PREAMBLE) {		switch (ZD_CS_RATE(modulation)) {		case ZD_CS_CCK_RATE_2M:		case ZD_CS_CCK_RATE_5_5M:		case ZD_CS_CCK_RATE_11M:			modulation |= ZD_CS_CCK_PREA_SHORT;			return modulation;		}	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -