📄 tx.c
字号:
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 + -