📄 hostap_80211_rx.c
字号:
/* Put this code here so that we avoid duplicating it in all * Rx paths. - Jean II */#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ /* If spy monitoring on */ if (iface->spy_data.spy_number > 0) { struct iw_quality wstats; wstats.level = rx_stats->signal; wstats.noise = rx_stats->noise; wstats.updated = IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED | IW_QUAL_QUAL_INVALID | IW_QUAL_DBM; /* Update spy records */ wireless_spy_update(dev, hdr->addr2, &wstats); }#endif /* IW_WIRELESS_SPY */#endif /* WIRELESS_EXT > 15 */ hostap_update_rx_stats(local->ap, hdr, rx_stats); if (local->iw_mode == IW_MODE_MONITOR) { monitor_rx(dev, skb, rx_stats); return; } if (local->host_decrypt) { int idx = 0; if (skb->len >= hdrlen + 3) idx = skb->data[hdrlen + 3] >> 6; crypt = local->crypt[idx]; sta = NULL; /* Use station specific key to override default keys if the * receiver address is a unicast address ("individual RA"). If * bcrx_sta_key parameter is set, station specific key is used * even with broad/multicast targets (this is against IEEE * 802.11, but makes it easier to use different keys with * stations that do not support WEP key mapping). */ if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) (void) hostap_handle_sta_crypto(local, hdr, &crypt, &sta); /* allow NULL decrypt to indicate an station specific override * for default encryption */ if (crypt && (crypt->ops == NULL || crypt->ops->decrypt_mpdu == NULL)) crypt = NULL; if (!crypt && (fc & WLAN_FC_ISWEP)) {#if 0 /* This seems to be triggered by some (multicast?) * frames from other than current BSS, so just drop the * frames silently instead of filling system log with * these reports. */ printk(KERN_DEBUG "%s: WEP decryption failed (not set)" " (SA=" MACSTR ")\n", local->dev->name, MAC2STR(hdr->addr2));#endif local->comm_tallies.rx_discards_wep_undecryptable++; goto rx_dropped; } } if (type != WLAN_FC_TYPE_DATA) { if (type == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_AUTH && fc & WLAN_FC_ISWEP && local->host_decrypt && (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) { printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " "from " MACSTR "\n", dev->name, MAC2STR(hdr->addr2)); /* TODO: could inform hostapd about this so that it * could send auth failure report */ goto rx_dropped; } if (hostap_rx_frame_mgmt(local, skb, rx_stats, type, stype)) goto rx_dropped; else goto rx_exit; } /* Data frame - extract src/dst addresses */ if (skb->len < IEEE80211_DATA_HDR3_LEN) goto rx_dropped; switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { case WLAN_FC_FROMDS: memcpy(dst, hdr->addr1, ETH_ALEN); memcpy(src, hdr->addr3, ETH_ALEN); break; case WLAN_FC_TODS: memcpy(dst, hdr->addr3, ETH_ALEN); memcpy(src, hdr->addr2, ETH_ALEN); break; case WLAN_FC_FROMDS | WLAN_FC_TODS: if (skb->len < IEEE80211_DATA_HDR4_LEN) goto rx_dropped; memcpy(dst, hdr->addr3, ETH_ALEN); memcpy(src, hdr->addr4, ETH_ALEN); break; case 0: memcpy(dst, hdr->addr1, ETH_ALEN); memcpy(src, hdr->addr2, ETH_ALEN); break; } if (hostap_rx_frame_wds(local, hdr, fc, &wds)) goto rx_dropped; if (wds) { skb->dev = dev = wds; stats = hostap_get_stats(dev); } if (local->iw_mode == IW_MODE_MASTER && !wds && (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == WLAN_FC_FROMDS && local->stadev && memcmp(hdr->addr2, local->assoc_ap_addr, ETH_ALEN) == 0) { /* Frame from BSSID of the AP for which we are a client */ skb->dev = dev = local->stadev; stats = hostap_get_stats(dev); from_assoc_ap = 1; } dev->last_rx = jiffies; if ((local->iw_mode == IW_MODE_MASTER || local->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) { switch (hostap_handle_sta_rx(local, dev, skb, rx_stats, wds != NULL)) { case AP_RX_CONTINUE_NOT_AUTHORIZED: frame_authorized = 0; break; case AP_RX_CONTINUE: frame_authorized = 1; break; case AP_RX_DROP: goto rx_dropped; case AP_RX_EXIT: goto rx_exit; } } /* Nullfunc frames may have PS-bit set, so they must be passed to * hostap_handle_sta_rx() before being dropped here. */ if (stype != WLAN_FC_STYPE_DATA && stype != WLAN_FC_STYPE_DATA_CFACK && stype != WLAN_FC_STYPE_DATA_CFPOLL && stype != WLAN_FC_STYPE_DATA_CFACKPOLL) { if (stype != WLAN_FC_STYPE_NULLFUNC) printk(KERN_DEBUG "%s: RX: dropped data frame " "with no data (type=0x%02x, subtype=0x%02x)\n", dev->name, type, stype); goto rx_dropped; } /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ if (local->host_decrypt && (fc & WLAN_FC_ISWEP) && (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) goto rx_dropped; hdr = (struct hostap_ieee80211_hdr *) skb->data; /* skb: hdr + (possibly fragmented) plaintext payload */ if (local->host_decrypt && (fc & WLAN_FC_ISWEP) && (frag != 0 || (fc & WLAN_FC_MOREFRAG))) { int flen; struct sk_buff *frag_skb = prism2_frag_cache_get(local, hdr); if (!frag_skb) { printk(KERN_DEBUG "%s: Rx cannot get skb from " "fragment cache (morefrag=%d seq=%u frag=%u)\n", dev->name, (fc & WLAN_FC_MOREFRAG) != 0, WLAN_GET_SEQ_SEQ(sc), frag); goto rx_dropped; } flen = skb->len; if (frag != 0) flen -= hdrlen; if (frag_skb->tail + flen > frag_skb->end) { printk(KERN_WARNING "%s: host decrypted and " "reassembled frame did not fit skb\n", dev->name); prism2_frag_cache_invalidate(local, hdr); goto rx_dropped; } if (frag == 0) { /* copy first fragment (including full headers) into * beginning of the fragment cache skb */ memcpy(skb_put(frag_skb, flen), skb->data, flen); } else { /* append frame payload to the end of the fragment * cache skb */ memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, flen); } dev_kfree_skb(skb); skb = NULL; if (fc & WLAN_FC_MOREFRAG) { /* more fragments expected - leave the skb in fragment * cache for now; it will be delivered to upper layers * after all fragments have been received */ goto rx_exit; } /* this was the last fragment and the frame will be * delivered, so remove skb from fragment cache */ skb = frag_skb; hdr = (struct hostap_ieee80211_hdr *) skb->data; prism2_frag_cache_invalidate(local, hdr); } /* skb: hdr + (possible reassembled) full MSDU payload; possibly still * encrypted/authenticated */ if (local->host_decrypt && (fc & WLAN_FC_ISWEP) && hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt)) goto rx_dropped; hdr = (struct hostap_ieee80211_hdr *) skb->data; if (crypt && !(fc & WLAN_FC_ISWEP) && !local->open_wep) { if (local->ieee_802_1x && hostap_is_eapol_frame(local, skb)) { /* pass unencrypted EAPOL frames even if encryption is * configured */ PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X - passing " "unencrypted EAPOL frame\n", local->dev->name); } else { printk(KERN_DEBUG "%s: encryption configured, but RX " "frame not encrypted (SA=" MACSTR ")\n", local->dev->name, MAC2STR(hdr->addr2)); goto rx_dropped; } } if (local->drop_unencrypted && !(fc & WLAN_FC_ISWEP) && !hostap_is_eapol_frame(local, skb)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: dropped unencrypted RX data " "frame from " MACSTR " (drop_unencrypted=1)\n", dev->name, MAC2STR(hdr->addr2)); } goto rx_dropped; } /* skb: hdr + (possible reassembled) full plaintext payload */ payload = skb->data + hdrlen; ethertype = (payload[6] << 8) | payload[7]; /* If IEEE 802.1X is used, check whether the port is authorized to send * the received frame. */ if (local->ieee_802_1x && local->iw_mode == IW_MODE_MASTER) { if (ethertype == ETH_P_PAE) { PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X frame\n", dev->name); if (local->hostapd && local->apdev) { /* Send IEEE 802.1X frames to the user * space daemon for processing */ prism2_rx_80211(local->apdev, skb, rx_stats, PRISM2_RX_MGMT); local->apdevstats.rx_packets++; local->apdevstats.rx_bytes += skb->len; goto rx_exit; } } else if (!frame_authorized) { printk(KERN_DEBUG "%s: dropped frame from " "unauthorized port (IEEE 802.1X): " "ethertype=0x%04x\n", dev->name, ethertype); goto rx_dropped; } } /* convert hdr + possible LLC headers into Ethernet header */ if (skb->len - hdrlen >= 8 && ((memcmp(payload, rfc1042_header, 6) == 0 && ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || memcmp(payload, bridge_tunnel_header, 6) == 0)) { /* remove RFC1042 or Bridge-Tunnel encapsulation and * replace EtherType */ skb_pull(skb, hdrlen + 6); memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); } else { u16 len; /* Leave Ethernet header part of hdr and full payload */ skb_pull(skb, hdrlen); len = htons(skb->len); memcpy(skb_push(skb, 2), &len, 2); memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); } if (wds && ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == WLAN_FC_TODS) && skb->len >= ETH_HLEN + ETH_ALEN) { /* Non-standard frame: get addr4 from its bogus location after * the payload */ memcpy(skb->data + ETH_ALEN, skb->data + skb->len - ETH_ALEN, ETH_ALEN); skb_trim(skb, skb->len - ETH_ALEN); } stats->rx_packets++; stats->rx_bytes += skb->len; if (local->iw_mode == IW_MODE_MASTER && !wds && local->ap->bridge_packets) { if (dst[0] & 0x01) { /* copy multicast frame both to the higher layers and * to the wireless media */ local->ap->bridged_multicast++; skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2 == NULL) printk(KERN_DEBUG "%s: skb_clone failed for " "multicast frame\n", dev->name); } else if (hostap_is_sta_authorized(local->ap, dst)) { /* send frame directly to the associated STA using * wireless media and not passing to higher layers */ local->ap->bridged_unicast++; skb2 = skb; skb = NULL; } } if (skb2 != NULL) { /* send to wireless media */ skb2->protocol = __constant_htons(ETH_P_802_3); skb2->mac.raw = skb2->nh.raw = skb2->data; /* skb2->nh.raw = skb2->data + ETH_HLEN; */ skb2->dev = dev; dev_queue_xmit(skb2); } if (skb) { skb->protocol = eth_type_trans(skb, dev); memset(skb->cb, 0, sizeof(skb->cb)); skb->dev = dev; netif_rx(skb); } rx_exit: if (sta) hostap_handle_sta_release(sta); return; rx_dropped: dev_kfree_skb(skb); stats->rx_dropped++; goto rx_exit;}EXPORT_SYMBOL(hostap_80211_rx);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -