📄 hostap_80211_tx.c
字号:
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 */static 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 prefix_len, postfix_len, hdr_len, res; DECLARE_MAC_BUF(mac); iface = netdev_priv(skb->dev); local = iface->local; if (skb->len < IEEE80211_DATA_HDR3_LEN) { kfree_skb(skb); return NULL; } if (local->tkip_countermeasures && 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 %s\n", local->dev->name, print_mac(mac, hdr->addr1)); } kfree_skb(skb); return NULL; } skb = skb_unshare(skb, GFP_ATOMIC); if (skb == NULL) return NULL; prefix_len = crypt->ops->extra_mpdu_prefix_len + crypt->ops->extra_msdu_prefix_len; postfix_len = crypt->ops->extra_mpdu_postfix_len + crypt->ops->extra_msdu_postfix_len; if ((skb_headroom(skb) < prefix_len || skb_tailroom(skb) < postfix_len) && pskb_expand_head(skb, prefix_len, 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_PROTECTED)) { 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_master_start_xmit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -