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

📄 zd_mac.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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"static void ieee_init(struct ieee80211_device *ieee);static void softmac_init(struct ieee80211softmac_device *sm);static void set_rts_cts_work(struct work_struct *work);static void set_basic_rates_work(struct work_struct *work);static void housekeeping_init(struct zd_mac *mac);static void housekeeping_enable(struct zd_mac *mac);static void housekeeping_disable(struct zd_mac *mac);static void set_multicast_hash_handler(struct work_struct *work);static void do_rx(unsigned long mac_ptr);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;	INIT_DELAYED_WORK(&mac->set_rts_cts_work, set_rts_cts_work);	INIT_DELAYED_WORK(&mac->set_basic_rates_work, set_basic_rates_work);	skb_queue_head_init(&mac->rx_queue);	tasklet_init(&mac->rx_tasklet, do_rx, (unsigned long)mac);	tasklet_disable(&mac->rx_tasklet);	ieee_init(ieee);	softmac_init(ieee80211_priv(netdev));	zd_chip_init(&mac->chip, netdev, intf);	housekeeping_init(mac);	INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler);	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_preinit_hw(struct zd_mac *mac){	int r;	u8 addr[ETH_ALEN];	r = zd_chip_read_mac_addr_fw(&mac->chip, addr);	if (r)		return r;	memcpy(mac->netdev->dev_addr, addr, ETH_ALEN);	return 0;}int zd_mac_init_hw(struct zd_mac *mac){	int r;	struct zd_chip *chip = &mac->chip;	u8 default_regdomain;	r = zd_chip_enable_int(chip);	if (r)		goto out;	r = zd_chip_init_hw(chip);	if (r)		goto disable_int;	ZD_ASSERT(!irqs_disabled());	r = zd_read_regdomain(chip, &default_regdomain);	if (r)		goto disable_int;	if (!zd_regdomain_supported(default_regdomain)) {		/* The vendor driver overrides the regulatory domain and		 * allowed channel registers and unconditionally restricts		 * available channels to 1-11 everywhere. Match their		 * questionable behaviour only for regdomains which we don't		 * recognise. */		dev_warn(zd_mac_dev(mac),  "Unrecognised regulatory domain: "			"%#04x. Defaulting to FCC.\n", default_regdomain);		default_regdomain = ZD_REGDOMAIN_FCC;	}	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){	flush_workqueue(zd_workqueue);	skb_queue_purge(&mac->rx_queue);	tasklet_kill(&mac->rx_tasklet);	zd_chip_clear(&mac->chip);	ZD_ASSERT(!spin_is_locked(&mac->lock));	ZD_MEMCLEAR(mac, sizeof(struct zd_mac));}static int set_rx_filter(struct zd_mac *mac){	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);	u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER;	return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);}static int set_sniffer(struct zd_mac *mac){	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);	return zd_iowrite32(&mac->chip, CR_SNIFFER_ON,		ieee->iw_mode == IW_MODE_MONITOR ? 1 : 0);	return 0;}static int set_mc_hash(struct zd_mac *mac){	struct zd_mc_hash hash;	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);	zd_mc_clear(&hash);	if (ieee->iw_mode == IW_MODE_MONITOR)		zd_mc_add_all(&hash);	return zd_chip_set_multicast_hash(&mac->chip, &hash);}int zd_mac_open(struct net_device *netdev){	struct zd_mac *mac = zd_netdev_mac(netdev);	struct zd_chip *chip = &mac->chip;	struct zd_usb *usb = &chip->usb;	int r;	if (!usb->initialized) {		r = zd_usb_init_hw(usb);		if (r)			goto out;	}	tasklet_enable(&mac->rx_tasklet);	r = zd_chip_enable_int(chip);	if (r < 0)		goto out;	r = zd_write_mac_addr(chip, netdev->dev_addr);	if (r)		goto disable_int;	r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G);	if (r < 0)		goto disable_int;	r = set_rx_filter(mac);	if (r)		goto disable_int;	r = set_sniffer(mac);	if (r)		goto disable_int;	r = set_mc_hash(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;	housekeeping_enable(mac);	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);	skb_queue_purge(&mac->rx_queue);	tasklet_disable(&mac->rx_tasklet);	housekeeping_disable(mac);	ieee80211softmac_stop(netdev);	/* Ensure no work items are running or queued from this point */	cancel_delayed_work(&mac->set_rts_cts_work);	cancel_delayed_work(&mac->set_basic_rates_work);	flush_workqueue(zd_workqueue);	mac->updating_rts_rate = 0;	mac->updating_basic_rates = 0;	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;	DECLARE_MAC_BUF(mac2);	if (!is_valid_ether_addr(addr->sa_data))		return -EADDRNOTAVAIL;	dev_dbg_f(zd_mac_dev(mac),		  "Setting MAC to %s\n", print_mac(mac2, addr->sa_data));	if (netdev->flags & IFF_UP) {		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;}static void set_multicast_hash_handler(struct work_struct *work){	struct zd_mac *mac = container_of(work, struct zd_mac,					  set_multicast_hash_work);	struct zd_mc_hash hash;	spin_lock_irq(&mac->lock);	hash = mac->multicast_hash;	spin_unlock_irq(&mac->lock);	zd_chip_set_multicast_hash(&mac->chip, &hash);}void zd_mac_set_multicast_list(struct net_device *dev){	struct zd_mac *mac = zd_netdev_mac(dev);	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);	struct zd_mc_hash hash;	struct dev_mc_list *mc;	unsigned long flags;	DECLARE_MAC_BUF(mac2);	if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI) ||			ieee->iw_mode == IW_MODE_MONITOR) {		zd_mc_add_all(&hash);	} else {		zd_mc_clear(&hash);		for (mc = dev->mc_list; mc; mc = mc->next) {			dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n",				  print_mac(mac2, mc->dmi_addr));			zd_mc_add_addr(&hash, mc->dmi_addr);		}	}	spin_lock_irqsave(&mac->lock, flags);	mac->multicast_hash = hash;	spin_unlock_irqrestore(&mac->lock, flags);	queue_work(zd_workqueue, &mac->set_multicast_hash_work);}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;}/* Fallback to lowest rate, if rate is unknown. */static u8 rate_to_zd_rate(u8 rate){	switch (rate) {	case IEEE80211_CCK_RATE_2MB:		return ZD_CCK_RATE_2M;	case IEEE80211_CCK_RATE_5MB:		return ZD_CCK_RATE_5_5M;	case IEEE80211_CCK_RATE_11MB:		return ZD_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_CCK_RATE_1M;}static u16 rate_to_cr_rate(u8 rate){	switch (rate) {	case IEEE80211_CCK_RATE_2MB:		return CR_RATE_1M;	case IEEE80211_CCK_RATE_5MB:		return CR_RATE_5_5M;	case IEEE80211_CCK_RATE_11MB:		return CR_RATE_11M;	case IEEE80211_OFDM_RATE_6MB:		return CR_RATE_6M;	case IEEE80211_OFDM_RATE_9MB:		return CR_RATE_9M;	case IEEE80211_OFDM_RATE_12MB:		return CR_RATE_12M;	case IEEE80211_OFDM_RATE_18MB:		return CR_RATE_18M;	case IEEE80211_OFDM_RATE_24MB:		return CR_RATE_24M;	case IEEE80211_OFDM_RATE_36MB:		return CR_RATE_36M;	case IEEE80211_OFDM_RATE_48MB:		return CR_RATE_48M;	case IEEE80211_OFDM_RATE_54MB:		return CR_RATE_54M;	}	return CR_RATE_1M;

⌨️ 快捷键说明

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