Exemplo n.º 1
0
/*
 * 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, int rssi, int nf)
{
	struct ieee80211vap *vap = ni->ni_vap;
	struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;

	/*
	 * 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, rssi, nf);
	switch (subtype) {
	case IEEE80211_FC0_SUBTYPE_BEACON:
		/* update rssi statistics for use by the hal */
		/* XXX unlocked check against vap->iv_bss? */
		ATH_RSSI_LPF(sc->sc_halstats.ns_avgbrssi, rssi);
		if (sc->sc_syncbeacon &&
		    ni == vap->iv_bss && vap->iv_state == IEEE80211_S_RUN) {
			/*
			 * Resync beacon timers using the tsf of the beacon
			 * frame we just received.
			 */
			ath_beacon_config(sc, vap);
		}
		/* fall thru... */
	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
		if (vap->iv_opmode == IEEE80211_M_IBSS &&
		    vap->iv_state == IEEE80211_S_RUN) {
			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;
	}
}
Exemplo n.º 2
0
/*
 * 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;
	}
}
Exemplo n.º 3
0
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);
    }

}
Exemplo n.º 4
0
void
arn_recv_mgmt(struct ieee80211com *ic, mblk_t *mp, struct ieee80211_node *in,
    int subtype, int rssi, uint32_t rstamp)
{
	struct arn_softc *sc = (struct arn_softc *)ic;

	/*
	 * Call up first so subsequent work can use information
	 * potentially stored in the node (e.g. for ibss merge).
	 */
	sc->sc_recv_mgmt(ic, mp, in, subtype, rssi, rstamp);

	ARN_LOCK(sc);
	switch (subtype) {
	case IEEE80211_FC0_SUBTYPE_BEACON:
		/* update rssi statistics */
		if (sc->sc_bsync && in == ic->ic_bss &&
		    ic->ic_state == IEEE80211_S_RUN) {
			/*
			 * Resync beacon timers using the tsf of the beacon
			 * frame we just received.
			 */
			arn_beacon_config(sc);
		}
		/* FALLTHRU */
	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
		if (ic->ic_opmode == IEEE80211_M_IBSS &&
		    ic->ic_state == IEEE80211_S_RUN &&
		    (in->in_capinfo & IEEE80211_CAPINFO_IBSS)) {
			uint64_t tsf = arn_extend_tsf(sc, rstamp);
			/*
			 * 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 (LE_64(in->in_tstamp.tsf) >= tsf) {
				ARN_DBG((ARN_DBG_BEACON, "arn: arn_recv_mgmt:"
				    "ibss merge, rstamp %u tsf %lu "
				    "tstamp %lu\n", rstamp, tsf,
				    in->in_tstamp.tsf));
				ARN_UNLOCK(sc);
				ARN_DBG((ARN_DBG_BEACON, "arn_recv_mgmt():"
				    "ibss_merge: rstamp=%d in_tstamp=%02x %02x"
				    " %02x %02x %02x %02x %02x %02x\n",
				    rstamp, in->in_tstamp.data[0],
				    in->in_tstamp.data[1],
				    in->in_tstamp.data[2],
				    in->in_tstamp.data[3],
				    in->in_tstamp.data[4],
				    in->in_tstamp.data[5],
				    in->in_tstamp.data[6],
				    in->in_tstamp.data[7]));
				(void) ieee80211_ibss_merge(in);
				return;
			}
		}
		break;
	}
	ARN_UNLOCK(sc);
}