| 1 | --- a/net80211/ieee80211_node.c |
| 2 | +++ b/net80211/ieee80211_node.c |
| 3 | @@ -123,6 +123,9 @@ static void ieee80211_node_table_cleanup |
| 4 | static void ieee80211_node_table_reset(struct ieee80211_node_table *, |
| 5 | struct ieee80211vap *); |
| 6 | |
| 7 | +static struct ieee80211_node * |
| 8 | +lookup_rxnode(struct ieee80211com *ic, struct ieee80211vap *vap, const u_int8_t *addr); |
| 9 | + |
| 10 | MALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state"); |
| 11 | |
| 12 | void |
| 13 | @@ -697,7 +700,7 @@ ieee80211_sta_join(struct ieee80211vap * |
| 14 | struct ieee80211com *ic = vap->iv_ic; |
| 15 | struct ieee80211_node *ni; |
| 16 | |
| 17 | - ni = ieee80211_find_node(&ic->ic_sta, se->se_macaddr); |
| 18 | + ni = lookup_rxnode(ic, vap, se->se_macaddr); |
| 19 | if (ni == NULL) { |
| 20 | ni = ieee80211_alloc_node_table(vap, se->se_macaddr); |
| 21 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, |
| 22 | @@ -1394,6 +1397,53 @@ ieee80211_add_neighbor(struct ieee80211v |
| 23 | return ni; |
| 24 | } |
| 25 | |
| 26 | +struct ieee80211vap * |
| 27 | +ieee80211_find_rxvap(struct ieee80211com *ic, const u_int8_t *mac) |
| 28 | +{ |
| 29 | + struct ieee80211vap *vap; |
| 30 | + |
| 31 | + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { |
| 32 | + if (IEEE80211_ADDR_EQ(vap->iv_myaddr, mac)) |
| 33 | + return vap; |
| 34 | + } |
| 35 | + return NULL; |
| 36 | +} |
| 37 | +EXPORT_SYMBOL(ieee80211_find_rxvap); |
| 38 | + |
| 39 | +static struct ieee80211_node * |
| 40 | +lookup_rxnode(struct ieee80211com *ic, struct ieee80211vap *vap, |
| 41 | + const u_int8_t *addr) |
| 42 | +{ |
| 43 | + struct ieee80211_node_table *nt; |
| 44 | + struct ieee80211_node *ni = NULL; |
| 45 | + int use_bss = 0; |
| 46 | + int hash; |
| 47 | + |
| 48 | + nt = &ic->ic_sta; |
| 49 | + IEEE80211_NODE_TABLE_LOCK_IRQ(nt); |
| 50 | + hash = IEEE80211_NODE_HASH(addr); |
| 51 | + LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { |
| 52 | + if (IEEE80211_ADDR_EQ(ni->ni_macaddr, addr)) { |
| 53 | + /* allow multiple nodes on different vaps */ |
| 54 | + if (vap && (ni->ni_vap != vap)) |
| 55 | + continue; |
| 56 | + |
| 57 | + ieee80211_ref_node(ni); |
| 58 | + goto out; |
| 59 | + } |
| 60 | + } |
| 61 | + |
| 62 | + /* no match found */ |
| 63 | + ni = NULL; |
| 64 | + |
| 65 | +out: |
| 66 | + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); |
| 67 | + return ni; |
| 68 | +#undef IS_PSPOLL |
| 69 | +#undef IS_CTL |
| 70 | +} |
| 71 | + |
| 72 | + |
| 73 | /* |
| 74 | * Return the node for the sender of a frame; if the sender is unknown return |
| 75 | * NULL. The caller is expected to deal with this. (The frame is sent to all |
| 76 | @@ -1403,10 +1453,10 @@ ieee80211_add_neighbor(struct ieee80211v |
| 77 | */ |
| 78 | struct ieee80211_node * |
| 79 | #ifdef IEEE80211_DEBUG_REFCNT |
| 80 | -ieee80211_find_rxnode_debug(struct ieee80211com *ic, |
| 81 | +ieee80211_find_rxnode_debug(struct ieee80211com *ic, struct ieee80211vap *vap, |
| 82 | const struct ieee80211_frame_min *wh, const char *func, int line) |
| 83 | #else |
| 84 | -ieee80211_find_rxnode(struct ieee80211com *ic, |
| 85 | +ieee80211_find_rxnode(struct ieee80211com *ic, struct ieee80211vap *vap, |
| 86 | const struct ieee80211_frame_min *wh) |
| 87 | #endif |
| 88 | { |
| 89 | @@ -1414,9 +1464,8 @@ ieee80211_find_rxnode(struct ieee80211co |
| 90 | ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) |
| 91 | #define IS_PSPOLL(wh) \ |
| 92 | ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL) |
| 93 | - struct ieee80211_node_table *nt; |
| 94 | - struct ieee80211_node *ni; |
| 95 | - struct ieee80211vap *vap, *avp; |
| 96 | + struct ieee80211_node *ni = NULL; |
| 97 | + struct ieee80211vap *avp; |
| 98 | const u_int8_t *addr; |
| 99 | |
| 100 | if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/) |
| 101 | @@ -1429,32 +1478,25 @@ ieee80211_find_rxnode(struct ieee80211co |
| 102 | |
| 103 | /* XXX check ic_bss first in station mode */ |
| 104 | /* XXX 4-address frames? */ |
| 105 | - nt = &ic->ic_sta; |
| 106 | - IEEE80211_NODE_TABLE_LOCK_IRQ(nt); |
| 107 | if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) { |
| 108 | - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { |
| 109 | + if (vap) { /* assume unicast if vap is set, mcast not supported for wds */ |
| 110 | TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) { |
| 111 | - if (!IEEE80211_ADDR_EQ(addr, avp->wds_mac)) |
| 112 | + if (!IEEE80211_ADDR_EQ(addr, avp->wds_mac) || |
| 113 | + !IEEE80211_ADDR_EQ(wh->i_addr1, avp->iv_myaddr)) |
| 114 | continue; |
| 115 | |
| 116 | if (avp->iv_wdsnode) |
| 117 | - return ieee80211_ref_node(avp->iv_wdsnode); |
| 118 | - else |
| 119 | - return NULL; |
| 120 | + ni = ieee80211_ref_node(avp->iv_wdsnode); |
| 121 | + return ni; |
| 122 | } |
| 123 | + if (!(vap->iv_flags_ext & IEEE80211_FEXT_WDS)) |
| 124 | + return NULL; |
| 125 | + } else { |
| 126 | + return NULL; |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | -#ifdef IEEE80211_DEBUG_REFCNT |
| 131 | - ni = ieee80211_find_node_locked_debug(nt, addr, func, line); |
| 132 | -#else |
| 133 | - ni = ieee80211_find_node_locked(nt, addr); |
| 134 | -#endif |
| 135 | - IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); |
| 136 | - |
| 137 | - return ni; |
| 138 | -#undef IS_PSPOLL |
| 139 | -#undef IS_CTL |
| 140 | + return lookup_rxnode(ic, vap, addr); |
| 141 | } |
| 142 | #ifdef IEEE80211_DEBUG_REFCNT |
| 143 | EXPORT_SYMBOL(ieee80211_find_rxnode_debug); |
| 144 | @@ -1479,15 +1521,14 @@ ieee80211_find_txnode(struct ieee80211va |
| 145 | struct ieee80211com *ic = vap->iv_ic; |
| 146 | struct ieee80211_node_table *nt; |
| 147 | struct ieee80211_node *ni = NULL; |
| 148 | + int hash; |
| 149 | |
| 150 | - IEEE80211_LOCK_IRQ(ic); |
| 151 | if (vap->iv_opmode == IEEE80211_M_WDS) { |
| 152 | if (vap->iv_wdsnode && (vap->iv_state == IEEE80211_S_RUN)) |
| 153 | return ieee80211_ref_node(vap->iv_wdsnode); |
| 154 | else |
| 155 | return NULL; |
| 156 | } |
| 157 | - IEEE80211_UNLOCK_IRQ(ic); |
| 158 | |
| 159 | /* |
| 160 | * The destination address should be in the node table |
| 161 | @@ -1505,11 +1546,22 @@ ieee80211_find_txnode(struct ieee80211va |
| 162 | /* XXX: Can't hold lock across dup_bss due to recursive locking. */ |
| 163 | nt = &vap->iv_ic->ic_sta; |
| 164 | IEEE80211_NODE_TABLE_LOCK_IRQ(nt); |
| 165 | + hash = IEEE80211_NODE_HASH(mac); |
| 166 | + LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { |
| 167 | + if (ni->ni_vap != vap) |
| 168 | + continue; |
| 169 | + |
| 170 | + if (IEEE80211_ADDR_EQ(ni->ni_macaddr, mac)) { |
| 171 | #ifdef IEEE80211_DEBUG_REFCNT |
| 172 | - ni = ieee80211_find_node_locked_debug(nt, mac, func, line); |
| 173 | + ieee80211_ref_node_debug(ni, func, line); |
| 174 | #else |
| 175 | - ni = ieee80211_find_node_locked(nt, mac); |
| 176 | + ieee80211_ref_node(ni); |
| 177 | #endif |
| 178 | + goto found; |
| 179 | + } |
| 180 | + } |
| 181 | + ni = NULL; |
| 182 | +found: |
| 183 | IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); |
| 184 | |
| 185 | if (ni == NULL) { |
| 186 | @@ -1964,13 +2016,32 @@ remove_worse_nodes(void *arg, struct iee |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | +static void |
| 191 | +remove_duplicate_nodes(void *arg, struct ieee80211_node *ni) |
| 192 | +{ |
| 193 | + struct ieee80211_node *rni = arg; |
| 194 | + |
| 195 | + if (ni == rni) |
| 196 | + return; |
| 197 | + |
| 198 | + if (ni->ni_vap == rni->ni_vap) |
| 199 | + return; |
| 200 | + |
| 201 | + if (!IEEE80211_ADDR_EQ(rni->ni_macaddr, ni->ni_macaddr)) |
| 202 | + return; |
| 203 | + |
| 204 | + ieee80211_node_leave(ni); |
| 205 | +} |
| 206 | + |
| 207 | void |
| 208 | ieee80211_node_join(struct ieee80211_node *ni, int resp) |
| 209 | { |
| 210 | struct ieee80211com *ic = ni->ni_ic; |
| 211 | struct ieee80211vap *vap = ni->ni_vap; |
| 212 | + struct ieee80211_node *tni; |
| 213 | int newassoc; |
| 214 | |
| 215 | + ieee80211_iterate_nodes(&ic->ic_sta, remove_duplicate_nodes, ni); |
| 216 | if (ni->ni_associd == 0) { |
| 217 | u_int16_t aid; |
| 218 | |
| 219 | --- a/net80211/ieee80211_input.c |
| 220 | +++ b/net80211/ieee80211_input.c |
| 221 | @@ -216,16 +216,14 @@ ieee80211_input(struct ieee80211vap * va |
| 222 | |
| 223 | type = -1; /* undefined */ |
| 224 | |
| 225 | - if (!vap) |
| 226 | - goto out; |
| 227 | + if (!vap || !vap->iv_bss || !vap->iv_dev || !vap->iv_ic) |
| 228 | + goto discard; |
| 229 | |
| 230 | ic = vap->iv_ic; |
| 231 | - if (!ic) |
| 232 | - goto out; |
| 233 | - |
| 234 | dev = vap->iv_dev; |
| 235 | - if (!dev) |
| 236 | - goto out; |
| 237 | + |
| 238 | + if ((vap->iv_dev->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) |
| 239 | + goto discard; |
| 240 | |
| 241 | /* initialize ni as in the previous API */ |
| 242 | if (ni_or_null == NULL) { |
| 243 | @@ -233,9 +231,10 @@ ieee80211_input(struct ieee80211vap * va |
| 244 | * guarantee its existence during the following call, hence |
| 245 | * briefly grab our own reference. */ |
| 246 | ni = ieee80211_ref_node(vap->iv_bss); |
| 247 | + KASSERT(ni != NULL, ("null node")); |
| 248 | + } else { |
| 249 | + ni->ni_inact = ni->ni_inact_reload; |
| 250 | } |
| 251 | - KASSERT(ni != NULL, ("null node")); |
| 252 | - ni->ni_inact = ni->ni_inact_reload; |
| 253 | |
| 254 | KASSERT(skb->len >= sizeof(struct ieee80211_frame_min), |
| 255 | ("frame length too short: %u", skb->len)); |
| 256 | @@ -844,10 +843,11 @@ ieee80211_input(struct ieee80211vap * va |
| 257 | err: |
| 258 | vap->iv_devstats.rx_errors++; |
| 259 | out: |
| 260 | - if (skb != NULL) |
| 261 | - ieee80211_dev_kfree_skb(&skb); |
| 262 | if (ni_or_null == NULL) |
| 263 | ieee80211_unref_node(&ni); |
| 264 | +discard: |
| 265 | + if (skb != NULL) |
| 266 | + ieee80211_dev_kfree_skb(&skb); |
| 267 | return type; |
| 268 | #undef HAS_SEQ |
| 269 | } |
| 270 | @@ -929,16 +929,23 @@ int |
| 271 | ieee80211_input_all(struct ieee80211com *ic, |
| 272 | struct sk_buff *skb, int rssi, u_int64_t rtsf) |
| 273 | { |
| 274 | + struct ieee80211_frame_min *wh = (struct ieee80211_frame_min *) skb->data; |
| 275 | struct ieee80211vap *vap; |
| 276 | int type = -1; |
| 277 | |
| 278 | /* XXX locking */ |
| 279 | TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { |
| 280 | + struct ieee80211_node *ni = NULL; |
| 281 | struct sk_buff *skb1; |
| 282 | |
| 283 | if ((vap->iv_dev->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) |
| 284 | continue; |
| 285 | |
| 286 | + if ((vap->iv_opmode == IEEE80211_M_HOSTAP) && |
| 287 | + !IEEE80211_IS_MULTICAST(wh->i_addr1)) |
| 288 | + continue; |
| 289 | + |
| 290 | + ni = ieee80211_find_rxnode(ic, vap, wh); |
| 291 | if (TAILQ_NEXT(vap, iv_next) != NULL) { |
| 292 | skb1 = skb_copy(skb, GFP_ATOMIC); |
| 293 | if (skb1 == NULL) { |
| 294 | @@ -950,8 +957,12 @@ ieee80211_input_all(struct ieee80211com |
| 295 | skb1 = skb; |
| 296 | skb = NULL; |
| 297 | } |
| 298 | - type = ieee80211_input(vap, NULL, skb1, rssi, rtsf); |
| 299 | + type = ieee80211_input(vap, ni, skb1, rssi, rtsf); |
| 300 | + if (ni) |
| 301 | + ieee80211_unref_node(&ni); |
| 302 | } |
| 303 | + |
| 304 | +out: |
| 305 | if (skb != NULL) /* no vaps, reclaim skb */ |
| 306 | ieee80211_dev_kfree_skb(&skb); |
| 307 | return type; |
| 308 | @@ -1147,11 +1158,9 @@ ieee80211_deliver_data(struct ieee80211_ |
| 309 | * sending it will not work; just let it be |
| 310 | * delivered normally. |
| 311 | */ |
| 312 | - struct ieee80211_node *ni1 = ieee80211_find_node( |
| 313 | - &vap->iv_ic->ic_sta, eh->ether_dhost); |
| 314 | + struct ieee80211_node *ni1 = ieee80211_find_txnode(vap, eh->ether_dhost); |
| 315 | if (ni1 != NULL) { |
| 316 | - if (ni1->ni_vap == vap && |
| 317 | - ieee80211_node_is_authorized(ni1) && |
| 318 | + if (ieee80211_node_is_authorized(ni1) && |
| 319 | !ni1->ni_subif && |
| 320 | ni1 != vap->iv_bss) { |
| 321 | |
| 322 | @@ -3520,6 +3529,7 @@ ieee80211_recv_mgmt(struct ieee80211vap |
| 323 | (vap->iv_opmode == IEEE80211_M_WDS)) && |
| 324 | (scan.capinfo & IEEE80211_CAPINFO_ESS))) { |
| 325 | struct ieee80211vap *avp = NULL; |
| 326 | + int do_unref = 0; |
| 327 | int found = 0; |
| 328 | |
| 329 | IEEE80211_LOCK_IRQ(vap->iv_ic); |
| 330 | @@ -3553,10 +3563,12 @@ ieee80211_recv_mgmt(struct ieee80211vap |
| 331 | ni->ni_associd |= 0xc000; |
| 332 | avp->iv_wdsnode = ieee80211_ref_node(ni); |
| 333 | IEEE80211_UNLOCK_IRQ(ic); |
| 334 | - } else if (vap->iv_opmode == IEEE80211_M_IBSS) { |
| 335 | + } else if ((vap->iv_opmode == IEEE80211_M_IBSS) && |
| 336 | + IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid)) { |
| 337 | /* Create a new entry in the neighbor table. */ |
| 338 | ni = ieee80211_add_neighbor(vap, wh, &scan); |
| 339 | } |
| 340 | + do_unref = 1; |
| 341 | } else { |
| 342 | /* |
| 343 | * Copy data from beacon to neighbor table. |
| 344 | @@ -3595,6 +3607,8 @@ ieee80211_recv_mgmt(struct ieee80211vap |
| 345 | ni->ni_rssi = rssi; |
| 346 | ni->ni_rtsf = rtsf; |
| 347 | ni->ni_last_rx = jiffies; |
| 348 | + if (do_unref) |
| 349 | + ieee80211_unref_node(&ni); |
| 350 | } |
| 351 | } |
| 352 | break; |
| 353 | --- a/ath/if_ath.c |
| 354 | +++ b/ath/if_ath.c |
| 355 | @@ -6589,9 +6589,8 @@ ath_recv_mgmt(struct ieee80211vap * vap, |
| 356 | |
| 357 | sc->sc_recv_mgmt(vap, ni_or_null, skb, subtype, rssi, rtsf); |
| 358 | |
| 359 | - |
| 360 | /* Lookup the new node if any (this grabs a reference to it) */ |
| 361 | - ni = ieee80211_find_rxnode(vap->iv_ic, |
| 362 | + ni = ieee80211_find_rxnode(vap->iv_ic, vap, |
| 363 | (const struct ieee80211_frame_min *)skb->data); |
| 364 | if (ni == NULL) { |
| 365 | DPRINTF(sc, ATH_DEBUG_BEACON, "Dropping; node unknown.\n"); |
| 366 | @@ -6746,7 +6745,9 @@ ath_rx_poll(struct net_device *dev, int |
| 367 | struct ath_desc *ds; |
| 368 | struct ath_rx_status *rs; |
| 369 | struct sk_buff *skb = NULL; |
| 370 | + struct ieee80211vap *vap; |
| 371 | struct ieee80211_node *ni; |
| 372 | + const struct ieee80211_frame_min *wh; |
| 373 | unsigned int len; |
| 374 | int type; |
| 375 | u_int phyerr; |
| 376 | @@ -6901,12 +6902,15 @@ rx_accept: |
| 377 | skb_trim(skb, skb->len - IEEE80211_CRC_LEN); |
| 378 | |
| 379 | if (mic_fail) { |
| 380 | + wh = (const struct ieee80211_frame_min *) skb->data; |
| 381 | + |
| 382 | /* Ignore control frames which are reported with mic error */ |
| 383 | - if ((((struct ieee80211_frame *)skb->data)->i_fc[0] & |
| 384 | + if ((wh->i_fc[0] & |
| 385 | IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) |
| 386 | goto drop_micfail; |
| 387 | |
| 388 | - ni = ieee80211_find_rxnode(ic, (const struct ieee80211_frame_min *) skb->data); |
| 389 | + vap = ieee80211_find_rxvap(ic, wh->i_addr1); |
| 390 | + ni = ieee80211_find_rxnode(ic, vap, wh); |
| 391 | |
| 392 | if (ni && ni->ni_table) { |
| 393 | ieee80211_check_mic(ni, skb); |
| 394 | @@ -6968,11 +6972,24 @@ drop_micfail: |
| 395 | * for its use. If the sender is unknown spam the |
| 396 | * frame; it'll be dropped where it's not wanted. |
| 397 | */ |
| 398 | - if (rs->rs_keyix != HAL_RXKEYIX_INVALID && |
| 399 | + wh = (const struct ieee80211_frame_min *) skb->data; |
| 400 | + if ((rs->rs_keyix != HAL_RXKEYIX_INVALID) && |
| 401 | (ni = sc->sc_keyixmap[rs->rs_keyix]) != NULL) { |
| 402 | /* Fast path: node is present in the key map; |
| 403 | * grab a reference for processing the frame. */ |
| 404 | - ni = ieee80211_ref_node(ni); |
| 405 | + ieee80211_ref_node(ni); |
| 406 | + if ((ATH_GET_VAP_ID(wh->i_addr1) != |
| 407 | + ATH_GET_VAP_ID(ni->ni_vap->iv_myaddr)) || |
| 408 | + ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == |
| 409 | + IEEE80211_FC1_DIR_DSTODS)) { |
| 410 | + /* key cache node lookup is fast, but it can |
| 411 | + * lead to problems in multi-bss (foreign vap |
| 412 | + * node reference) or wds (wdsap node ref instead |
| 413 | + * of base ap node ref). |
| 414 | + * use slowpath lookup in both cases |
| 415 | + */ |
| 416 | + goto lookup_slowpath; |
| 417 | + } |
| 418 | ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi); |
| 419 | type = ieee80211_input(ni->ni_vap, ni, skb, rs->rs_rssi, bf->bf_tsf); |
| 420 | ieee80211_unref_node(&ni); |
| 421 | @@ -6981,24 +6998,39 @@ drop_micfail: |
| 422 | * No key index or no entry, do a lookup and |
| 423 | * add the node to the mapping table if possible. |
| 424 | */ |
| 425 | - ni = ieee80211_find_rxnode(ic, |
| 426 | - (const struct ieee80211_frame_min *)skb->data); |
| 427 | + |
| 428 | +lookup_slowpath: |
| 429 | + if (IEEE80211_IS_MULTICAST(wh->i_addr1)) |
| 430 | + vap = NULL; |
| 431 | + else |
| 432 | + vap = ieee80211_find_rxvap(ic, wh->i_addr1); |
| 433 | + |
| 434 | + if (vap) |
| 435 | + ni = ieee80211_find_rxnode(ic, vap, wh); |
| 436 | + else |
| 437 | + ni = NULL; |
| 438 | + |
| 439 | if (ni != NULL) { |
| 440 | ieee80211_keyix_t keyix; |
| 441 | |
| 442 | ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi); |
| 443 | - type = ieee80211_input(ni->ni_vap, ni, skb, rs->rs_rssi, bf->bf_tsf); |
| 444 | + type = ieee80211_input(vap, ni, skb, rs->rs_rssi, bf->bf_tsf); |
| 445 | /* |
| 446 | * If the station has a key cache slot assigned |
| 447 | * update the key->node mapping table. |
| 448 | */ |
| 449 | keyix = ni->ni_ucastkey.wk_keyix; |
| 450 | if (keyix != IEEE80211_KEYIX_NONE && |
| 451 | - sc->sc_keyixmap[keyix] == NULL) |
| 452 | + sc->sc_keyixmap[keyix] == NULL) { |
| 453 | sc->sc_keyixmap[keyix] = ieee80211_ref_node(ni); |
| 454 | + } |
| 455 | ieee80211_unref_node(&ni); |
| 456 | - } else |
| 457 | - type = ieee80211_input_all(ic, skb, rs->rs_rssi, bf->bf_tsf); |
| 458 | + } else { |
| 459 | + if (vap) |
| 460 | + type = ieee80211_input(vap, NULL, skb, rs->rs_rssi, bf->bf_tsf); |
| 461 | + else |
| 462 | + type = ieee80211_input_all(ic, skb, rs->rs_rssi, bf->bf_tsf); |
| 463 | + } |
| 464 | } |
| 465 | |
| 466 | if (sc->sc_diversity) { |
| 467 | --- a/net80211/ieee80211_node.h |
| 468 | +++ b/net80211/ieee80211_node.h |
| 469 | @@ -286,15 +286,18 @@ struct ieee80211_node *ieee80211_find_no |
| 470 | const u_int8_t *); |
| 471 | #endif /* #ifdef IEEE80211_DEBUG_REFCNT */ |
| 472 | |
| 473 | +struct ieee80211vap * |
| 474 | +ieee80211_find_rxvap(struct ieee80211com *ic, const u_int8_t *mac); |
| 475 | + |
| 476 | /* Returns a ieee80211_node* with refcount incremented, if found */ |
| 477 | #ifdef IEEE80211_DEBUG_REFCNT |
| 478 | -#define ieee80211_find_rxnode(_nt, _wh) \ |
| 479 | - ieee80211_find_rxnode_debug(_nt, _wh, __func__, __LINE__) |
| 480 | +#define ieee80211_find_rxnode(_nt, _vap, _wh) \ |
| 481 | + ieee80211_find_rxnode_debug(_nt, _vap, _wh, __func__, __LINE__) |
| 482 | struct ieee80211_node *ieee80211_find_rxnode_debug(struct ieee80211com *, |
| 483 | - const struct ieee80211_frame_min *, const char *, int); |
| 484 | + struct ieee80211vap *, const struct ieee80211_frame_min *, const char *, int); |
| 485 | #else |
| 486 | struct ieee80211_node *ieee80211_find_rxnode(struct ieee80211com *, |
| 487 | - const struct ieee80211_frame_min *); |
| 488 | + struct ieee80211vap *, const struct ieee80211_frame_min *); |
| 489 | #endif /* #ifdef IEEE80211_DEBUG_REFCNT */ |
| 490 | |
| 491 | /* Returns a ieee80211_node* with refcount incremented, if found */ |
| 492 | |