📄 ieee80211_input.c.svn-base
字号:
case IEEE80211_M_STA: if ((dir != IEEE80211_FC1_DIR_FROMDS) && (!((vap->iv_flags_ext & IEEE80211_FEXT_WDS) && (dir == IEEE80211_FC1_DIR_DSTODS)))) { IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, wh, "data", "invalid dir 0x%x", dir); vap->iv_stats.is_rx_wrongdir++; goto out; } if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { /* Discard multicast if IFF_MULTICAST not set */ if ((0 != memcmp(wh->i_addr3, dev->broadcast, ETH_ALEN)) && (0 == (dev->flags & IFF_MULTICAST))) { IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, NULL, "%s", "multicast disabled."); printk(KERN_ERR "CONFIG ERROR: multicast flag " "cleared on radio, but multicast was used.\n"); vap->iv_stats.is_rx_mcastdisabled++; goto out; } /* Discard echos of our own multicast or broadcast */ if (IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_myaddr)) { /* * In IEEE802.11 network, multicast packet * sent from me is broadcasted from AP. * It should be silently discarded for * SIMPLEX interface. * * NB: Linux has no IFF_ flag to indicate * if an interface is SIMPLEX or not; * so we always assume it to be true. */ IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, NULL, "%s", "multicast echo"); vap->iv_stats.is_rx_mcastecho++; goto out; } /* * if it is brodcasted by me on behalf of * a station behind me, drop it. */ if (vap->iv_flags_ext & IEEE80211_FEXT_WDS) { struct ieee80211_node_table *nt; struct ieee80211_node *ni_wds; nt = &ic->ic_sta; ni_wds = ieee80211_find_wds_node(nt, wh->i_addr3); if (ni_wds) { ieee80211_unref_node(&ni_wds); IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, NULL, "%s", "multicast echo originated from node behind me"); vap->iv_stats.is_rx_mcastecho++; goto out; } } } break; case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: if (dir != IEEE80211_FC1_DIR_NODS) { IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, wh, "data", "invalid dir 0x%x", dir); vap->iv_stats.is_rx_wrongdir++; goto out; } /* XXX no power-save support */ break; case IEEE80211_M_HOSTAP: if ((dir != IEEE80211_FC1_DIR_TODS) && (dir != IEEE80211_FC1_DIR_DSTODS)) { IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, wh, "data", "invalid dir 0x%x", dir); vap->iv_stats.is_rx_wrongdir++; goto out; } /* check if source STA is associated */ if (ni == vap->iv_bss) { IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, "data", "%s", "unknown src"); /* NB: caller deals with reference */ if (vap->iv_state == IEEE80211_S_RUN) ieee80211_send_error(ni, wh->i_addr2, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_NOT_AUTHED); vap->iv_stats.is_rx_notassoc++; goto err; } if (ni->ni_associd == 0) { IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, "data", "%s", "unassoc src"); IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DISASSOC, IEEE80211_REASON_NOT_ASSOCED); vap->iv_stats.is_rx_notassoc++; goto err; } /* * If we're a 4 address packet, make sure we have an entry in * the node table for the packet source address (addr4). * If not, add one. */ /* XXX: Useless node mgmt API; make better */ if (dir == IEEE80211_FC1_DIR_DSTODS) { struct ieee80211_node_table *nt; struct ieee80211_frame_addr4 *wh4; struct ieee80211_node *ni_wds; if (!(vap->iv_flags_ext & IEEE80211_FEXT_WDS)) { IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, "data", "%s", "4 addr not allowed"); goto err; } wh4 = (struct ieee80211_frame_addr4 *)skb->data; nt = &ic->ic_sta; ni_wds = ieee80211_find_wds_node(nt, wh4->i_addr4); /* Last call increments ref count if !NULL */ if ((ni_wds != NULL) && (ni_wds != ni)) { /* * node with source address (addr4) moved * to another WDS capable station. remove the * reference to the previous station and add * reference to the new one */ (void) ieee80211_remove_wds_addr(nt, wh4->i_addr4); ieee80211_add_wds_addr(nt, ni, wh4->i_addr4, 0); } if (ni_wds == NULL) ieee80211_add_wds_addr(nt, ni, wh4->i_addr4, 0); else ieee80211_unref_node(&ni_wds); } /* * Check for power save state change. */ if (!(ni->ni_flags & IEEE80211_NODE_UAPSD)) { if ((wh->i_fc[1] & IEEE80211_FC1_PWR_MGT) ^ (ni->ni_flags & IEEE80211_NODE_PWR_MGT)) ieee80211_node_pwrsave(ni, wh->i_fc[1] & IEEE80211_FC1_PWR_MGT); } else if (ni->ni_flags & IEEE80211_NODE_PS_CHANGED) { int pwr_save_changed = 0; IEEE80211_LOCK_IRQ(ic); if ((*(__le16 *)(&wh->i_seq[0])) == ni->ni_pschangeseq) { ni->ni_flags &= ~IEEE80211_NODE_PS_CHANGED; pwr_save_changed = 1; } IEEE80211_UNLOCK_IRQ(ic); if (pwr_save_changed) ieee80211_node_pwrsave(ni, wh->i_fc[1] & IEEE80211_FC1_PWR_MGT); } break; case IEEE80211_M_WDS: if (dir != IEEE80211_FC1_DIR_DSTODS) { IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, wh, "data", "invalid dir 0x%x", dir); vap->iv_stats.is_rx_wrongdir++; goto out; } break; default: /* XXX here to keep compiler happy */ goto out; } /* These frames have no further meaning. */ if ((subtype == IEEE80211_FC0_SUBTYPE_NULL) || (subtype == IEEE80211_FC0_SUBTYPE_QOS_NULL)) goto out; /* * Handle privacy requirements. Note that we * must not be preempted from here until after * we (potentially) call ieee80211_crypto_demic; * otherwise we may violate assumptions in the * crypto cipher modules used to do delayed update * of replay sequence numbers. */ if (wh->i_fc[1] & IEEE80211_FC1_PROT) { if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) { /* * Discard encrypted frames when privacy is off. */ IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, "WEP", "%s", "PRIVACY off"); vap->iv_stats.is_rx_noprivacy++; IEEE80211_NODE_STAT(ni, rx_noprivacy); goto out; } key = ieee80211_crypto_decap(ni, skb, hdrlen); if (key == NULL) { /* NB: stats+msgs handled in crypto_decap */ IEEE80211_NODE_STAT(ni, rx_wepfail); goto out; } wh = (struct ieee80211_frame *)skb->data; wh->i_fc[1] &= ~IEEE80211_FC1_PROT; } else key = NULL; /* Next up, any fragmentation. */ if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { skb = ieee80211_defrag(ni, skb, hdrlen); if (skb == NULL) { /* Fragment dropped or frame not complete yet */ goto out; } } wh = NULL; /* no longer valid, catch any uses */ /* Next strip any MSDU crypto. bits. */ if (key != NULL && !ieee80211_crypto_demic(vap, key, skb, hdrlen, 0)) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, ni->ni_macaddr, "data", "%s", "demic error"); IEEE80211_NODE_STAT(ni, rx_demicfail); goto out; } /* Finally, strip the 802.11 header. */ skb = ieee80211_decap(vap, skb, hdrlen); if (skb == NULL) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, ni->ni_macaddr, "data", "%s", "decap error"); vap->iv_stats.is_rx_decap++; IEEE80211_NODE_STAT(ni, rx_decap); goto err; } eh = (struct ether_header *)skb->data; if (!accept_data_frame(vap, ni, key, skb, eh)) goto out; vap->iv_devstats.rx_packets++; vap->iv_devstats.rx_bytes += skb->len; IEEE80211_NODE_STAT(ni, rx_data); IEEE80211_NODE_STAT_ADD(ni, rx_bytes, skb->len); ic->ic_lastdata = jiffies;#ifdef ATH_SUPERG_FF /* check for FF */ llc = (struct llc *)(skb->data + sizeof(struct ether_header)); if (ntohs(llc->llc_snap.ether_type) == (u_int16_t)ATH_ETH_TYPE) { struct sk_buff *skb1 = NULL; struct ether_header *eh_tmp; struct athl2p_tunnel_hdr *ath_hdr; unsigned int frame_len; /* NB: assumes linear (i.e., non-fragmented) skb */ /* get to the tunneled headers */ ath_hdr = (struct athl2p_tunnel_hdr *) skb_pull(skb, sizeof(struct ether_header) + LLC_SNAPFRAMELEN); /* ignore invalid frames */ if (ath_hdr == NULL) goto err; /* only implementing FF now. drop all others. */ if (ath_hdr->proto != ATH_L2TUNNEL_PROTO_FF) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_SUPG | IEEE80211_MSG_INPUT, eh->ether_shost, "fast-frame", "bad atheros tunnel prot %u", ath_hdr->proto); vap->iv_stats.is_rx_badathtnl++; goto err; } vap->iv_stats.is_rx_ffcnt++; /* move past the tunneled header, with alignment */ skb_pull(skb, roundup(sizeof(struct athl2p_tunnel_hdr) - 2, 4) + 2); eh_tmp = (struct ether_header *)skb->data; /* ether_type must be length as FF frames are always LLC/SNAP encap'd */ frame_len = ntohs(eh_tmp->ether_type); skb1 = skb_copy(skb, GFP_ATOMIC); if (skb1 == NULL) goto err; ieee80211_skb_copy_noderef(skb, skb1); /* we now have 802.3 MAC hdr followed by 802.2 LLC/SNAP; convert to EthernetII. * Note that the frame is at least IEEE80211_MIN_LEN, due to the driver code. */ athff_decap(skb); /* remove second frame from end of first */ skb_trim(skb, sizeof(struct ether_header) + frame_len - LLC_SNAPFRAMELEN); /* prepare second tunneled frame */ skb_pull(skb1, roundup(sizeof(struct ether_header) + frame_len, 4)); /* Fail if there is no space left for at least the necessary headers */ if (athff_decap(skb1)) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, ni->ni_macaddr, "data", "%s", "Decapsulation error"); vap->iv_stats.is_rx_decap++; IEEE80211_NODE_STAT(ni, rx_decap); ieee80211_dev_kfree_skb(&skb1); /* This is a copy! */ goto err; } /* Deliver the frames. */ ieee80211_deliver_data(ni, skb); ieee80211_deliver_data(ni, skb1); } else { /* Assume non-atheros LLC type. */ ieee80211_deliver_data(ni, skb); }#else /* !ATH_SUPERG_FF */ ieee80211_deliver_data(ni, skb);#endif if (ni_or_null == NULL) ieee80211_unref_node(&ni); /* XXX: Why doesn't this use 'goto out'? * If it did, then the SKB would be accessed after we * have given it to ieee80211_deliver_data and we get * crashes/errors. */ return IEEE80211_FC0_TYPE_DATA; case IEEE80211_FC0_TYPE_MGT: /* WDS opmode does not support management frames. */ if (vap->iv_opmode == IEEE80211_M_WDS) { vap->iv_stats.is_rx_mgtdiscard++; goto out; } IEEE80211_NODE_STAT(ni, rx_mgmt); if (dir != IEEE80211_FC1_DIR_NODS) { vap->iv_stats.is_rx_wrongdir++; goto err; } if (skb->len < sizeof(struct ieee80211_frame)) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, ni->ni_macaddr, "mgt", "too short: len %u", skb->len); vap->iv_stats.is_rx_tooshort++; goto out; }#ifdef IEEE80211_DEBUG if ((ieee80211_msg_debug(vap) && doprint(vap, subtype)) || ieee80211_msg_dumppkts(vap)) { ieee80211_note(vap, "received %s from " MAC_FMT " rssi %d\n", ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], MAC_ADDR(wh->i_addr2), rssi); }#endif if (wh->i_fc[1] & IEEE80211_FC1_PROT) { if (subtype != IEEE80211_FC0_SUBTYPE_AUTH) { /* * Only shared key auth frames with a challenge * should be encrypted, discard all others. */ IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], "%s", "WEP set but not permitted"); vap->iv_stats.is_rx_mgtdiscard++; /* XXX */ goto out; } if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) { /* * Discard encrypted frames when privacy is off. */ IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, "mgt", "%s", "WEP set but PRIVACY off"); vap->iv_stats.is_rx_noprivacy++; goto out; } hdrlen = ieee80211_hdrsize(wh); key = ieee80211_crypto_decap(ni, skb, hdrlen); if (key == NULL) { /* NB: stats+msgs handled in crypto_decap */ goto out; } wh = (struct ieee80211_frame *)skb->data; wh->i_fc[1] &= ~IEEE80211_FC1_PROT; } ic->ic_recv_mgmt(vap, ni_or_null, skb, subtype, rssi, rtsf); goto out; case IEEE80211_FC0_TYPE_CTL: IEEE80211_NODE_STAT(ni, rx_ctrl); vap->iv_stats.is_rx_ctl++; if (vap->iv_opmode == IEEE80211_M_HOSTAP) if (subtype == IEEE80211_FC0_SUBTYPE_PS_POLL) ieee80211_recv_pspoll(ni, skb); goto out; default: IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, wh, NULL, "bad frame type 0x%x", type); /* should not come here */ break; }err: vap->iv_devstats.rx_errors++;out: ieee80211_dev_kfree_skb(&skb); if (ni_or_null == NULL) ieee80211_unref_node(&ni); return type;#undef HAS_SEQ}EXPORT_SYMBOL(ieee80211_input);/* * Context: softIRQ (tasklet) */ int ieee80211_input_all(struct ieee80211com *ic, struct sk_buff *skb, int rssi, u_int64_t rtsf) { struct ieee80211vap *vap, *next_vap; struct sk_buff *tskb = NULL; int type = -1; /* Used to determine when to blinks LEDs. */ /* Create a new SKB copy for each VAP except the last * one, which gets the original SKB. */ vap = TAILQ_FIRST(&ic->ic_vaps); while (vap) { for (next_vap = TAILQ_NEXT(vap, iv_next); next_vap; next_vap = TAILQ_NEXT(next_vap, iv_next)) { if ((next_vap->iv_dev->flags & (IFF_RUNNING | IFF_UP)) == (IFF_RUNNING | IFF_UP)) break; } if (!next_vap) { tskb = skb; skb = NULL; } else tskb = skb_copy(skb, GFP_ATOMIC); if (!tskb) /* XXX: Brilliant OOM handling. */ vap->iv_devstats.tx_dropped++; else type = ieee80211_input(vap, NULL, tskb, rssi, rtsf); vap = next_vap; };
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -