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

📄 hostap_80211_tx.c

📁 linux-2.6.15.6
💻 C
字号:
void hostap_dump_tx_80211(const char *name, struct sk_buff *skb){	struct ieee80211_hdr_4addr *hdr;	u16 fc;	hdr = (struct ieee80211_hdr_4addr *) skb->data;	printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n",	       name, skb->len, jiffies);	if (skb->len < 2)		return;	fc = le16_to_cpu(hdr->frame_ctl);	printk(KERN_DEBUG "   FC=0x%04x (type=%d:%d)%s%s",	       fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4,	       fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",	       fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");	if (skb->len < IEEE80211_DATA_HDR3_LEN) {		printk("\n");		return;	}	printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),	       le16_to_cpu(hdr->seq_ctl));	printk(KERN_DEBUG "   A1=" MACSTR " A2=" MACSTR " A3=" MACSTR,	       MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3));	if (skb->len >= 30)		printk(" A4=" MACSTR, MAC2STR(hdr->addr4));	printk("\n");}/* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta) * Convert Ethernet header into a suitable IEEE 802.11 header depending on * device configuration. */int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct hostap_interface *iface;	local_info_t *local;	int need_headroom, need_tailroom = 0;	struct ieee80211_hdr_4addr hdr;	u16 fc, ethertype = 0;	enum {		WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME	} use_wds = WDS_NO;	u8 *encaps_data;	int hdr_len, encaps_len, skip_header_bytes;	int to_assoc_ap = 0;	struct hostap_skb_tx_data *meta;	iface = netdev_priv(dev);	local = iface->local;	if (skb->len < ETH_HLEN) {		printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb "		       "(len=%d)\n", dev->name, skb->len);		kfree_skb(skb);		return 0;	}	if (local->ddev != dev) {		use_wds = (local->iw_mode == IW_MODE_MASTER &&			   !(local->wds_type & HOSTAP_WDS_STANDARD_FRAME)) ?			WDS_OWN_FRAME : WDS_COMPLIANT_FRAME;		if (dev == local->stadev) {			to_assoc_ap = 1;			use_wds = WDS_NO;		} else if (dev == local->apdev) {			printk(KERN_DEBUG "%s: prism2_tx: trying to use "			       "AP device with Ethernet net dev\n", dev->name);			kfree_skb(skb);			return 0;		}	} else {		if (local->iw_mode == IW_MODE_REPEAT) {			printk(KERN_DEBUG "%s: prism2_tx: trying to use "			       "non-WDS link in Repeater mode\n", dev->name);			kfree_skb(skb);			return 0;		} else if (local->iw_mode == IW_MODE_INFRA &&			   (local->wds_type & HOSTAP_WDS_AP_CLIENT) &&			   memcmp(skb->data + ETH_ALEN, dev->dev_addr,				  ETH_ALEN) != 0) {			/* AP client mode: send frames with foreign src addr			 * using 4-addr WDS frames */			use_wds = WDS_COMPLIANT_FRAME;		}	}	/* Incoming skb->data: dst_addr[6], src_addr[6], proto[2], payload	 * ==>	 * Prism2 TX frame with 802.11 header:	 * txdesc (address order depending on used mode; includes dst_addr and	 * src_addr), possible encapsulation (RFC1042/Bridge-Tunnel;	 * proto[2], payload {, possible addr4[6]} */	ethertype = (skb->data[12] << 8) | skb->data[13];	memset(&hdr, 0, sizeof(hdr));	/* Length of data after IEEE 802.11 header */	encaps_data = NULL;	encaps_len = 0;	skip_header_bytes = ETH_HLEN;	if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {		encaps_data = bridge_tunnel_header;		encaps_len = sizeof(bridge_tunnel_header);		skip_header_bytes -= 2;	} else if (ethertype >= 0x600) {		encaps_data = rfc1042_header;		encaps_len = sizeof(rfc1042_header);		skip_header_bytes -= 2;	}	fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;	hdr_len = IEEE80211_DATA_HDR3_LEN;	if (use_wds != WDS_NO) {		/* Note! Prism2 station firmware has problems with sending real		 * 802.11 frames with four addresses; until these problems can		 * be fixed or worked around, 4-addr frames needed for WDS are		 * using incompatible format: FromDS flag is not set and the		 * fourth address is added after the frame payload; it is		 * assumed, that the receiving station knows how to handle this		 * frame format */		if (use_wds == WDS_COMPLIANT_FRAME) {			fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;			/* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA,			 * Addr4 = SA */			memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);			hdr_len += ETH_ALEN;		} else {			/* bogus 4-addr format to workaround Prism2 station			 * f/w bug */			fc |= IEEE80211_FCTL_TODS;			/* From DS: Addr1 = DA (used as RA),			 * Addr2 = BSSID (used as TA), Addr3 = SA (used as DA),			 */			/* SA from skb->data + ETH_ALEN will be added after			 * frame payload; use hdr.addr4 as a temporary buffer			 */			memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);			need_tailroom += ETH_ALEN;		}		/* send broadcast and multicast frames to broadcast RA, if		 * configured; otherwise, use unicast RA of the WDS link */		if ((local->wds_type & HOSTAP_WDS_BROADCAST_RA) &&		    skb->data[0] & 0x01)			memset(&hdr.addr1, 0xff, ETH_ALEN);		else if (iface->type == HOSTAP_INTERFACE_WDS)			memcpy(&hdr.addr1, iface->u.wds.remote_addr,			       ETH_ALEN);		else			memcpy(&hdr.addr1, local->bssid, ETH_ALEN);		memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);		memcpy(&hdr.addr3, skb->data, ETH_ALEN);	} else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) {		fc |= IEEE80211_FCTL_FROMDS;		/* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */		memcpy(&hdr.addr1, skb->data, ETH_ALEN);		memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);		memcpy(&hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);	} else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) {		fc |= IEEE80211_FCTL_TODS;		/* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */		memcpy(&hdr.addr1, to_assoc_ap ?		       local->assoc_ap_addr : local->bssid, ETH_ALEN);		memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);		memcpy(&hdr.addr3, skb->data, ETH_ALEN);	} else if (local->iw_mode == IW_MODE_ADHOC) {		/* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */		memcpy(&hdr.addr1, skb->data, ETH_ALEN);		memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);		memcpy(&hdr.addr3, local->bssid, ETH_ALEN);	}	hdr.frame_ctl = cpu_to_le16(fc);	skb_pull(skb, skip_header_bytes);	need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len;	if (skb_tailroom(skb) < need_tailroom) {		skb = skb_unshare(skb, GFP_ATOMIC);		if (skb == NULL) {			iface->stats.tx_dropped++;			return 0;		}		if (pskb_expand_head(skb, need_headroom, need_tailroom,				     GFP_ATOMIC)) {			kfree_skb(skb);			iface->stats.tx_dropped++;			return 0;		}	} else if (skb_headroom(skb) < need_headroom) {		struct sk_buff *tmp = skb;		skb = skb_realloc_headroom(skb, need_headroom);		kfree_skb(tmp);		if (skb == NULL) {			iface->stats.tx_dropped++;			return 0;		}	} else {		skb = skb_unshare(skb, GFP_ATOMIC);		if (skb == NULL) {			iface->stats.tx_dropped++;			return 0;		}	}	if (encaps_data)		memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);	memcpy(skb_push(skb, hdr_len), &hdr, hdr_len);	if (use_wds == WDS_OWN_FRAME) {		memcpy(skb_put(skb, ETH_ALEN), &hdr.addr4, ETH_ALEN);	}	iface->stats.tx_packets++;	iface->stats.tx_bytes += skb->len;	skb->mac.raw = skb->data;	meta = (struct hostap_skb_tx_data *) skb->cb;	memset(meta, 0, sizeof(*meta));	meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;	if (use_wds)		meta->flags |= HOSTAP_TX_FLAGS_WDS;	meta->ethertype = ethertype;	meta->iface = iface;	/* Send IEEE 802.11 encapsulated frame using the master radio device */	skb->dev = local->dev;	dev_queue_xmit(skb);	return 0;}/* hard_start_xmit function for hostapd wlan#ap interfaces */int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct hostap_interface *iface;	local_info_t *local;	struct hostap_skb_tx_data *meta;	struct ieee80211_hdr_4addr *hdr;	u16 fc;	iface = netdev_priv(dev);	local = iface->local;	if (skb->len < 10) {		printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb "		       "(len=%d)\n", dev->name, skb->len);		kfree_skb(skb);		return 0;	}	iface->stats.tx_packets++;	iface->stats.tx_bytes += skb->len;	meta = (struct hostap_skb_tx_data *) skb->cb;	memset(meta, 0, sizeof(*meta));	meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;	meta->iface = iface;	if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) {		hdr = (struct ieee80211_hdr_4addr *) skb->data;		fc = le16_to_cpu(hdr->frame_ctl);		if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&		    WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_DATA) {			u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN +					     sizeof(rfc1042_header)];			meta->ethertype = (pos[0] << 8) | pos[1];		}	}	/* Send IEEE 802.11 encapsulated frame using the master radio device */	skb->dev = local->dev;	dev_queue_xmit(skb);	return 0;}/* Called only from software IRQ */struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,				   struct ieee80211_crypt_data *crypt){	struct hostap_interface *iface;	local_info_t *local;	struct ieee80211_hdr_4addr *hdr;	u16 fc;	int hdr_len, res;	iface = netdev_priv(skb->dev);	local = iface->local;	if (skb->len < IEEE80211_DATA_HDR3_LEN) {		kfree_skb(skb);		return NULL;	}	if (local->tkip_countermeasures &&	    crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) {		hdr = (struct ieee80211_hdr_4addr *) skb->data;		if (net_ratelimit()) {			printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "			       "TX packet to " MACSTR "\n",			       local->dev->name, MAC2STR(hdr->addr1));		}		kfree_skb(skb);		return NULL;	}	skb = skb_unshare(skb, GFP_ATOMIC);	if (skb == NULL)		return NULL;	if ((skb_headroom(skb) < crypt->ops->extra_mpdu_prefix_len ||	     skb_tailroom(skb) < crypt->ops->extra_mpdu_postfix_len) &&	    pskb_expand_head(skb, crypt->ops->extra_mpdu_prefix_len,			     crypt->ops->extra_mpdu_postfix_len, GFP_ATOMIC)) {		kfree_skb(skb);		return NULL;	}	hdr = (struct ieee80211_hdr_4addr *) skb->data; 	fc = le16_to_cpu(hdr->frame_ctl);	hdr_len = hostap_80211_get_hdrlen(fc);	/* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so	 * call both MSDU and MPDU encryption functions from here. */	atomic_inc(&crypt->refcnt);	res = 0;	if (crypt->ops->encrypt_msdu)		res = crypt->ops->encrypt_msdu(skb, hdr_len, crypt->priv);	if (res == 0 && crypt->ops->encrypt_mpdu)		res = crypt->ops->encrypt_mpdu(skb, hdr_len, crypt->priv);	atomic_dec(&crypt->refcnt);	if (res < 0) {		kfree_skb(skb);		return NULL;	}	return skb;}/* hard_start_xmit function for master radio interface wifi#. * AP processing (TX rate control, power save buffering, etc.). * Use hardware TX function to send the frame. */int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct hostap_interface *iface;	local_info_t *local;	int ret = 1;	u16 fc;	struct hostap_tx_data tx;	ap_tx_ret tx_ret;	struct hostap_skb_tx_data *meta;	int no_encrypt = 0;	struct ieee80211_hdr_4addr *hdr;	iface = netdev_priv(dev);	local = iface->local;	tx.skb = skb;	tx.sta_ptr = NULL;	meta = (struct hostap_skb_tx_data *) skb->cb;	if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) {		printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "		       "expected 0x%08x)\n",		       dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC);		ret = 0;		iface->stats.tx_dropped++;		goto fail;	}	if (local->host_encrypt) {		/* Set crypt to default algorithm and key; will be replaced in		 * AP code if STA has own alg/key */		tx.crypt = local->crypt[local->tx_keyidx];		tx.host_encrypt = 1;	} else {		tx.crypt = NULL;		tx.host_encrypt = 0;	}	if (skb->len < 24) {		printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb "		       "(len=%d)\n", dev->name, skb->len);		ret = 0;		iface->stats.tx_dropped++;		goto fail;	}	/* FIX (?):	 * Wi-Fi 802.11b test plan suggests that AP should ignore power save	 * bit in authentication and (re)association frames and assume tha	 * STA remains awake for the response. */	tx_ret = hostap_handle_sta_tx(local, &tx);	skb = tx.skb;	meta = (struct hostap_skb_tx_data *) skb->cb;	hdr = (struct ieee80211_hdr_4addr *) skb->data; 	fc = le16_to_cpu(hdr->frame_ctl);	switch (tx_ret) {	case AP_TX_CONTINUE:		break;	case AP_TX_CONTINUE_NOT_AUTHORIZED:		if (local->ieee_802_1x &&		    WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&		    meta->ethertype != ETH_P_PAE &&		    !(meta->flags & HOSTAP_TX_FLAGS_WDS)) {			printk(KERN_DEBUG "%s: dropped frame to unauthorized "			       "port (IEEE 802.1X): ethertype=0x%04x\n",			       dev->name, meta->ethertype);			hostap_dump_tx_80211(dev->name, skb);			ret = 0; /* drop packet */			iface->stats.tx_dropped++;			goto fail;		}		break;	case AP_TX_DROP:		ret = 0; /* drop packet */		iface->stats.tx_dropped++;		goto fail;	case AP_TX_RETRY:		goto fail;	case AP_TX_BUFFERED:		/* do not free skb here, it will be freed when the		 * buffered frame is sent/timed out */		ret = 0;		goto tx_exit;	}	/* Request TX callback if protocol version is 2 in 802.11 header;	 * this version 2 is a special case used between hostapd and kernel	 * driver */	if (((fc & IEEE80211_FCTL_VERS) == BIT(1)) &&	    local->ap && local->ap->tx_callback_idx && meta->tx_cb_idx == 0) {		meta->tx_cb_idx = local->ap->tx_callback_idx;		/* remove special version from the frame header */		fc &= ~IEEE80211_FCTL_VERS;		hdr->frame_ctl = cpu_to_le16(fc);	}	if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_DATA) {		no_encrypt = 1;		tx.crypt = NULL;	}	if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt &&	    !(fc & IEEE80211_FCTL_VERS)) {		no_encrypt = 1;		PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing "		       "unencrypted EAPOL frame\n", dev->name);		tx.crypt = NULL; /* no encryption for IEEE 802.1X frames */	}	if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu))		tx.crypt = NULL;	else if ((tx.crypt || local->crypt[local->tx_keyidx]) && !no_encrypt) {		/* Add ISWEP flag both for firmware and host based encryption		 */		fc |= IEEE80211_FCTL_PROTECTED;		hdr->frame_ctl = cpu_to_le16(fc);	} else if (local->drop_unencrypted &&		   WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&		   meta->ethertype != ETH_P_PAE) {		if (net_ratelimit()) {			printk(KERN_DEBUG "%s: dropped unencrypted TX data "			       "frame (drop_unencrypted=1)\n", dev->name);		}		iface->stats.tx_dropped++;		ret = 0;		goto fail;	}	if (tx.crypt) {		skb = hostap_tx_encrypt(skb, tx.crypt);		if (skb == NULL) {			printk(KERN_DEBUG "%s: TX - encryption failed\n",			       dev->name);			ret = 0;			goto fail;		}		meta = (struct hostap_skb_tx_data *) skb->cb;		if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) {			printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "			       "expected 0x%08x) after hostap_tx_encrypt\n",			       dev->name, meta->magic,			       HOSTAP_SKB_TX_DATA_MAGIC);			ret = 0;			iface->stats.tx_dropped++;			goto fail;		}	}	if (local->func->tx == NULL || local->func->tx(skb, dev)) {		ret = 0;		iface->stats.tx_dropped++;	} else {		ret = 0;		iface->stats.tx_packets++;		iface->stats.tx_bytes += skb->len;	} fail:	if (!ret && skb)		dev_kfree_skb(skb); tx_exit:	if (tx.sta_ptr)		hostap_handle_sta_release(tx.sta_ptr);	return ret;}EXPORT_SYMBOL(hostap_dump_tx_80211);EXPORT_SYMBOL(hostap_tx_encrypt);EXPORT_SYMBOL(hostap_master_start_xmit);

⌨️ 快捷键说明

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