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); } }
/* * Send a probe response frame. * NB: for probe response, the node may not represent the peer STA. * We could use BSS node to reduce the memory usage from temporary node. */ int ieee80211_send_proberesp(struct ieee80211_node *ni, u_int8_t *macaddr, const void *optie, const size_t optielen) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct ieee80211_rsnparms *rsn = &vap->iv_rsn; wbuf_t wbuf; struct ieee80211_frame *wh; u_int8_t *frm; u_int16_t capinfo; int enable_htrates; bool add_wpa_ie = true; ASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS || vap->iv_opmode == IEEE80211_M_BTAMP); wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, MAX_TX_RX_PACKET_SIZE); if (wbuf == NULL) return -ENOMEM; #ifdef IEEE80211_DEBUG_REFCNT printk("%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 wireless header */ wh = (struct ieee80211_frame *)wbuf_header(wbuf); ieee80211_send_setup(vap, ni, wh, IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP, vap->iv_myaddr, macaddr, ieee80211_node_get_bssid(ni)); frm = (u_int8_t *)&wh[1]; /* * probe response frame format * [8] time stamp * [2] beacon interval * [2] cabability information * [tlv] ssid * [tlv] supported rates * [tlv] parameter set (FH/DS) * [tlv] parameter set (IBSS) * [tlv] extended rate phy (ERP) * [tlv] extended supported rates * [tlv] country (if present) * [3] power constraint * [tlv] WPA * [tlv] WME * [tlv] HT Capabilities * [tlv] HT Information * [tlv] Atheros Advanced Capabilities */ OS_MEMZERO(frm, 8); /* timestamp should be filled later */ frm += 8; *(u_int16_t *)frm = htole16(vap->iv_bss->ni_intval); frm += 2; if (vap->iv_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (IEEE80211_VAP_IS_PRIVACY_ENABLED(vap)) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; if (ieee80211_ic_doth_is_set(ic) && ieee80211_vap_doth_is_set(vap)) capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; *(u_int16_t *)frm = htole16(capinfo); frm += 2; frm = ieee80211_add_ssid(frm, vap->iv_bss->ni_essid, vap->iv_bss->ni_esslen); frm = ieee80211_add_rates(frm, &vap->iv_bss->ni_rates, ic); if (!IEEE80211_IS_CHAN_FHSS(vap->iv_bsschan)) { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan); } if (vap->iv_opmode == IEEE80211_M_IBSS) { *frm++ = IEEE80211_ELEMID_IBSSPARMS; *frm++ = 2; *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ } if (IEEE80211_IS_COUNTRYIE_ENABLED(ic)) { frm = ieee80211_add_country(frm, vap); } if (ieee80211_ic_doth_is_set(ic) && ieee80211_vap_doth_is_set(vap)) { *frm++ = IEEE80211_ELEMID_PWRCNSTR; *frm++ = 1; *frm++ = IEEE80211_PWRCONSTRAINT_VAL(vap); } #if ATH_SUPPORT_IBSS_DFS if (vap->iv_opmode == IEEE80211_M_IBSS) { frm = ieee80211_add_ibss_dfs(frm,vap); } #endif if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) || IEEE80211_IS_CHAN_11NG(ic->ic_curchan)) { frm = ieee80211_add_erp(frm, ic); } /* * check if os shim has setup RSN IE it self. */ IEEE80211_VAP_LOCK(vap); if (vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].length) { add_wpa_ie = ieee80211_check_wpaie(vap, vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].ie, vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].length); } if (vap->iv_opt_ie.length) { add_wpa_ie = ieee80211_check_wpaie(vap, vap->iv_opt_ie.ie, vap->iv_opt_ie.length); } IEEE80211_VAP_UNLOCK(vap); if (add_wpa_ie) { if (RSN_AUTH_IS_RSNA(rsn)) frm = ieee80211_setup_rsn_ie(vap, frm); } #if ATH_SUPPORT_WAPI if (RSN_AUTH_IS_WAI(rsn)) frm = ieee80211_setup_wapi_ie(vap, frm); #endif frm = ieee80211_add_xrates(frm, &vap->iv_bss->ni_rates, ic); enable_htrates = ieee80211vap_htallowed(vap); if (IEEE80211_IS_CHAN_11N(ic->ic_curchan) && enable_htrates) { frm = ieee80211_add_htcap(frm, ni, IEEE80211_FC0_SUBTYPE_PROBE_RESP); if (!IEEE80211_IS_HTVIE_ENABLED(ic)) frm = ieee80211_add_htcap_pre_ana(frm, ni, IEEE80211_FC0_SUBTYPE_PROBE_RESP); frm = ieee80211_add_htinfo(frm, ni); if (!IEEE80211_IS_HTVIE_ENABLED(ic)) frm = ieee80211_add_htinfo_pre_ana(frm, ni); if (!(ic->ic_flags & IEEE80211_F_COEXT_DISABLE)) { frm = ieee80211_add_obss_scan(frm, ni); frm = ieee80211_add_extcap(frm, ni); } } if (add_wpa_ie) { if (RSN_AUTH_IS_WPA(rsn)) frm = ieee80211_setup_wpa_ie(vap, frm); } if (ieee80211_vap_wme_is_set(vap) && (vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_BTAMP)) /* don't support WMM in ad-hoc for now */ frm = ieee80211_add_wme_param(frm, &ic->ic_wme, IEEE80211_VAP_IS_UAPSD_ENABLED(vap)); if ((IEEE80211_IS_CHAN_11N(ic->ic_curchan)) && (IEEE80211_IS_HTVIE_ENABLED(ic)) && enable_htrates) { frm = ieee80211_add_htcap_vendor_specific(frm, ni, IEEE80211_FC0_SUBTYPE_PROBE_RESP); frm = ieee80211_add_htinfo_vendor_specific(frm, ni); } if (vap->iv_bss->ni_ath_flags) { frm = ieee80211_add_athAdvCap(frm, vap->iv_bss->ni_ath_flags, vap->iv_bss->ni_ath_defkeyindex); } else { frm = ieee80211_add_athAdvCap(frm, 0, IEEE80211_INVAL_DEFKEY); } /* Insert ieee80211_ie_ath_extcap IE to beacon */ if (ic->ic_ath_extcap) frm = ieee80211_add_athextcap(frm, ic->ic_ath_extcap, ic->ic_weptkipaggr_rxdelim); #ifdef notyet if (ni->ni_ath_ie != NULL) /* XXX */ frm = ieee80211_add_ath(frm, ni); #endif IEEE80211_VAP_LOCK(vap); if (vap->iv_opt_ie.length) { OS_MEMCPY(frm, vap->iv_opt_ie.ie, vap->iv_opt_ie.length); frm += vap->iv_opt_ie.length; } if (vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].length) { OS_MEMCPY(frm, vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].ie, vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].length); frm += vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].length; } /* Add the Application IE's */ frm = ieee80211_mlme_app_ie_append(vap, IEEE80211_FRAME_TYPE_PROBERESP, frm); IEEE80211_VAP_UNLOCK(vap); if (optie != NULL && optielen != 0) { OS_MEMCPY(frm, optie, optielen); frm += optielen; } wbuf_set_pktlen(wbuf, (frm - (u_int8_t *)wbuf_header(wbuf))); return ieee80211_send_mgmt(vap,ni, wbuf,true); }