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

📄 tx.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		encaps_len = sizeof(rfc1042_header);		skip_header_bytes -= 2;	} else {		encaps_data = NULL;		encaps_len = 0;	}	skb_pull(skb, skip_header_bytes);	nh_pos -= skip_header_bytes;	h_pos -= skip_header_bytes;	/* TODO: implement support for fragments so that there is no need to	 * reallocate and copy payload; it might be enough to support one	 * extra fragment that would be copied in the beginning of the frame	 * data.. anyway, it would be nice to include this into skb structure	 * somehow	 *	 * There are few options for this:	 * use skb->cb as an extra space for 802.11 header	 * allocate new buffer if not enough headroom	 * make sure that there is enough headroom in every skb by increasing	 * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and	 * alloc_skb() (net/core/skbuff.c)	 */	head_need = hdrlen + encaps_len + local->tx_headroom;	head_need -= skb_headroom(skb);	/* We are going to modify skb data, so make a copy of it if happens to	 * be cloned. This could happen, e.g., with Linux bridge code passing	 * us broadcast frames. */	if (head_need > 0 || skb_cloned(skb)) {#if 0		printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes "		       "of headroom\n", dev->name, head_need);#endif		if (skb_cloned(skb))			I802_DEBUG_INC(local->tx_expand_skb_head_cloned);		else			I802_DEBUG_INC(local->tx_expand_skb_head);		/* Since we have to reallocate the buffer, make sure that there		 * is enough room for possible WEP IV/ICV and TKIP (8 bytes		 * before payload and 12 after). */		if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8),				     12, GFP_ATOMIC)) {			printk(KERN_DEBUG "%s: failed to reallocate TX buffer"			       "\n", dev->name);			goto fail;		}	}	if (encaps_data) {		memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);		nh_pos += encaps_len;		h_pos += encaps_len;	}	if (fc & IEEE80211_STYPE_QOS_DATA) {		__le16 *qos_control;		qos_control = (__le16*) skb_push(skb, 2);		memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2);		/*		 * Maybe we could actually set some fields here, for now just		 * initialise to zero to indicate no special operation.		 */		*qos_control = 0;	} else		memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);	nh_pos += hdrlen;	h_pos += hdrlen;	pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;	memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));	pkt_data->ifindex = dev->ifindex;	skb->dev = local->mdev;	dev->stats.tx_packets++;	dev->stats.tx_bytes += skb->len;	/* Update skb pointers to various headers since this modified frame	 * is going to go through Linux networking code that may potentially	 * need things like pointer to IP header. */	skb_set_mac_header(skb, 0);	skb_set_network_header(skb, nh_pos);	skb_set_transport_header(skb, h_pos);	dev->trans_start = jiffies;	dev_queue_xmit(skb);	return 0; fail:	if (!ret)		dev_kfree_skb(skb);	return ret;}/* * This is the transmit routine for the 802.11 type interfaces * called by upper layers of the linux networking * stack when it has a frame to transmit */int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct ieee80211_sub_if_data *sdata;	struct ieee80211_tx_packet_data *pkt_data;	struct ieee80211_hdr *hdr;	u16 fc;	sdata = IEEE80211_DEV_TO_SUB_IF(dev);	if (skb->len < 10) {		dev_kfree_skb(skb);		return 0;	}	if (skb_headroom(skb) < sdata->local->tx_headroom) {		if (pskb_expand_head(skb, sdata->local->tx_headroom,				     0, GFP_ATOMIC)) {			dev_kfree_skb(skb);			return 0;		}	}	hdr = (struct ieee80211_hdr *) skb->data;	fc = le16_to_cpu(hdr->frame_control);	pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;	memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));	pkt_data->ifindex = sdata->dev->ifindex;	skb->priority = 20; /* use hardcoded priority for mgmt TX queue */	skb->dev = sdata->local->mdev;	/*	 * We're using the protocol field of the the frame control header	 * to request TX callback for hostapd. BIT(1) is checked.	 */	if ((fc & BIT(1)) == BIT(1)) {		pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;		fc &= ~BIT(1);		hdr->frame_control = cpu_to_le16(fc);	}	if (!(fc & IEEE80211_FCTL_PROTECTED))		pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;	dev->stats.tx_packets++;	dev->stats.tx_bytes += skb->len;	dev_queue_xmit(skb);	return 0;}/* helper functions for pending packets for when queues are stopped */void ieee80211_clear_tx_pending(struct ieee80211_local *local){	int i, j;	struct ieee80211_tx_stored_packet *store;	for (i = 0; i < local->hw.queues; i++) {		if (!__ieee80211_queue_pending(local, i))			continue;		store = &local->pending_packet[i];		kfree_skb(store->skb);		for (j = 0; j < store->num_extra_frag; j++)			kfree_skb(store->extra_frag[j]);		kfree(store->extra_frag);		clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]);	}}void ieee80211_tx_pending(unsigned long data){	struct ieee80211_local *local = (struct ieee80211_local *)data;	struct net_device *dev = local->mdev;	struct ieee80211_tx_stored_packet *store;	struct ieee80211_txrx_data tx;	int i, ret, reschedule = 0;	netif_tx_lock_bh(dev);	for (i = 0; i < local->hw.queues; i++) {		if (__ieee80211_queue_stopped(local, i))			continue;		if (!__ieee80211_queue_pending(local, i)) {			reschedule = 1;			continue;		}		store = &local->pending_packet[i];		tx.u.tx.control = &store->control;		tx.u.tx.extra_frag = store->extra_frag;		tx.u.tx.num_extra_frag = store->num_extra_frag;		tx.u.tx.last_frag_hwrate = store->last_frag_hwrate;		tx.u.tx.last_frag_rate = store->last_frag_rate;		tx.flags = 0;		if (store->last_frag_rate_ctrl_probe)			tx.flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG;		ret = __ieee80211_tx(local, store->skb, &tx);		if (ret) {			if (ret == IEEE80211_TX_FRAG_AGAIN)				store->skb = NULL;		} else {			clear_bit(IEEE80211_LINK_STATE_PENDING,				  &local->state[i]);			reschedule = 1;		}	}	netif_tx_unlock_bh(dev);	if (reschedule) {		if (!ieee80211_qdisc_installed(dev)) {			if (!__ieee80211_queue_stopped(local, 0))				netif_wake_queue(dev);		} else			netif_schedule(dev);	}}/* functions for drivers to get certain frames */static void ieee80211_beacon_add_tim(struct ieee80211_local *local,				     struct ieee80211_if_ap *bss,				     struct sk_buff *skb){	u8 *pos, *tim;	int aid0 = 0;	int i, have_bits = 0, n1, n2;	/* Generate bitmap for TIM only if there are any STAs in power save	 * mode. */	read_lock_bh(&local->sta_lock);	if (atomic_read(&bss->num_sta_ps) > 0)		/* in the hope that this is faster than		 * checking byte-for-byte */		have_bits = !bitmap_empty((unsigned long*)bss->tim,					  IEEE80211_MAX_AID+1);	if (bss->dtim_count == 0)		bss->dtim_count = bss->dtim_period - 1;	else		bss->dtim_count--;	tim = pos = (u8 *) skb_put(skb, 6);	*pos++ = WLAN_EID_TIM;	*pos++ = 4;	*pos++ = bss->dtim_count;	*pos++ = bss->dtim_period;	if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))		aid0 = 1;	if (have_bits) {		/* Find largest even number N1 so that bits numbered 1 through		 * (N1 x 8) - 1 in the bitmap are 0 and number N2 so that bits		 * (N2 + 1) x 8 through 2007 are 0. */		n1 = 0;		for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) {			if (bss->tim[i]) {				n1 = i & 0xfe;				break;			}		}		n2 = n1;		for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) {			if (bss->tim[i]) {				n2 = i;				break;			}		}		/* Bitmap control */		*pos++ = n1 | aid0;		/* Part Virt Bitmap */		memcpy(pos, bss->tim + n1, n2 - n1 + 1);		tim[1] = n2 - n1 + 4;		skb_put(skb, n2 - n1);	} else {		*pos++ = aid0; /* Bitmap control */		*pos++ = 0; /* Part Virt Bitmap */	}	read_unlock_bh(&local->sta_lock);}struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,				     struct ieee80211_tx_control *control){	struct ieee80211_local *local = hw_to_local(hw);	struct sk_buff *skb;	struct net_device *bdev;	struct ieee80211_sub_if_data *sdata = NULL;	struct ieee80211_if_ap *ap = NULL;	struct ieee80211_rate *rate;	struct rate_control_extra extra;	u8 *b_head, *b_tail;	int bh_len, bt_len;	bdev = dev_get_by_index(&init_net, if_id);	if (bdev) {		sdata = IEEE80211_DEV_TO_SUB_IF(bdev);		ap = &sdata->u.ap;		dev_put(bdev);	}	if (!ap || sdata->type != IEEE80211_IF_TYPE_AP ||	    !ap->beacon_head) {#ifdef CONFIG_MAC80211_VERBOSE_DEBUG		if (net_ratelimit())			printk(KERN_DEBUG "no beacon data avail for idx=%d "			       "(%s)\n", if_id, bdev ? bdev->name : "N/A");#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */		return NULL;	}	/* Assume we are generating the normal beacon locally */	b_head = ap->beacon_head;	b_tail = ap->beacon_tail;	bh_len = ap->beacon_head_len;	bt_len = ap->beacon_tail_len;	skb = dev_alloc_skb(local->tx_headroom +		bh_len + bt_len + 256 /* maximum TIM len */);	if (!skb)		return NULL;	skb_reserve(skb, local->tx_headroom);	memcpy(skb_put(skb, bh_len), b_head, bh_len);	ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);	ieee80211_beacon_add_tim(local, ap, skb);	if (b_tail) {		memcpy(skb_put(skb, bt_len), b_tail, bt_len);	}	if (control) {		memset(&extra, 0, sizeof(extra));		extra.mode = local->oper_hw_mode;		rate = rate_control_get_rate(local, local->mdev, skb, &extra);		if (!rate) {			if (net_ratelimit()) {				printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate "				       "found\n", wiphy_name(local->hw.wiphy));			}			dev_kfree_skb(skb);			return NULL;		}		control->tx_rate =			((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) &&			(rate->flags & IEEE80211_RATE_PREAMBLE2)) ?			rate->val2 : rate->val;		control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;		control->power_level = local->hw.conf.power_level;		control->flags |= IEEE80211_TXCTL_NO_ACK;		control->retry_limit = 1;		control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;	}	ap->num_beacons++;	return skb;}EXPORT_SYMBOL(ieee80211_beacon_get);void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id,		       const void *frame, size_t frame_len,		       const struct ieee80211_tx_control *frame_txctl,		       struct ieee80211_rts *rts){	const struct ieee80211_hdr *hdr = frame;	u16 fctl;	fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;	rts->frame_control = cpu_to_le16(fctl);	rts->duration = ieee80211_rts_duration(hw, if_id, frame_len, frame_txctl);	memcpy(rts->ra, hdr->addr1, sizeof(rts->ra));	memcpy(rts->ta, hdr->addr2, sizeof(rts->ta));}EXPORT_SYMBOL(ieee80211_rts_get);void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id,			     const void *frame, size_t frame_len,			     const struct ieee80211_tx_control *frame_txctl,			     struct ieee80211_cts *cts){	const struct ieee80211_hdr *hdr = frame;	u16 fctl;	fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS;	cts->frame_control = cpu_to_le16(fctl);	cts->duration = ieee80211_ctstoself_duration(hw, if_id, frame_len, frame_txctl);	memcpy(cts->ra, hdr->addr1, sizeof(cts->ra));}EXPORT_SYMBOL(ieee80211_ctstoself_get);struct sk_buff *ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,			  struct ieee80211_tx_control *control){	struct ieee80211_local *local = hw_to_local(hw);	struct sk_buff *skb;	struct sta_info *sta;	ieee80211_tx_handler *handler;	struct ieee80211_txrx_data tx;	ieee80211_txrx_result res = TXRX_DROP;	struct net_device *bdev;	struct ieee80211_sub_if_data *sdata;	struct ieee80211_if_ap *bss = NULL;	bdev = dev_get_by_index(&init_net, if_id);	if (bdev) {		sdata = IEEE80211_DEV_TO_SUB_IF(bdev);		bss = &sdata->u.ap;		dev_put(bdev);	}	if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head)		return NULL;	if (bss->dtim_count != 0)		return NULL; /* send buffered bc/mc only after DTIM beacon */	memset(control, 0, sizeof(*control));	while (1) {		skb = skb_dequeue(&bss->ps_bc_buf);		if (!skb)			return NULL;		local->total_ps_buffered--;		if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) {			struct ieee80211_hdr *hdr =				(struct ieee80211_hdr *) skb->data;			/* more buffered multicast/broadcast frames ==> set			 * MoreData flag in IEEE 802.11 header to inform PS			 * STAs */			hdr->frame_control |=				cpu_to_le16(IEEE80211_FCTL_MOREDATA);		}		if (!ieee80211_tx_prepare(&tx, skb, local->mdev, control))			break;		dev_kfree_skb_any(skb);	}	sta = tx.sta;	tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED;	tx.u.tx.mode = local->hw.conf.mode;	for (handler = local->tx_handlers; *handler != NULL; handler++) {		res = (*handler)(&tx);		if (res == TXRX_DROP || res == TXRX_QUEUED)			break;	}	dev_put(tx.dev);	skb = tx.skb; /* handlers are allowed to change skb */	if (res == TXRX_DROP) {		I802_DEBUG_INC(local->tx_handlers_drop);		dev_kfree_skb(skb);		skb = NULL;	} else if (res == TXRX_QUEUED) {		I802_DEBUG_INC(local->tx_handlers_queued);		skb = NULL;	}	if (sta)		sta_info_put(sta);	return skb;}EXPORT_SYMBOL(ieee80211_get_buffered_bc);

⌨️ 快捷键说明

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