struct ieee80211_hdr hdr; 
struct ieee80211_hdr_4addr hdr; 
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 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;}
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/d041674d62e1ad565f2fb6d53ae80b31d6656033/hostap_80211_tx.c/clean/drivers/net/wireless/hostap/hostap_80211_tx.c