📄 tx.c
字号:
* __ieee80211_parse_tx_radiotap has now removed * the radiotap header that was present and pre-filled * 'tx' with tx control information. */ } hdr = (struct ieee80211_hdr *) skb->data; tx->sta = sta_info_get(local, hdr->addr1); tx->fc = le16_to_cpu(hdr->frame_control); if (is_multicast_ether_addr(hdr->addr1)) { tx->flags &= ~IEEE80211_TXRXD_TXUNICAST; control->flags |= IEEE80211_TXCTL_NO_ACK; } else { tx->flags |= IEEE80211_TXRXD_TXUNICAST; control->flags &= ~IEEE80211_TXCTL_NO_ACK; } if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) { if ((tx->flags & IEEE80211_TXRXD_TXUNICAST) && skb->len + FCS_LEN > local->fragmentation_threshold && !local->ops->set_frag_threshold) tx->flags |= IEEE80211_TXRXD_FRAGMENTED; else tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; } if (!tx->sta) control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; else if (tx->sta->clear_dst_mask) { control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; tx->sta->clear_dst_mask = 0; } hdrlen = ieee80211_get_hdrlen(tx->fc); if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)]; tx->ethertype = (pos[0] << 8) | pos[1]; } control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT; return res;}/* Device in tx->dev has a reference added; use dev_put(tx->dev) when * finished with it. * * NB: @tx is uninitialised when passed in here */static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, struct sk_buff *skb, struct net_device *mdev, struct ieee80211_tx_control *control){ struct ieee80211_tx_packet_data *pkt_data; struct net_device *dev; pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; dev = dev_get_by_index(&init_net, pkt_data->ifindex); if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { dev_put(dev); dev = NULL; } if (unlikely(!dev)) return -ENODEV; /* initialises tx with control */ __ieee80211_tx_prepare(tx, skb, dev, control); return 0;}static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_txrx_data *tx){ struct ieee80211_tx_control *control = tx->u.tx.control; int ret, i; if (!ieee80211_qdisc_installed(local->mdev) && __ieee80211_queue_stopped(local, 0)) { netif_stop_queue(local->mdev); return IEEE80211_TX_AGAIN; } if (skb) { ieee80211_dump_frame(wiphy_name(local->hw.wiphy), "TX to low-level driver", skb); ret = local->ops->tx(local_to_hw(local), skb, control); if (ret) return IEEE80211_TX_AGAIN; local->mdev->trans_start = jiffies; ieee80211_led_tx(local, 1); } if (tx->u.tx.extra_frag) { control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | IEEE80211_TXCTL_USE_CTS_PROTECT | IEEE80211_TXCTL_CLEAR_DST_MASK | IEEE80211_TXCTL_FIRST_FRAGMENT); for (i = 0; i < tx->u.tx.num_extra_frag; i++) { if (!tx->u.tx.extra_frag[i]) continue; if (__ieee80211_queue_stopped(local, control->queue)) return IEEE80211_TX_FRAG_AGAIN; if (i == tx->u.tx.num_extra_frag) { control->tx_rate = tx->u.tx.last_frag_hwrate; control->rate = tx->u.tx.last_frag_rate; if (tx->flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG) control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; else control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; } ieee80211_dump_frame(wiphy_name(local->hw.wiphy), "TX to low-level driver", tx->u.tx.extra_frag[i]); ret = local->ops->tx(local_to_hw(local), tx->u.tx.extra_frag[i], control); if (ret) return IEEE80211_TX_FRAG_AGAIN; local->mdev->trans_start = jiffies; ieee80211_led_tx(local, 1); tx->u.tx.extra_frag[i] = NULL; } kfree(tx->u.tx.extra_frag); tx->u.tx.extra_frag = NULL; } return IEEE80211_TX_OK;}static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, struct ieee80211_tx_control *control){ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; ieee80211_tx_handler *handler; struct ieee80211_txrx_data tx; ieee80211_txrx_result res = TXRX_DROP, res_prepare; int ret, i; WARN_ON(__ieee80211_queue_pending(local, control->queue)); if (unlikely(skb->len < 10)) { dev_kfree_skb(skb); return 0; } /* initialises tx */ res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); if (res_prepare == TXRX_DROP) { dev_kfree_skb(skb); return 0; } /* * key references are protected using RCU and this requires that * we are in a read-site RCU section during receive processing */ rcu_read_lock(); sta = tx.sta; tx.u.tx.mode = local->hw.conf.mode; for (handler = local->tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); if (res != TXRX_CONTINUE) break; } skb = tx.skb; /* handlers are allowed to change skb */ if (sta) sta_info_put(sta); if (unlikely(res == TXRX_DROP)) { I802_DEBUG_INC(local->tx_handlers_drop); goto drop; } if (unlikely(res == TXRX_QUEUED)) { I802_DEBUG_INC(local->tx_handlers_queued); rcu_read_unlock(); return 0; } if (tx.u.tx.extra_frag) { for (i = 0; i < tx.u.tx.num_extra_frag; i++) { int next_len, dur; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx.u.tx.extra_frag[i]->data; if (i + 1 < tx.u.tx.num_extra_frag) { next_len = tx.u.tx.extra_frag[i + 1]->len; } else { next_len = 0; tx.u.tx.rate = tx.u.tx.last_frag_rate; tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val; } dur = ieee80211_duration(&tx, 0, next_len); hdr->duration_id = cpu_to_le16(dur); } }retry: ret = __ieee80211_tx(local, skb, &tx); if (ret) { struct ieee80211_tx_stored_packet *store = &local->pending_packet[control->queue]; if (ret == IEEE80211_TX_FRAG_AGAIN) skb = NULL; set_bit(IEEE80211_LINK_STATE_PENDING, &local->state[control->queue]); smp_mb(); /* When the driver gets out of buffers during sending of * fragments and calls ieee80211_stop_queue, there is * a small window between IEEE80211_LINK_STATE_XOFF and * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer * gets available in that window (i.e. driver calls * ieee80211_wake_queue), we would end up with ieee80211_tx * called with IEEE80211_LINK_STATE_PENDING. Prevent this by * continuing transmitting here when that situation is * possible to have happened. */ if (!__ieee80211_queue_stopped(local, control->queue)) { clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[control->queue]); goto retry; } memcpy(&store->control, control, sizeof(struct ieee80211_tx_control)); store->skb = skb; store->extra_frag = tx.u.tx.extra_frag; store->num_extra_frag = tx.u.tx.num_extra_frag; store->last_frag_hwrate = tx.u.tx.last_frag_hwrate; store->last_frag_rate = tx.u.tx.last_frag_rate; store->last_frag_rate_ctrl_probe = !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG); } rcu_read_unlock(); return 0; drop: if (skb) dev_kfree_skb(skb); for (i = 0; i < tx.u.tx.num_extra_frag; i++) if (tx.u.tx.extra_frag[i]) dev_kfree_skb(tx.u.tx.extra_frag[i]); kfree(tx.u.tx.extra_frag); rcu_read_unlock(); return 0;}/* device xmit handlers */int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct ieee80211_tx_control control; struct ieee80211_tx_packet_data *pkt_data; struct net_device *odev = NULL; struct ieee80211_sub_if_data *osdata; int headroom; int ret; /* * copy control out of the skb so other people can use skb->cb */ pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; memset(&control, 0, sizeof(struct ieee80211_tx_control)); if (pkt_data->ifindex) odev = dev_get_by_index(&init_net, pkt_data->ifindex); if (unlikely(odev && !is_ieee80211_device(odev, dev))) { dev_put(odev); odev = NULL; } if (unlikely(!odev)) {#ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: Discarded packet with nonexistent " "originating device\n", dev->name);#endif dev_kfree_skb(skb); return 0; } osdata = IEEE80211_DEV_TO_SUB_IF(odev); headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM; if (skb_headroom(skb) < headroom) { if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { dev_kfree_skb(skb); dev_put(odev); return 0; } } control.ifindex = odev->ifindex; control.type = osdata->type; if (pkt_data->flags & IEEE80211_TXPD_REQ_TX_STATUS) control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS; if (pkt_data->flags & IEEE80211_TXPD_DO_NOT_ENCRYPT) control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) control.flags |= IEEE80211_TXCTL_REQUEUE; control.queue = pkt_data->queue; ret = ieee80211_tx(odev, skb, &control); dev_put(odev); return ret;}int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_tx_packet_data *pkt_data; struct ieee80211_radiotap_header *prthdr = (struct ieee80211_radiotap_header *)skb->data; u16 len_rthdr; /* check for not even having the fixed radiotap header part */ if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) goto fail; /* too short to be possibly valid */ /* is it a header version we can trust to find length from? */ if (unlikely(prthdr->it_version)) goto fail; /* only version 0 is supported */ /* then there must be a radiotap header with a length we can use */ len_rthdr = ieee80211_get_radiotap_len(skb->data); /* does the skb contain enough to deliver on the alleged length? */ if (unlikely(skb->len < len_rthdr)) goto fail; /* skb too short for claimed rt header extent */ skb->dev = local->mdev; pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; memset(pkt_data, 0, sizeof(*pkt_data)); /* needed because we set skb device to master */ pkt_data->ifindex = dev->ifindex; pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; /* * fix up the pointers accounting for the radiotap * header still being in there. We are being given * a precooked IEEE80211 header so no need for * normal processing */ skb_set_mac_header(skb, len_rthdr); /* * these are just fixed to the end of the rt area since we * don't have any better information and at this point, nobody cares */ skb_set_network_header(skb, len_rthdr); skb_set_transport_header(skb, len_rthdr); /* pass the radiotap header up to the next stage intact */ dev_queue_xmit(skb); return NETDEV_TX_OK;fail: dev_kfree_skb(skb); return NETDEV_TX_OK; /* meaning, we dealt with the skb */}/** * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type * subinterfaces (wlan#, WDS, and VLAN interfaces) * @skb: packet to be sent * @dev: incoming interface * * Returns: 0 on success (and frees skb in this case) or 1 on failure (skb will * not be freed, and caller is responsible for either retrying later or freeing * skb). * * This function takes in an Ethernet header and encapsulates it with suitable * IEEE 802.11 header based on which interface the packet is coming in. The * encapsulated packet will then be passed to master interface, wlan#.11, for * transmission (through low-level driver). */int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_tx_packet_data *pkt_data; struct ieee80211_sub_if_data *sdata; int ret = 1, head_need; u16 ethertype, hdrlen, fc; struct ieee80211_hdr hdr; const u8 *encaps_data; int encaps_len, skip_header_bytes; int nh_pos, h_pos; struct sta_info *sta; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (unlikely(skb->len < ETH_HLEN)) { printk(KERN_DEBUG "%s: short skb (len=%d)\n", dev->name, skb->len); ret = 0; goto fail; } nh_pos = skb_network_header(skb) - skb->data; h_pos = skb_transport_header(skb) - skb->data; /* convert Ethernet header to proper 802.11 header (based on * operation mode) */ ethertype = (skb->data[12] << 8) | skb->data[13]; /* TODO: handling for 802.1x authorized/unauthorized port */ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; switch (sdata->type) { case IEEE80211_IF_TYPE_AP: case IEEE80211_IF_TYPE_VLAN: fc |= IEEE80211_FCTL_FROMDS; /* DA BSSID 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); hdrlen = 24; break; case IEEE80211_IF_TYPE_WDS: fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; /* RA TA DA SA */ memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN); memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); memcpy(hdr.addr3, skb->data, ETH_ALEN); memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 30; break; case IEEE80211_IF_TYPE_STA: fc |= IEEE80211_FCTL_TODS; /* BSSID SA DA */ memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN); memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); memcpy(hdr.addr3, skb->data, ETH_ALEN); hdrlen = 24; break; case IEEE80211_IF_TYPE_IBSS: /* DA SA BSSID */ memcpy(hdr.addr1, skb->data, ETH_ALEN); memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN); hdrlen = 24; break; default: ret = 0; goto fail; } /* receiver is QoS enabled, use a QoS type frame */ sta = sta_info_get(local, hdr.addr1); if (sta) { if (sta->flags & WLAN_STA_WME) { fc |= IEEE80211_STYPE_QOS_DATA; hdrlen += 2; } sta_info_put(sta); } hdr.frame_control = cpu_to_le16(fc); hdr.duration_id = 0; hdr.seq_ctrl = 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -