示例#1
0
static void
tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
	int subtype, int rssi, int nf)
{
	struct ieee80211com *ic = ni->ni_ic;
	struct ieee80211vap *vap = ni->ni_vap;
	struct ieee80211_tdma_state *ts = vap->iv_tdma;

	if (subtype == IEEE80211_FC0_SUBTYPE_BEACON &&
	    (ic->ic_flags & IEEE80211_F_SCAN) == 0) {
		struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *);
		struct ieee80211_scanparams scan;

		if (ieee80211_parse_beacon(ni, m0, &scan) != 0)
			return;
		if (scan.tdma == NULL) {
			/*
			 * TDMA stations must beacon a TDMA ie; ignore
			 * any other station.
			 * XXX detect overlapping bss and change channel
			 */
			IEEE80211_DISCARD(vap,
			    IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
			    wh, ieee80211_mgt_subtype_name[subtype >>
				IEEE80211_FC0_SUBTYPE_SHIFT],
			    "%s", "no TDMA ie");
			vap->iv_stats.is_rx_mgtdiscard++;
			return;
		}
		if (ni == vap->iv_bss &&
		    !IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) {
			/*
			 * Fake up a node for this newly
			 * discovered member of the IBSS.
			 */
			ni = ieee80211_add_neighbor(vap, wh, &scan);
			if (ni == NULL) {
				/* NB: stat kept for alloc failure */
				return;
			}
		}
		/*
		 * Check for state updates.
		 */
		if (IEEE80211_ADDR_EQ(wh->i_addr3, ni->ni_bssid)) {
			/*
			 * Count frame now that we know it's to be processed.
			 */
			vap->iv_stats.is_rx_beacon++;
			IEEE80211_NODE_STAT(ni, rx_beacons);
			/*
			 * Record tsf of last beacon.  NB: this must be
			 * done before calling tdma_process_params
			 * as deeper routines reference it.
			 */
			memcpy(&ni->ni_tstamp.data, scan.tstamp,
				sizeof(ni->ni_tstamp.data));
			/*
			 * Count beacon frame for s/w bmiss handling.
			 */
			vap->iv_swbmiss_count++;
			/*
			 * Process tdma ie.  The contents are used to sync
			 * the slot timing, reconfigure the bss, etc.
			 */
			(void) tdma_process_params(ni, scan.tdma, rssi, nf, wh);
			return;
		}
		/*
		 * NB: defer remaining work to the adhoc code; this causes
		 *     2x parsing of the frame but should happen infrequently
		 */
	}
示例#2
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);
    }

}