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

📄 ieee80211.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <net/mac80211.h>#include <net/ieee80211_radiotap.h>#include <linux/module.h>#include <linux/init.h>#include <linux/netdevice.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/skbuff.h>#include <linux/etherdevice.h>#include <linux/if_arp.h>#include <linux/wireless.h>#include <linux/rtnetlink.h>#include <linux/bitmap.h>#include <net/net_namespace.h>#include <net/cfg80211.h>#include "ieee80211_i.h"#include "ieee80211_rate.h"#include "wep.h"#include "wme.h"#include "aes_ccm.h"#include "ieee80211_led.h"#include "cfg.h"#include "debugfs.h"#include "debugfs_netdev.h"/* * For seeing transmitted packets on monitor interfaces * we have a radiotap header too. */struct ieee80211_tx_status_rtap_hdr {	struct ieee80211_radiotap_header hdr;	__le16 tx_flags;	u8 data_retries;} __attribute__ ((packed));/* common interface routines */static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr){	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */	return ETH_ALEN;}/* must be called under mdev tx lock */static void ieee80211_configure_filter(struct ieee80211_local *local){	unsigned int changed_flags;	unsigned int new_flags = 0;	if (atomic_read(&local->iff_promiscs))		new_flags |= FIF_PROMISC_IN_BSS;	if (atomic_read(&local->iff_allmultis))		new_flags |= FIF_ALLMULTI;	if (local->monitors)		new_flags |= FIF_CONTROL |			     FIF_OTHER_BSS |			     FIF_BCN_PRBRESP_PROMISC;	changed_flags = local->filter_flags ^ new_flags;	/* be a bit nasty */	new_flags |= (1<<31);	local->ops->configure_filter(local_to_hw(local),				     changed_flags, &new_flags,				     local->mdev->mc_count,				     local->mdev->mc_list);	WARN_ON(new_flags & (1<<31));	local->filter_flags = new_flags & ~(1<<31);}/* master interface */static int ieee80211_master_open(struct net_device *dev){	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);	struct ieee80211_sub_if_data *sdata;	int res = -EOPNOTSUPP;	/* we hold the RTNL here so can safely walk the list */	list_for_each_entry(sdata, &local->interfaces, list) {		if (sdata->dev != dev && netif_running(sdata->dev)) {			res = 0;			break;		}	}	return res;}static int ieee80211_master_stop(struct net_device *dev){	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);	struct ieee80211_sub_if_data *sdata;	/* we hold the RTNL here so can safely walk the list */	list_for_each_entry(sdata, &local->interfaces, list)		if (sdata->dev != dev && netif_running(sdata->dev))			dev_close(sdata->dev);	return 0;}static void ieee80211_master_set_multicast_list(struct net_device *dev){	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);	ieee80211_configure_filter(local);}/* regular interfaces */static int ieee80211_change_mtu(struct net_device *dev, int new_mtu){	/* FIX: what would be proper limits for MTU?	 * This interface uses 802.3 frames. */	if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) {		printk(KERN_WARNING "%s: invalid MTU %d\n",		       dev->name, new_mtu);		return -EINVAL;	}#ifdef CONFIG_MAC80211_VERBOSE_DEBUG	printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */	dev->mtu = new_mtu;	return 0;}static inline int identical_mac_addr_allowed(int type1, int type2){	return (type1 == IEEE80211_IF_TYPE_MNTR ||		type2 == IEEE80211_IF_TYPE_MNTR ||		(type1 == IEEE80211_IF_TYPE_AP &&		 type2 == IEEE80211_IF_TYPE_WDS) ||		(type1 == IEEE80211_IF_TYPE_WDS &&		 (type2 == IEEE80211_IF_TYPE_WDS ||		  type2 == IEEE80211_IF_TYPE_AP)) ||		(type1 == IEEE80211_IF_TYPE_AP &&		 type2 == IEEE80211_IF_TYPE_VLAN) ||		(type1 == IEEE80211_IF_TYPE_VLAN &&		 (type2 == IEEE80211_IF_TYPE_AP ||		  type2 == IEEE80211_IF_TYPE_VLAN)));}static int ieee80211_open(struct net_device *dev){	struct ieee80211_sub_if_data *sdata, *nsdata;	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);	struct ieee80211_if_init_conf conf;	int res;	sdata = IEEE80211_DEV_TO_SUB_IF(dev);	/* we hold the RTNL here so can safely walk the list */	list_for_each_entry(nsdata, &local->interfaces, list) {		struct net_device *ndev = nsdata->dev;		if (ndev != dev && ndev != local->mdev && netif_running(ndev) &&		    compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0) {			/*			 * check whether it may have the same address			 */			if (!identical_mac_addr_allowed(sdata->type,							nsdata->type))				return -ENOTUNIQ;			/*			 * can only add VLANs to enabled APs			 */			if (sdata->type == IEEE80211_IF_TYPE_VLAN &&			    nsdata->type == IEEE80211_IF_TYPE_AP &&			    netif_running(nsdata->dev))				sdata->u.vlan.ap = nsdata;		}	}	switch (sdata->type) {	case IEEE80211_IF_TYPE_WDS:		if (is_zero_ether_addr(sdata->u.wds.remote_addr))			return -ENOLINK;		break;	case IEEE80211_IF_TYPE_VLAN:		if (!sdata->u.vlan.ap)			return -ENOLINK;		break;	case IEEE80211_IF_TYPE_AP:	case IEEE80211_IF_TYPE_STA:	case IEEE80211_IF_TYPE_MNTR:	case IEEE80211_IF_TYPE_IBSS:		/* no special treatment */		break;	case IEEE80211_IF_TYPE_INVALID:		/* cannot happen */		WARN_ON(1);		break;	}	if (local->open_count == 0) {		res = 0;		if (local->ops->start)			res = local->ops->start(local_to_hw(local));		if (res)			return res;		ieee80211_hw_config(local);	}	switch (sdata->type) {	case IEEE80211_IF_TYPE_VLAN:		list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans);		/* no need to tell driver */		break;	case IEEE80211_IF_TYPE_MNTR:		/* must be before the call to ieee80211_configure_filter */		local->monitors++;		if (local->monitors == 1) {			netif_tx_lock_bh(local->mdev);			ieee80211_configure_filter(local);			netif_tx_unlock_bh(local->mdev);			local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;		}		break;	case IEEE80211_IF_TYPE_STA:	case IEEE80211_IF_TYPE_IBSS:		sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;		/* fall through */	default:		conf.if_id = dev->ifindex;		conf.type = sdata->type;		conf.mac_addr = dev->dev_addr;		res = local->ops->add_interface(local_to_hw(local), &conf);		if (res && !local->open_count && local->ops->stop)			local->ops->stop(local_to_hw(local));		if (res)			return res;		ieee80211_if_config(dev);		ieee80211_reset_erp_info(dev);		ieee80211_enable_keys(sdata);		if (sdata->type == IEEE80211_IF_TYPE_STA &&		    !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))			netif_carrier_off(dev);		else			netif_carrier_on(dev);	}	if (local->open_count == 0) {		res = dev_open(local->mdev);		WARN_ON(res);		tasklet_enable(&local->tx_pending_tasklet);		tasklet_enable(&local->tasklet);	}	/*	 * set_multicast_list will be invoked by the networking core	 * which will check whether any increments here were done in	 * error and sync them down to the hardware as filter flags.	 */	if (sdata->flags & IEEE80211_SDATA_ALLMULTI)		atomic_inc(&local->iff_allmultis);	if (sdata->flags & IEEE80211_SDATA_PROMISC)		atomic_inc(&local->iff_promiscs);	local->open_count++;	netif_start_queue(dev);	return 0;}static int ieee80211_stop(struct net_device *dev){	struct ieee80211_sub_if_data *sdata;	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);	struct ieee80211_if_init_conf conf;	sdata = IEEE80211_DEV_TO_SUB_IF(dev);	netif_stop_queue(dev);	/*	 * Don't count this interface for promisc/allmulti while it	 * is down. dev_mc_unsync() will invoke set_multicast_list	 * on the master interface which will sync these down to the	 * hardware as filter flags.	 */	if (sdata->flags & IEEE80211_SDATA_ALLMULTI)		atomic_dec(&local->iff_allmultis);	if (sdata->flags & IEEE80211_SDATA_PROMISC)		atomic_dec(&local->iff_promiscs);	dev_mc_unsync(local->mdev, dev);	/* down all dependent devices, that is VLANs */	if (sdata->type == IEEE80211_IF_TYPE_AP) {		struct ieee80211_sub_if_data *vlan, *tmp;		list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans,					 u.vlan.list)			dev_close(vlan->dev);		WARN_ON(!list_empty(&sdata->u.ap.vlans));	}	local->open_count--;	switch (sdata->type) {	case IEEE80211_IF_TYPE_VLAN:		list_del(&sdata->u.vlan.list);		sdata->u.vlan.ap = NULL;		/* no need to tell driver */		break;	case IEEE80211_IF_TYPE_MNTR:		local->monitors--;		if (local->monitors == 0) {			netif_tx_lock_bh(local->mdev);			ieee80211_configure_filter(local);			netif_tx_unlock_bh(local->mdev);			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;		}		break;	case IEEE80211_IF_TYPE_STA:	case IEEE80211_IF_TYPE_IBSS:		sdata->u.sta.state = IEEE80211_DISABLED;		del_timer_sync(&sdata->u.sta.timer);		/*		 * When we get here, the interface is marked down.		 * Call synchronize_rcu() to wait for the RX path		 * should it be using the interface and enqueuing		 * frames at this very time on another CPU.		 */		synchronize_rcu();		skb_queue_purge(&sdata->u.sta.skb_queue);		if (!local->ops->hw_scan &&		    local->scan_dev == sdata->dev) {			local->sta_scanning = 0;			cancel_delayed_work(&local->scan_work);		}		flush_workqueue(local->hw.workqueue);		sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;		kfree(sdata->u.sta.extra_ie);		sdata->u.sta.extra_ie = NULL;		sdata->u.sta.extra_ie_len = 0;		/* fall through */	default:		conf.if_id = dev->ifindex;		conf.type = sdata->type;		conf.mac_addr = dev->dev_addr;		/* disable all keys for as long as this netdev is down */		ieee80211_disable_keys(sdata);		local->ops->remove_interface(local_to_hw(local), &conf);	}	if (local->open_count == 0) {		if (netif_running(local->mdev))			dev_close(local->mdev);		if (local->ops->stop)			local->ops->stop(local_to_hw(local));		tasklet_disable(&local->tx_pending_tasklet);		tasklet_disable(&local->tasklet);	}	return 0;}static void ieee80211_set_multicast_list(struct net_device *dev){	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);	int allmulti, promisc, sdata_allmulti, sdata_promisc;	allmulti = !!(dev->flags & IFF_ALLMULTI);	promisc = !!(dev->flags & IFF_PROMISC);	sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI);	sdata_promisc = !!(sdata->flags & IEEE80211_SDATA_PROMISC);	if (allmulti != sdata_allmulti) {		if (dev->flags & IFF_ALLMULTI)			atomic_inc(&local->iff_allmultis);		else			atomic_dec(&local->iff_allmultis);		sdata->flags ^= IEEE80211_SDATA_ALLMULTI;	}	if (promisc != sdata_promisc) {		if (dev->flags & IFF_PROMISC)			atomic_inc(&local->iff_promiscs);		else			atomic_dec(&local->iff_promiscs);		sdata->flags ^= IEEE80211_SDATA_PROMISC;	}	dev_mc_sync(local->mdev, dev);}static const struct header_ops ieee80211_header_ops = {	.create		= eth_header,	.parse		= header_parse_80211,	.rebuild	= eth_rebuild_header,	.cache		= eth_header_cache,	.cache_update	= eth_header_cache_update,};/* Must not be called for mdev */void ieee80211_if_setup(struct net_device *dev){	ether_setup(dev);	dev->hard_start_xmit = ieee80211_subif_start_xmit;	dev->wireless_handlers = &ieee80211_iw_handler_def;	dev->set_multicast_list = ieee80211_set_multicast_list;	dev->change_mtu = ieee80211_change_mtu;	dev->open = ieee80211_open;

⌨️ 快捷键说明

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