/* * Drivers call this, so increase the reference count before returning * the node. */ struct ieee80211_node * ieee80211_find_rxnode(struct ieee80211com *ic, struct ieee80211_frame *wh) { struct ieee80211_node *ni; const static u_int8_t zero[IEEE80211_ADDR_LEN]; u_int8_t *bssid; if (!ieee80211_needs_rxnode(ic, wh, &bssid)) return ieee80211_ref_node(ic->ic_bss); IEEE80211_NODE_LOCK(ic); ni = ieee80211_find_node(ic, wh->i_addr2); IEEE80211_NODE_UNLOCK(ic); if (ni != NULL) return ieee80211_ref_node(ni); if (ic->ic_opmode == IEEE80211_M_HOSTAP) return ieee80211_ref_node(ic->ic_bss); /* XXX see remarks in ieee80211_find_txnode */ /* XXX no rate negotiation; just dup */ if ((ni = ieee80211_dup_bss(ic, wh->i_addr2)) == NULL) return ieee80211_ref_node(ic->ic_bss); IEEE80211_ADDR_COPY(ni->ni_bssid, (bssid != NULL) ? bssid : zero); ni->ni_rates = ic->ic_bss->ni_rates; if (ic->ic_newassoc) (*ic->ic_newassoc)(ic, ni, 1); IEEE80211_DPRINTF(("%s: faked-up node %p for %s\n", __func__, ni, ether_sprintf(wh->i_addr2))); return ieee80211_ref_node(ni); }
/* * Drivers call this, so increase the reference count before returning * the node. */ struct ieee80211_node * Voodoo80211Device:: ieee80211_find_rxnode(struct ieee80211com *ic, const struct ieee80211_frame *wh) { static const u_int8_t zero[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; struct ieee80211_node *ni; const u_int8_t *bssid; int s; if (!ieee80211_needs_rxnode(ic, wh, &bssid)) return ieee80211_ref_node(ic->ic_bss); s = splnet(); ni = ieee80211_find_node(ic, wh->i_addr2); splx(s); if (ni != NULL) return ieee80211_ref_node(ni); /* XXX see remarks in ieee80211_find_txnode */ /* XXX no rate negotiation; just dup */ if ((ni = ieee80211_dup_bss(ic, wh->i_addr2)) == NULL) return ieee80211_ref_node(ic->ic_bss); IEEE80211_ADDR_COPY(ni->ni_bssid, (bssid != NULL) ? bssid : zero); ni->ni_rates = ic->ic_bss->ni_rates; ieee80211_newassoc(ic, ni, 1); DPRINTF(("faked-up node %p for %s\n", ni, ether_sprintf((u_int8_t *)wh->i_addr2))); return ieee80211_ref_node(ni); }
u_int32_t ieee80211_aow_tx_ctrl(u_int8_t* data, u_int32_t datalen, u_int64_t tsf) { aow_ctrl_data_msg_t* pd = NULL; struct ieee80211_node *ni = NULL; struct ieee80211com *ic = aowinfo.ic; int is_cmd_local; u_int32_t cmd = 0; u_int8_t event_subtype = CM_SEND_BUFFER_STATUS_FAIL; aow_ctrl_msg_t* mh = (aow_ctrl_msg_t*)data; is_cmd_local = IS_AOW_CTRL_MSG_LOCAL(mh); cmd = get_ctrl_msg_cmd_type(mh); /* * The command is meant for this device, * pass it to athcm connection manager */ if (is_cmd_local) { aow_ci_send(ic, data, datalen); return 0; } pd = (aow_ctrl_data_msg_t*)(mh->data); ni = ieee80211_find_node(&ic->ic_sta, pd->addr); if (ni) { ieee80211_send_aow_ctrl_ipformat(ni, pd->data, __bswap32(pd->length) , 0, tsf, 0, 0); event_subtype = CM_SEND_BUFFER_STATUS_PASS; } ieee80211_aow_send_to_host(ic, &event_subtype, sizeof(event_subtype), AOW_HOST_PKT_EVENT, event_subtype, NULL); return 0; }
static int wmi_peer_sta_kickout_event_handler(ol_scn_t scn, u_int8_t *data, u_int16_t datalen, void *context) { struct ieee80211com *ic = &scn->sc_ic; A_UINT8 peer_macaddr[ATH_MAC_LEN]; struct ieee80211_node *ni; wmi_peer_sta_kickout_event *kickout_event = (wmi_peer_sta_kickout_event *)data; WMI_MAC_ADDR_TO_CHAR_ARRAY(&kickout_event->peer_macaddr,peer_macaddr); ni = ieee80211_find_node(&ic->ic_sta, peer_macaddr); if (!ni) { return -1; } ieee80211_kick_node(ni); ieee80211_free_node(ni); return 0; }
/* * Return a reference to the appropriate node for sending * a data frame. This handles node discovery in adhoc networks. * * Drivers will call this, so increase the reference count before * returning the node. */ struct ieee80211_node * ieee80211_find_txnode(struct ieee80211com *ic, const u_int8_t *macaddr) { #ifndef IEEE80211_STA_ONLY struct ieee80211_node *ni; int s; #endif /* * The destination address should be in the node table * unless we are operating in station mode or this is a * multicast/broadcast frame. */ if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr)) return ieee80211_ref_node(ic->ic_bss); #ifndef IEEE80211_STA_ONLY s = splnet(); ni = ieee80211_find_node(ic, macaddr); splx(s); if (ni == NULL) { if (ic->ic_opmode != IEEE80211_M_IBSS && ic->ic_opmode != IEEE80211_M_AHDEMO) return NULL; /* * Fake up a node; this handles node discovery in * adhoc mode. Note that for the driver's benefit * we we treat this like an association so the driver * has an opportunity to setup its private state. * * XXX need better way to handle this; issue probe * request so we can deduce rate set, etc. */ if ((ni = ieee80211_dup_bss(ic, macaddr)) == NULL) return NULL; /* XXX no rate negotiation; just dup */ ni->ni_rates = ic->ic_bss->ni_rates; ni->ni_txrate = 0; if (ic->ic_newassoc) (*ic->ic_newassoc)(ic, ni, 1); } return ieee80211_ref_node(ni); #else return NULL; /* can't get there */ #endif /* IEEE80211_STA_ONLY */ }
u_int32_t ieee80211_aow_disconnect_device(struct ieee80211com* ic, u_int32_t channel) { struct ether_addr macaddr; struct ieee80211_node *ni = NULL; if (!aow_get_macaddr(channel, 0, &macaddr)) { return FALSE; } if ((ni = ieee80211_find_node(&ic->ic_sta, macaddr.octet)) != NULL) { ieee80211_send_disassoc(ni, IEEE80211_REASON_UNSPECIFIED); IEEE80211_NODE_LEAVE(ni); ieee80211_free_node(ni); } return TRUE; }
/* * Return a reference to the appropriate node for sending * a data frame. This handles node discovery in adhoc networks. * * Drivers will call this, so increase the reference count before * returning the node. */ struct ieee80211_node * ieee80211_find_txnode(struct ieee80211com *ic, u_int8_t *macaddr) { struct ieee80211_node *ni; /* * The destination address should be in the node table * unless we are operating in station mode or this is a * multicast/broadcast frame. */ if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr)) return ieee80211_ref_node(ic->ic_bss); /* XXX can't hold lock across dup_bss 'cuz of recursive locking */ IEEE80211_NODE_LOCK(ic); ni = ieee80211_find_node(ic, macaddr); IEEE80211_NODE_UNLOCK(ic); if (ni == NULL) { if (ic->ic_opmode != IEEE80211_M_IBSS && ic->ic_opmode != IEEE80211_M_AHDEMO) return NULL; /* * Fake up a node; this handles node discovery in * adhoc mode. Note that for the driver's benefit * we we treat this like an association so the driver * has an opportunity to setup its private state. * * XXX need better way to handle this; issue probe * request so we can deduce rate set, etc. */ if ((ni = ieee80211_dup_bss(ic, macaddr)) == NULL) return NULL; /* XXX no rate negotiation; just dup */ ni->ni_rates = ic->ic_bss->ni_rates; if (ic->ic_newassoc) (*ic->ic_newassoc)(ic, ni, 1); } return ieee80211_ref_node(ni); }
/* * CONNECTED */ static void ieee80211_btamp_conn_state_connected_entry(void *ctx) { wlan_btamp_conn_sm_t sm = (wlan_btamp_conn_sm_t) ctx; struct ieee80211vap *vap = (struct ieee80211vap *)sm->vap_handle; struct ieee80211com *ic = vap->iv_ic; struct ieee80211_node *ni = NULL; /* Authorize peer node */ wlan_node_authorize(sm->vap_handle, true, sm->peer); ni = ieee80211_find_node(&ic->ic_sta, sm->peer); if (ni) { /* Set up node tx rate */ if (ic->ic_newassoc) ic->ic_newassoc(ni, TRUE); ieee80211_free_node(ni); } ieee80211_send_event(sm, WLAN_BTAMP_CONN_SM_CONNECTION_UP, WLAN_BTAMP_CONN_SM_REASON_NONE); }
struct ieee80211_node * ieee80211_find_node_for_beacon(struct ieee80211com *ic, u_int8_t *macaddr, struct ieee80211_channel *chan, char *ssid, u_int8_t rssi) { struct ieee80211_node *ni, *keep = NULL; int score = 0; if ((ni = ieee80211_find_node(ic, macaddr)) != NULL) { IEEE80211_NODE_LOCK(ic); if (ni->ni_chan != chan && ni->ni_rssi >= rssi) score++; if (ssid[1] == 0 && ni->ni_esslen != 0) score++; if (score > 0) keep = ni; IEEE80211_NODE_UNLOCK(ic); } return (keep); }
struct ieee80211_node * ieee80211_find_node_for_beacon(struct ieee80211com *ic, const u_int8_t *macaddr, const struct ieee80211_channel *chan, const char *ssid, u_int8_t rssi) { struct ieee80211_node *ni, *keep = NULL; int s, score = 0; if ((ni = ieee80211_find_node(ic, macaddr)) != NULL) { s = splnet(); if (ni->ni_chan != chan && ni->ni_rssi >= rssi) score++; if (ssid[1] == 0 && ni->ni_esslen != 0) score++; if (score > 0) keep = ni; splx(s); } return (keep); }
int ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ieee80211com *ic = (void *)ifp; struct ifreq *ifr = (struct ifreq *)data; int i, error = 0; struct ieee80211_nwid nwid; struct ieee80211_wpapsk *psk; struct ieee80211_wmmparams *wmm; struct ieee80211_power *power; struct ieee80211_bssid *bssid; struct ieee80211chanreq *chanreq; struct ieee80211_channel *chan; struct ieee80211_txpower *txpower; static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; struct ieee80211_nodereq *nr, nrbuf; struct ieee80211_nodereq_all *na; struct ieee80211_node *ni; u_int32_t flags; switch (cmd) { case SIOCSIFADDR: case SIOCGIFADDR: error = ether_ioctl(ifp, &ic->ic_ac, cmd, data); break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); break; case SIOCS80211NWID: if ((error = suser(curproc, 0)) != 0) break; if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0) break; if (nwid.i_len > IEEE80211_NWID_LEN) { error = EINVAL; break; } memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); ic->ic_des_esslen = nwid.i_len; memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len); error = ENETRESET; break; case SIOCG80211NWID: memset(&nwid, 0, sizeof(nwid)); switch (ic->ic_state) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: nwid.i_len = ic->ic_des_esslen; memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len); break; default: nwid.i_len = ic->ic_bss->ni_esslen; memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len); break; } error = copyout(&nwid, ifr->ifr_data, sizeof(nwid)); break; case SIOCS80211NWKEY: if ((error = suser(curproc, 0)) != 0) break; error = ieee80211_ioctl_setnwkeys(ic, (void *)data); break; case SIOCG80211NWKEY: error = ieee80211_ioctl_getnwkeys(ic, (void *)data); break; case SIOCS80211WMMPARMS: if ((error = suser(curproc, 0)) != 0) break; if (!(ic->ic_flags & IEEE80211_C_QOS)) { error = ENODEV; break; } wmm = (struct ieee80211_wmmparams *)data; if (wmm->i_enabled) ic->ic_flags |= IEEE80211_F_QOS; else ic->ic_flags &= ~IEEE80211_F_QOS; error = ENETRESET; break; case SIOCG80211WMMPARMS: wmm = (struct ieee80211_wmmparams *)data; wmm->i_enabled = (ic->ic_flags & IEEE80211_F_QOS) ? 1 : 0; break; case SIOCS80211WPAPARMS: if ((error = suser(curproc, 0)) != 0) break; error = ieee80211_ioctl_setwpaparms(ic, (void *)data); break; case SIOCG80211WPAPARMS: error = ieee80211_ioctl_getwpaparms(ic, (void *)data); break; case SIOCS80211WPAPSK: if ((error = suser(curproc, 0)) != 0) break; psk = (struct ieee80211_wpapsk *)data; if (psk->i_enabled) { ic->ic_flags |= IEEE80211_F_PSK; memcpy(ic->ic_psk, psk->i_psk, sizeof(ic->ic_psk)); } else { ic->ic_flags &= ~IEEE80211_F_PSK; memset(ic->ic_psk, 0, sizeof(ic->ic_psk)); } error = ENETRESET; break; case SIOCG80211WPAPSK: psk = (struct ieee80211_wpapsk *)data; if (ic->ic_flags & IEEE80211_F_PSK) { psk->i_enabled = 1; /* do not show any keys to non-root user */ if (suser(curproc, 0) != 0) { psk->i_enabled = 2; memset(psk->i_psk, 0, sizeof(psk->i_psk)); break; /* return ok but w/o key */ } memcpy(psk->i_psk, ic->ic_psk, sizeof(psk->i_psk)); } else psk->i_enabled = 0; break; case SIOCS80211POWER: if ((error = suser(curproc, 0)) != 0) break; power = (struct ieee80211_power *)data; ic->ic_lintval = power->i_maxsleep; if (power->i_enabled != 0) { if ((ic->ic_caps & IEEE80211_C_PMGT) == 0) error = EINVAL; else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) { ic->ic_flags |= IEEE80211_F_PMGTON; error = ENETRESET; } } else { if (ic->ic_flags & IEEE80211_F_PMGTON) { ic->ic_flags &= ~IEEE80211_F_PMGTON; error = ENETRESET; } } break; case SIOCG80211POWER: power = (struct ieee80211_power *)data; power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0; power->i_maxsleep = ic->ic_lintval; break; case SIOCS80211BSSID: if ((error = suser(curproc, 0)) != 0) break; bssid = (struct ieee80211_bssid *)data; if (IEEE80211_ADDR_EQ(bssid->i_bssid, empty_macaddr)) ic->ic_flags &= ~IEEE80211_F_DESBSSID; else { ic->ic_flags |= IEEE80211_F_DESBSSID; IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid); } if (ic->ic_opmode == IEEE80211_M_HOSTAP) break; switch (ic->ic_state) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: error = ENETRESET; break; default: if ((ic->ic_flags & IEEE80211_F_DESBSSID) && !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ic->ic_bss->ni_bssid)) error = ENETRESET; break; } break; case SIOCG80211BSSID: bssid = (struct ieee80211_bssid *)data; switch (ic->ic_state) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: if (ic->ic_opmode == IEEE80211_M_HOSTAP) IEEE80211_ADDR_COPY(bssid->i_bssid, ic->ic_myaddr); else if (ic->ic_flags & IEEE80211_F_DESBSSID) IEEE80211_ADDR_COPY(bssid->i_bssid, ic->ic_des_bssid); else memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN); break; default: IEEE80211_ADDR_COPY(bssid->i_bssid, ic->ic_bss->ni_bssid); break; } break; case SIOCS80211CHANNEL: if ((error = suser(curproc, 0)) != 0) break; chanreq = (struct ieee80211chanreq *)data; if (chanreq->i_channel == IEEE80211_CHAN_ANY) ic->ic_des_chan = IEEE80211_CHAN_ANYC; else if (chanreq->i_channel > IEEE80211_CHAN_MAX || isclr(ic->ic_chan_active, chanreq->i_channel)) { error = EINVAL; break; } else ic->ic_ibss_chan = ic->ic_des_chan = &ic->ic_channels[chanreq->i_channel]; switch (ic->ic_state) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: error = ENETRESET; break; default: if (ic->ic_opmode == IEEE80211_M_STA) { if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && ic->ic_bss->ni_chan != ic->ic_des_chan) error = ENETRESET; } else { if (ic->ic_bss->ni_chan != ic->ic_ibss_chan) error = ENETRESET; } break; } break; case SIOCG80211CHANNEL: chanreq = (struct ieee80211chanreq *)data; switch (ic->ic_state) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: if (ic->ic_opmode == IEEE80211_M_STA) chan = ic->ic_des_chan; else chan = ic->ic_ibss_chan; break; default: chan = ic->ic_bss->ni_chan; break; } chanreq->i_channel = ieee80211_chan2ieee(ic, chan); break; #if 0 case SIOCG80211ZSTATS: #endif case SIOCG80211STATS: ifr = (struct ifreq *)data; copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats)); #if 0 if (cmd == SIOCG80211ZSTATS) memset(&ic->ic_stats, 0, sizeof(ic->ic_stats)); #endif break; case SIOCS80211TXPOWER: if ((error = suser(curproc, 0)) != 0) break; txpower = (struct ieee80211_txpower *)data; if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) { error = EINVAL; break; } if (IEEE80211_TXPOWER_MIN > txpower->i_val || txpower->i_val > IEEE80211_TXPOWER_MAX) { error = EINVAL; break; } ic->ic_txpower = txpower->i_val; error = ENETRESET; break; case SIOCG80211TXPOWER: txpower = (struct ieee80211_txpower *)data; if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) error = EINVAL; else txpower->i_val = ic->ic_txpower; break; case SIOCSIFMTU: ifr = (struct ifreq *)data; if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu && ifr->ifr_mtu <= IEEE80211_MTU_MAX)) error = EINVAL; else ifp->if_mtu = ifr->ifr_mtu; break; case SIOCS80211SCAN: if ((error = suser(curproc, 0)) != 0) break; if (ic->ic_opmode == IEEE80211_M_HOSTAP) break; if ((ifp->if_flags & IFF_UP) == 0) { error = ENETDOWN; break; } if ((ic->ic_scan_lock & IEEE80211_SCAN_REQUEST) == 0) { if (ic->ic_scan_lock & IEEE80211_SCAN_LOCKED) ic->ic_scan_lock |= IEEE80211_SCAN_RESUME; ic->ic_scan_lock |= IEEE80211_SCAN_REQUEST; if (ic->ic_state != IEEE80211_S_SCAN) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); } /* Let the userspace process wait for completion */ error = tsleep(&ic->ic_scan_lock, PCATCH, "80211scan", hz * IEEE80211_SCAN_TIMEOUT); break; case SIOCG80211NODE: nr = (struct ieee80211_nodereq *)data; ni = ieee80211_find_node(ic, nr->nr_macaddr); if (ni == NULL) { error = ENOENT; break; } ieee80211_node2req(ic, ni, nr); break; case SIOCS80211NODE: if ((error = suser(curproc, 0)) != 0) break; if (ic->ic_opmode == IEEE80211_M_HOSTAP) { error = EINVAL; break; } nr = (struct ieee80211_nodereq *)data; ni = ieee80211_find_node(ic, nr->nr_macaddr); if (ni == NULL) ni = ieee80211_alloc_node(ic, nr->nr_macaddr); if (ni == NULL) { error = ENOENT; break; } if (nr->nr_flags & IEEE80211_NODEREQ_COPY) ieee80211_req2node(ic, nr, ni); break; case SIOCS80211DELNODE: if ((error = suser(curproc, 0)) != 0) break; nr = (struct ieee80211_nodereq *)data; ni = ieee80211_find_node(ic, nr->nr_macaddr); if (ni == NULL) error = ENOENT; else if (ni == ic->ic_bss) error = EPERM; else { if (ni->ni_state == IEEE80211_STA_COLLECT) break; /* Disassociate station. */ if (ni->ni_state == IEEE80211_STA_ASSOC) IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DISASSOC, IEEE80211_REASON_ASSOC_LEAVE); /* Deauth station. */ if (ni->ni_state >= IEEE80211_STA_AUTH) IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_LEAVE); ieee80211_release_node(ic, ni); } break; case SIOCG80211ALLNODES: na = (struct ieee80211_nodereq_all *)data; na->na_nodes = i = 0; ni = RB_MIN(ieee80211_tree, &ic->ic_tree); while (ni && na->na_size >= i + sizeof(struct ieee80211_nodereq)) { ieee80211_node2req(ic, ni, &nrbuf); error = copyout(&nrbuf, (caddr_t)na->na_node + i, sizeof(struct ieee80211_nodereq)); if (error) break; i += sizeof(struct ieee80211_nodereq); na->na_nodes++; ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni); } break; case SIOCG80211FLAGS: flags = ic->ic_flags; if (ic->ic_opmode != IEEE80211_M_HOSTAP) flags &= ~IEEE80211_F_HOSTAPMASK; ifr->ifr_flags = flags >> IEEE80211_F_USERSHIFT; break; case SIOCS80211FLAGS: if ((error = suser(curproc, 0)) != 0) break; flags = (u_int32_t)ifr->ifr_flags << IEEE80211_F_USERSHIFT; if (ic->ic_opmode != IEEE80211_M_HOSTAP && (flags & IEEE80211_F_HOSTAPMASK)) { error = EINVAL; break; } ic->ic_flags = (ic->ic_flags & ~IEEE80211_F_USERMASK) | flags; error = ENETRESET; break; default: error = ENOTTY; break; } return error; }
/* * Join an infrastructure network */ int ieee80211_sta_join(struct ieee80211vap *vap, ieee80211_scan_entry_t scan_entry) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_node_table *nt = &ic->ic_sta; struct ieee80211_node *ni = NULL; const u_int8_t *macaddr = ieee80211_scan_entry_macaddr(scan_entry); int error = 0; ASSERT(vap->iv_opmode == IEEE80211_M_STA); ni = ieee80211_find_node(nt, macaddr); if (ni) { /* * reusing old node has a potential for several bugs . The old node may have some state info from previous association. * get rid of the old bss node and create a new bss node. */ ieee80211_sta_leave(ni); ieee80211_free_node(ni); } /* * Create a BSS node. */ ni = ieee80211_alloc_node(nt, vap, macaddr); if (ni == NULL) return -ENOMEM; /* set the maximum number frmaes to be queued when the vap is in fake sleep */ ieee80211_node_saveq_set_param(ni,IEEE80211_NODE_SAVEQ_DATA_Q_LEN,IEE80211_STA_MAX_NODE_SAVEQ_LEN); /* To become a bss node, a node need an extra reference count, which alloc node already gives */ #ifdef IEEE80211_DEBUG_REFCNT ieee80211_note(ni->ni_vap,"%s ,line %u: increase node %p <%s> refcnt to %d\n", __func__, __LINE__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)); #endif /* setup the bss node for association */ error = ieee80211_setup_node(ni, scan_entry); if (error != 0) { ieee80211_free_node(ni); return error; } /* copy the beacon timestamp */ OS_MEMCPY(ni->ni_tstamp.data, ieee80211_scan_entry_tsf(scan_entry), sizeof(ni->ni_tstamp)); /* * Join the BSS represented by this new node. * This function will free up the old BSS node * and use this one as the new BSS node. */ ieee80211_sta_join_bss(ni); IEEE80211_ADD_NODE_TARGET(ni, ni->ni_vap, 0); /* Save our home channel */ vap->iv_bsschan = ni->ni_chan; vap->iv_cur_mode = ieee80211_chan2mode(ni->ni_chan); /* Update the DotH falg */ ieee80211_update_spectrumrequirement(vap); /* * The OS will control our security keys. * If clear, keys will be cleared. * If static WEP, keys will be plumbed before JoinInfra. * If WPA/WPA2, ciphers will be setup, but no keys will be plumbed until * after they are negotiated. * XXX We should ASSERT that all of the foregoing is true. */ return 0; }
static int ieee80211_crypto_keymiss(struct ieee80211_node *ni, wbuf_t wbuf, struct ieee80211_rx_status *rs) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = vap->iv_ic; struct ieee80211_frame *wh; int off, kid, hdrspace; u_int8_t *buf = NULL; struct ieee80211_key k, *key = NULL; const struct ieee80211_cipher *cip; struct ieee80211_node_table *nt = &ic->ic_sta; struct ieee80211_node *sender=NULL; /* * Verify if WEP is set and * retrieve the key index from the packet. */ wh = (struct ieee80211_frame *)wbuf_header(wbuf); buf = (u_int8_t*)wbuf_raw_data(wbuf); if (wh->i_fc[1] & IEEE80211_FC1_WEP) { off = ieee80211_anyhdrspace(ic, wh); kid = buf[off+IEEE80211_WEP_IVLEN] >> 6; sender = ieee80211_find_node(nt, wh->i_addr2); if(sender == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "%s: Node not found\n", __func__); goto bad; } /* * Using the key index specified in the packet. */ if (kid >= IEEE80211_WEP_NKID) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "%s: Incorrect keyid (%d) specified in the packet!\n", __func__, kid); goto bad; } key = &vap->iv_nw_keys[kid]; cip = key->wk_cipher; if (cip->ic_cipher != IEEE80211_CIPHER_WEP) { ieee80211_free_node(sender); return 1; } hdrspace = ieee80211_hdrspace(ic, wh); IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "%s: kid=%d, ni=0x%p, sender=0x%p, vap=0x%p\n", __func__, kid, ni, sender, vap); /* * Create a temporary key for installing the * rx key for the station. */ OS_MEMCPY(&k, key, sizeof(*key)); k.wk_flags |= IEEE80211_KEY_SWCRYPT; if (cip->ic_decap(&k, wbuf, hdrspace, rs) ) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "Decrypt using entry(s) %d worked.\n", key->wk_keyix); wh = (struct ieee80211_frame *)wbuf_header(wbuf); /* * The packet has been decrypted correctly, therefore the WEP bit * should be cleared. */ wh->i_fc[1] &= ~IEEE80211_FC1_WEP; k.wk_flags &= ~IEEE80211_KEY_SWCRYPT; if (!crypto_installkey(&k, vap, sender)) goto bad; sender->ni_wep_mbssid.rxvapkey = key; if(vap->iv_opmode == IEEE80211_M_STA) { if (!crypto_install_mcastkey(&k, vap, sender)) goto bad; } ieee80211_free_node(sender); key->wk_private = k.wk_private; return 1; } else IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, "Decrypt using entry(s) %d didn't work.\n", key->wk_keyix); } /* if wep is enabled */