/* * 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); }
/* * Update the dynamic parts of a beacon frame based on the current state. */ int ieee80211_beacon_update(struct ieee80211_node *ni, struct ieee80211_beacon_offsets *bo, struct sk_buff *skb, int mcast) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; int len_changed = 0; u_int16_t capinfo; IEEE80211_LOCK(ic); if ((ic->ic_flags & IEEE80211_F_DOTH) && (vap->iv_flags & IEEE80211_F_CHANSWITCH) && (vap->iv_chanchange_count == ic->ic_chanchange_tbtt)) { u_int8_t *frm; struct ieee80211_channel *c; vap->iv_chanchange_count = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, "%s: reinit beacon\n", __func__); /* * NB: ic_bsschan is in the DSPARMS beacon IE, so must set this * prior to the beacon re-init, below. */ c = ieee80211_doth_findchan(vap, ic->ic_chanchange_chan); if (c == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, "%s: find channel failure\n", __func__); IEEE80211_UNLOCK(ic); return 0; } ic->ic_bsschan = c; skb_pull(skb, sizeof(struct ieee80211_frame)); skb_trim(skb, 0); frm = skb->data; skb_put(skb, ieee80211_beacon_init(ni, bo, frm) - frm); skb_push(skb, sizeof(struct ieee80211_frame)); vap->iv_flags &= ~IEEE80211_F_CHANSWITCH; ic->ic_flags &= ~IEEE80211_F_CHANSWITCH; /* NB: only for the first VAP to get here */ if (ic->ic_curchan != c) { ic->ic_curchan = c; ic->ic_set_channel(ic); } len_changed = 1; } /* XXX faster to recalculate entirely or just changes? */ if (vap->iv_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (vap->iv_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ic->ic_bsschan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; if (ic->ic_flags & IEEE80211_F_DOTH) capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; *bo->bo_caps = htole16(capinfo); if (vap->iv_flags & IEEE80211_F_WME) { struct ieee80211_wme_state *wme = &ic->ic_wme; /* * Check for aggressive mode change. When there is * significant high priority traffic in the BSS * throttle back BE traffic by using conservative * parameters. Otherwise BE uses aggressive params * to optimize performance of legacy/non-QoS traffic. */ if (wme->wme_flags & WME_F_AGGRMODE) { if (wme->wme_hipri_traffic > wme->wme_hipri_switch_thresh) { IEEE80211_NOTE(vap, IEEE80211_MSG_WME, ni, "%s: traffic %u, disable aggressive mode", __func__, wme->wme_hipri_traffic); wme->wme_flags &= ~WME_F_AGGRMODE; ieee80211_wme_updateparams_locked(vap); wme->wme_hipri_traffic = wme->wme_hipri_switch_hysteresis; } else wme->wme_hipri_traffic = 0; } else { if (wme->wme_hipri_traffic <= wme->wme_hipri_switch_thresh) { IEEE80211_NOTE(vap, IEEE80211_MSG_WME, ni, "%s: traffic %u, enable aggressive mode", __func__, wme->wme_hipri_traffic); wme->wme_flags |= WME_F_AGGRMODE; ieee80211_wme_updateparams_locked(vap); wme->wme_hipri_traffic = 0; } else wme->wme_hipri_traffic = wme->wme_hipri_switch_hysteresis; } /* XXX multi-bss */ if (vap->iv_flags & IEEE80211_F_WMEUPDATE) { (void) ieee80211_add_wme_param(bo->bo_wme, wme, IEEE80211_VAP_UAPSD_ENABLED(vap)); vap->iv_flags &= ~IEEE80211_F_WMEUPDATE; } } if (vap->iv_opmode == IEEE80211_M_HOSTAP) { /* NB: no IBSS support*/ struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) bo->bo_tim; if (vap->iv_flags & IEEE80211_F_TIMUPDATE) { u_int timlen, timoff, i; /* * ATIM/DTIM needs updating. If it fits in the * current space allocated then just copy in the * new bits. Otherwise we need to move any trailing * data to make room. Note that we know there is * contiguous space because ieee80211_beacon_allocate * ensures there is space in the mbuf to write a * maximal-size virtual bitmap (based on ic_max_aid). */ /* * Calculate the bitmap size and offset, copy any * trailer out of the way, and then copy in the * new bitmap and update the information element. * Note that the tim bitmap must contain at least * one byte and any offset must be even. */ if (vap->iv_ps_pending != 0) { timoff = 128; /* impossibly large */ for (i = 0; i < vap->iv_tim_len; i++) if (vap->iv_tim_bitmap[i]) { timoff = i &~ 1; break; } KASSERT(timoff != 128, ("tim bitmap empty!")); for (i = vap->iv_tim_len-1; i >= timoff; i--) if (vap->iv_tim_bitmap[i]) break; timlen = 1 + (i - timoff); } else { timoff = 0; timlen = 1; } if (timlen != bo->bo_tim_len) { /* copy up/down trailer */ int trailer_adjust = (tie->tim_bitmap+timlen) - (bo->bo_tim_trailer); memmove(tie->tim_bitmap+timlen, bo->bo_tim_trailer, bo->bo_tim_trailerlen); bo->bo_tim_trailer = tie->tim_bitmap+timlen; bo->bo_chanswitch += trailer_adjust; bo->bo_wme += trailer_adjust; bo->bo_erp += trailer_adjust; bo->bo_ath_caps += trailer_adjust; bo->bo_xr += trailer_adjust; if (timlen > bo->bo_tim_len) skb_put(skb, timlen - bo->bo_tim_len); else skb_trim(skb, skb->len - (bo->bo_tim_len - timlen)); bo->bo_tim_len = timlen; /* update information element */ tie->tim_len = 3 + timlen; tie->tim_bitctl = timoff; len_changed = 1; } memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff, bo->bo_tim_len); vap->iv_flags &= ~IEEE80211_F_TIMUPDATE; IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "%s: TIM updated, pending %u, off %u, len %u", __func__, vap->iv_ps_pending, timoff, timlen); } /* count down DTIM period */ if (tie->tim_count == 0) tie->tim_count = tie->tim_period - 1; else tie->tim_count--; /* update state for buffered multicast frames on DTIM */ if (mcast && (tie->tim_count == 0)) tie->tim_bitctl |= 1; else tie->tim_bitctl &= ~1; if ((ic->ic_flags & IEEE80211_F_DOTH) && (ic->ic_flags & IEEE80211_F_CHANSWITCH)) { if (!vap->iv_chanchange_count) { vap->iv_flags |= IEEE80211_F_CHANSWITCH; /* copy out trailer to open up a slot */ memmove(bo->bo_chanswitch + IEEE80211_CHANSWITCHANN_BYTES, bo->bo_chanswitch, bo->bo_chanswitch_trailerlen); /* add ie in opened slot */ bo->bo_chanswitch[0] = IEEE80211_ELEMID_CHANSWITCHANN; bo->bo_chanswitch[1] = 3; /* fixed length */ bo->bo_chanswitch[2] = 1; /* stas get off for now */ bo->bo_chanswitch[3] = ic->ic_chanchange_chan; bo->bo_chanswitch[4] = ic->ic_chanchange_tbtt; /* update the trailer lens */ bo->bo_chanswitch_trailerlen += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_tim_trailerlen += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_wme += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_erp += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_ath_caps += IEEE80211_CHANSWITCHANN_BYTES; bo->bo_xr += IEEE80211_CHANSWITCHANN_BYTES; /* indicate new beacon length so other layers may manage memory */ skb_put(skb, IEEE80211_CHANSWITCHANN_BYTES); len_changed = 1; } else bo->bo_chanswitch[4]--; vap->iv_chanchange_count++; IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, "%s: CHANSWITCH IE, change in %d\n", __func__, bo->bo_chanswitch[4]); } #ifdef ATH_SUPERG_XR if (vap->iv_flags & IEEE80211_F_XRUPDATE) { if (vap->iv_xrvap) (void) ieee80211_add_xr_param(bo->bo_xr, vap); vap->iv_flags &= ~IEEE80211_F_XRUPDATE; } #endif if (ic->ic_flags_ext & IEEE80211_FEXT_ERPUPDATE) { (void) ieee80211_add_erp(bo->bo_erp, ic); ic->ic_flags_ext &= ~IEEE80211_FEXT_ERPUPDATE; } } /* if it is a mode change beacon for dynamic turbo case */ if (((ic->ic_ath_cap & IEEE80211_ATHC_BOOST) != 0) ^ IEEE80211_IS_CHAN_TURBO(ic->ic_curchan)) ieee80211_add_athAdvCap(bo->bo_ath_caps, vap->iv_bss->ni_ath_flags, vap->iv_bss->ni_ath_defkeyindex); /* add APP_IE buffer if app updated it */ if (vap->iv_flags_ext & IEEE80211_FEXT_APPIE_UPDATE) { /* adjust the buffer size if the size is changed */ if (vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length != bo->bo_appie_buf_len) { int diff_len; diff_len = vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length - bo->bo_appie_buf_len; if (diff_len > 0) skb_put(skb, diff_len); else skb_trim(skb, skb->len + diff_len); bo->bo_appie_buf_len = vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length; /* update the trailer lens */ bo->bo_chanswitch_trailerlen += diff_len; bo->bo_tim_trailerlen += diff_len; len_changed = 1; } memcpy(bo->bo_appie_buf,vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].ie, vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length); vap->iv_flags_ext &= ~IEEE80211_FEXT_APPIE_UPDATE; } IEEE80211_UNLOCK(ic); return len_changed; }
static u_int8_t * ieee80211_beacon_init(struct ieee80211_node *ni, struct ieee80211_beacon_offsets *bo, u_int8_t *frm) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; u_int16_t capinfo; struct ieee80211_rateset *rs = &ni->ni_rates; KASSERT(ic->ic_bsschan != IEEE80211_CHAN_ANYC, ("no bss chan")); /* XXX timestamp is set by hardware/driver */ memset(frm, 0, 8); frm += 8; /* beacon interval */ *(__le16 *)frm = htole16(ni->ni_intval); frm += 2; /* capability information */ if (vap->iv_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (vap->iv_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ic->ic_bsschan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; if (ic->ic_flags & IEEE80211_F_DOTH) capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; bo->bo_caps = (__le16 *)frm; *(__le16 *)frm = htole16(capinfo); frm += 2; /* ssid */ *frm++ = IEEE80211_ELEMID_SSID; if ((vap->iv_flags & IEEE80211_F_HIDESSID) == 0) { *frm++ = ni->ni_esslen; memcpy(frm, ni->ni_essid, ni->ni_esslen); frm += ni->ni_esslen; } else *frm++ = 0; /* supported rates */ frm = ieee80211_add_rates(frm, rs); /* XXX: better way to check this? */ /* XXX: how about DS ? */ if (!IEEE80211_IS_CHAN_FHSS(ic->ic_bsschan)) { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, ic->ic_bsschan); } bo->bo_tim = frm; /* IBSS/TIM */ if (vap->iv_opmode == IEEE80211_M_IBSS) { *frm++ = IEEE80211_ELEMID_IBSSPARMS; *frm++ = 2; *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ bo->bo_tim_len = 0; } else { struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; tie->tim_ie = IEEE80211_ELEMID_TIM; tie->tim_len = 4; /* length */ tie->tim_count = 0; /* DTIM count */ tie->tim_period = vap->iv_dtim_period; /* DTIM period */ tie->tim_bitctl = 0; /* bitmap control */ tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ frm += sizeof(struct ieee80211_tim_ie); bo->bo_tim_len = 1; } bo->bo_tim_trailer = frm; /* country */ if ((ic->ic_flags & IEEE80211_F_DOTH) || (ic->ic_flags_ext & IEEE80211_FEXT_COUNTRYIE)) { frm = ieee80211_add_country(frm, ic); } /* power constraint */ if (ic->ic_flags & IEEE80211_F_DOTH) { *frm++ = IEEE80211_ELEMID_PWRCNSTR; *frm++ = 1; *frm++ = IEEE80211_PWRCONSTRAINT_VAL(ic); } /* XXX: channel switch announcement ? */ bo->bo_chanswitch = frm; /* ERP */ if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan)) { bo->bo_erp = frm; frm = ieee80211_add_erp(frm, ic); } /* Ext. Supp. Rates */ frm = ieee80211_add_xrates(frm, rs); /* WME */ if (vap->iv_flags & IEEE80211_F_WME) { bo->bo_wme = frm; frm = ieee80211_add_wme_param(frm, &ic->ic_wme, IEEE80211_VAP_UAPSD_ENABLED(vap)); vap->iv_flags &= ~IEEE80211_F_WMEUPDATE; } /* WPA 1+2 */ if (vap->iv_flags & IEEE80211_F_WPA) frm = ieee80211_add_wpa(frm, vap); /* athAdvCaps */ bo->bo_ath_caps = frm; if (vap->iv_bss && vap->iv_bss->ni_ath_flags) frm = ieee80211_add_athAdvCap(frm, vap->iv_bss->ni_ath_flags, vap->iv_bss->ni_ath_defkeyindex); /* XR */ bo->bo_xr = frm; #ifdef ATH_SUPERG_XR if (vap->iv_xrvap && vap->iv_ath_cap & IEEE80211_ATHC_XR) /* XR */ frm = ieee80211_add_xr_param(frm, vap); #endif bo->bo_appie_buf = frm; bo->bo_appie_buf_len = 0; bo->bo_tim_trailerlen = frm - bo->bo_tim_trailer; bo->bo_chanswitch_trailerlen = frm - bo->bo_chanswitch; return frm; }
static u_int8_t * ieee80211_beacon_init(struct ieee80211_node *ni, struct ieee80211_beacon_offsets *bo, u_int8_t *frm) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; u_int16_t capinfo; struct ieee80211_rateset *rs = &ni->ni_rates; struct ieee80211_rsnparms *rsn = &vap->iv_rsn; int enable_htrates; bool add_wpa_ie = true; /*Begin: Added by zhanghu for increasing rate*/ ic->ic_rate_mask_bak = ic->ic_rate_mask; ic->ic_mcs_mask_bak = ic->ic_mcs_mask; /*End: Added by zhanghu for increasing rate*/ KASSERT(vap->iv_bsschan != IEEE80211_CHAN_ANYC, ("no bss chan")); OS_MEMZERO(frm, 8); /* XXX timestamp is set by hardware/driver */ frm += 8; *(u_int16_t *)frm = htole16(ieee80211_node_get_beacon_interval(ni)); 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(vap->iv_bsschan)) 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; if (IEEE80211_VAP_IS_PUREB_ENABLED(vap)) { capinfo &= ~IEEE80211_CAPINFO_SHORT_SLOTTIME; rs = &ic->ic_sup_rates[IEEE80211_MODE_11B]; } else if (IEEE80211_VAP_IS_PUREG_ENABLED(vap)) { ieee80211_setpuregbasicrates(rs); } bo->bo_caps = (u_int16_t *)frm; *(u_int16_t *)frm = htole16(capinfo); frm += 2; *frm++ = IEEE80211_ELEMID_SSID; if (IEEE80211_VAP_IS_HIDESSID_ENABLED(vap)) { *frm++ = 0; } else { /* AUTELAN-Added-Begin : &tuqiang for openessid */ #if 0 *frm++ = ni->ni_esslen; OS_MEMCPY(frm, ni->ni_essid, ni->ni_esslen); frm += ni->ni_esslen; #endif if(!(openessid_param & OPENESSID_ENABLE_MASK)){ /* openessid disable */ *frm++ = ni->ni_esslen; OS_MEMCPY(frm, ni->ni_essid, ni->ni_esslen); frm += ni->ni_esslen; } else { /* openessid enable */ int index; while(vap->iv_essid_be_cnt < 4) { index = vap->iv_essid_index[vap->iv_essid_be_cnt]; vap->iv_essid_be_cnt++; if(index < 0) continue; *frm++ = g_essid_table[index].len; OS_MEMCPY(frm, g_essid_table[index].essid, g_essid_table[index].len); frm += g_essid_table[index].len; break; /* break while */ } /* end while */ if(vap->iv_essid_be_cnt == 4){ vap->iv_essid_be_cnt = 0; } } /* AUTELAN-Added-End : [email protected] */ } frm = ieee80211_add_rates(frm, rs, ic); /* XXX better way to check this? */ if (!IEEE80211_IS_CHAN_FHSS(vap->iv_bsschan)) { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, vap->iv_bsschan); } bo->bo_tim = frm; if (vap->iv_opmode == IEEE80211_M_IBSS) { *frm++ = IEEE80211_ELEMID_IBSSPARMS; *frm++ = 2; *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ bo->bo_tim_len = 0; } else { struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; tie->tim_ie = IEEE80211_ELEMID_TIM; tie->tim_len = 4; /* length */ tie->tim_count = 0; /* DTIM count */ tie->tim_period = vap->iv_dtim_period; /* DTIM period */ tie->tim_bitctl = 0; /* bitmap control */ tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ frm += sizeof(struct ieee80211_tim_ie); bo->bo_tim_len = 1; } bo->bo_tim_trailer = frm; 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); } bo->bo_chanswitch = frm; #if ATH_SUPPORT_IBSS_DFS if (vap->iv_opmode == IEEE80211_M_IBSS) { if (ieee80211_ibss_dfs_element_enable(vap, ic)) { ieee80211_build_ibss_dfs_ie(vap); bo->bo_ibssdfs = frm; frm = ieee80211_add_ibss_dfs(frm,vap); } else { bo->bo_ibssdfs = NULL; OS_MEMZERO(&vap->iv_ibssdfs_ie_data, sizeof(struct ieee80211_ibssdfs_ie)); } } #endif /* ATH_SUPPORT_IBSS_DFS */ enable_htrates = ieee80211vap_htallowed(vap); if (IEEE80211_IS_CHAN_ANYG(vap->iv_bsschan) || IEEE80211_IS_CHAN_11NG(vap->iv_bsschan)) { bo->bo_erp = frm; 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_BEACON].length) { add_wpa_ie = ieee80211_check_wpaie(vap, vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].ie, vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].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); /* XXX: put IEs in the order of element IDs. */ 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, rs, ic); #ifdef E_CSA bo->bo_extchanswitch = frm; #endif /* E_CSA */ /* * HT cap. check for vap is done in ieee80211vap_htallowed. * TBD: remove iv_bsschan check to support multiple channel operation. */ if (IEEE80211_IS_CHAN_11N(vap->iv_bsschan) && enable_htrates) { bo->bo_htcap = frm; frm = ieee80211_add_htcap(frm, ni, IEEE80211_FC0_SUBTYPE_BEACON); bo->bo_htinfo = frm; frm = ieee80211_add_htinfo(frm, ni); if (!(ic->ic_flags & IEEE80211_F_COEXT_DISABLE)) { bo->bo_obss_scan = frm; frm = ieee80211_add_obss_scan(frm, ni); bo->bo_extcap = frm; 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 || #if ATH_SUPPORT_IBSS_WMM vap->iv_opmode == IEEE80211_M_IBSS || #endif vap->iv_opmode == IEEE80211_M_BTAMP)) { bo->bo_wme = frm; frm = ieee80211_add_wme_param(frm, &ic->ic_wme, IEEE80211_VAP_IS_UAPSD_ENABLED(vap)); vap->iv_flags &= ~IEEE80211_F_WMEUPDATE; } if ((IEEE80211_IS_CHAN_11N(vap->iv_bsschan)) && IEEE80211_IS_HTVIE_ENABLED(ic) && enable_htrates) { frm = ieee80211_add_htcap_vendor_specific(frm, ni,IEEE80211_FC0_SUBTYPE_BEACON); bo->bo_htinfo_vendor_specific = frm; frm = ieee80211_add_htinfo_vendor_specific(frm, ni); } bo->bo_ath_caps = frm; if (vap->iv_bss && 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); bo->bo_xr = frm; bo->bo_appie_buf = frm; bo->bo_appie_buf_len = 0; 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_BEACON].length > 0) { OS_MEMCPY(frm,vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].ie, vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].length); frm += vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].length; bo->bo_appie_buf_len = vap->iv_app_ie[IEEE80211_FRAME_TYPE_BEACON].length; } /* Add the Application IE's */ frm = ieee80211_mlme_app_ie_append(vap, IEEE80211_FRAME_TYPE_BEACON, frm); bo->bo_appie_buf_len += vap->iv_app_ie_list[IEEE80211_FRAME_TYPE_BEACON].total_ie_len; IEEE80211_VAP_UNLOCK(vap); bo->bo_tim_trailerlen = frm - bo->bo_tim_trailer; bo->bo_chanswitch_trailerlen = frm - bo->bo_chanswitch; #ifdef E_CSA bo->bo_extchanswitch_trailerlen = frm - bo->bo_extchanswitch; #endif /* E_CSA */ #if ATH_SUPPORT_IBSS_DFS if (vap->iv_opmode == IEEE80211_M_IBSS && (bo->bo_ibssdfs != NULL)) { struct ieee80211_ibssdfs_ie * ibss_dfs_ie = (struct ieee80211_ibssdfs_ie *)bo->bo_ibssdfs; bo->bo_ibssdfs_trailerlen = frm - (bo->bo_ibssdfs + 2 + ibss_dfs_ie->len); } #endif /* ATH_SUPPORT_IBSS_DFS */ return frm; }