/* * It is usually desirable to process a Rx packet using its sender's * node-record instead of the BSS record. * * - AP mode: keep a node-record for every authenticated/associated * station *in the BSS*. For future use, we also track neighboring * APs, since they might belong to the same ESS. APs in the same * ESS may bridge packets to each other, forming a Wireless * Distribution System (WDS). * * - IBSS mode: keep a node-record for every station *in the BSS*. * Also track neighboring stations by their beacons/probe responses. * * - monitor mode: keep a node-record for every sender, regardless * of BSS. * * - STA mode: the only available node-record is the BSS record, * ic->ic_bss. * * Of all the 802.11 Control packets, only the node-records for * RTS packets node-record can be looked up. * * Return non-zero if the packet's node-record is kept, zero * otherwise. */ static __inline int ieee80211_needs_rxnode(struct ieee80211com *ic, struct ieee80211_frame *wh, u_int8_t **bssid) { struct ieee80211_node *bss = ic->ic_bss; int monitor, rc = 0; monitor = (ic->ic_opmode == IEEE80211_M_MONITOR); *bssid = NULL; switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { case IEEE80211_FC0_TYPE_CTL: if (!monitor) break; return (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_RTS; case IEEE80211_FC0_TYPE_MGT: *bssid = wh->i_addr3; switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { case IEEE80211_FC0_SUBTYPE_BEACON: case IEEE80211_FC0_SUBTYPE_PROBE_RESP: rc = 1; break; default: if (ic->ic_opmode == IEEE80211_M_STA) break; rc = IEEE80211_ADDR_EQ(*bssid, bss->ni_bssid) || IEEE80211_ADDR_EQ(*bssid, etherbroadcastaddr); break; } break; case IEEE80211_FC0_TYPE_DATA: switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { case IEEE80211_FC1_DIR_NODS: *bssid = wh->i_addr3; if (ic->ic_opmode == IEEE80211_M_IBSS || ic->ic_opmode == IEEE80211_M_AHDEMO) rc = IEEE80211_ADDR_EQ(*bssid, bss->ni_bssid); break; case IEEE80211_FC1_DIR_TODS: *bssid = wh->i_addr1; if (ic->ic_opmode == IEEE80211_M_HOSTAP) rc = IEEE80211_ADDR_EQ(*bssid, bss->ni_bssid); break; case IEEE80211_FC1_DIR_FROMDS: case IEEE80211_FC1_DIR_DSTODS: *bssid = wh->i_addr2; rc = (ic->ic_opmode == IEEE80211_M_HOSTAP); break; } break; } return monitor || rc; }
void ath_remove_audio_channel(struct ieee80211com* ic, int channel, struct ether_addr* macaddr) { struct ath_softc_net80211 *scn = ATH_SOFTC_NET80211(ic); struct ath_softc *sc = ATH_DEV_TO_SC(scn->sc_dev); int i = 0; if ((channel < 0) || (channel > (AOW_MAX_AUDIO_CHANNELS - 1))) { return; } for (i = 0 ; i < AOW_MAX_RECEIVER_COUNT; i++) { if (!IS_ETHER_ADDR_NULL(sc->sc_aow.chan_addr[channel].addr[i].octet)) { if (IEEE80211_ADDR_EQ(&sc->sc_aow.chan_addr[channel].addr[i], macaddr)) { memset(&sc->sc_aow.chan_addr[channel].addr[i], 0 , IEEE80211_ADDR_LEN); sc->sc_aow.chan_addr[channel].dst_cnt--; sc->sc_aow.mapped_recv_cnt--; } } } if (!sc->sc_aow.chan_addr[channel].dst_cnt) { sc->sc_aow.chan_addr[channel].valid = AH_FALSE; sc->sc_aow.chan_addr[channel].seqno = 0; ic->ic_aow.channel_set_flag &= ~(1 << channel); } }
static void wlan_setstamac(struct wlanstatfoo *wf0, const uint8_t *mac) { static const uint8_t zeromac[IEEE80211_ADDR_LEN]; struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) wf0; if (mac == NULL) { switch (wlan_getopmode(wf0)) { case IEEE80211_M_HOSTAP: case IEEE80211_M_MONITOR: getlladdr(wf); break; case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: /* * NB: this may not work in which case the * mac must be specified on the command line */ if (getbssid(wf) < 0 || IEEE80211_ADDR_EQ(wf->mac, zeromac)) getlladdr(wf); break; case IEEE80211_M_STA: if (getbssid(wf) < 0) err(1, "%s (IEEE80211_IOC_BSSID)", wf->ireq.i_name); break; } } else IEEE80211_ADDR_COPY(wf->mac, mac); }
/* * Find an instance by it's mac address. */ struct ieee80211com * ieee80211_find_vap(const u_int8_t mac[IEEE80211_ADDR_LEN]) { int s; struct ieee80211com *ic; s = splnet(); SLIST_FOREACH(ic, &ieee80211_list, ic_next) if (IEEE80211_ADDR_EQ(mac, ic->ic_myaddr)) break; splx(s); return ic; }
/* * Handle a station leave event; destroy any associated WDS vap. */ static void wds_leave(const uint8_t bssid[IEEE80211_ADDR_LEN]) { struct wds *p, **pp; for (pp = &wds; (p = *pp) != NULL; pp = &p->next) if (IEEE80211_ADDR_EQ(p->bssid, bssid)) break; if (p != NULL) { *pp = p->next; if (wds_vap_destroy(p->ifname) >= 0) syslog(LOG_INFO, "[%s] wds vap %s destroyed", ether_sprintf(bssid), p->ifname); free(p); } }
int wlan_reset(wlan_if_t vaphandle, ieee80211_reset_request *reset_req) { struct ieee80211vap *vap = vaphandle; struct ieee80211com *ic = vap->iv_ic; int err = 0; /* NB: must set H/W MAC address before chip reset */ if (reset_req->reset_mac && IEEE80211_ADDR_IS_VALID(reset_req->macaddr) && !IEEE80211_ADDR_EQ(reset_req->macaddr, ic->ic_myaddr)) { IEEE80211_ADDR_COPY(ic->ic_myaddr, reset_req->macaddr); ic->ic_set_macaddr(ic, reset_req->macaddr); IEEE80211_ADDR_COPY(vap->iv_myaddr, ic->ic_myaddr); /* * TBD: if OS tries to set mac addr when multiple VAP co-exist, * we need to notify other VAPs and the corresponding ports * so that the port owner can change source address!! */ } /* reset UMAC software states */ if (reset_req->type == IEEE80211_RESET_TYPE_DOT11_INTF) { /* * In case iv_bss was not stopped. */ wlan_mlme_stop_bss(vap, WLAN_MLME_STOP_BSS_F_FORCE_STOP_RESET | WLAN_MLME_STOP_BSS_F_WAIT_RX_DONE); err = ieee80211_vap_reset(vap, reset_req); } else if (reset_req->type == IEEE80211_RESET_TYPE_DEVICE) { u_int32_t num_vaps; struct ieee80211_vap_iter_reset_arg params; params.err=0; params.reset_req = reset_req; ieee80211_iterate_vap_list_internal(ic,ieee80211_vap_iter_reset,((void *) ¶ms),num_vaps); err = params.err; } /* TBD: Always reset the hardware? */ err = ic->ic_reset(ic); if (err) return err; return err; }
static bss_t * _ieee80211_find_node(struct ieee80211_node_table *nt, const A_UINT8 *macaddr) { bss_t *ni = NULL; int hash = 0; IEEE80211_NODE_LOCK_ASSERT(nt); hash = IEEE80211_NODE_HASH(macaddr); if (hash >= IEEE80211_NODE_HASHSIZE) { // overflow???? return NULL; } if (hash < 0) { // underflow???? return NULL; } if (NULL == nt) { return NULL; } if (NULL == nt->nt_hash) { return NULL; } if (NULL == nt->nt_hash[hash]) { return NULL; } for(ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) { if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { ieee80211_node_incref(ni); /* mark referenced */ return ni; } } return NULL; }
static void ieee80211_vap_iter_find_connection(void *arg, struct ieee80211vap *vap, bool is_last_vap) { struct ieee80211_mlme_find_connection *pmlme_find_connection_data = arg; UNREFERENCED_PARAMETER(is_last_vap); /* * If we haven't found a connection yet, check to see if current VAP is * connected to the specified AP. */ if (! pmlme_find_connection_data->connection_found) { /* * Since ieee80211_mlme_get_bss_entry is not implemented, compare * iv_bss's and scan_entry's SSID and BSSID. */ struct ieee80211_node *bss_node = ieee80211vap_get_bssnode(vap); if (bss_node != NULL) { /* * Check for BSSID match first; SSID matching is a more expensive * operation and should be checked last. */ if (IEEE80211_ADDR_EQ(wlan_node_getbssid(bss_node), wlan_scan_entry_bssid(pmlme_find_connection_data->scan_entry))) { ieee80211_ssid bss_ssid; u_int8_t scan_entry_ssid_len; u_int8_t *scan_entry_ssid; /* * BSSID matched, let's check the SSID */ wlan_get_bss_essid(vap, &bss_ssid); scan_entry_ssid = wlan_scan_entry_ssid(pmlme_find_connection_data->scan_entry, &scan_entry_ssid_len); if (scan_entry_ssid != NULL) { pmlme_find_connection_data->connection_found = (scan_entry_ssid_len == bss_ssid.len) && (OS_MEMCMP(scan_entry_ssid, bss_ssid.ssid, bss_ssid.len) == 0); } } } } }
static A_BOOL is_node_self_peer(struct ieee80211vap *vap, const u_int8_t *macaddr) { A_BOOL is_self_peer = FALSE; switch (vap->iv_opmode) { case IEEE80211_M_STA: if (IEEE80211_ADDR_EQ(macaddr, vap->iv_myaddr)) { is_self_peer = TRUE; } break; default: break; } return is_self_peer; }
/* * Handle WDS discovery; create a WDS vap for the specified bssid. * If a vap already exists then do nothing (can happen when a flood * of 4-address frames causes multiple events to be queued before * we create a vap). */ static void wds_discovery(const char *ifname, const uint8_t bssid[IEEE80211_ADDR_LEN]) { struct wds *p; char parent[256]; char cmd[1024]; int status; for (p = wds; p != NULL; p = p->next) if (IEEE80211_ADDR_EQ(p->bssid, bssid)) { syslog(LOG_INFO, "[%s] wds vap already created (%s)", ether_sprintf(bssid), ifname); return; } if (getparent(ifname, parent) < 0) { syslog(LOG_ERR, "%s: no pointer to parent interface: %m", ifname); return; } p = malloc(sizeof(struct wds)); if (p == NULL) { syslog(LOG_ERR, "%s: malloc failed: %m", __func__); return; } IEEE80211_ADDR_COPY(p->bssid, bssid); if (wds_vap_create(parent, p) < 0) { free(p); return; } /* * Add to table and launch setup script. */ p->next = wds; wds = p; syslog(LOG_INFO, "[%s] create wds vap %s", ether_sprintf(bssid), p->ifname); if (script != NULL) { snprintf(cmd, sizeof(cmd), "%s %s", script, p->ifname); status = system(cmd); if (status) syslog(LOG_ERR, "vap setup script %s exited with " "status %d", script, status); } }
static bss_t * _ieee80211_find_node(struct ieee80211_node_table *nt, const A_UINT8 *macaddr) { bss_t *ni; int hash; IEEE80211_NODE_LOCK_ASSERT(nt); hash = IEEE80211_NODE_HASH(macaddr); for(ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) { if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { ieee80211_node_incref(ni); /* mark referenced */ return ni; } } return NULL; }
void ieee80211_delete_vap_target(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211vap_target vt; u_int8_t vapindex = 0; int i; #if 0 /* Dump mac address */ printk("%s, mac: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", __FUNCTION__, vap->iv_myaddr[0], vap->iv_myaddr[1], vap->iv_myaddr[2], vap->iv_myaddr[3], vap->iv_myaddr[4], vap->iv_myaddr[5]); #endif for (i = 0; i < HTC_MAX_VAP_NUM; i++) { if (ic->target_vap_bitmap[i].vap_valid == 1) { /* Compare mac address */ if (IEEE80211_ADDR_EQ(ic->target_vap_bitmap[i].vap_macaddr, vap->iv_myaddr)) { vapindex = i; ic->target_vap_bitmap[i].vap_valid = 0; OS_MEMZERO(ic->target_vap_bitmap[i].vap_macaddr, IEEE80211_ADDR_LEN); break; } } } if (i == HTC_MAX_VAP_NUM) { printk("%s: Can't find desired vap\n", __FUNCTION__); return; } //printk("%s: vapindex: %d\n", __FUNCTION__, vapindex); vt.iv_vapindex = vapindex;//vap->iv_vapindex; vt.iv_opmode = 0;//vap->iv_opmode; vt.iv_mcast_rate = 0;//vap->iv_mcast_rate; vt.iv_rtsthreshold = 0;//vap->iv_rtsthreshold; ic->ic_delete_vap_target(ic, &vt, sizeof(vt)); //printk("%s Exit \n", __FUNCTION__); }
void ieee80211_delete_node_target(struct ieee80211_node *ni, struct ieee80211com *ic, struct ieee80211vap *vap, u_int8_t is_reset_bss) { int i; u_int8_t nodeindex = 0xff; //printk("%s: vap: 0x%08x, ni: 0x%08x, is_reset_bss: %d\n", __FUNCTION__, vap, ni, is_reset_bss); /* Dump mac address */ /* printk("%s, mac: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", __FUNCTION__, ni->ni_macaddr[0], ni->ni_macaddr[1], ni->ni_macaddr[2], ni->ni_macaddr[3], ni->ni_macaddr[4], ni->ni_macaddr[5]); */ for (i = 0; i < HTC_MAX_NODE_NUM; i++) { if (ni->ni_ic->target_node_bitmap[i].ni_valid == 1) { /* avoid upper layer add the same vap twice */ if (IEEE80211_ADDR_EQ(ic->target_node_bitmap[i].ni_macaddr, ni->ni_macaddr)) { if(is_reset_bss == 1 && ic->target_node_bitmap[i].ni_is_vapnode == 1) { return; } OS_MEMZERO(ic->target_node_bitmap[i].ni_macaddr, IEEE80211_ADDR_LEN); ic->target_node_bitmap[i].ni_valid = 0; nodeindex = i; break; } } } if (i == HTC_MAX_NODE_NUM) { /*printk("%s: Can't find desired node\n", __FUNCTION__);*/ return; } /* printk("%s: ni: 0x%08x, nodeindex: %d, is_reset_bss: %d\n", __FUNCTION__, (u_int32_t)ni, nodeindex, is_reset_bss); */ ic->ic_delete_node_target(ic, &nodeindex, sizeof(nodeindex)); }
static void hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni, const struct ieee80211_frame *wh, const struct ieee80211_meshrann_ie *rann) { struct ieee80211_mesh_state *ms = vap->iv_mesh; struct ieee80211_hwmp_state *hs = vap->iv_hwmp; struct ieee80211_mesh_route *rt = NULL; struct ieee80211_hwmp_route *hr; struct ieee80211_meshrann_ie prann; if (ni == vap->iv_bss || ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED || IEEE80211_ADDR_EQ(rann->rann_addr, vap->iv_myaddr)) return; rt = ieee80211_mesh_rt_find(vap, rann->rann_addr); /* * Discover the path to the root mesh STA. * If we already know it, propagate the RANN element. */ if (rt == NULL) { hwmp_discover(vap, rann->rann_addr, NULL); return; } hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); if (HWMP_SEQ_GT(rann->rann_seq, hr->hr_seq)) { hr->hr_seq = rann->rann_seq; if (rann->rann_ttl > 1 && rann->rann_hopcount < hs->hs_maxhops && (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) { memcpy(&prann, rann, sizeof(prann)); prann.rann_hopcount += 1; prann.rann_ttl -= 1; prann.rann_metric += ms->ms_pmetric->mpm_metric(ni); hwmp_send_rann(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &prann); } } }
void ieee80211_update_vap_target(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211vap_update_tgt tmp_vap_update; u_int8_t vapindex = 0; adf_os_mem_zero(&tmp_vap_update , sizeof(struct ieee80211vap_update_tgt)); /*searching vapindex */ for (vapindex = 0; vapindex < HTC_MAX_VAP_NUM; vapindex++) { if ((ic->target_vap_bitmap[vapindex].vap_valid) && (IEEE80211_ADDR_EQ(ic->target_vap_bitmap[vapindex].vap_macaddr,vap->iv_myaddr))) break; } tmp_vap_update.iv_flags = htonl(vap->iv_flags); tmp_vap_update.iv_flags_ext = htonl(vap->iv_flags_ext); tmp_vap_update.iv_vapindex = htonl(vapindex); tmp_vap_update.iv_rtsthreshold = htons(vap->iv_rtsthreshold); ic->ic_update_vap_target(ic, &tmp_vap_update, sizeof(tmp_vap_update)); }
STATION * CAR6KMini::GetStation(A_UINT8 *sta,A_UINT16 aid) { STATION *adstation = NULL; A_UINT8 i, maxstation; switch(m_networkType) { case AP_NETWORK: maxstation = AP_MAX_NUM_STA; break; default: maxstation = 0; break; } for(i =0 ;i < maxstation; i++) { if(!sta) { if(m_staList[i].aid == aid) { adstation = &m_staList[i]; break; } } else { if(IEEE80211_ADDR_EQ(sta,m_staList[i].mac)) { adstation = &m_staList[i]; break; } } } return adstation; }
/* * IEEE80211_M_IBSS+IEEE80211_M_AHDEMO vap state machine handler. */ static int adhoc_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_node *ni; enum ieee80211_state ostate; IEEE80211_LOCK_ASSERT(vap->iv_ic); ostate = vap->iv_state; IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n", __func__, ieee80211_state_name[ostate], ieee80211_state_name[nstate], arg); vap->iv_state = nstate; /* state transition */ if (ostate != IEEE80211_S_SCAN) ieee80211_cancel_scan(vap); /* background scan */ ni = vap->iv_bss; /* NB: no reference held */ switch (nstate) { case IEEE80211_S_INIT: switch (ostate) { case IEEE80211_S_SCAN: ieee80211_cancel_scan(vap); break; default: break; } if (ostate != IEEE80211_S_INIT) { /* NB: optimize INIT -> INIT case */ ieee80211_reset_bss(vap); } break; case IEEE80211_S_SCAN: switch (ostate) { case IEEE80211_S_RUN: /* beacon miss */ /* purge station table; entries are stale */ ieee80211_iterate_nodes(&ic->ic_sta, sta_leave, vap); /* fall thru... */ case IEEE80211_S_INIT: if (vap->iv_des_chan != IEEE80211_CHAN_ANYC && !IEEE80211_IS_CHAN_RADAR(vap->iv_des_chan)) { /* * Already have a channel; bypass the * scan and startup immediately. */ ieee80211_create_ibss(vap, ieee80211_ht_adjust_channel(ic, vap->iv_des_chan, vap->iv_flags_ht)); break; } /* * Initiate a scan. We can come here as a result * of an IEEE80211_IOC_SCAN_REQ too in which case * the vap will be marked with IEEE80211_FEXT_SCANREQ * and the scan request parameters will be present * in iv_scanreq. Otherwise we do the default. */ if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) { ieee80211_check_scan(vap, vap->iv_scanreq_flags, vap->iv_scanreq_duration, vap->iv_scanreq_mindwell, vap->iv_scanreq_maxdwell, vap->iv_scanreq_nssid, vap->iv_scanreq_ssid); vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ; } else ieee80211_check_scan_current(vap); break; case IEEE80211_S_SCAN: /* * This can happen because of a change in state * that requires a reset. Trigger a new scan * unless we're in manual roaming mode in which * case an application must issue an explicit request. */ if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) ieee80211_check_scan_current(vap); break; default: goto invalid; } break; case IEEE80211_S_RUN: if (vap->iv_flags & IEEE80211_F_WPA) { /* XXX validate prerequisites */ } switch (ostate) { case IEEE80211_S_SCAN: #ifdef IEEE80211_DEBUG if (ieee80211_msg_debug(vap)) { ieee80211_note(vap, "synchronized with %s ssid ", ether_sprintf(ni->ni_bssid)); ieee80211_print_essid(vap->iv_bss->ni_essid, ni->ni_esslen); /* XXX MCS/HT */ printf(" channel %d start %uMb\n", ieee80211_chan2ieee(ic, ic->ic_curchan), IEEE80211_RATE2MBS(ni->ni_txrate)); } #endif break; case IEEE80211_S_RUN: /* IBSS merge */ break; default: goto invalid; } /* * When 802.1x is not in use mark the port authorized * at this point so traffic can flow. */ if (ni->ni_authmode != IEEE80211_AUTH_8021X) ieee80211_node_authorize(ni); /* * Fake association when joining an existing bss. */ if (!IEEE80211_ADDR_EQ(ni->ni_macaddr, vap->iv_myaddr) && ic->ic_newassoc != NULL) ic->ic_newassoc(ni, ostate != IEEE80211_S_RUN); break; case IEEE80211_S_SLEEP: vap->iv_sta_ps(vap, 0); break; default: invalid: IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: unexpected state transition %s -> %s\n", __func__, ieee80211_state_name[ostate], ieee80211_state_name[nstate]); break; } return 0; }
int wlan_mlme_deauth_request(wlan_if_t vaphandle, u_int8_t *macaddr, IEEE80211_REASON_CODE reason) { struct ieee80211vap *vap = vaphandle; struct ieee80211_node *ni; int error = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__); /* * if a node exist with the given address already , use it. * if not use bss node. */ ni = ieee80211_vap_find_node(vap, macaddr); if (ni == NULL) { if (IEEE80211_ADDR_EQ(macaddr, IEEE80211_GET_BCAST_ADDR(vap->iv_ic))) ni = ieee80211_ref_node(vap->iv_bss); else{ error = -EIO; goto exit; } } /* Send deauth frame */ error = ieee80211_send_deauth(ni, reason); /* Node needs to be removed from table as well, do it only for AP/IBSS now */ #if ATH_SUPPORT_IBSS if ((vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS) && ni != vap->iv_bss) { #else if (vap->iv_opmode == IEEE80211_M_HOSTAP && ni != vap->iv_bss) { #if ATH_SUPPORT_AOW ieee80211_aow_join_indicate(ni->ni_ic, AOW_STA_DISCONNECTED, ni); #endif /* ATH_SUPPORT_AOW */ #endif /* ATH_SUPPORT_IBSS */ IEEE80211_NODE_LEAVE(ni); } /* claim node immediately */ ieee80211_free_node(ni); if (error) { goto exit; } /* * Call MLME confirmation handler => mlme_deauth_complete * This should reflect the tx completion status of the deauth frame, * but since we don't have per frame completion, we'll always indicate success here. */ IEEE80211_DELIVER_EVENT_MLME_DEAUTH_COMPLETE(vap,macaddr, IEEE80211_STATUS_SUCCESS); exit: return error; } int wlan_mlme_disassoc_request(wlan_if_t vaphandle, u_int8_t *macaddr, IEEE80211_REASON_CODE reason) { struct ieee80211vap *vap = vaphandle; struct ieee80211_node *ni; int error = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__); /* Broadcast Addr - disassociate all stations */ if (IEEE80211_ADDR_EQ(macaddr, IEEE80211_GET_BCAST_ADDR(vap->iv_ic))) { if (vap->iv_opmode == IEEE80211_M_STA) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: unexpected station vap with all 0xff mac address", __func__); ASSERT(0); goto exit; } else { /* Iterate station list only when PMF is not enabled */ if (!wlan_vap_is_pmf_enabled(vap)) { wlan_iterate_station_list(vap, sta_disassoc, NULL); goto exit; } } } /* * if a node exist with the given address already , use it. * if not use bss node. */ ni = ieee80211_vap_find_node(vap, macaddr); if (ni == NULL) { if (IEEE80211_ADDR_EQ(macaddr, IEEE80211_GET_BCAST_ADDR(vap->iv_ic))) ni = ieee80211_ref_node(vap->iv_bss); else{ error = -EIO; goto exit; } } /* Send disassoc frame */ error = ieee80211_send_disassoc(ni, reason); /* Node needs to be removed from table as well, do it only for AP now */ if (vap->iv_opmode == IEEE80211_M_HOSTAP && ni != vap->iv_bss) { #if ATH_SUPPORT_AOW ieee80211_aow_join_indicate(ni->ni_ic, AOW_STA_DISCONNECTED, ni); #endif /* ATH_SUPPORT_AOW */ IEEE80211_NODE_LEAVE(ni); } /* claim node immediately */ ieee80211_free_node(ni); if (error) { goto exit; } /* * Call MLME confirmation handler => mlme_disassoc_complete * This should reflect the tx completion status of the disassoc frame, * but since we don't have per frame completion, we'll always indicate success here. */ IEEE80211_DELIVER_EVENT_MLME_DISASSOC_COMPLETE(vap, macaddr, reason, IEEE80211_STATUS_SUCCESS); exit: return error; } int wlan_mlme_start_bss(wlan_if_t vaphandle) { struct ieee80211vap *vap = vaphandle; struct ieee80211_mlme_priv *mlme_priv = vap->iv_mlme_priv; int error = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__); switch(vap->iv_opmode) { case IEEE80211_M_IBSS: IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: Create adhoc bss\n", __func__); /* Reset state */ mlme_priv->im_connection_up = 0; error = mlme_create_adhoc_bss(vap); break; case IEEE80211_M_MONITOR: case IEEE80211_M_HOSTAP: case IEEE80211_M_BTAMP: /* * start the AP . the channel/ssid should have been setup already. */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: Create infrastructure(AP) bss\n", __func__); error = mlme_create_infra_bss(vap); break; default: ASSERT(0); } return error; } bool wlan_coext_enabled(wlan_if_t vaphandle) { struct ieee80211com *ic = vaphandle->iv_ic; return (ic->ic_flags & IEEE80211_F_COEXT_DISABLE) ? FALSE : TRUE; } void wlan_determine_cw(wlan_if_t vaphandle, wlan_chan_t channel) { struct ieee80211com *ic = vaphandle->iv_ic; int is_chan_ht40 = channel->ic_flags & (IEEE80211_CHAN_11NG_HT40PLUS | IEEE80211_CHAN_11NG_HT40MINUS); if (is_chan_ht40 && (channel->ic_flags & IEEE80211_CHAN_HT40INTOL)) { ic->ic_bss_to20(ic); } } static void sta_deauth(void *arg, struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; u_int8_t macaddr[6]; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: deauth station %s \n", __func__,ether_sprintf(ni->ni_macaddr)); IEEE80211_ADDR_COPY(macaddr, ni->ni_macaddr); if (ni->ni_associd) { /* * if it is associated, then send disassoc. */ ieee80211_send_deauth(ni, IEEE80211_REASON_AUTH_LEAVE); } IEEE80211_NODE_LEAVE(ni); IEEE80211_DELIVER_EVENT_MLME_DEAUTH_INDICATION(vap, macaddr, IEEE80211_REASON_AUTH_LEAVE); } static void sta_disassoc(void *arg, struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; u_int8_t macaddr[6]; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: disassoc station %s \n", __func__,ether_sprintf(ni->ni_macaddr)); IEEE80211_ADDR_COPY(macaddr, ni->ni_macaddr); if (ni->ni_associd) { /* * if it is associated, then send disassoc. */ ieee80211_send_disassoc(ni, IEEE80211_REASON_ASSOC_LEAVE); #if ATH_SUPPORT_AOW ieee80211_aow_join_indicate(ni->ni_ic, AOW_STA_DISCONNECTED, ni); #endif /* ATH_SUPPORT_AOW */ } IEEE80211_NODE_LEAVE(ni); IEEE80211_DELIVER_EVENT_MLME_DISASSOC_COMPLETE(vap, macaddr, IEEE80211_REASON_ASSOC_LEAVE, IEEE80211_STATUS_SUCCESS); } int wlan_mlme_stop_bss(wlan_if_t vaphandle, int flags) { #define WAIT_RX_INTERVAL 10000 u_int32_t elapsed_time = 0; struct ieee80211vap *vap = vaphandle; struct ieee80211_mlme_priv *mlme_priv = vap->iv_mlme_priv; int error = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s flags = 0x%x\n", __func__, flags); /* * Wait for current rx path to finish. Assume only one rx thread. */ if (flags & WLAN_MLME_STOP_BSS_F_WAIT_RX_DONE) { do { if (OS_ATOMIC_CMPXCHG(&vap->iv_rx_gate, 0, 1) == 0) { break; } OS_SLEEP(WAIT_RX_INTERVAL); elapsed_time += WAIT_RX_INTERVAL; if (elapsed_time > (100 * WAIT_RX_INTERVAL)) ieee80211_note (vap,"%s: Rx pending count stuck. Investigate!!!\n", __func__); } while (1); } switch(vap->iv_opmode) { #if UMAC_SUPPORT_IBSS case IEEE80211_M_IBSS: mlme_stop_adhoc_bss(vap, flags); break; #endif case IEEE80211_M_HOSTAP: case IEEE80211_M_BTAMP: /* disassoc/deauth all stations */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: dsassocing/deauth all stations \n", __func__); if(vap->iv_send_deauth) wlan_iterate_station_list(vap, sta_deauth, NULL); else wlan_iterate_station_list(vap, sta_disassoc, NULL); break; case IEEE80211_M_STA: /* There should be no mlme requests pending */ ASSERT(vap->iv_mlme_priv->im_request_type == MLME_REQ_NONE); /* Reset state variables */ mlme_priv->im_connection_up = 0; mlme_sta_swbmiss_timer_stop(vap); ieee80211_sta_leave(vap->iv_bss); break; default: break; } if (flags & WLAN_MLME_STOP_BSS_F_FORCE_STOP_RESET) { /* put vap in init state */ ieee80211_vap_stop(vap, TRUE); } else { /* put vap in stopping state */ if (flags & WLAN_MLME_STOP_BSS_F_STANDBY) ieee80211_vap_standby(vap); else ieee80211_vap_stop(vap, FALSE); } if (!(flags & WLAN_MLME_STOP_BSS_F_NO_RESET)) error = ieee80211_reset_bss(vap); /* * Release the rx mutex. */ if (flags & WLAN_MLME_STOP_BSS_F_WAIT_RX_DONE) { (void) OS_ATOMIC_CMPXCHG(&vap->iv_rx_gate, 1, 0); } return error; #undef WAIT_RX_INTERVAL }
int ieee80211_recv_asreq(struct ieee80211_node *ni, wbuf_t wbuf, int subtype) { struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_frame *wh; u_int8_t *frm, *efrm; u_int16_t capinfo, bintval; struct ieee80211_rsnparms rsn; u_int8_t reason; int reassoc, resp; u_int8_t *ssid, *rates, *xrates, *wpa, *wme, *ath, *htcap,*vendor_ie, *wps; u_int8_t *athextcap; if (vap->iv_opmode != IEEE80211_M_HOSTAP && vap->iv_opmode != IEEE80211_M_BTAMP) { vap->iv_stats.is_rx_mgtdiscard++; return -EINVAL; } wh = (struct ieee80211_frame *) wbuf_header(wbuf); frm = (u_int8_t *)&wh[1]; efrm = wbuf_header(wbuf) + wbuf_get_pktlen(wbuf); if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { reassoc = 1; resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP; /*zhaoyang1 transplant from 717*/ /*pengruofeng add start for management frame stats 2011-5-9*/ vap->iv_stats.is_rx_reassoc++; /*pengruofeng add end 2011-5-9*/ /*zhaoyang1 transplant end*/ } else { reassoc = 0; resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP; } /* * asreq frame format * [2] capability information * [2] listen interval * [6*] current AP address (reassoc only) * [tlv] ssid * [tlv] supported rates * [tlv] extended supported rates * [tlv] WPA or RSN * [tlv] WME * [tlv] HT Capabilities * [tlv] Atheros capabilities */ IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4)); if (!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bss->ni_bssid)) { IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, wh, ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], "%s\n", "wrong bssid"); /*zhaoyang1 transplant from 717*/ /*pengruofeng add start for management frame stats 2011-5-9*/ if (reassoc) { vap->iv_stats.is_rx_reassoc_bss++; } else { vap->iv_stats.is_rx_assoc_bss++; } /*pengruofeng add end 2011-5-9*/ /*zhaoyang1 transplant end*/ return -EINVAL; }
/* * Process a received frame. The node associated with the sender * should be supplied. If nothing was found in the node table then * the caller is assumed to supply a reference to ic_bss instead. * The RSSI and a timestamp are also supplied. The RSSI data is used * during AP scanning to select a AP to associate with; it can have * any units so long as values have consistent units and higher values * mean ``better signal''. The receive timestamp is currently not used * by the 802.11 layer. */ int ieee80211_input(ieee80211com_t *ic, mblk_t *mp, struct ieee80211_node *in, int32_t rssi, uint32_t rstamp) { struct ieee80211_frame *wh; struct ieee80211_key *key; uint8_t *bssid; int hdrspace; int len; uint16_t rxseq; uint8_t dir; uint8_t type; uint8_t subtype; uint8_t tid; uint8_t qos; if (mp->b_flag & M_AMPDU) { /* * Fastpath for A-MPDU reorder q resubmission. Frames * w/ M_AMPDU marked have already passed through here * but were received out of order and been held on the * reorder queue. When resubmitted they are marked * with the M_AMPDU flag and we can bypass most of the * normal processing. */ IEEE80211_LOCK(ic); wh = (struct ieee80211_frame *)mp->b_rptr; type = IEEE80211_FC0_TYPE_DATA; dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; subtype = IEEE80211_FC0_SUBTYPE_QOS; hdrspace = ieee80211_hdrspace(ic, wh); /* optimize */ /* clear driver/net80211 flags before passing up */ mp->b_flag &= ~M_AMPDU; goto resubmit_ampdu; } ASSERT(in != NULL); in->in_inact = in->in_inact_reload; type = (uint8_t)-1; /* undefined */ len = MBLKL(mp); if (len < sizeof (struct ieee80211_frame_min)) { ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: " "too short (1): len %u", len); goto out; } /* * Bit of a cheat here, we use a pointer for a 3-address * frame format but don't reference fields past outside * ieee80211_frame_min w/o first validating the data is * present. */ wh = (struct ieee80211_frame *)mp->b_rptr; if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != IEEE80211_FC0_VERSION_0) { ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: " "discard pkt with wrong version %x", wh->i_fc[0]); goto out; } dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; IEEE80211_LOCK(ic); if (!(ic->ic_flags & IEEE80211_F_SCAN)) { switch (ic->ic_opmode) { case IEEE80211_M_STA: bssid = wh->i_addr2; if (!IEEE80211_ADDR_EQ(bssid, in->in_bssid)) goto out_exit_mutex; break; case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: if (dir != IEEE80211_FC1_DIR_NODS) { bssid = wh->i_addr1; } else if (type == IEEE80211_FC0_TYPE_CTL) { bssid = wh->i_addr1; } else { if (len < sizeof (struct ieee80211_frame)) { ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: too short(2):" "len %u\n", len); goto out_exit_mutex; } bssid = wh->i_addr3; } if (type != IEEE80211_FC0_TYPE_DATA) break; /* * Data frame, validate the bssid. */ if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss->in_bssid) && !IEEE80211_ADDR_EQ(bssid, wifi_bcastaddr)) { /* not interested in */ ieee80211_dbg(IEEE80211_MSG_INPUT, "ieee80211_input: not to bss %s\n", ieee80211_macaddr_sprintf(bssid)); goto out_exit_mutex; } /* * For adhoc mode we cons up a node when it doesn't * exist. This should probably done after an ACL check. */ if (in == ic->ic_bss && ic->ic_opmode != IEEE80211_M_HOSTAP && !IEEE80211_ADDR_EQ(wh->i_addr2, in->in_macaddr)) { /* * Fake up a node for this newly * discovered member of the IBSS. */ in = ieee80211_fakeup_adhoc_node(&ic->ic_sta, wh->i_addr2); if (in == NULL) { /* NB: stat kept for alloc failure */ goto out_exit_mutex; } } break; default: goto out_exit_mutex; } in->in_rssi = (uint8_t)rssi; in->in_rstamp = rstamp; if (!(type & IEEE80211_FC0_TYPE_CTL)) { if (IEEE80211_QOS_HAS_SEQ(wh)) { tid = ((struct ieee80211_qosframe *)wh)-> i_qos[0] & IEEE80211_QOS_TID; if (TID_TO_WME_AC(tid) >= WME_AC_VI) ic->ic_wme.wme_hipri_traffic++; tid++; } else { tid = IEEE80211_NONQOS_TID; } rxseq = LE_16(*(uint16_t *)wh->i_seq); if ((in->in_flags & IEEE80211_NODE_HT) == 0 && (wh->i_fc[1] & IEEE80211_FC1_RETRY) && (rxseq - in->in_rxseqs[tid]) <= 0) { /* duplicate, discard */ ieee80211_dbg(IEEE80211_MSG_INPUT, "ieee80211_input: duplicate", "seqno <%u,%u> fragno <%u,%u> tid %u", rxseq >> IEEE80211_SEQ_SEQ_SHIFT, in->in_rxseqs[tid] >> IEEE80211_SEQ_SEQ_SHIFT, rxseq & IEEE80211_SEQ_FRAG_MASK, in->in_rxseqs[tid] & IEEE80211_SEQ_FRAG_MASK, tid); ic->ic_stats.is_rx_dups++; goto out_exit_mutex; } in->in_rxseqs[tid] = rxseq; } }
/* * Intercept management frames to collect beacon rssi data * and to do ibss merges. */ void ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf) { struct ieee80211vap *vap = ni->ni_vap; struct ath_softc *sc = vap->iv_ic->ic_softc; uint64_t tsf_beacon_old, tsf_beacon; uint64_t nexttbtt; int64_t tsf_delta; int32_t tsf_delta_bmiss; int32_t tsf_remainder; uint64_t tsf_beacon_target; int tsf_intval; tsf_beacon_old = ((uint64_t) le32dec(ni->ni_tstamp.data + 4)) << 32; tsf_beacon_old |= le32dec(ni->ni_tstamp.data); #define TU_TO_TSF(_tu) (((u_int64_t)(_tu)) << 10) tsf_intval = 1; if (ni->ni_intval > 0) { tsf_intval = TU_TO_TSF(ni->ni_intval); } #undef TU_TO_TSF /* * Call up first so subsequent work can use information * potentially stored in the node (e.g. for ibss merge). */ ATH_VAP(vap)->av_recv_mgmt(ni, m, subtype, rxs, rssi, nf); switch (subtype) { case IEEE80211_FC0_SUBTYPE_BEACON: /* * Only do the following processing if it's for * the current BSS. * * In scan and IBSS mode we receive all beacons, * which means we need to filter out stuff * that isn't for us or we'll end up constantly * trying to sync / merge to BSSes that aren't * actually us. */ if (IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid)) { /* update rssi statistics for use by the hal */ /* XXX unlocked check against vap->iv_bss? */ ATH_RSSI_LPF(sc->sc_halstats.ns_avgbrssi, rssi); tsf_beacon = ((uint64_t) le32dec(ni->ni_tstamp.data + 4)) << 32; tsf_beacon |= le32dec(ni->ni_tstamp.data); nexttbtt = ath_hal_getnexttbtt(sc->sc_ah); /* * Let's calculate the delta and remainder, so we can see * if the beacon timer from the AP is varying by more than * a few TU. (Which would be a huge, huge problem.) */ tsf_delta = (long long) tsf_beacon - (long long) tsf_beacon_old; tsf_delta_bmiss = tsf_delta / tsf_intval; /* * If our delta is greater than half the beacon interval, * let's round the bmiss value up to the next beacon * interval. Ie, we're running really, really early * on the next beacon. */ if (tsf_delta % tsf_intval > (tsf_intval / 2)) tsf_delta_bmiss ++; tsf_beacon_target = tsf_beacon_old + (((unsigned long long) tsf_delta_bmiss) * (long long) tsf_intval); /* * The remainder using '%' is between 0 .. intval-1. * If we're actually running too fast, then the remainder * will be some large number just under intval-1. * So we need to look at whether we're running * before or after the target beacon interval * and if we are, modify how we do the remainder * calculation. */ if (tsf_beacon < tsf_beacon_target) { tsf_remainder = -(tsf_intval - ((tsf_beacon - tsf_beacon_old) % tsf_intval)); } else { tsf_remainder = (tsf_beacon - tsf_beacon_old) % tsf_intval; } DPRINTF(sc, ATH_DEBUG_BEACON, "%s: old_tsf=%llu, new_tsf=%llu, target_tsf=%llu, delta=%lld, bmiss=%d, remainder=%d\n", __func__, (unsigned long long) tsf_beacon_old, (unsigned long long) tsf_beacon, (unsigned long long) tsf_beacon_target, (long long) tsf_delta, tsf_delta_bmiss, tsf_remainder); DPRINTF(sc, ATH_DEBUG_BEACON, "%s: tsf=%llu, nexttbtt=%llu, delta=%d\n", __func__, (unsigned long long) tsf_beacon, (unsigned long long) nexttbtt, (int32_t) tsf_beacon - (int32_t) nexttbtt + tsf_intval); /* We only do syncbeacon on STA VAPs; not on IBSS */ if (vap->iv_opmode == IEEE80211_M_STA && sc->sc_syncbeacon && ni == vap->iv_bss && (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP)) { DPRINTF(sc, ATH_DEBUG_BEACON, "%s: syncbeacon=1; syncing\n", __func__); /* * Resync beacon timers using the tsf of the beacon * frame we just received. */ ath_beacon_config(sc, vap); sc->sc_syncbeacon = 0; } } /* fall thru... */ case IEEE80211_FC0_SUBTYPE_PROBE_RESP: if (vap->iv_opmode == IEEE80211_M_IBSS && vap->iv_state == IEEE80211_S_RUN && ieee80211_ibss_merge_check(ni)) { uint32_t rstamp = sc->sc_lastrs->rs_tstamp; uint64_t tsf = ath_extend_tsf(sc, rstamp, ath_hal_gettsf64(sc->sc_ah)); /* * Handle ibss merge as needed; check the tsf on the * frame before attempting the merge. The 802.11 spec * says the station should change it's bssid to match * the oldest station with the same ssid, where oldest * is determined by the tsf. Note that hardware * reconfiguration happens through callback to * ath_newstate as the state machine will go from * RUN -> RUN when this happens. */ if (le64toh(ni->ni_tstamp.tsf) >= tsf) { DPRINTF(sc, ATH_DEBUG_STATE, "ibss merge, rstamp %u tsf %ju " "tstamp %ju\n", rstamp, (uintmax_t)tsf, (uintmax_t)ni->ni_tstamp.tsf); (void) ieee80211_ibss_merge(ni); } } break; } }
void ieee80211_recv_beacon_ibss(struct ieee80211_node *ni, wbuf_t wbuf, int subtype, struct ieee80211_rx_status *rs, ieee80211_scan_entry_t scan_entry) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; u_int16_t capinfo; int ibssmerge = 0; struct ieee80211_channelswitch_ie *chanie = NULL; struct ieee80211_extendedchannelswitch_ie *echanie = NULL; struct ieee80211_frame *wh; u_int64_t tsf; u_int8_t *quiet_elm = NULL; bool free_node = FALSE; #if ATH_SUPPORT_IBSS_DFS struct ieee80211_ibssdfs_ie *ibssdfsie = NULL; #endif /* ATH_SUPPORT_IBSS_DFS */ wh = (struct ieee80211_frame *)wbuf_header(wbuf); capinfo = ieee80211_scan_entry_capinfo(scan_entry); if (!(capinfo & IEEE80211_CAPINFO_IBSS)) return; OS_MEMCPY((u_int8_t *)&tsf, ieee80211_scan_entry_tsf(scan_entry), sizeof(tsf)); if (ni != ni->ni_bss_node) { OS_MEMCPY(ni->ni_tstamp.data, &tsf, sizeof(ni->ni_tstamp)); /* update activity indication */ ni->ni_beacon_rstamp = OS_GET_TIMESTAMP(); ni->ni_probe_ticks = 0; } /* * Check BBSID before updating our beacon configuration to make * sure the received beacon really belongs to our Adhoc network. */ if ((subtype == IEEE80211_FC0_SUBTYPE_BEACON) && ieee80211_vap_ready_is_set(vap) && (IEEE80211_ADDR_EQ(wh->i_addr3, ieee80211_node_get_bssid(vap->iv_bss)))) { /* * if the neighbor is not in the list, add it to the list. */ if (ni == ni->ni_bss_node) { ni = ieee80211_add_neighbor(ni, scan_entry); if (ni == NULL) { return; } OS_MEMCPY(ni->ni_tstamp.data, &tsf, sizeof(ni->ni_tstamp)); free_node = TRUE; } ni->ni_rssi = rs->rs_rssi; /* * record tsf of last beacon into bss node */ OS_MEMCPY(ni->ni_bss_node->ni_tstamp.data, &tsf, sizeof(ni->ni_tstamp)); /* * record absolute time of last beacon */ vap->iv_last_beacon_time = OS_GET_TIMESTAMP(); ic->ic_beacon_update(ni, rs->rs_rssi); #if ATH_SUPPORT_IBSS_WMM /* * check for WMM parameters */ if ((ieee80211_scan_entry_wmeparam_ie(scan_entry) != NULL) || (ieee80211_scan_entry_wmeinfo_ie(scan_entry) != NULL)) { /* Node is WMM-capable if WME IE (either subtype) is present */ ni->ni_ext_caps |= IEEE80211_NODE_C_QOS; /* QOS-enable */ ieee80211node_set_flag(ni, IEEE80211_NODE_QOS); } else { /* If WME IE not present node is not WMM capable */ ni->ni_ext_caps &= ~IEEE80211_NODE_C_QOS; ieee80211node_clear_flag(ni, IEEE80211_NODE_QOS); } #endif #if ATH_SUPPORT_IBSS_DFS if (ic->ic_curchan->ic_flagext & IEEE80211_CHAN_DFS) { //check and see if we need to update other info for ibss_dfsie ibssdfsie = (struct ieee80211_ibssdfs_ie *)ieee80211_scan_entry_ibssdfs_ie(scan_entry); if(ibssdfsie) { if (ieee80211_check_and_update_ibss_dfs(vap, ibssdfsie)) { ieee80211_ibss_beacon_update_start(ic); } } /* update info from DFS owner */ if(ibssdfsie){ if(IEEE80211_ADDR_EQ(wh->i_addr2, ibssdfsie->owner)) { if(OS_MEMCMP(ibssdfsie, &vap->iv_ibssdfs_ie_data, MIN_IBSS_DFS_IE_CONTENT_SIZE)) { if(le64_to_cpu(tsf) >= rs->rs_tstamp.tsf){ IEEE80211_ADDR_COPY(vap->iv_ibssdfs_ie_data.owner, ibssdfsie->owner); vap->iv_ibssdfs_ie_data.rec_interval = ibssdfsie->rec_interval; ieee80211_ibss_beacon_update_start(ic); } } } } /* check if owner and it is not transmitting ibssIE */ else if(IEEE80211_ADDR_EQ(wh->i_addr2, vap->iv_ibssdfs_ie_data.owner)){ IEEE80211_ADDR_COPY(vap->iv_ibssdfs_ie_data.owner, vap->iv_myaddr); vap->iv_ibssdfs_state = IEEE80211_IBSSDFS_OWNER; ieee80211_ibss_beacon_update_start(ic); } } #endif /* ATH_SUPPORT_IBSS_DFS */ /* * check for spectrum management */ if (capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) { chanie = (struct ieee80211_channelswitch_ie *) ieee80211_scan_entry_csa(scan_entry); #if ATH_SUPPORT_IBSS_DFS if(chanie) { OS_MEMCPY(&vap->iv_channelswitch_ie_data, chanie, sizeof(struct ieee80211_channelswitch_ie)); ieee80211_ibss_beacon_update_start(ic); } #endif /* ATH_SUPPORT_IBSS_DFS */ echanie = (struct ieee80211_extendedchannelswitch_ie *) ieee80211_scan_entry_xcsa(scan_entry); if ((!chanie) && (!echanie)) { quiet_elm = ieee80211_scan_entry_quiet(scan_entry); } } } /* * Handle ibss merge as needed; check the tsf on the * frame before attempting the merge. The 802.11 spec * says the station should change its bssid to match * the oldest station with the same ssid, where oldest * is determined by the tsf. Note that hardware * reconfiguration happens through callback to * ath as the state machine will go from * RUN -> RUN when this happens. */ if (ieee80211_vap_ready_is_set(vap) && (le64_to_cpu(tsf) >= rs->rs_tstamp.tsf)) { ibssmerge = ieee80211_ibss_merge(ni,scan_entry); } if (ibssmerge) { ieee80211_mlme_adhoc_merge_start(ni); } /* * RNWF-specific: indicate to NDIS about the potential association. * It should be done after IBSS merge, which is called from ath_beacon_update(). */ if (IEEE80211_ADDR_EQ(wh->i_addr3, ieee80211_node_get_bssid(ni))) { /* Indicate node joined IBSS */ if ((capinfo & IEEE80211_CAPINFO_RADIOMEAS) && ieee80211_vap_rrm_is_set(vap)) { if(ni->ni_assoc_state != IEEE80211_NODE_ADHOC_STATE_AUTH_ASSOC) ieee80211_set_node_rrm(ni,TRUE); } else { ieee80211_set_node_rrm(ni,FALSE); } ieee80211_mlme_adhoc_join_indication(ni, wbuf); /* notify mlme of beacon reception */ ieee80211_mlme_join_complete_adhoc(ni); } if (ibssmerge) { ieee80211_mlme_adhoc_merge_completion(ni); } if (quiet_elm) { ic->ic_set_quiet(ni, quiet_elm); } if (free_node == TRUE) { ieee80211_free_node(ni); } }
static int ieee80211_do_slow_print(struct ieee80211com *ic, int *did_print) { static const struct timeval merge_print_intvl = { .tv_sec = 1, .tv_usec = 0 }; if ((ic->ic_if.if_flags & IFF_LINK0) == 0) return 0; if (!*did_print && (ic->ic_if.if_flags & IFF_DEBUG) == 0 && !ratecheck(&ic->ic_last_merge_print, &merge_print_intvl)) return 0; *did_print = 1; return 1; } /* ieee80211_ibss_merge helps merge 802.11 ad hoc networks. The * convention, set by the Wireless Ethernet Compatibility Alliance * (WECA), is that an 802.11 station will change its BSSID to match * the "oldest" 802.11 ad hoc network, on the same channel, that * has the station's desired SSID. The "oldest" 802.11 network * sends beacons with the greatest TSF timestamp. * * Return ENETRESET if the BSSID changed, 0 otherwise. * * XXX Perhaps we should compensate for the time that elapses * between the MAC receiving the beacon and the host processing it * in ieee80211_ibss_merge. */ int ieee80211_ibss_merge(struct ieee80211com *ic, struct ieee80211_node *ni, u_int64_t local_tsft) { u_int64_t beacon_tsft; int did_print = 0, sign; union { u_int64_t word; u_int8_t tstamp[8]; } u; /* ensure alignment */ (void)memcpy(&u, &ni->ni_tstamp[0], sizeof(u)); beacon_tsft = letoh64(u.word); /* we are faster, let the other guy catch up */ if (beacon_tsft < local_tsft) sign = -1; else sign = 1; if (IEEE80211_ADDR_EQ(ni->ni_bssid, ic->ic_bss->ni_bssid)) { if (!ieee80211_do_slow_print(ic, &did_print)) return 0; printf("%s: tsft offset %s%llu\n", ic->ic_if.if_xname, (sign < 0) ? "-" : "", (sign < 0) ? (local_tsft - beacon_tsft) : (beacon_tsft - local_tsft)); return 0; } if (sign < 0) return 0; if (ieee80211_match_bss(ic, ni) != 0) return 0; if (ieee80211_do_slow_print(ic, &did_print)) { printf("%s: ieee80211_ibss_merge: bssid mismatch %s\n", ic->ic_if.if_xname, ether_sprintf(ni->ni_bssid)); printf("%s: my tsft %llu beacon tsft %llu\n", ic->ic_if.if_xname, local_tsft, beacon_tsft); printf("%s: sync TSF with %s\n", ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr)); } ic->ic_flags &= ~IEEE80211_F_SIBSS; /* negotiate rates with new IBSS */ ieee80211_fix_rate(ic, ni, IEEE80211_F_DOFRATE | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); if (ni->ni_rates.rs_nrates == 0) { if (ieee80211_do_slow_print(ic, &did_print)) { printf("%s: rates mismatch, BSSID %s\n", ic->ic_if.if_xname, ether_sprintf(ni->ni_bssid)); } return 0; } if (ieee80211_do_slow_print(ic, &did_print)) { printf("%s: sync BSSID %s -> ", ic->ic_if.if_xname, ether_sprintf(ic->ic_bss->ni_bssid)); printf("%s ", ether_sprintf(ni->ni_bssid)); printf("(from %s)\n", ether_sprintf(ni->ni_macaddr)); } ieee80211_node_newstate(ni, IEEE80211_STA_BSS); (*ic->ic_node_copy)(ic, ic->ic_bss, ni); return ENETRESET; }
static void hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni, const struct ieee80211_frame *wh, const struct ieee80211_meshprep_ie *prep) { struct ieee80211_mesh_state *ms = vap->iv_mesh; struct ieee80211_hwmp_state *hs = vap->iv_hwmp; struct ieee80211_mesh_route *rt = NULL; struct ieee80211_hwmp_route *hr; struct ieee80211com *ic = vap->iv_ic; struct ifnet *ifp = vap->iv_ifp; struct mbuf *m, *next; #ifdef IEEE80211_DEBUG char ethstr[ETHER_ADDRSTRLEN + 1]; #endif /* * Acceptance criteria: if the corresponding PREQ was not generated * by us and forwarding is disabled, discard this PREP. */ if (ni == vap->iv_bss || ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) return; if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) && !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) return; IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "received PREP from %s", kether_ntoa(prep->prep_targetaddr, ethstr)); rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr); if (rt == NULL) { /* * If we have no entry this could be a reply to a root PREQ. */ if (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) { rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr); if (rt == NULL) { IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "unable to add PREP path to %s", kether_ntoa(prep->prep_targetaddr, ethstr)); vap->iv_stats.is_mesh_rtaddfailed++; return; } IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2); rt->rt_nhops = prep->prep_hopcount; rt->rt_lifetime = prep->prep_lifetime; rt->rt_metric = prep->prep_metric; rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "add root path to %s nhops %d metric %d (PREP)", kether_ntoa(prep->prep_targetaddr, ethstr), rt->rt_nhops, rt->rt_metric); return; } return; } /* * Sequence number validation. */ hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq)) { IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "discard PREP from %s, old seq no %u <= %u", kether_ntoa(prep->prep_targetaddr, ethstr), prep->prep_targetseq, hr->hr_seq); return; } hr->hr_seq = prep->prep_targetseq; /* * If it's NOT for us, propagate the PREP. */ if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) && prep->prep_ttl > 1 && prep->prep_hopcount < hs->hs_maxhops) { struct ieee80211_meshprep_ie pprep; /* propagated PREP */ IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "propagate PREP from %s", kether_ntoa(prep->prep_targetaddr, ethstr)); memcpy(&pprep, prep, sizeof(pprep)); pprep.prep_hopcount += 1; pprep.prep_ttl -= 1; pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni); IEEE80211_ADDR_COPY(pprep.prep_targetaddr, vap->iv_myaddr); hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &pprep); } hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) { /* NB: never clobber a proxy entry */; IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "discard PREP for %s, route is marked PROXY", kether_ntoa(prep->prep_targetaddr, ethstr)); vap->iv_stats.is_hwmp_proxy++; } else if (prep->prep_origseq == hr->hr_origseq) { /* * Check if we already have a path to this node. * If we do, check if this path reply contains a * better route. */ if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 || (prep->prep_hopcount < rt->rt_nhops || prep->prep_metric < rt->rt_metric)) { IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "%s path to %s, hopcount %d:%d metric %d:%d", rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ? "prefer" : "update", kether_ntoa(prep->prep_origaddr, ethstr), rt->rt_nhops, prep->prep_hopcount, rt->rt_metric, prep->prep_metric); IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2); rt->rt_nhops = prep->prep_hopcount; rt->rt_lifetime = prep->prep_lifetime; rt->rt_metric = prep->prep_metric; rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID; } else { IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "ignore PREP for %s, hopcount %d:%d metric %d:%d", kether_ntoa(prep->prep_targetaddr, ethstr), rt->rt_nhops, prep->prep_hopcount, rt->rt_metric, prep->prep_metric); } } else { IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "discard PREP for %s, wrong seqno %u != %u", kether_ntoa(prep->prep_targetaddr, ethstr), prep->prep_origseq, hr->hr_seq); vap->iv_stats.is_hwmp_wrongseq++; } /* * Check for frames queued awaiting path discovery. * XXX probably can tell exactly and avoid remove call * NB: hash may have false matches, if so they will get * stuck back on the stageq because there won't be * a path. */ m = ieee80211_ageq_remove(&ic->ic_stageq, (struct ieee80211_node *)(uintptr_t) ieee80211_mac_hash(ic, rt->rt_dest)); for (; m != NULL; m = next) { next = m->m_nextpkt; m->m_nextpkt = NULL; IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "flush queued frame %p len %d", m, m->m_pkthdr.len); ieee80211_handoff(ifp, m); } }
static void hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni, const struct ieee80211_frame *wh, const struct ieee80211_meshpreq_ie *preq) { struct ieee80211_mesh_state *ms = vap->iv_mesh; struct ieee80211_mesh_route *rt = NULL; struct ieee80211_mesh_route *rtorig = NULL; struct ieee80211_hwmp_route *hrorig; struct ieee80211_hwmp_state *hs = vap->iv_hwmp; struct ieee80211_meshprep_ie prep; #ifdef IEEE80211_DEBUG char ethstr[ETHER_ADDRSTRLEN + 1]; #endif if (ni == vap->iv_bss || ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) return; /* * Ignore PREQs from us. Could happen because someone forward it * back to us. */ if (IEEE80211_ADDR_EQ(vap->iv_myaddr, preq->preq_origaddr)) return; IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "received PREQ, source %s", kether_ntoa(preq->preq_origaddr, ethstr)); /* * Acceptance criteria: if the PREQ is not for us and * forwarding is disabled, discard this PREQ. */ if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) && !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP, preq->preq_origaddr, NULL, "%s", "not accepting PREQ"); return; } rtorig = ieee80211_mesh_rt_find(vap, preq->preq_origaddr); if (rtorig == NULL) rtorig = ieee80211_mesh_rt_add(vap, preq->preq_origaddr); if (rtorig == NULL) { /* XXX stat */ return; } hrorig = IEEE80211_MESH_ROUTE_PRIV(rtorig, struct ieee80211_hwmp_route); /* * Sequence number validation. */ if (HWMP_SEQ_LEQ(preq->preq_id, hrorig->hr_preqid) && HWMP_SEQ_LEQ(preq->preq_origseq, hrorig->hr_seq)) { IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "discard PREQ from %s, old seq no %u <= %u", kether_ntoa(preq->preq_origaddr, ethstr), preq->preq_origseq, hrorig->hr_seq); return; } hrorig->hr_preqid = preq->preq_id; hrorig->hr_seq = preq->preq_origseq; /* * Check if the PREQ is addressed to us. */ if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) { IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "reply to %s", kether_ntoa(preq->preq_origaddr, ethstr)); /* * Build and send a PREP frame. */ prep.prep_flags = 0; prep.prep_hopcount = 0; prep.prep_ttl = ms->ms_ttl; IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr); prep.prep_targetseq = ++hs->hs_seq; prep.prep_lifetime = preq->preq_lifetime; prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL; IEEE80211_ADDR_COPY(prep.prep_origaddr, preq->preq_origaddr); prep.prep_origseq = preq->preq_origseq; hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep); /* * Build the reverse path, if we don't have it already. */ rt = ieee80211_mesh_rt_find(vap, preq->preq_origaddr); if (rt == NULL) hwmp_discover(vap, preq->preq_origaddr, NULL); else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) hwmp_discover(vap, rt->rt_dest, NULL); return; } /* * Proactive PREQ: reply with a proactive PREP to the * root STA if requested. */ if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr) && (PREQ_TFLAGS(0) & ((IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF) == (IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF)))) { uint8_t rootmac[IEEE80211_ADDR_LEN]; IEEE80211_ADDR_COPY(rootmac, preq->preq_origaddr); rt = ieee80211_mesh_rt_find(vap, rootmac); if (rt == NULL) { rt = ieee80211_mesh_rt_add(vap, rootmac); if (rt == NULL) { IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "unable to add root mesh path to %s", kether_ntoa(rootmac, ethstr)); vap->iv_stats.is_mesh_rtaddfailed++; return; } } IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "root mesh station @ %s", kether_ntoa(rootmac, ethstr)); /* * Reply with a PREP if we don't have a path to the root * or if the root sent us a proactive PREQ. */ if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 || (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) { prep.prep_flags = 0; prep.prep_hopcount = 0; prep.prep_ttl = ms->ms_ttl; IEEE80211_ADDR_COPY(prep.prep_origaddr, rootmac); prep.prep_origseq = preq->preq_origseq; prep.prep_lifetime = preq->preq_lifetime; prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL; IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr); prep.prep_targetseq = ++hs->hs_seq; hwmp_send_prep(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &prep); } hwmp_discover(vap, rootmac, NULL); return; } rt = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0)); /* * Forwarding and Intermediate reply for PREQs with 1 target. */ if (preq->preq_tcount == 1) { struct ieee80211_meshpreq_ie ppreq; /* propagated PREQ */ memcpy(&ppreq, preq, sizeof(ppreq)); /* * We have a valid route to this node. */ if (rt != NULL && (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) { if (preq->preq_ttl > 1 && preq->preq_hopcount < hs->hs_maxhops) { IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "forward PREQ from %s", kether_ntoa(preq->preq_origaddr, ethstr)); /* * Propagate the original PREQ. */ ppreq.preq_hopcount += 1; ppreq.preq_ttl -= 1; ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni); /* * Set TO and unset RF bits because we are going * to send a PREP next. */ ppreq.preq_targets[0].target_flags |= IEEE80211_MESHPREQ_TFLAGS_TO; ppreq.preq_targets[0].target_flags &= ~IEEE80211_MESHPREQ_TFLAGS_RF; hwmp_send_preq(ni, vap->iv_myaddr, broadcastaddr, &ppreq); } /* * Check if we can send an intermediate Path Reply, * i.e., Target Only bit is not set. */ if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) { struct ieee80211_meshprep_ie prep; IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "intermediate reply for PREQ from %s", kether_ntoa(preq->preq_origaddr, ethstr)); prep.prep_flags = 0; prep.prep_hopcount = rt->rt_nhops + 1; prep.prep_ttl = ms->ms_ttl; IEEE80211_ADDR_COPY(&prep.prep_targetaddr, PREQ_TADDR(0)); prep.prep_targetseq = hrorig->hr_seq; prep.prep_lifetime = preq->preq_lifetime; prep.prep_metric = rt->rt_metric + ms->ms_pmetric->mpm_metric(ni); IEEE80211_ADDR_COPY(&prep.prep_origaddr, preq->preq_origaddr); prep.prep_origseq = hrorig->hr_seq; hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &prep); } /* * We have no information about this path, * propagate the PREQ. */ } else if (preq->preq_ttl > 1 && preq->preq_hopcount < hs->hs_maxhops) { if (rt == NULL) { rt = ieee80211_mesh_rt_add(vap, PREQ_TADDR(0)); if (rt == NULL) { IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "unable to add PREQ path to %s", kether_ntoa(PREQ_TADDR(0), ethstr)); vap->iv_stats.is_mesh_rtaddfailed++; return; } } rt->rt_metric = preq->preq_metric; rt->rt_lifetime = preq->preq_lifetime; hrorig = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); hrorig->hr_seq = preq->preq_origseq; hrorig->hr_preqid = preq->preq_id; IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "forward PREQ from %s", kether_ntoa(preq->preq_origaddr, ethstr)); ppreq.preq_hopcount += 1; ppreq.preq_ttl -= 1; ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni); hwmp_send_preq(ni, vap->iv_myaddr, broadcastaddr, &ppreq); } } }
static struct ieee80211_node * hwmp_discover(struct ieee80211vap *vap, const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m) { struct ieee80211_hwmp_state *hs = vap->iv_hwmp; struct ieee80211_mesh_state *ms = vap->iv_mesh; struct ieee80211_mesh_route *rt = NULL; struct ieee80211_hwmp_route *hr; struct ieee80211_meshpreq_ie preq; struct ieee80211_node *ni; int sendpreq = 0; #ifdef IEEE80211_DEBUG char ethstr[ETHER_ADDRSTRLEN + 1]; #endif KASSERT(vap->iv_opmode == IEEE80211_M_MBSS, ("not a mesh vap, opmode %d", vap->iv_opmode)); KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest), ("%s: discovering self!", __func__)); ni = NULL; if (!IEEE80211_IS_MULTICAST(dest)) { rt = ieee80211_mesh_rt_find(vap, dest); if (rt == NULL) { rt = ieee80211_mesh_rt_add(vap, dest); if (rt == NULL) { IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "unable to add discovery path to %s", kether_ntoa(dest, ethstr)); vap->iv_stats.is_mesh_rtaddfailed++; goto done; } } hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route); if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) { if (hr->hr_origseq == 0) hr->hr_origseq = ++hs->hs_seq; rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL; rt->rt_lifetime = ticks_to_msecs(ieee80211_hwmp_pathtimeout); /* XXX check preq retries */ sendpreq = 1; if (m != NULL) { IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest, "%s", "start path discovery (src <none>)"); } else { IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP, dest, "start path discovery (src %s)", kether_ntoa( mtod(m, struct ether_header *)->ether_shost, ethstr)); } /* * Try to discover the path for this node. */ preq.preq_flags = 0; preq.preq_hopcount = 0; preq.preq_ttl = ms->ms_ttl; preq.preq_id = ++hs->hs_preqid; IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr); preq.preq_origseq = hr->hr_origseq; preq.preq_lifetime = rt->rt_lifetime; preq.preq_metric = rt->rt_metric; preq.preq_tcount = 1; IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest); PREQ_TFLAGS(0) = 0; if (ieee80211_hwmp_targetonly) PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO; if (ieee80211_hwmp_replyforward) PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_RF; PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN; PREQ_TSEQ(0) = 0; /* XXX check return value */ hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &preq); } if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) ni = ieee80211_find_txnode(vap, rt->rt_nexthop); } else {
/* * processes data frames. * ieee80211_wow_magic_parser parses the wbuf to check if match magic packet. */ void ieee80211_wow_magic_parser(struct ieee80211_node *ni, wbuf_t wbuf) { struct ieee80211vap *vap = ni->ni_vap; a_uint8_t i_addr[IEEE80211_ADDR_LEN]; a_int32_t left_len = wbuf_get_pktlen(wbuf); a_uint8_t *cur_ptr; a_uint32_t dup_cnt, is_match = FALSE, is_bcast = FALSE; //wow_dump_pkt(wbuf->data, wbuf->len); if (left_len < IEEE80211_WOW_MAGIC_PKTLEN) return; cur_ptr = wbuf_header(wbuf); IEEE80211_ADDR_COPY(i_addr, vap->iv_myaddr); /* parse whole pkt */ while (cur_ptr && (left_len>0) && (!is_match)) { /* left len is less than magic pkt size, give up */ if (left_len < IEEE80211_WOW_MAGIC_PKTLEN) break; /* to skip continuous 0xFF and to match last 6 bytes of 0xFF */ while (IEEE80211_IS_BROADCAST(cur_ptr) && (left_len>=IEEE80211_WOW_MAGIC_PKTLEN)) { is_bcast = TRUE; cur_ptr += IEEE80211_ADDR_LEN; left_len -= IEEE80211_ADDR_LEN; } /* 6 bytes of 0xFF matched, to check if 16 duplications of the IEEE address */ if (is_bcast) { dup_cnt = 0; /* if 0xFF exists at head, skip it */ while ((cur_ptr[0]==0xFF) && (left_len>=IEEE80211_WOW_MAGIC_DUPLEN)) { cur_ptr++; left_len--; } /* left len is less than duplication size, give up */ if (left_len < IEEE80211_WOW_MAGIC_DUPLEN) break; /* to check if 16 duplications of the IEEE address */ while (cur_ptr && (left_len>=IEEE80211_ADDR_LEN) && IEEE80211_ADDR_EQ(cur_ptr, i_addr)) { cur_ptr += IEEE80211_ADDR_LEN; left_len -= IEEE80211_ADDR_LEN; dup_cnt++; if (dup_cnt >= IEEE80211_WOW_MAGIC_DUPCNT) { is_match = TRUE; break; } } /* not match magic pkt, keep parsing */ is_bcast = FALSE; } else { cur_ptr++; left_len--; } } if (is_match) { adf_os_print("Magic packet received...\n"); ieee80211_wow_set_gpio(vap); } }
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; }
static void tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype, int rssi, int nf) { struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_tdma_state *ts = vap->iv_tdma; if (subtype == IEEE80211_FC0_SUBTYPE_BEACON && (ic->ic_flags & IEEE80211_F_SCAN) == 0) { struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *); struct ieee80211_scanparams scan; if (ieee80211_parse_beacon(ni, m0, &scan) != 0) return; if (scan.tdma == NULL) { /* * TDMA stations must beacon a TDMA ie; ignore * any other station. * XXX detect overlapping bss and change channel */ IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT, wh, ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], "%s", "no TDMA ie"); vap->iv_stats.is_rx_mgtdiscard++; return; } if (ni == vap->iv_bss && !IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) { /* * Fake up a node for this newly * discovered member of the IBSS. */ ni = ieee80211_add_neighbor(vap, wh, &scan); if (ni == NULL) { /* NB: stat kept for alloc failure */ return; } } /* * Check for state updates. */ if (IEEE80211_ADDR_EQ(wh->i_addr3, ni->ni_bssid)) { /* * Count frame now that we know it's to be processed. */ vap->iv_stats.is_rx_beacon++; IEEE80211_NODE_STAT(ni, rx_beacons); /* * Record tsf of last beacon. NB: this must be * done before calling tdma_process_params * as deeper routines reference it. */ memcpy(&ni->ni_tstamp.data, scan.tstamp, sizeof(ni->ni_tstamp.data)); /* * Count beacon frame for s/w bmiss handling. */ vap->iv_swbmiss_count++; /* * Process tdma ie. The contents are used to sync * the slot timing, reconfigure the bss, etc. */ (void) tdma_process_params(ni, scan.tdma, rssi, nf, wh); return; } /* * NB: defer remaining work to the adhoc code; this causes * 2x parsing of the frame but should happen infrequently */ }
int ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni) { u_int8_t rate; int fail; fail = 0; if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) fail |= 0x01; if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && ni->ni_chan != ic->ic_des_chan) fail |= 0x01; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_IBSS) { if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) fail |= 0x02; } else #endif { if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) fail |= 0x02; } if (ic->ic_flags & (IEEE80211_F_WEPON | IEEE80211_F_RSNON)) { if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) fail |= 0x04; } else { if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) fail |= 0x04; } rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DONEGO); if (rate & IEEE80211_RATE_BASIC) fail |= 0x08; if (ic->ic_des_esslen != 0 && (ni->ni_esslen != ic->ic_des_esslen || memcmp(ni->ni_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0)) fail |= 0x10; if ((ic->ic_flags & IEEE80211_F_DESBSSID) && !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid)) fail |= 0x20; if (ic->ic_flags & IEEE80211_F_RSNON) { /* * If at least one RSN IE field from the AP's RSN IE fails * to overlap with any value the STA supports, the STA shall * decline to associate with that AP. */ if ((ni->ni_rsnprotos & ic->ic_rsnprotos) == 0) fail |= 0x40; if ((ni->ni_rsnakms & ic->ic_rsnakms) == 0) fail |= 0x40; if ((ni->ni_rsnakms & ic->ic_rsnakms & ~(IEEE80211_AKM_PSK | IEEE80211_AKM_SHA256_PSK)) == 0) { /* AP only supports PSK AKMPs */ if (!(ic->ic_flags & IEEE80211_F_PSK)) fail |= 0x40; } if (ni->ni_rsngroupcipher != IEEE80211_CIPHER_WEP40 && ni->ni_rsngroupcipher != IEEE80211_CIPHER_TKIP && ni->ni_rsngroupcipher != IEEE80211_CIPHER_CCMP && ni->ni_rsngroupcipher != IEEE80211_CIPHER_WEP104) fail |= 0x40; if ((ni->ni_rsnciphers & ic->ic_rsnciphers) == 0) fail |= 0x40; /* we only support BIP as the IGTK cipher */ if ((ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC) && ni->ni_rsngroupmgmtcipher != IEEE80211_CIPHER_BIP) fail |= 0x40; /* we do not support MFP but AP requires it */ if (!(ic->ic_caps & IEEE80211_C_MFP) && (ni->ni_rsncaps & IEEE80211_RSNCAP_MFPR)) fail |= 0x40; /* we require MFP but AP does not support it */ if ((ic->ic_caps & IEEE80211_C_MFP) && (ic->ic_flags & IEEE80211_F_MFPR) && !(ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC)) fail |= 0x40; } #ifdef IEEE80211_DEBUG if (ic->ic_if.if_flags & IFF_DEBUG) { printf(" %c %s", fail ? '-' : '+', ether_sprintf(ni->ni_macaddr)); printf(" %s%c", ether_sprintf(ni->ni_bssid), fail & 0x20 ? '!' : ' '); printf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan), fail & 0x01 ? '!' : ' '); printf(" %+4d", ni->ni_rssi); printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, fail & 0x08 ? '!' : ' '); printf(" %4s%c", (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : "????", fail & 0x02 ? '!' : ' '); printf(" %7s%c ", (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? "privacy" : "no", fail & 0x04 ? '!' : ' '); printf(" %3s%c ", (ic->ic_flags & IEEE80211_F_RSNON) ? "rsn" : "no", fail & 0x40 ? '!' : ' '); ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); printf("%s\n", fail & 0x10 ? "!" : ""); } #endif return fail; }