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

📄 ieee80211.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	dev->stop = ieee80211_stop;	dev->destructor = ieee80211_if_free;}/* WDS specialties */int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr){	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);	struct sta_info *sta;	DECLARE_MAC_BUF(mac);	if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0)		return 0;	/* Create STA entry for the new peer */	sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL);	if (!sta)		return -ENOMEM;	sta_info_put(sta);	/* Remove STA entry for the old peer */	sta = sta_info_get(local, sdata->u.wds.remote_addr);	if (sta) {		sta_info_free(sta);		sta_info_put(sta);	} else {		printk(KERN_DEBUG "%s: could not find STA entry for WDS link "		       "peer %s\n",		       dev->name, print_mac(mac, sdata->u.wds.remote_addr));	}	/* Update WDS link data */	memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN);	return 0;}/* everything else */static int __ieee80211_if_config(struct net_device *dev,				 struct sk_buff *beacon,				 struct ieee80211_tx_control *control){	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);	struct ieee80211_if_conf conf;	if (!local->ops->config_interface || !netif_running(dev))		return 0;	memset(&conf, 0, sizeof(conf));	conf.type = sdata->type;	if (sdata->type == IEEE80211_IF_TYPE_STA ||	    sdata->type == IEEE80211_IF_TYPE_IBSS) {		conf.bssid = sdata->u.sta.bssid;		conf.ssid = sdata->u.sta.ssid;		conf.ssid_len = sdata->u.sta.ssid_len;	} else if (sdata->type == IEEE80211_IF_TYPE_AP) {		conf.ssid = sdata->u.ap.ssid;		conf.ssid_len = sdata->u.ap.ssid_len;		conf.beacon = beacon;		conf.beacon_control = control;	}	return local->ops->config_interface(local_to_hw(local),					   dev->ifindex, &conf);}int ieee80211_if_config(struct net_device *dev){	return __ieee80211_if_config(dev, NULL, NULL);}int ieee80211_if_config_beacon(struct net_device *dev){	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);	struct ieee80211_tx_control control;	struct sk_buff *skb;	if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))		return 0;	skb = ieee80211_beacon_get(local_to_hw(local), dev->ifindex, &control);	if (!skb)		return -ENOMEM;	return __ieee80211_if_config(dev, skb, &control);}int ieee80211_hw_config(struct ieee80211_local *local){	struct ieee80211_hw_mode *mode;	struct ieee80211_channel *chan;	int ret = 0;	if (local->sta_scanning) {		chan = local->scan_channel;		mode = local->scan_hw_mode;	} else {		chan = local->oper_channel;		mode = local->oper_hw_mode;	}	local->hw.conf.channel = chan->chan;	local->hw.conf.channel_val = chan->val;	if (!local->hw.conf.power_level) {		local->hw.conf.power_level = chan->power_level;	} else {		local->hw.conf.power_level = min(chan->power_level,						 local->hw.conf.power_level);	}	local->hw.conf.freq = chan->freq;	local->hw.conf.phymode = mode->mode;	local->hw.conf.antenna_max = chan->antenna_max;	local->hw.conf.chan = chan;	local->hw.conf.mode = mode;#ifdef CONFIG_MAC80211_VERBOSE_DEBUG	printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d "	       "phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq,	       local->hw.conf.phymode);#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */	if (local->open_count)		ret = local->ops->config(local_to_hw(local), &local->hw.conf);	return ret;}void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes){	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);	if (local->ops->erp_ie_changed)		local->ops->erp_ie_changed(local_to_hw(local), changes,			!!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION),			!(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE));}void ieee80211_reset_erp_info(struct net_device *dev){	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);	sdata->flags &= ~(IEEE80211_SDATA_USE_PROTECTION |			IEEE80211_SDATA_SHORT_PREAMBLE);	ieee80211_erp_info_change_notify(dev,					 IEEE80211_ERP_CHANGE_PROTECTION |					 IEEE80211_ERP_CHANGE_PREAMBLE);}void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,				 struct sk_buff *skb,				 struct ieee80211_tx_status *status){	struct ieee80211_local *local = hw_to_local(hw);	struct ieee80211_tx_status *saved;	int tmp;	skb->dev = local->mdev;	saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC);	if (unlikely(!saved)) {		if (net_ratelimit())			printk(KERN_WARNING "%s: Not enough memory, "			       "dropping tx status", skb->dev->name);		/* should be dev_kfree_skb_irq, but due to this function being		 * named _irqsafe instead of just _irq we can't be sure that		 * people won't call it from non-irq contexts */		dev_kfree_skb_any(skb);		return;	}	memcpy(saved, status, sizeof(struct ieee80211_tx_status));	/* copy pointer to saved status into skb->cb for use by tasklet */	memcpy(skb->cb, &saved, sizeof(saved));	skb->pkt_type = IEEE80211_TX_STATUS_MSG;	skb_queue_tail(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS ?		       &local->skb_queue : &local->skb_queue_unreliable, skb);	tmp = skb_queue_len(&local->skb_queue) +		skb_queue_len(&local->skb_queue_unreliable);	while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&	       (skb = skb_dequeue(&local->skb_queue_unreliable))) {		memcpy(&saved, skb->cb, sizeof(saved));		kfree(saved);		dev_kfree_skb_irq(skb);		tmp--;		I802_DEBUG_INC(local->tx_status_drop);	}	tasklet_schedule(&local->tasklet);}EXPORT_SYMBOL(ieee80211_tx_status_irqsafe);static void ieee80211_tasklet_handler(unsigned long data){	struct ieee80211_local *local = (struct ieee80211_local *) data;	struct sk_buff *skb;	struct ieee80211_rx_status rx_status;	struct ieee80211_tx_status *tx_status;	while ((skb = skb_dequeue(&local->skb_queue)) ||	       (skb = skb_dequeue(&local->skb_queue_unreliable))) {		switch (skb->pkt_type) {		case IEEE80211_RX_MSG:			/* status is in skb->cb */			memcpy(&rx_status, skb->cb, sizeof(rx_status));			/* Clear skb->type in order to not confuse kernel			 * netstack. */			skb->pkt_type = 0;			__ieee80211_rx(local_to_hw(local), skb, &rx_status);			break;		case IEEE80211_TX_STATUS_MSG:			/* get pointer to saved status out of skb->cb */			memcpy(&tx_status, skb->cb, sizeof(tx_status));			skb->pkt_type = 0;			ieee80211_tx_status(local_to_hw(local),					    skb, tx_status);			kfree(tx_status);			break;		default: /* should never get here! */			printk(KERN_ERR "%s: Unknown message type (%d)\n",			       wiphy_name(local->hw.wiphy), skb->pkt_type);			dev_kfree_skb(skb);			break;		}	}}/* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to * make a prepared TX frame (one that has been given to hw) to look like brand * new IEEE 802.11 frame that is ready to go through TX processing again. * Also, tx_packet_data in cb is restored from tx_control. */static void ieee80211_remove_tx_extra(struct ieee80211_local *local,				      struct ieee80211_key *key,				      struct sk_buff *skb,				      struct ieee80211_tx_control *control){	int hdrlen, iv_len, mic_len;	struct ieee80211_tx_packet_data *pkt_data;	pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;	pkt_data->ifindex = control->ifindex;	pkt_data->flags = 0;	if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS)		pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;	if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)		pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;	if (control->flags & IEEE80211_TXCTL_REQUEUE)		pkt_data->flags |= IEEE80211_TXPD_REQUEUE;	pkt_data->queue = control->queue;	hdrlen = ieee80211_get_hdrlen_from_skb(skb);	if (!key)		goto no_key;	switch (key->conf.alg) {	case ALG_WEP:		iv_len = WEP_IV_LEN;		mic_len = WEP_ICV_LEN;		break;	case ALG_TKIP:		iv_len = TKIP_IV_LEN;		mic_len = TKIP_ICV_LEN;		break;	case ALG_CCMP:		iv_len = CCMP_HDR_LEN;		mic_len = CCMP_MIC_LEN;		break;	default:		goto no_key;	}	if (skb->len >= mic_len &&	    !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))		skb_trim(skb, skb->len - mic_len);	if (skb->len >= iv_len && skb->len > hdrlen) {		memmove(skb->data + iv_len, skb->data, hdrlen);		skb_pull(skb, iv_len);	}no_key:	{		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;		u16 fc = le16_to_cpu(hdr->frame_control);		if ((fc & 0x8C) == 0x88) /* QoS Control Field */ {			fc &= ~IEEE80211_STYPE_QOS_DATA;			hdr->frame_control = cpu_to_le16(fc);			memmove(skb->data + 2, skb->data, hdrlen - 2);			skb_pull(skb, 2);		}	}}void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,			 struct ieee80211_tx_status *status){	struct sk_buff *skb2;	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;	struct ieee80211_local *local = hw_to_local(hw);	u16 frag, type;	struct ieee80211_tx_status_rtap_hdr *rthdr;	struct ieee80211_sub_if_data *sdata;	int monitors;	if (!status) {		printk(KERN_ERR		       "%s: ieee80211_tx_status called with NULL status\n",		       wiphy_name(local->hw.wiphy));		dev_kfree_skb(skb);		return;	}	if (status->excessive_retries) {		struct sta_info *sta;		sta = sta_info_get(local, hdr->addr1);		if (sta) {			if (sta->flags & WLAN_STA_PS) {				/* The STA is in power save mode, so assume				 * that this TX packet failed because of that.				 */				status->excessive_retries = 0;				status->flags |= IEEE80211_TX_STATUS_TX_FILTERED;			}			sta_info_put(sta);		}	}	if (status->flags & IEEE80211_TX_STATUS_TX_FILTERED) {		struct sta_info *sta;		sta = sta_info_get(local, hdr->addr1);		if (sta) {			sta->tx_filtered_count++;			/* Clear the TX filter mask for this STA when sending			 * the next packet. If the STA went to power save mode,			 * this will happen when it is waking up for the next			 * time. */			sta->clear_dst_mask = 1;			/* TODO: Is the WLAN_STA_PS flag always set here or is			 * the race between RX and TX status causing some			 * packets to be filtered out before 80211.o gets an			 * update for PS status? This seems to be the case, so			 * no changes are likely to be needed. */			if (sta->flags & WLAN_STA_PS &&			    skb_queue_len(&sta->tx_filtered) <			    STA_MAX_TX_BUFFER) {				ieee80211_remove_tx_extra(local, sta->key,							  skb,							  &status->control);				skb_queue_tail(&sta->tx_filtered, skb);			} else if (!(sta->flags & WLAN_STA_PS) &&				   !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {				/* Software retry the packet once */				status->control.flags |= IEEE80211_TXCTL_REQUEUE;				ieee80211_remove_tx_extra(local, sta->key,							  skb,							  &status->control);				dev_queue_xmit(skb);			} else {				if (net_ratelimit()) {					printk(KERN_DEBUG "%s: dropped TX "					       "filtered frame queue_len=%d "					       "PS=%d @%lu\n",					       wiphy_name(local->hw.wiphy),					       skb_queue_len(						       &sta->tx_filtered),					       !!(sta->flags & WLAN_STA_PS),					       jiffies);				}				dev_kfree_skb(skb);			}			sta_info_put(sta);			return;		}	} else {		/* FIXME: STUPID to call this with both local and local->mdev */		rate_control_tx_status(local, local->mdev, skb, status);	}	ieee80211_led_tx(local, 0);	/* SNMP counters	 * Fragments are passed to low-level drivers as separate skbs, so these	 * are actually fragments, not frames. Update frame counters only for	 * the first fragment of the frame. */	frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;	type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;	if (status->flags & IEEE80211_TX_STATUS_ACK) {		if (frag == 0) {			local->dot11TransmittedFrameCount++;			if (is_multicast_ether_addr(hdr->addr1))				local->dot11MulticastTransmittedFrameCount++;			if (status->retry_count > 0)				local->dot11RetryCount++;			if (status->retry_count > 1)				local->dot11MultipleRetryCount++;		}		/* This counter shall be incremented for an acknowledged MPDU		 * with an individual address in the address 1 field or an MPDU		 * with a multicast address in the address 1 field of type Data		 * or Management. */		if (!is_multicast_ether_addr(hdr->addr1) ||		    type == IEEE80211_FTYPE_DATA ||		    type == IEEE80211_FTYPE_MGMT)			local->dot11TransmittedFragmentCount++;	} else {		if (frag == 0)			local->dot11FailedCount++;	}	/* this was a transmitted frame, but now we want to reuse it */	skb_orphan(skb);	if (!local->monitors) {		dev_kfree_skb(skb);		return;	}	/* send frame to monitor interfaces now */	if (skb_headroom(skb) < sizeof(*rthdr)) {		printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");		dev_kfree_skb(skb);		return;	}	rthdr = (struct ieee80211_tx_status_rtap_hdr*)				skb_push(skb, sizeof(*rthdr));	memset(rthdr, 0, sizeof(*rthdr));	rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));	rthdr->hdr.it_present =

⌨️ 快捷键说明

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