📄 zd_mac.c
字号:
/* 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 + -