示例#1
0
static char
channel_type(const struct ieee80211_channel *c)
{
	if (IEEE80211_IS_CHAN_ST(c))
		return 'S';
	if (IEEE80211_IS_CHAN_108A(c))
		return 'T';
	if (IEEE80211_IS_CHAN_108G(c))
		return 'G';
	if (IEEE80211_IS_CHAN_HT(c))
		return 'n';
	if (IEEE80211_IS_CHAN_A(c))
		return 'a';
	if (IEEE80211_IS_CHAN_ANYG(c))
		return 'g';
	if (IEEE80211_IS_CHAN_B(c))
		return 'b';
	return 'f';
}
示例#2
0
/*
 * Fill in 802.11 available channel set, mark
 * all available channels as active, and pick
 * a default channel if not already specified.
 */
static void
ieee80211_chan_init(struct ieee80211com *ic)
{
#define	DEFAULTRATES(m, def) do { \
	if (ic->ic_sup_rates[m].rs_nrates == 0) \
		ic->ic_sup_rates[m] = def; \
} while (0)
	struct ieee80211_channel *c;
	int i;

	KASSERT(0 < ic->ic_nchans && ic->ic_nchans <= IEEE80211_CHAN_MAX,
		("invalid number of channels specified: %u", ic->ic_nchans));
	memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail));
	memset(ic->ic_modecaps, 0, sizeof(ic->ic_modecaps));
	setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO);
	for (i = 0; i < ic->ic_nchans; i++) {
		c = &ic->ic_channels[i];
		KASSERT(c->ic_flags != 0, ("channel with no flags"));
		/*
		 * Help drivers that work only with frequencies by filling
		 * in IEEE channel #'s if not already calculated.  Note this
		 * mimics similar work done in ieee80211_setregdomain when
		 * changing regulatory state.
		 */
		if (c->ic_ieee == 0)
			c->ic_ieee = ieee80211_mhz2ieee(c->ic_freq,c->ic_flags);
		if (IEEE80211_IS_CHAN_HT40(c) && c->ic_extieee == 0)
			c->ic_extieee = ieee80211_mhz2ieee(c->ic_freq +
			    (IEEE80211_IS_CHAN_HT40U(c) ? 20 : -20),
			    c->ic_flags);
		/* default max tx power to max regulatory */
		if (c->ic_maxpower == 0)
			c->ic_maxpower = 2*c->ic_maxregpower;
		setbit(ic->ic_chan_avail, c->ic_ieee);
		/*
		 * Identify mode capabilities.
		 */
		if (IEEE80211_IS_CHAN_A(c))
			setbit(ic->ic_modecaps, IEEE80211_MODE_11A);
		if (IEEE80211_IS_CHAN_B(c))
			setbit(ic->ic_modecaps, IEEE80211_MODE_11B);
		if (IEEE80211_IS_CHAN_ANYG(c))
			setbit(ic->ic_modecaps, IEEE80211_MODE_11G);
		if (IEEE80211_IS_CHAN_FHSS(c))
			setbit(ic->ic_modecaps, IEEE80211_MODE_FH);
		if (IEEE80211_IS_CHAN_108A(c))
			setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_A);
		if (IEEE80211_IS_CHAN_108G(c))
			setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_G);
		if (IEEE80211_IS_CHAN_ST(c))
			setbit(ic->ic_modecaps, IEEE80211_MODE_STURBO_A);
		if (IEEE80211_IS_CHAN_HALF(c))
			setbit(ic->ic_modecaps, IEEE80211_MODE_HALF);
		if (IEEE80211_IS_CHAN_QUARTER(c))
			setbit(ic->ic_modecaps, IEEE80211_MODE_QUARTER);
		if (IEEE80211_IS_CHAN_HTA(c))
			setbit(ic->ic_modecaps, IEEE80211_MODE_11NA);
		if (IEEE80211_IS_CHAN_HTG(c))
			setbit(ic->ic_modecaps, IEEE80211_MODE_11NG);
	}
	/* initialize candidate channels to all available */
	memcpy(ic->ic_chan_active, ic->ic_chan_avail,
		sizeof(ic->ic_chan_avail));

	/* sort channel table to allow lookup optimizations */
	ieee80211_sort_channels(ic->ic_channels, ic->ic_nchans);

	/* invalidate any previous state */
	ic->ic_bsschan = IEEE80211_CHAN_ANYC;
	ic->ic_prevchan = NULL;
	ic->ic_csa_newchan = NULL;
	/* arbitrarily pick the first channel */
	ic->ic_curchan = &ic->ic_channels[0];
	ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan);

	/* fillin well-known rate sets if driver has not specified */
	DEFAULTRATES(IEEE80211_MODE_11B,	 ieee80211_rateset_11b);
	DEFAULTRATES(IEEE80211_MODE_11G,	 ieee80211_rateset_11g);
	DEFAULTRATES(IEEE80211_MODE_11A,	 ieee80211_rateset_11a);
	DEFAULTRATES(IEEE80211_MODE_TURBO_A,	 ieee80211_rateset_11a);
	DEFAULTRATES(IEEE80211_MODE_TURBO_G,	 ieee80211_rateset_11g);
	DEFAULTRATES(IEEE80211_MODE_STURBO_A,	 ieee80211_rateset_11a);
	DEFAULTRATES(IEEE80211_MODE_HALF,	 ieee80211_rateset_half);
	DEFAULTRATES(IEEE80211_MODE_QUARTER,	 ieee80211_rateset_quarter);
	DEFAULTRATES(IEEE80211_MODE_11NA,	 ieee80211_rateset_11a);
	DEFAULTRATES(IEEE80211_MODE_11NG,	 ieee80211_rateset_11g);

	/*
	 * Set auto mode to reset active channel state and any desired channel.
	 */
	(void) ieee80211_setmode(ic, IEEE80211_MODE_AUTO);
#undef DEFAULTRATES
}
示例#3
0
/*
 * Handle a station leaving an 11g network.
 */
static void
ieee80211_node_leave_11g(struct ieee80211_node *ni)
{
    struct ieee80211com *ic = ni->ni_ic;
    struct ieee80211vap *vap = ni->ni_vap;
   
    KASSERT((IEEE80211_IS_CHAN_ANYG(vap->iv_bsschan)
             || IEEE80211_IS_CHAN_11NG(vap->iv_bsschan)),
            ("not in 11g, bss %u:0x%x, curmode %u", vap->iv_bsschan->ic_freq,
             vap->iv_bsschan->ic_flags, ic->ic_curmode));

    KASSERT((ni->ni_vap->iv_opmode == IEEE80211_M_HOSTAP ||
             ni->ni_vap->iv_opmode == IEEE80211_M_BTAMP), (" node leave in invalid opmode "));

    /*
     * If a long slot station do the slot time bookkeeping.
     */
    if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) {
        if (ic->ic_longslotsta) {
           ic->ic_longslotsta--; 
           IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
                       "long slot time station leaves, count now %d",
                       ic->ic_longslotsta);
        } else {
#ifdef NOT_YET
           KASSERT(ic->ic_longslotsta > 0,
                ("bogus long slot station count %d", ic->ic_longslotsta));
#endif
           IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
                "bogus long slot station count %d", ic->ic_longslotsta);
        }

        if (ic->ic_longslotsta == 0) {
            /*
             * Re-enable use of short slot time if supported
             * and not operating in IBSS mode (per spec).
             */
            if (ic->ic_caps & IEEE80211_C_SHSLOT) {
                IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
                                  "%s: re-enable use of short slot time\n",
                                  __func__);
                ieee80211_set_shortslottime(ic, 1);
            }
        }
    }
    
    /*
     * If a non-ERP station do the protection-related bookkeeping.
     */
    if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) {
        KASSERT(ic->ic_nonerpsta > 0, ("bogus non-ERP station count %d", ic->ic_nonerpsta));
        ic->ic_nonerpsta--;
        IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
                       "non-ERP station leaves, count now %d", ic->ic_nonerpsta);
        if (ic->ic_nonerpsta == 0) {
	    struct ieee80211vap *tmpvap;
            ieee80211_update_erp_info(vap); 
            /* XXX verify mode? */
            if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) {
                IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
                                  "%s: re-enable use of short preamble\n",
                                  __func__);
                ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
                ic->ic_flags &= ~IEEE80211_F_USEBARKER;
            }
 	    TAILQ_FOREACH(tmpvap, &(ic)->ic_vaps, iv_next)
		ieee80211_vap_erpupdate_set(tmpvap);
        }
    }
}
示例#4
0
/*
 * function to handle station joining infrastructure network.
 * used for AP mode vap only.
 */  
int ieee80211_node_join(struct ieee80211_node *ni)
{
    struct ieee80211com *ic = ni->ni_ic;
    struct ieee80211vap *vap = ni->ni_vap;

    IEEE80211_NODE_STATE_LOCK(ni);
    if (ni->ni_associd == 0) {
        u_int16_t aid;

        if (vap->iv_aid_bitmap == NULL || IEEE80211_IS_TDLS_NODE(ni)) {
            IEEE80211_NODE_STATE_UNLOCK(ni);
            return -1; /* vap is being deleted */
        }

        /*
         * It would be good to search the bitmap
         * more efficiently, but this will do for now.
         */
        if (!IEEE80211_IS_TDLS_NODE(ni)) {
        for (aid = 1; aid < vap->iv_max_aid; aid++) {
            if (!IEEE80211_AID_ISSET(vap, aid))
                break;
        }

        if (aid >= vap->iv_max_aid) {
            /*
             * Keep stats on this situation.
             */
            IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, "aid (%d)"
                              " greater than max aid (%d)\n", aid,
                              vap->iv_max_aid);
            IEEE80211_NODE_STATE_UNLOCK(ni);
            IEEE80211_NODE_LEAVE(ni);
            return -1;
        }

        ni->ni_associd = aid | 0xc000;
        IEEE80211_AID_SET(vap, ni->ni_associd);
	} else {
            /* To keep the other parts of code happy. Otherwise the code assumes
             * node disconnected and tries to delete it.There are no associd for
            * TDLS nodes.
            */
            ni->ni_associd = vap->iv_bss->ni_associd;
        }

        vap->iv_sta_assoc++;
        ic->ic_sta_assoc++;
        /* Update bss load element in beacon */
        ieee80211_vap_bssload_update_set(vap);
        if ((ni->ni_flags & IEEE80211_NODE_HT) &&
            (ni->ni_flags & IEEE80211_NODE_40_INTOLERANT)) {
            ieee80211_change_cw(ic);
        }
        if (IEEE80211_IS_AMPDU_ENABLED(ic)) {
            ieee80211node_clear_flag(ni, IEEE80211_NODE_NOAMPDU);
        }
        else {
            ieee80211node_set_flag(ni, IEEE80211_NODE_NOAMPDU);
        }
        if (IEEE80211_NODE_USEAMPDU(ni)) {
            ic->ic_ht_sta_assoc++;
            if (ni->ni_htcap & IEEE80211_HTCAP_C_GREENFIELD)
                ic->ic_ht_gf_sta_assoc++;
        }
        if (ni->ni_chwidth == IEEE80211_CWM_WIDTH40)
            ic->ic_ht40_sta_assoc++;
        if ((IEEE80211_IS_CHAN_ANYG(vap->iv_bsschan) ||
            IEEE80211_IS_CHAN_11NG(vap->iv_bsschan)) && !IEEE80211_IS_TDLS_NODE(ni))
            ieee80211_node_join_11g(ni);
    }
#if ATH_SUPPORT_WIFIPOS
    // Time stamp to send in status response
    ni->last_rx_desc_tsf = ic->ic_get_TSF32(ic);
#endif
    ni->ni_inact_reload = ni->ni_vap->iv_inact_auth;
    ni->ni_inact = ni->ni_inact_reload;
    
    /* Multicast enhancement: If the entry with the node's address exists in 
     * the snoop table, it should be removed.
     */
    if (vap->iv_ique_ops.me_clean) {
        vap->iv_ique_ops.me_clean(ni);
    }
    /*
     * HBR / headline block removal: add the node entity to the table
     * for HBR purpose
     */
    if (vap->iv_ique_ops.hbr_nodejoin) {
        vap->iv_ique_ops.hbr_nodejoin(vap, ni);
    }
    IEEE80211_NODE_STATE_UNLOCK(ni);
    IEEE80211_ADD_NODE_TARGET(ni, ni->ni_vap, 0);
	return 0;
}
示例#5
0
/*
 * Handle a station joining an 11g network.
 */
static void
ieee80211_node_join_11g(struct ieee80211_node *ni)
{
    struct ieee80211com *ic = ni->ni_ic;
    struct ieee80211vap *vap = ni->ni_vap;

    KASSERT((IEEE80211_IS_CHAN_ANYG(vap->iv_bsschan) ||
             IEEE80211_IS_CHAN_11NG(vap->iv_bsschan)),
            ("not in 11g, bss %u:0x%x, curmode %u", vap->iv_bsschan->ic_freq,
             vap->iv_bsschan->ic_flags, ic->ic_curmode));

    KASSERT((ni->ni_vap->iv_opmode == IEEE80211_M_HOSTAP ||
             ni->ni_vap->iv_opmode == IEEE80211_M_BTAMP), (" node join in invalid opmode "));
    /*
     * Station isn't capable of short slot time.  Bump
     * the count of long slot time stations and disable
     * use of short slot time.  Note that the actual switch
     * over to long slot time use may not occur until the
     * next beacon transmission (per sec. 7.3.1.4 of 11g).
     */
    if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) {
        ic->ic_longslotsta++;
        IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
                       "station needs long slot time, count %d",
                       ic->ic_longslotsta);
        /* XXX vap's w/ conflicting needs won't work */
        if (!IEEE80211_IS_CHAN_108G(vap->iv_bsschan)) {
            /*
             * Don't force slot time when switched to turbo
             * mode as non-ERP stations won't be present; this
             * need only be done when on the normal G channel.
             */
            ieee80211_set_shortslottime(ic, 0);
        }
    }
    /*
     * If the new station is not an ERP station
     * then bump the counter and enable protection
     * if configured.
     */
    if (!ieee80211_iserp_rateset(ic, &ni->ni_rates)) {
        ic->ic_nonerpsta++;
        IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
                       "station is !ERP, %d non-ERP stations associated",
                       ic->ic_nonerpsta);
            /*
             * If protection is configured, enable it.
             */
            if (ic->ic_protmode != IEEE80211_PROT_NONE) {
                IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC,
                                  "%s: enable use of protection\n", __func__);
                ic->ic_flags |= IEEE80211_F_USEPROT;
                ic->ic_update_protmode(ic);
            }
            /*
             * If station does not support short preamble
             * then we must enable use of Barker preamble.
             */
            if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) {
                IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
                               "%s", "station needs long preamble");
                ic->ic_flags |= IEEE80211_F_USEBARKER;
                ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
            }

            /* Update ERP element if this is first non ERP station */
            if (ic->ic_nonerpsta == 1) {
	          struct ieee80211vap *tmpvap;
	          TAILQ_FOREACH(tmpvap, &(ic)->ic_vaps, iv_next)
		    ieee80211_vap_erpupdate_set(tmpvap);
	      }
    } else
        ni->ni_flags |= IEEE80211_NODE_ERP;
}
示例#6
0
bool _ieee80211_node_leave(struct ieee80211_node *ni)
#endif
{
    struct ieee80211com *ic = ni->ni_ic;
    struct ieee80211vap *vap = ni->ni_vap;
	bool   retval = false;
#ifdef IEEE80211_DEBUG_REFCNT
    TRACENODE(ni, func, line);
#endif
    IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni,
                   "station with aid %d leaves (refcnt %u) \n",
                   IEEE80211_NODE_AID(ni), ieee80211_node_refcnt(ni));
#ifdef ATH_SWRETRY
    (ni->ni_ic)->ic_reset_pause_tid(ni->ni_ic, ni);
#endif

    if (!IEEE80211_IS_TDLS_NODE(ni)) 
    KASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP
            || vap->iv_opmode == IEEE80211_M_WDS || vap->iv_opmode == IEEE80211_M_BTAMP,
            ("unexpected operating mode %u", vap->iv_opmode));

    /* Multicast enhancement: If the entry with the node's address exists in 
     * the snoop table, it should be removed.
     */
    if (vap->iv_ique_ops.me_clean) {
        vap->iv_ique_ops.me_clean(ni);
    }
	/*    
     * HBR / headline block removal: delete the node entity from the table
     * for HBR purpose
     */
    if (vap->iv_ique_ops.hbr_nodeleave) {
        vap->iv_ique_ops.hbr_nodeleave(vap, ni);
    }
    /*
     * If node wasn't previously associated all
     * we need to do is reclaim the reference.
     */
    /* XXX ibss mode bypasses 11g and notification */

    IEEE80211_NODE_STATE_LOCK(ni);
    if (ni->ni_associd) {
        vap->iv_sta_assoc--;
        ic->ic_sta_assoc--;
        /* Update bss load element in beacon */
        ieee80211_vap_bssload_update_set(vap);

        if (IEEE80211_NODE_USEAMPDU(ni)) {
            ic->ic_ht_sta_assoc--;
            if (ni->ni_htcap & IEEE80211_HTCAP_C_GREENFIELD) {
                ASSERT(ic->ic_ht_gf_sta_assoc > 0);
                ic->ic_ht_gf_sta_assoc--;
            }
        }
        if (ni->ni_chwidth == IEEE80211_CWM_WIDTH40)
            ic->ic_ht40_sta_assoc--;

        if ((IEEE80211_IS_CHAN_ANYG(vap->iv_bsschan) ||
            IEEE80211_IS_CHAN_11NG(vap->iv_bsschan))  && !IEEE80211_IS_TDLS_NODE(ni))
            ieee80211_node_leave_11g(ni);

        IEEE80211_NODE_STATE_UNLOCK(ni);
        IEEE80211_DELETE_NODE_TARGET(ni, ic, vap, 0);
    } else {
        IEEE80211_NODE_STATE_UNLOCK(ni);
    }

    ieee80211_admctl_node_leave(vap, ni);

    /*
     * Cleanup station state.  In particular clear various state that 
     * might otherwise be reused if the node is reused before the
     * reference count goes to zero (and memory is reclaimed).
     *
     * If ni is not in node table, it has been reclaimed in another thread.
     */
    retval = ieee80211_sta_leave(ni);

    if ((ni->ni_flags & IEEE80211_NODE_HT) && 
        (ni->ni_flags & IEEE80211_NODE_40_INTOLERANT)) {
        ieee80211_change_cw(ic);
    }


	return retval;
}
示例#7
0
/*
 * Calculate the receive filter according to the
 * operating mode and state:
 *
 * o always accept unicast, broadcast, and multicast traffic
 * o accept PHY error frames when hardware doesn't have MIB support
 *   to count and we need them for ANI (sta mode only until recently)
 *   and we are not scanning (ANI is disabled)
 *   NB: older hal's add rx filter bits out of sight and we need to
 *	 blindly preserve them
 * o probe request frames are accepted only when operating in
 *   hostap, adhoc, mesh, or monitor modes
 * o enable promiscuous mode
 *   - when in monitor mode
 *   - if interface marked PROMISC (assumes bridge setting is filtered)
 * o accept beacons:
 *   - when operating in station mode for collecting rssi data when
 *     the station is otherwise quiet, or
 *   - when operating in adhoc mode so the 802.11 layer creates
 *     node table entries for peers,
 *   - when scanning
 *   - when doing s/w beacon miss (e.g. for ap+sta)
 *   - when operating in ap mode in 11g to detect overlapping bss that
 *     require protection
 *   - when operating in mesh mode to detect neighbors
 * o accept control frames:
 *   - when in monitor mode
 * XXX HT protection for 11n
 */
u_int32_t
ath_calcrxfilter(struct ath_softc *sc)
{
	struct ieee80211com *ic = &sc->sc_ic;
	u_int32_t rfilt;

	rfilt = HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST;
	if (!sc->sc_needmib && !sc->sc_scanning)
		rfilt |= HAL_RX_FILTER_PHYERR;
	if (ic->ic_opmode != IEEE80211_M_STA)
		rfilt |= HAL_RX_FILTER_PROBEREQ;
	/* XXX ic->ic_monvaps != 0? */
	if (ic->ic_opmode == IEEE80211_M_MONITOR || ic->ic_promisc > 0)
		rfilt |= HAL_RX_FILTER_PROM;

	/*
	 * Only listen to all beacons if we're scanning.
	 *
	 * Otherwise we only really need to hear beacons from
	 * our own BSSID.
	 *
	 * IBSS? software beacon miss? Just receive all beacons.
	 * We need to hear beacons/probe requests from everyone so
	 * we can merge ibss.
	 */
	if (ic->ic_opmode == IEEE80211_M_IBSS || sc->sc_swbmiss) {
		rfilt |= HAL_RX_FILTER_BEACON;
	} else if (ic->ic_opmode == IEEE80211_M_STA) {
		if (sc->sc_do_mybeacon && ! sc->sc_scanning) {
			rfilt |= HAL_RX_FILTER_MYBEACON;
		} else { /* scanning, non-mybeacon chips */
			rfilt |= HAL_RX_FILTER_BEACON;
		}
	}

	/*
	 * NB: We don't recalculate the rx filter when
	 * ic_protmode changes; otherwise we could do
	 * this only when ic_protmode != NONE.
	 */
	if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
	    IEEE80211_IS_CHAN_ANYG(ic->ic_curchan))
		rfilt |= HAL_RX_FILTER_BEACON;

	/*
	 * Enable hardware PS-POLL RX only for hostap mode;
	 * STA mode sends PS-POLL frames but never
	 * receives them.
	 */
	if (ath_hal_getcapability(sc->sc_ah, HAL_CAP_PSPOLL,
	    0, NULL) == HAL_OK &&
	    ic->ic_opmode == IEEE80211_M_HOSTAP)
		rfilt |= HAL_RX_FILTER_PSPOLL;

	if (sc->sc_nmeshvaps) {
		rfilt |= HAL_RX_FILTER_BEACON;
		if (sc->sc_hasbmatch)
			rfilt |= HAL_RX_FILTER_BSSID;
		else
			rfilt |= HAL_RX_FILTER_PROM;
	}
	if (ic->ic_opmode == IEEE80211_M_MONITOR)
		rfilt |= HAL_RX_FILTER_CONTROL;

	/*
	 * Enable RX of compressed BAR frames only when doing
	 * 802.11n. Required for A-MPDU.
	 */
	if (IEEE80211_IS_CHAN_HT(ic->ic_curchan))
		rfilt |= HAL_RX_FILTER_COMPBAR;

	/*
	 * Enable radar PHY errors if requested by the
	 * DFS module.
	 */
	if (sc->sc_dodfs)
		rfilt |= HAL_RX_FILTER_PHYRADAR;

	/*
	 * Enable spectral PHY errors if requested by the
	 * spectral module.
	 */
	if (sc->sc_dospectral)
		rfilt |= HAL_RX_FILTER_PHYRADAR;

	DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x, %s\n",
	    __func__, rfilt, ieee80211_opmode_name[ic->ic_opmode]);
	return rfilt;
}
示例#8
0
/*
 * Calculate the receive filter according to the
 * operating mode and state:
 *
 * o always accept unicast, broadcast, and multicast traffic
 * o accept PHY error frames when hardware doesn't have MIB support
 *   to count and we need them for ANI (sta mode only until recently)
 *   and we are not scanning (ANI is disabled)
 *   NB: older hal's add rx filter bits out of sight and we need to
 *	 blindly preserve them
 * o probe request frames are accepted only when operating in
 *   hostap, adhoc, mesh, or monitor modes
 * o enable promiscuous mode
 *   - when in monitor mode
 *   - if interface marked PROMISC (assumes bridge setting is filtered)
 * o accept beacons:
 *   - when operating in station mode for collecting rssi data when
 *     the station is otherwise quiet, or
 *   - when operating in adhoc mode so the 802.11 layer creates
 *     node table entries for peers,
 *   - when scanning
 *   - when doing s/w beacon miss (e.g. for ap+sta)
 *   - when operating in ap mode in 11g to detect overlapping bss that
 *     require protection
 *   - when operating in mesh mode to detect neighbors
 * o accept control frames:
 *   - when in monitor mode
 * XXX HT protection for 11n
 */
u_int32_t
ath_calcrxfilter(struct ath_softc *sc)
{
	struct ifnet *ifp = sc->sc_ifp;
	struct ieee80211com *ic = ifp->if_l2com;
	u_int32_t rfilt;

	rfilt = HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST;
	if (!sc->sc_needmib && !sc->sc_scanning)
		rfilt |= HAL_RX_FILTER_PHYERR;
	if (ic->ic_opmode != IEEE80211_M_STA)
		rfilt |= HAL_RX_FILTER_PROBEREQ;
	/* XXX ic->ic_monvaps != 0? */
	if (ic->ic_opmode == IEEE80211_M_MONITOR || (ifp->if_flags & IFF_PROMISC))
		rfilt |= HAL_RX_FILTER_PROM;
	if (ic->ic_opmode == IEEE80211_M_STA ||
	    ic->ic_opmode == IEEE80211_M_IBSS ||
	    sc->sc_swbmiss || sc->sc_scanning)
		rfilt |= HAL_RX_FILTER_BEACON;
	/*
	 * NB: We don't recalculate the rx filter when
	 * ic_protmode changes; otherwise we could do
	 * this only when ic_protmode != NONE.
	 */
	if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
	    IEEE80211_IS_CHAN_ANYG(ic->ic_curchan))
		rfilt |= HAL_RX_FILTER_BEACON;

	/*
	 * Enable hardware PS-POLL RX only for hostap mode;
	 * STA mode sends PS-POLL frames but never
	 * receives them.
	 */
	if (ath_hal_getcapability(sc->sc_ah, HAL_CAP_PSPOLL,
	    0, NULL) == HAL_OK &&
	    ic->ic_opmode == IEEE80211_M_HOSTAP)
		rfilt |= HAL_RX_FILTER_PSPOLL;

	if (sc->sc_nmeshvaps) {
		rfilt |= HAL_RX_FILTER_BEACON;
		if (sc->sc_hasbmatch)
			rfilt |= HAL_RX_FILTER_BSSID;
		else
			rfilt |= HAL_RX_FILTER_PROM;
	}
	if (ic->ic_opmode == IEEE80211_M_MONITOR)
		rfilt |= HAL_RX_FILTER_CONTROL;

	/*
	 * Enable RX of compressed BAR frames only when doing
	 * 802.11n. Required for A-MPDU.
	 */
	if (IEEE80211_IS_CHAN_HT(ic->ic_curchan))
		rfilt |= HAL_RX_FILTER_COMPBAR;

	/*
	 * Enable radar PHY errors if requested by the
	 * DFS module.
	 */
	if (sc->sc_dodfs)
		rfilt |= HAL_RX_FILTER_PHYRADAR;

	/*
	 * Enable spectral PHY errors if requested by the
	 * spectral module.
	 */
	if (sc->sc_dospectral)
		rfilt |= HAL_RX_FILTER_PHYRADAR;

	DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x, %s if_flags 0x%x\n",
	    __func__, rfilt, ieee80211_opmode_name[ic->ic_opmode], ifp->if_flags);
	return rfilt;
}
示例#9
0
/*
 * 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);
}
示例#10
0
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;
}
示例#11
0
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;
}