Exemple #1
0
/*
 * It is usually desirable to process a Rx packet using its sender's
 * node-record instead of the BSS record.
 *
 * - AP mode: keep a node-record for every authenticated/associated
 *   station *in the BSS*. For future use, we also track neighboring
 *   APs, since they might belong to the same ESS.  APs in the same
 *   ESS may bridge packets to each other, forming a Wireless
 *   Distribution System (WDS).
 *
 * - IBSS mode: keep a node-record for every station *in the BSS*.
 *   Also track neighboring stations by their beacons/probe responses.
 *
 * - monitor mode: keep a node-record for every sender, regardless
 *   of BSS.
 *
 * - STA mode: the only available node-record is the BSS record,
 *   ic->ic_bss.
 *
 * Of all the 802.11 Control packets, only the node-records for
 * RTS packets node-record can be looked up.
 *
 * Return non-zero if the packet's node-record is kept, zero
 * otherwise.
 */
static __inline int
ieee80211_needs_rxnode(struct ieee80211com *ic, struct ieee80211_frame *wh,
    u_int8_t **bssid)
{
	struct ieee80211_node *bss = ic->ic_bss;
	int monitor, rc = 0;

	monitor = (ic->ic_opmode == IEEE80211_M_MONITOR);

	*bssid = NULL;

	switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
	case IEEE80211_FC0_TYPE_CTL:
		if (!monitor)
			break;
		return (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
		    IEEE80211_FC0_SUBTYPE_RTS;
	case IEEE80211_FC0_TYPE_MGT:
		*bssid = wh->i_addr3;
		switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
		case IEEE80211_FC0_SUBTYPE_BEACON:
		case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
			rc = 1;
			break;
		default:
			if (ic->ic_opmode == IEEE80211_M_STA)
				break;
			rc = IEEE80211_ADDR_EQ(*bssid, bss->ni_bssid) ||
			     IEEE80211_ADDR_EQ(*bssid, etherbroadcastaddr);
			break;
		}
		break;
	case IEEE80211_FC0_TYPE_DATA:
		switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
		case IEEE80211_FC1_DIR_NODS:
			*bssid = wh->i_addr3;
			if (ic->ic_opmode == IEEE80211_M_IBSS ||
			    ic->ic_opmode == IEEE80211_M_AHDEMO)
				rc = IEEE80211_ADDR_EQ(*bssid, bss->ni_bssid);
			break;
		case IEEE80211_FC1_DIR_TODS:
			*bssid = wh->i_addr1;
			if (ic->ic_opmode == IEEE80211_M_HOSTAP)
				rc = IEEE80211_ADDR_EQ(*bssid, bss->ni_bssid);
			break;
		case IEEE80211_FC1_DIR_FROMDS:
		case IEEE80211_FC1_DIR_DSTODS:
			*bssid = wh->i_addr2;
			rc = (ic->ic_opmode == IEEE80211_M_HOSTAP);
			break;
		}
		break;
	}
	return monitor || rc;
}
Exemple #2
0
void ath_remove_audio_channel(struct ieee80211com* ic, int channel, struct ether_addr* macaddr)
{
    struct ath_softc_net80211 *scn = ATH_SOFTC_NET80211(ic);
    struct ath_softc *sc = ATH_DEV_TO_SC(scn->sc_dev);
    int i = 0;

    if ((channel < 0) || (channel > (AOW_MAX_AUDIO_CHANNELS - 1))) {
        return;
    }        

    for (i = 0 ; i < AOW_MAX_RECEIVER_COUNT; i++) {
        if (!IS_ETHER_ADDR_NULL(sc->sc_aow.chan_addr[channel].addr[i].octet)) {
            if (IEEE80211_ADDR_EQ(&sc->sc_aow.chan_addr[channel].addr[i], macaddr)) {
                memset(&sc->sc_aow.chan_addr[channel].addr[i], 0 , IEEE80211_ADDR_LEN);
                sc->sc_aow.chan_addr[channel].dst_cnt--;
                sc->sc_aow.mapped_recv_cnt--;
            }
        }
    }

    if (!sc->sc_aow.chan_addr[channel].dst_cnt) {
        sc->sc_aow.chan_addr[channel].valid = AH_FALSE;
        sc->sc_aow.chan_addr[channel].seqno = 0;
        ic->ic_aow.channel_set_flag &= ~(1 << channel);
    }        
}
Exemple #3
0
static void
wlan_setstamac(struct wlanstatfoo *wf0, const uint8_t *mac)
{
	static const uint8_t zeromac[IEEE80211_ADDR_LEN];
	struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) wf0;

	if (mac == NULL) {
		switch (wlan_getopmode(wf0)) {
		case IEEE80211_M_HOSTAP:
		case IEEE80211_M_MONITOR:
			getlladdr(wf);
			break;
		case IEEE80211_M_IBSS:
		case IEEE80211_M_AHDEMO:
			/*
			 * NB: this may not work in which case the
			 * mac must be specified on the command line
			 */
			if (getbssid(wf) < 0 ||
			    IEEE80211_ADDR_EQ(wf->mac, zeromac))
				getlladdr(wf);
			break;
		case IEEE80211_M_STA:
			if (getbssid(wf) < 0)
				err(1, "%s (IEEE80211_IOC_BSSID)",
				    wf->ireq.i_name);
			break;
		}
	} else
		IEEE80211_ADDR_COPY(wf->mac, mac);
}
Exemple #4
0
/*
 * Find an instance by it's mac address.
 */
struct ieee80211com *
ieee80211_find_vap(const u_int8_t mac[IEEE80211_ADDR_LEN])
{
	int s;
	struct ieee80211com *ic;

	s = splnet();
	SLIST_FOREACH(ic, &ieee80211_list, ic_next)
		if (IEEE80211_ADDR_EQ(mac, ic->ic_myaddr))
			break;
	splx(s);
	return ic;
}
Exemple #5
0
/*
 * Handle a station leave event; destroy any associated WDS vap.
 */
static void
wds_leave(const uint8_t bssid[IEEE80211_ADDR_LEN])
{
	struct wds *p, **pp;

	for (pp = &wds; (p = *pp) != NULL; pp = &p->next)
		if (IEEE80211_ADDR_EQ(p->bssid, bssid))
			break;
	if (p != NULL) {
		*pp = p->next;
		if (wds_vap_destroy(p->ifname) >= 0)
			syslog(LOG_INFO, "[%s] wds vap %s destroyed",
			    ether_sprintf(bssid), p->ifname);
		free(p);
	}
}
Exemple #6
0
int
wlan_reset(wlan_if_t vaphandle, ieee80211_reset_request *reset_req)
{
    struct ieee80211vap *vap = vaphandle;
    struct ieee80211com *ic = vap->iv_ic;
    int err = 0;

    /* NB: must set H/W MAC address before chip reset */
    if (reset_req->reset_mac && IEEE80211_ADDR_IS_VALID(reset_req->macaddr) &&
        !IEEE80211_ADDR_EQ(reset_req->macaddr, ic->ic_myaddr)) {

        IEEE80211_ADDR_COPY(ic->ic_myaddr, reset_req->macaddr);
        ic->ic_set_macaddr(ic, reset_req->macaddr);
        IEEE80211_ADDR_COPY(vap->iv_myaddr, ic->ic_myaddr);
        /*
         * TBD: if OS tries to set mac addr when multiple VAP co-exist,
         * we need to notify other VAPs and the corresponding ports
         * so that the port owner can change source address!!
         */
    }

    /* reset UMAC software states */
    if (reset_req->type == IEEE80211_RESET_TYPE_DOT11_INTF) {
        /*
         * In case iv_bss was not stopped.
         */
        wlan_mlme_stop_bss(vap,
                           WLAN_MLME_STOP_BSS_F_FORCE_STOP_RESET |
                           WLAN_MLME_STOP_BSS_F_WAIT_RX_DONE);

        err = ieee80211_vap_reset(vap, reset_req);
    } else if (reset_req->type == IEEE80211_RESET_TYPE_DEVICE) {
        u_int32_t num_vaps;
        struct ieee80211_vap_iter_reset_arg params; 
        params.err=0;
        params.reset_req = reset_req;
        ieee80211_iterate_vap_list_internal(ic,ieee80211_vap_iter_reset,((void *) &params),num_vaps);  
        err = params.err;
    }

    /* TBD: Always reset the hardware? */
    err = ic->ic_reset(ic);
    if (err)
        return err;

    return err;
}
Exemple #7
0
static bss_t *
_ieee80211_find_node(struct ieee80211_node_table *nt,
    const A_UINT8 *macaddr)
{
    bss_t *ni = NULL;
    int hash = 0;

    IEEE80211_NODE_LOCK_ASSERT(nt);

    hash = IEEE80211_NODE_HASH(macaddr);

    if (hash >= IEEE80211_NODE_HASHSIZE)
    {
        // overflow????
        return NULL;
    }

    if (hash < 0)
    {
        // underflow????
        return NULL;
    }

    if (NULL == nt)
    {
        return NULL;
    }

    if (NULL == nt->nt_hash)
    {
        return NULL;
    }

    if (NULL == nt->nt_hash[hash])
    {
        return NULL;
    }

    for(ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) {
        if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
            ieee80211_node_incref(ni);  /* mark referenced */
            return ni;
        }
    }
    return NULL;
}
Exemple #8
0
static void
ieee80211_vap_iter_find_connection(void *arg, struct ieee80211vap *vap, bool is_last_vap)
{
    struct ieee80211_mlme_find_connection    *pmlme_find_connection_data = arg;

    UNREFERENCED_PARAMETER(is_last_vap);

    /*
     * If we haven't found a connection yet, check to see if current VAP is 
     * connected to the specified AP.
     */
    if (! pmlme_find_connection_data->connection_found) {
        /*
         * Since ieee80211_mlme_get_bss_entry is not implemented, compare
         * iv_bss's and scan_entry's SSID and BSSID.
         */
        struct ieee80211_node    *bss_node = ieee80211vap_get_bssnode(vap);

        if (bss_node != NULL) {
            /* 
             * Check for BSSID match first; SSID matching is a more expensive
             * operation and should be checked last.
             */
            if (IEEE80211_ADDR_EQ(wlan_node_getbssid(bss_node), 
                                  wlan_scan_entry_bssid(pmlme_find_connection_data->scan_entry))) {
                ieee80211_ssid    bss_ssid;
                u_int8_t          scan_entry_ssid_len;
                u_int8_t          *scan_entry_ssid;

                /*
                 * BSSID matched, let's check the SSID
                 */
                wlan_get_bss_essid(vap, &bss_ssid);
                scan_entry_ssid  = 
                    wlan_scan_entry_ssid(pmlme_find_connection_data->scan_entry,
                                         &scan_entry_ssid_len);

                if (scan_entry_ssid != NULL) {
                    pmlme_find_connection_data->connection_found =                    
                        (scan_entry_ssid_len == bss_ssid.len)          &&
                        (OS_MEMCMP(scan_entry_ssid, bss_ssid.ssid, bss_ssid.len) == 0);
                }
            }
        }
    }
}
Exemple #9
0
static A_BOOL
is_node_self_peer(struct ieee80211vap *vap, const u_int8_t *macaddr)
{
    A_BOOL is_self_peer = FALSE;

    switch (vap->iv_opmode) {
    case IEEE80211_M_STA:
        if (IEEE80211_ADDR_EQ(macaddr, vap->iv_myaddr)) {
            is_self_peer = TRUE;
        }
        break;
    default:
        break;
    }

    return is_self_peer;
}
Exemple #10
0
/*
 * Handle WDS discovery; create a WDS vap for the specified bssid.
 * If a vap already exists then do nothing (can happen when a flood
 * of 4-address frames causes multiple events to be queued before
 * we create a vap).
 */
static void
wds_discovery(const char *ifname, const uint8_t bssid[IEEE80211_ADDR_LEN])
{
	struct wds *p;
	char parent[256];
	char cmd[1024];
	int status;

	for (p = wds; p != NULL; p = p->next)
		if (IEEE80211_ADDR_EQ(p->bssid, bssid)) {
			syslog(LOG_INFO, "[%s] wds vap already created (%s)",
			    ether_sprintf(bssid), ifname);
			return;
		}
	if (getparent(ifname, parent) < 0) {
		syslog(LOG_ERR, "%s: no pointer to parent interface: %m",
		    ifname);
		return;
	}

	p = malloc(sizeof(struct wds));
	if (p == NULL) {
		syslog(LOG_ERR, "%s: malloc failed: %m", __func__);
		return;
	}
	IEEE80211_ADDR_COPY(p->bssid, bssid);
	if (wds_vap_create(parent, p) < 0) {
		free(p);
		return;
	}
	/*
	 * Add to table and launch setup script.
	 */
	p->next = wds;
	wds = p;
	syslog(LOG_INFO, "[%s] create wds vap %s", ether_sprintf(bssid),
	    p->ifname);
	if (script != NULL) {
		snprintf(cmd, sizeof(cmd), "%s %s", script, p->ifname);
		status = system(cmd);
		if (status)
			syslog(LOG_ERR, "vap setup script %s exited with "
			    "status %d", script, status);
	}
}
Exemple #11
0
static bss_t *
_ieee80211_find_node(struct ieee80211_node_table *nt,
    const A_UINT8 *macaddr)
{
    bss_t *ni;
    int hash;

    IEEE80211_NODE_LOCK_ASSERT(nt);

    hash = IEEE80211_NODE_HASH(macaddr);
    for(ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) {
        if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
            ieee80211_node_incref(ni);  /* mark referenced */
            return ni;
        }
    }
    return NULL;
}
Exemple #12
0
void
ieee80211_delete_vap_target(struct ieee80211vap *vap)
{
    struct ieee80211com *ic = vap->iv_ic;
    struct ieee80211vap_target vt;
    u_int8_t vapindex = 0;
    int i;

#if 0
    /* Dump mac address */
    printk("%s, mac: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
        __FUNCTION__, vap->iv_myaddr[0], vap->iv_myaddr[1], vap->iv_myaddr[2],
        vap->iv_myaddr[3], vap->iv_myaddr[4], vap->iv_myaddr[5]);
#endif

    for (i = 0; i < HTC_MAX_VAP_NUM; i++) {
        if (ic->target_vap_bitmap[i].vap_valid == 1) {
            /* Compare mac address */
            if (IEEE80211_ADDR_EQ(ic->target_vap_bitmap[i].vap_macaddr, vap->iv_myaddr)) {
                vapindex = i;
                ic->target_vap_bitmap[i].vap_valid = 0;
                OS_MEMZERO(ic->target_vap_bitmap[i].vap_macaddr, IEEE80211_ADDR_LEN);
                break;
            }
        }
    }

    if (i == HTC_MAX_VAP_NUM) {
        printk("%s: Can't find desired vap\n", __FUNCTION__);
        return;
    }

    //printk("%s: vapindex: %d\n", __FUNCTION__, vapindex);

    vt.iv_vapindex = vapindex;//vap->iv_vapindex;
    vt.iv_opmode = 0;//vap->iv_opmode;
    vt.iv_mcast_rate = 0;//vap->iv_mcast_rate; 
    vt.iv_rtsthreshold = 0;//vap->iv_rtsthreshold;

    ic->ic_delete_vap_target(ic, &vt, sizeof(vt));

    //printk("%s Exit \n", __FUNCTION__);
}
Exemple #13
0
void
ieee80211_delete_node_target(struct ieee80211_node *ni, struct ieee80211com *ic,
    struct ieee80211vap *vap, u_int8_t is_reset_bss)
{
    int i;
    u_int8_t nodeindex = 0xff;

    //printk("%s: vap: 0x%08x, ni: 0x%08x, is_reset_bss: %d\n", __FUNCTION__, vap, ni, is_reset_bss);

    /* Dump mac address */
    /* printk("%s, mac: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
        __FUNCTION__, ni->ni_macaddr[0], ni->ni_macaddr[1], ni->ni_macaddr[2],
        ni->ni_macaddr[3], ni->ni_macaddr[4], ni->ni_macaddr[5]); */

    for (i = 0; i < HTC_MAX_NODE_NUM; i++) {
        if (ni->ni_ic->target_node_bitmap[i].ni_valid == 1) {
            /* avoid upper layer add the same vap twice */
            if (IEEE80211_ADDR_EQ(ic->target_node_bitmap[i].ni_macaddr, ni->ni_macaddr)) {
                if(is_reset_bss == 1 && ic->target_node_bitmap[i].ni_is_vapnode == 1)
                {
                    return;
                }                                            
                OS_MEMZERO(ic->target_node_bitmap[i].ni_macaddr, IEEE80211_ADDR_LEN);
                ic->target_node_bitmap[i].ni_valid = 0;
                nodeindex = i;
                break;
            }
        }
    }

    if (i == HTC_MAX_NODE_NUM) {
        /*printk("%s: Can't find desired node\n", __FUNCTION__);*/
        return;
    }

    /* printk("%s: ni: 0x%08x, nodeindex: %d, is_reset_bss: %d\n", __FUNCTION__,
    (u_int32_t)ni, nodeindex, is_reset_bss); */

    ic->ic_delete_node_target(ic, &nodeindex, sizeof(nodeindex));
}
Exemple #14
0
static void
hwmp_recv_rann(struct ieee80211vap *vap, struct ieee80211_node *ni,
    const struct ieee80211_frame *wh, const struct ieee80211_meshrann_ie *rann)
{
	struct ieee80211_mesh_state *ms = vap->iv_mesh;
	struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
	struct ieee80211_mesh_route *rt = NULL;
	struct ieee80211_hwmp_route *hr;
	struct ieee80211_meshrann_ie prann;

	if (ni == vap->iv_bss ||
	    ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED ||
	    IEEE80211_ADDR_EQ(rann->rann_addr, vap->iv_myaddr))
		return;

	rt = ieee80211_mesh_rt_find(vap, rann->rann_addr);
	/*
	 * Discover the path to the root mesh STA.
	 * If we already know it, propagate the RANN element.
	 */
	if (rt == NULL) {
		hwmp_discover(vap, rann->rann_addr, NULL);
		return;
	}
	hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
	if (HWMP_SEQ_GT(rann->rann_seq, hr->hr_seq)) {
		hr->hr_seq = rann->rann_seq;
		if (rann->rann_ttl > 1 &&
		    rann->rann_hopcount < hs->hs_maxhops &&
		    (ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
			memcpy(&prann, rann, sizeof(prann));
			prann.rann_hopcount += 1;
			prann.rann_ttl -= 1;
			prann.rann_metric += ms->ms_pmetric->mpm_metric(ni);
			hwmp_send_rann(vap->iv_bss, vap->iv_myaddr,
			    broadcastaddr, &prann);
		}
	}
}
Exemple #15
0
void
ieee80211_update_vap_target(struct ieee80211vap *vap)
{
    struct ieee80211com *ic = vap->iv_ic;
    struct ieee80211vap_update_tgt tmp_vap_update;
    u_int8_t vapindex = 0;

    adf_os_mem_zero(&tmp_vap_update , sizeof(struct ieee80211vap_update_tgt)); 

    /*searching vapindex */
    for (vapindex = 0; vapindex < HTC_MAX_VAP_NUM; vapindex++) {
        if ((ic->target_vap_bitmap[vapindex].vap_valid) && 
                (IEEE80211_ADDR_EQ(ic->target_vap_bitmap[vapindex].vap_macaddr,vap->iv_myaddr))) 
            break;
    }

    tmp_vap_update.iv_flags         = htonl(vap->iv_flags);
    tmp_vap_update.iv_flags_ext     = htonl(vap->iv_flags_ext);
    tmp_vap_update.iv_vapindex      = htonl(vapindex);
    tmp_vap_update.iv_rtsthreshold  = htons(vap->iv_rtsthreshold);

    ic->ic_update_vap_target(ic, &tmp_vap_update, sizeof(tmp_vap_update));
}
Exemple #16
0
 STATION *
 CAR6KMini::GetStation(A_UINT8 *sta,A_UINT16 aid)
 {
     STATION *adstation = NULL;
     A_UINT8 i, maxstation;

     switch(m_networkType)
     {
         case AP_NETWORK:
         maxstation = AP_MAX_NUM_STA;
             break;
         default:
         maxstation = 0;
             break;
     }

     for(i =0 ;i < maxstation; i++)
     {
         if(!sta)
         {
             if(m_staList[i].aid == aid)
             {
                 adstation = &m_staList[i];
                 break;
             }
         }
         else
         {
             if(IEEE80211_ADDR_EQ(sta,m_staList[i].mac))
             {
                 adstation = &m_staList[i];
                 break;
             }
         }
     }
     return adstation;
 }
Exemple #17
0
/*
 * IEEE80211_M_IBSS+IEEE80211_M_AHDEMO vap state machine handler.
 */
static int
adhoc_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
{
	struct ieee80211com *ic = vap->iv_ic;
	struct ieee80211_node *ni;
	enum ieee80211_state ostate;

	IEEE80211_LOCK_ASSERT(vap->iv_ic);

	ostate = vap->iv_state;
	IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n",
	    __func__, ieee80211_state_name[ostate],
	    ieee80211_state_name[nstate], arg);
	vap->iv_state = nstate;			/* state transition */
	if (ostate != IEEE80211_S_SCAN)
		ieee80211_cancel_scan(vap);	/* background scan */
	ni = vap->iv_bss;			/* NB: no reference held */
	switch (nstate) {
	case IEEE80211_S_INIT:
		switch (ostate) {
		case IEEE80211_S_SCAN:
			ieee80211_cancel_scan(vap);
			break;
		default:
			break;
		}
		if (ostate != IEEE80211_S_INIT) {
			/* NB: optimize INIT -> INIT case */
			ieee80211_reset_bss(vap);
		}
		break;
	case IEEE80211_S_SCAN:
		switch (ostate) {
		case IEEE80211_S_RUN:		/* beacon miss */
			/* purge station table; entries are stale */
			ieee80211_iterate_nodes(&ic->ic_sta, sta_leave, vap);
			/* fall thru... */
		case IEEE80211_S_INIT:
			if (vap->iv_des_chan != IEEE80211_CHAN_ANYC &&
			    !IEEE80211_IS_CHAN_RADAR(vap->iv_des_chan)) {
				/*
				 * Already have a channel; bypass the
				 * scan and startup immediately.
				 */
				ieee80211_create_ibss(vap,
				    ieee80211_ht_adjust_channel(ic,
				    vap->iv_des_chan, vap->iv_flags_ht));
				break;
			}
			/*
			 * Initiate a scan.  We can come here as a result
			 * of an IEEE80211_IOC_SCAN_REQ too in which case
			 * the vap will be marked with IEEE80211_FEXT_SCANREQ
			 * and the scan request parameters will be present
			 * in iv_scanreq.  Otherwise we do the default.
			 */
			if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) {
				ieee80211_check_scan(vap,
				    vap->iv_scanreq_flags,
				    vap->iv_scanreq_duration,
				    vap->iv_scanreq_mindwell,
				    vap->iv_scanreq_maxdwell,
				    vap->iv_scanreq_nssid, vap->iv_scanreq_ssid);
				vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ;
			} else
				ieee80211_check_scan_current(vap);
			break;
		case IEEE80211_S_SCAN:
			/*
			 * This can happen because of a change in state
			 * that requires a reset.  Trigger a new scan
			 * unless we're in manual roaming mode in which
			 * case an application must issue an explicit request.
			 */
			if (vap->iv_roaming == IEEE80211_ROAMING_AUTO)
				ieee80211_check_scan_current(vap);
			break;
		default:
			goto invalid;
		}
		break;
	case IEEE80211_S_RUN:
		if (vap->iv_flags & IEEE80211_F_WPA) {
			/* XXX validate prerequisites */
		}
		switch (ostate) {
		case IEEE80211_S_SCAN:
#ifdef IEEE80211_DEBUG
			if (ieee80211_msg_debug(vap)) {
				ieee80211_note(vap,
				    "synchronized with %s ssid ",
				    ether_sprintf(ni->ni_bssid));
				ieee80211_print_essid(vap->iv_bss->ni_essid,
				    ni->ni_esslen);
				/* XXX MCS/HT */
				printf(" channel %d start %uMb\n",
				    ieee80211_chan2ieee(ic, ic->ic_curchan),
				    IEEE80211_RATE2MBS(ni->ni_txrate));
			}
#endif
			break;
		case IEEE80211_S_RUN:	/* IBSS merge */
			break;
		default:
			goto invalid;
		}
		/*
		 * When 802.1x is not in use mark the port authorized
		 * at this point so traffic can flow.
		 */
		if (ni->ni_authmode != IEEE80211_AUTH_8021X)
			ieee80211_node_authorize(ni);
		/*
		 * Fake association when joining an existing bss.
		 */
		if (!IEEE80211_ADDR_EQ(ni->ni_macaddr, vap->iv_myaddr) &&
		    ic->ic_newassoc != NULL)
			ic->ic_newassoc(ni, ostate != IEEE80211_S_RUN);
		break;
	case IEEE80211_S_SLEEP:
		vap->iv_sta_ps(vap, 0);
		break;
	default:
	invalid:
		IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
		    "%s: unexpected state transition %s -> %s\n", __func__,
		    ieee80211_state_name[ostate], ieee80211_state_name[nstate]);
		break;
	}
	return 0;
}
Exemple #18
0
int wlan_mlme_deauth_request(wlan_if_t vaphandle, u_int8_t *macaddr, IEEE80211_REASON_CODE reason)
{
    struct ieee80211vap      *vap = vaphandle;
    struct ieee80211_node    *ni;
    int                      error = 0;

    IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__);

    /*
     * if a node exist with the given address already , use it.
     * if not use bss node.
     */
    ni = ieee80211_vap_find_node(vap, macaddr);
    if (ni == NULL) {
        if (IEEE80211_ADDR_EQ(macaddr, IEEE80211_GET_BCAST_ADDR(vap->iv_ic)))
            ni = ieee80211_ref_node(vap->iv_bss);
        else{
            error = -EIO;
            goto exit;
        }
    }

    /* Send deauth frame */
    error = ieee80211_send_deauth(ni, reason);

    /* Node needs to be removed from table as well, do it only for AP/IBSS now */
#if ATH_SUPPORT_IBSS
    if ((vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS) && ni != vap->iv_bss) {
#else
    if (vap->iv_opmode == IEEE80211_M_HOSTAP && ni != vap->iv_bss) {
#if ATH_SUPPORT_AOW
        ieee80211_aow_join_indicate(ni->ni_ic, AOW_STA_DISCONNECTED, ni);
#endif  /* ATH_SUPPORT_AOW */
#endif  /* ATH_SUPPORT_IBSS */
        IEEE80211_NODE_LEAVE(ni);
    }        

    /* claim node immediately */
    ieee80211_free_node(ni);

    if (error) {
        goto exit;
    }

    /* 
     * Call MLME confirmation handler => mlme_deauth_complete 
     * This should reflect the tx completion status of the deauth frame,
     * but since we don't have per frame completion, we'll always indicate success here. 
     */
    IEEE80211_DELIVER_EVENT_MLME_DEAUTH_COMPLETE(vap,macaddr, IEEE80211_STATUS_SUCCESS); 

exit:
    return error;
}

int wlan_mlme_disassoc_request(wlan_if_t vaphandle, u_int8_t *macaddr, IEEE80211_REASON_CODE reason)
{
    struct ieee80211vap      *vap = vaphandle;
    struct ieee80211_node    *ni;
    int                      error = 0;

    IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__);

    /* Broadcast Addr - disassociate all stations */
    if (IEEE80211_ADDR_EQ(macaddr, IEEE80211_GET_BCAST_ADDR(vap->iv_ic))) {
        if (vap->iv_opmode == IEEE80211_M_STA) {
            IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME,
                              "%s: unexpected station vap with all 0xff mac address", __func__);
            ASSERT(0);
            goto exit;
		} else {
            /* Iterate station list only when PMF is not enabled */
            if (!wlan_vap_is_pmf_enabled(vap)) {
                wlan_iterate_station_list(vap, sta_disassoc, NULL);
                goto exit;
            }
        }
    }

    /*
     * if a node exist with the given address already , use it.
     * if not use bss node.
     */
    ni = ieee80211_vap_find_node(vap, macaddr);
    if (ni == NULL) {
        if (IEEE80211_ADDR_EQ(macaddr, IEEE80211_GET_BCAST_ADDR(vap->iv_ic)))
            ni = ieee80211_ref_node(vap->iv_bss);
        else{
            error = -EIO;
            goto exit;
        }
    }

    /* Send disassoc frame */
    error = ieee80211_send_disassoc(ni, reason);

    /* Node needs to be removed from table as well, do it only for AP now */
    if (vap->iv_opmode == IEEE80211_M_HOSTAP  && ni != vap->iv_bss) {
#if ATH_SUPPORT_AOW
        ieee80211_aow_join_indicate(ni->ni_ic, AOW_STA_DISCONNECTED, ni);
#endif  /* ATH_SUPPORT_AOW */
        IEEE80211_NODE_LEAVE(ni);
    }        

    /* claim node immediately */
    ieee80211_free_node(ni);

    if (error) {
        goto exit;
    }

    /* 
     * Call MLME confirmation handler => mlme_disassoc_complete 
     * This should reflect the tx completion status of the disassoc frame,
     * but since we don't have per frame completion, we'll always indicate success here. 
     */
    IEEE80211_DELIVER_EVENT_MLME_DISASSOC_COMPLETE(vap, macaddr, reason, IEEE80211_STATUS_SUCCESS); 

exit:
    return error;
}


int wlan_mlme_start_bss(wlan_if_t vaphandle)
{
    struct ieee80211vap           *vap = vaphandle;
    struct ieee80211_mlme_priv    *mlme_priv = vap->iv_mlme_priv;
    int                           error = 0;

    IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__);

    switch(vap->iv_opmode) {
    case IEEE80211_M_IBSS:
        IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: Create adhoc bss\n", __func__);
        /* Reset state */
        mlme_priv->im_connection_up = 0;

        error = mlme_create_adhoc_bss(vap);
        break;
    case IEEE80211_M_MONITOR:
    case IEEE80211_M_HOSTAP:
    case IEEE80211_M_BTAMP:
        /* 
         * start the AP . the channel/ssid should have been setup already.
         */
        IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: Create infrastructure(AP) bss\n", __func__);
        error = mlme_create_infra_bss(vap);
        break;
    default:
        ASSERT(0);
    }

    return error;
}

bool wlan_coext_enabled(wlan_if_t vaphandle)
{
    struct ieee80211com    *ic = vaphandle->iv_ic;

    return (ic->ic_flags & IEEE80211_F_COEXT_DISABLE) ? FALSE : TRUE;
}

void wlan_determine_cw(wlan_if_t vaphandle, wlan_chan_t channel)
{
    struct ieee80211com    *ic = vaphandle->iv_ic;
    int is_chan_ht40 = channel->ic_flags & (IEEE80211_CHAN_11NG_HT40PLUS |
                                            IEEE80211_CHAN_11NG_HT40MINUS);

    if (is_chan_ht40 && (channel->ic_flags & IEEE80211_CHAN_HT40INTOL)) {
        ic->ic_bss_to20(ic);
    }
}


static void
sta_deauth(void *arg, struct ieee80211_node *ni)
{
    struct ieee80211vap    *vap = ni->ni_vap;
    u_int8_t macaddr[6];

    IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: deauth station %s \n",
                      __func__,ether_sprintf(ni->ni_macaddr));
    IEEE80211_ADDR_COPY(macaddr, ni->ni_macaddr);
    if (ni->ni_associd) {
        /*
         * if it is associated, then send disassoc.
         */
        ieee80211_send_deauth(ni, IEEE80211_REASON_AUTH_LEAVE);
    }
    IEEE80211_NODE_LEAVE(ni);
    IEEE80211_DELIVER_EVENT_MLME_DEAUTH_INDICATION(vap, macaddr, IEEE80211_REASON_AUTH_LEAVE);
}

static void
sta_disassoc(void *arg, struct ieee80211_node *ni)
{
    struct ieee80211vap    *vap = ni->ni_vap;
    u_int8_t macaddr[6];

    IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: disassoc station %s \n",
                      __func__,ether_sprintf(ni->ni_macaddr));
    IEEE80211_ADDR_COPY(macaddr, ni->ni_macaddr);
    if (ni->ni_associd) {
        /*
         * if it is associated, then send disassoc.
         */
        ieee80211_send_disassoc(ni, IEEE80211_REASON_ASSOC_LEAVE);
#if ATH_SUPPORT_AOW
        ieee80211_aow_join_indicate(ni->ni_ic, AOW_STA_DISCONNECTED, ni);
#endif  /* ATH_SUPPORT_AOW */
    }
    IEEE80211_NODE_LEAVE(ni);
    IEEE80211_DELIVER_EVENT_MLME_DISASSOC_COMPLETE(vap, macaddr, 
                                                     IEEE80211_REASON_ASSOC_LEAVE, IEEE80211_STATUS_SUCCESS); 
}


int wlan_mlme_stop_bss(wlan_if_t vaphandle, int flags)
{
#define WAIT_RX_INTERVAL 10000
    u_int32_t                       elapsed_time = 0;
    struct ieee80211vap             *vap = vaphandle;
    struct ieee80211_mlme_priv      *mlme_priv = vap->iv_mlme_priv;
    int                             error = 0;

    IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s flags = 0x%x\n", __func__, flags);

    /*
     * Wait for current rx path to finish. Assume only one rx thread.
     */
    if (flags & WLAN_MLME_STOP_BSS_F_WAIT_RX_DONE) {
        do {
            if (OS_ATOMIC_CMPXCHG(&vap->iv_rx_gate, 0, 1) == 0) {
                break;
            }

            OS_SLEEP(WAIT_RX_INTERVAL);
            elapsed_time += WAIT_RX_INTERVAL;

            if (elapsed_time > (100 * WAIT_RX_INTERVAL))
               ieee80211_note (vap,"%s: Rx pending count stuck. Investigate!!!\n", __func__);
        } while (1);
    }

    switch(vap->iv_opmode) {
#if UMAC_SUPPORT_IBSS
    case IEEE80211_M_IBSS:
        mlme_stop_adhoc_bss(vap, flags);
        break;
#endif
    case IEEE80211_M_HOSTAP:
    case IEEE80211_M_BTAMP:
        /* disassoc/deauth all stations */
        IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: dsassocing/deauth all stations \n", __func__);
        if(vap->iv_send_deauth)
            wlan_iterate_station_list(vap, sta_deauth, NULL);
        else
            wlan_iterate_station_list(vap, sta_disassoc, NULL);
        break;

    case IEEE80211_M_STA:
        /* There should be no mlme requests pending */
        ASSERT(vap->iv_mlme_priv->im_request_type == MLME_REQ_NONE);

        /* Reset state variables */
        mlme_priv->im_connection_up = 0;
        mlme_sta_swbmiss_timer_stop(vap);
        ieee80211_sta_leave(vap->iv_bss);
        break;

    default:
        break;
    }

    if (flags & WLAN_MLME_STOP_BSS_F_FORCE_STOP_RESET) {
        /* put vap in init state */
        ieee80211_vap_stop(vap, TRUE);
    } else {
        /* put vap in stopping state */
        if (flags & WLAN_MLME_STOP_BSS_F_STANDBY)
            ieee80211_vap_standby(vap);
        else
            ieee80211_vap_stop(vap, FALSE);
    }

    if (!(flags & WLAN_MLME_STOP_BSS_F_NO_RESET))
        error = ieee80211_reset_bss(vap);

    /*
     * Release the rx mutex.
     */
    if (flags & WLAN_MLME_STOP_BSS_F_WAIT_RX_DONE) {
        (void) OS_ATOMIC_CMPXCHG(&vap->iv_rx_gate, 1, 0);
    }

    return error;
#undef WAIT_RX_INTERVAL
}
int
ieee80211_recv_asreq(struct ieee80211_node *ni, wbuf_t wbuf, int subtype)
{
    struct ieee80211com *ic = ni->ni_ic;
    struct ieee80211vap *vap = ni->ni_vap;
    struct ieee80211_frame *wh;
    u_int8_t *frm, *efrm;
    u_int16_t capinfo, bintval;
    struct ieee80211_rsnparms rsn;
    u_int8_t reason;
    int reassoc, resp;
    u_int8_t *ssid, *rates, *xrates, *wpa, *wme, *ath, *htcap,*vendor_ie, *wps;
    u_int8_t *athextcap;

    if (vap->iv_opmode != IEEE80211_M_HOSTAP && vap->iv_opmode != IEEE80211_M_BTAMP) {
        vap->iv_stats.is_rx_mgtdiscard++;
        return -EINVAL;
    }

    wh = (struct ieee80211_frame *) wbuf_header(wbuf);
    frm = (u_int8_t *)&wh[1];
    efrm = wbuf_header(wbuf) + wbuf_get_pktlen(wbuf);

    if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
        reassoc = 1;
        resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP;
		/*zhaoyang1 transplant from 717*/
		/*pengruofeng add start for management frame stats 2011-5-9*/
		vap->iv_stats.is_rx_reassoc++;
		/*pengruofeng add end 2011-5-9*/	
		/*zhaoyang1 transplant end*/
    } else {
        reassoc = 0;
        resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP;
    }
    /*
     * asreq frame format
     *    [2] capability information
     *    [2] listen interval
     *    [6*] current AP address (reassoc only)
     *    [tlv] ssid
     *    [tlv] supported rates
     *    [tlv] extended supported rates
     *    [tlv] WPA or RSN
     *    [tlv] WME
     *    [tlv] HT Capabilities
     *    [tlv] Atheros capabilities
     */
    IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4));
    if (!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bss->ni_bssid)) {
        IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
                          wh, ieee80211_mgt_subtype_name[subtype >>
                                                         IEEE80211_FC0_SUBTYPE_SHIFT],
                          "%s\n", "wrong bssid");
		/*zhaoyang1 transplant from 717*/
		/*pengruofeng add start for management frame stats 2011-5-9*/
		if (reassoc) {
		
			vap->iv_stats.is_rx_reassoc_bss++;
		} else {
		
			vap->iv_stats.is_rx_assoc_bss++;
		}
		/*pengruofeng add end 2011-5-9*/
		/*zhaoyang1 transplant end*/
		
        return -EINVAL;
    }
Exemple #20
0
/*
 * Process a received frame.  The node associated with the sender
 * should be supplied.  If nothing was found in the node table then
 * the caller is assumed to supply a reference to ic_bss instead.
 * The RSSI and a timestamp are also supplied.  The RSSI data is used
 * during AP scanning to select a AP to associate with; it can have
 * any units so long as values have consistent units and higher values
 * mean ``better signal''.  The receive timestamp is currently not used
 * by the 802.11 layer.
 */
int
ieee80211_input(ieee80211com_t *ic, mblk_t *mp, struct ieee80211_node *in,
    int32_t rssi, uint32_t rstamp)
{
	struct ieee80211_frame *wh;
	struct ieee80211_key *key;
	uint8_t *bssid;
	int hdrspace;
	int len;
	uint16_t rxseq;
	uint8_t dir;
	uint8_t type;
	uint8_t subtype;
	uint8_t tid;
	uint8_t qos;

	if (mp->b_flag & M_AMPDU) {
		/*
		 * Fastpath for A-MPDU reorder q resubmission.  Frames
		 * w/ M_AMPDU marked have already passed through here
		 * but were received out of order and been held on the
		 * reorder queue.  When resubmitted they are marked
		 * with the M_AMPDU flag and we can bypass most of the
		 * normal processing.
		 */
		IEEE80211_LOCK(ic);
		wh = (struct ieee80211_frame *)mp->b_rptr;
		type = IEEE80211_FC0_TYPE_DATA;
		dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
		subtype = IEEE80211_FC0_SUBTYPE_QOS;
		hdrspace = ieee80211_hdrspace(ic, wh);	/* optimize */
		/* clear driver/net80211 flags before passing up */
		mp->b_flag &= ~M_AMPDU;
		goto resubmit_ampdu;
	}

	ASSERT(in != NULL);
	in->in_inact = in->in_inact_reload;
	type = (uint8_t)-1;		/* undefined */
	len = MBLKL(mp);
	if (len < sizeof (struct ieee80211_frame_min)) {
		ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: "
		    "too short (1): len %u", len);
		goto out;
	}
	/*
	 * Bit of a cheat here, we use a pointer for a 3-address
	 * frame format but don't reference fields past outside
	 * ieee80211_frame_min w/o first validating the data is
	 * present.
	 */
	wh = (struct ieee80211_frame *)mp->b_rptr;
	if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
	    IEEE80211_FC0_VERSION_0) {
		ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_input: "
		    "discard pkt with wrong version %x", wh->i_fc[0]);
		goto out;
	}

	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;

	IEEE80211_LOCK(ic);
	if (!(ic->ic_flags & IEEE80211_F_SCAN)) {
		switch (ic->ic_opmode) {
		case IEEE80211_M_STA:
			bssid = wh->i_addr2;
			if (!IEEE80211_ADDR_EQ(bssid, in->in_bssid))
				goto out_exit_mutex;
			break;
		case IEEE80211_M_IBSS:
		case IEEE80211_M_AHDEMO:
			if (dir != IEEE80211_FC1_DIR_NODS) {
				bssid = wh->i_addr1;
			} else if (type == IEEE80211_FC0_TYPE_CTL) {
				bssid = wh->i_addr1;
			} else {
				if (len < sizeof (struct ieee80211_frame)) {
					ieee80211_dbg(IEEE80211_MSG_ANY,
					    "ieee80211_input: too short(2):"
					    "len %u\n", len);
					goto out_exit_mutex;
				}
				bssid = wh->i_addr3;
			}
			if (type != IEEE80211_FC0_TYPE_DATA)
				break;
			/*
			 * Data frame, validate the bssid.
			 */
			if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss->in_bssid) &&
			    !IEEE80211_ADDR_EQ(bssid, wifi_bcastaddr)) {
				/* not interested in */
				ieee80211_dbg(IEEE80211_MSG_INPUT,
				    "ieee80211_input: not to bss %s\n",
				    ieee80211_macaddr_sprintf(bssid));
				goto out_exit_mutex;
			}
			/*
			 * For adhoc mode we cons up a node when it doesn't
			 * exist. This should probably done after an ACL check.
			 */
			if (in == ic->ic_bss &&
			    ic->ic_opmode != IEEE80211_M_HOSTAP &&
			    !IEEE80211_ADDR_EQ(wh->i_addr2, in->in_macaddr)) {
				/*
				 * Fake up a node for this newly
				 * discovered member of the IBSS.
				 */
				in = ieee80211_fakeup_adhoc_node(&ic->ic_sta,
				    wh->i_addr2);
				if (in == NULL) {
					/* NB: stat kept for alloc failure */
					goto out_exit_mutex;
				}
			}
			break;
		default:
			goto out_exit_mutex;
		}
		in->in_rssi = (uint8_t)rssi;
		in->in_rstamp = rstamp;
		if (!(type & IEEE80211_FC0_TYPE_CTL)) {
			if (IEEE80211_QOS_HAS_SEQ(wh)) {
				tid = ((struct ieee80211_qosframe *)wh)->
				    i_qos[0] & IEEE80211_QOS_TID;
				if (TID_TO_WME_AC(tid) >= WME_AC_VI)
					ic->ic_wme.wme_hipri_traffic++;
				tid++;
			} else {
				tid = IEEE80211_NONQOS_TID;
			}
			rxseq = LE_16(*(uint16_t *)wh->i_seq);
			if ((in->in_flags & IEEE80211_NODE_HT) == 0 &&
			    (wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
			    (rxseq - in->in_rxseqs[tid]) <= 0) {
				/* duplicate, discard */
				ieee80211_dbg(IEEE80211_MSG_INPUT,
				    "ieee80211_input: duplicate",
				    "seqno <%u,%u> fragno <%u,%u> tid %u",
				    rxseq >> IEEE80211_SEQ_SEQ_SHIFT,
				    in->in_rxseqs[tid] >>
				    IEEE80211_SEQ_SEQ_SHIFT,
				    rxseq & IEEE80211_SEQ_FRAG_MASK,
				    in->in_rxseqs[tid] &
				    IEEE80211_SEQ_FRAG_MASK,
				    tid);
				ic->ic_stats.is_rx_dups++;
				goto out_exit_mutex;
			}
			in->in_rxseqs[tid] = rxseq;
		}
	}
Exemple #21
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;
	}
}
Exemple #22
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);
    }

}
Exemple #23
0
static int
ieee80211_do_slow_print(struct ieee80211com *ic, int *did_print)
{
	static const struct timeval merge_print_intvl = {
		.tv_sec = 1, .tv_usec = 0
	};
	if ((ic->ic_if.if_flags & IFF_LINK0) == 0)
		return 0;
	if (!*did_print && (ic->ic_if.if_flags & IFF_DEBUG) == 0 &&
	    !ratecheck(&ic->ic_last_merge_print, &merge_print_intvl))
		return 0;

	*did_print = 1;
	return 1;
}

/* ieee80211_ibss_merge helps merge 802.11 ad hoc networks.  The
 * convention, set by the Wireless Ethernet Compatibility Alliance
 * (WECA), is that an 802.11 station will change its BSSID to match
 * the "oldest" 802.11 ad hoc network, on the same channel, that
 * has the station's desired SSID.  The "oldest" 802.11 network
 * sends beacons with the greatest TSF timestamp.
 *
 * Return ENETRESET if the BSSID changed, 0 otherwise.
 *
 * XXX Perhaps we should compensate for the time that elapses
 * between the MAC receiving the beacon and the host processing it
 * in ieee80211_ibss_merge.
 */
int
ieee80211_ibss_merge(struct ieee80211com *ic, struct ieee80211_node *ni,
    u_int64_t local_tsft)
{
	u_int64_t beacon_tsft;
	int did_print = 0, sign;
	union {
		u_int64_t	word;
		u_int8_t	tstamp[8];
	} u;

	/* ensure alignment */
	(void)memcpy(&u, &ni->ni_tstamp[0], sizeof(u));
	beacon_tsft = letoh64(u.word);

	/* we are faster, let the other guy catch up */
	if (beacon_tsft < local_tsft)
		sign = -1;
	else
		sign = 1;

	if (IEEE80211_ADDR_EQ(ni->ni_bssid, ic->ic_bss->ni_bssid)) {
		if (!ieee80211_do_slow_print(ic, &did_print))
			return 0;
		printf("%s: tsft offset %s%llu\n", ic->ic_if.if_xname,
		    (sign < 0) ? "-" : "",
		    (sign < 0)
			? (local_tsft - beacon_tsft)
			: (beacon_tsft - local_tsft));
		return 0;
	}

	if (sign < 0)
		return 0;

	if (ieee80211_match_bss(ic, ni) != 0)
		return 0;

	if (ieee80211_do_slow_print(ic, &did_print)) {
		printf("%s: ieee80211_ibss_merge: bssid mismatch %s\n",
		    ic->ic_if.if_xname, ether_sprintf(ni->ni_bssid));
		printf("%s: my tsft %llu beacon tsft %llu\n",
		    ic->ic_if.if_xname, local_tsft, beacon_tsft);
		printf("%s: sync TSF with %s\n",
		    ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr));
	}

	ic->ic_flags &= ~IEEE80211_F_SIBSS;

	/* negotiate rates with new IBSS */
	ieee80211_fix_rate(ic, ni, IEEE80211_F_DOFRATE |
	    IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
	if (ni->ni_rates.rs_nrates == 0) {
		if (ieee80211_do_slow_print(ic, &did_print)) {
			printf("%s: rates mismatch, BSSID %s\n",
			    ic->ic_if.if_xname, ether_sprintf(ni->ni_bssid));
		}
		return 0;
	}

	if (ieee80211_do_slow_print(ic, &did_print)) {
		printf("%s: sync BSSID %s -> ",
		    ic->ic_if.if_xname, ether_sprintf(ic->ic_bss->ni_bssid));
		printf("%s ", ether_sprintf(ni->ni_bssid));
		printf("(from %s)\n", ether_sprintf(ni->ni_macaddr));
	}

	ieee80211_node_newstate(ni, IEEE80211_STA_BSS);
	(*ic->ic_node_copy)(ic, ic->ic_bss, ni);

	return ENETRESET;
}
Exemple #24
0
static void
hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni,
    const struct ieee80211_frame *wh, const struct ieee80211_meshprep_ie *prep)
{
	struct ieee80211_mesh_state *ms = vap->iv_mesh;
	struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
	struct ieee80211_mesh_route *rt = NULL;
	struct ieee80211_hwmp_route *hr;
	struct ieee80211com *ic = vap->iv_ic;
	struct ifnet *ifp = vap->iv_ifp;
	struct mbuf *m, *next;
#ifdef IEEE80211_DEBUG
	char ethstr[ETHER_ADDRSTRLEN + 1];
#endif

	/*
	 * Acceptance criteria: if the corresponding PREQ was not generated
	 * by us and forwarding is disabled, discard this PREP.
	 */
	if (ni == vap->iv_bss ||
	    ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
		return;
	if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
	    !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD))
		return;

	IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
	    "received PREP from %s", kether_ntoa(prep->prep_targetaddr, ethstr));

	rt = ieee80211_mesh_rt_find(vap, prep->prep_targetaddr);
	if (rt == NULL) {
		/*
		 * If we have no entry this could be a reply to a root PREQ.
		 */
		if (hs->hs_rootmode != IEEE80211_HWMP_ROOTMODE_DISABLED) {
			rt = ieee80211_mesh_rt_add(vap, prep->prep_targetaddr);
			if (rt == NULL) {
				IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
				    ni, "unable to add PREP path to %s",
				    kether_ntoa(prep->prep_targetaddr, ethstr));
				vap->iv_stats.is_mesh_rtaddfailed++;
				return;
			}
			IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
			rt->rt_nhops = prep->prep_hopcount;
			rt->rt_lifetime = prep->prep_lifetime;
			rt->rt_metric = prep->prep_metric;
			rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
			IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
			    "add root path to %s nhops %d metric %d (PREP)",
			    kether_ntoa(prep->prep_targetaddr, ethstr),
			    rt->rt_nhops, rt->rt_metric);
			return;
		} 
		return;
	}
	/*
	 * Sequence number validation.
	 */
	hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
	if (HWMP_SEQ_LEQ(prep->prep_targetseq, hr->hr_seq)) {
		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
		    "discard PREP from %s, old seq no %u <= %u",
		    kether_ntoa(prep->prep_targetaddr, ethstr),
		    prep->prep_targetseq, hr->hr_seq);
		return;
	}
	hr->hr_seq = prep->prep_targetseq;
	/*
	 * If it's NOT for us, propagate the PREP.
	 */
	if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, prep->prep_origaddr) &&
	    prep->prep_ttl > 1 && prep->prep_hopcount < hs->hs_maxhops) {
		struct ieee80211_meshprep_ie pprep; /* propagated PREP */

		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
		    "propagate PREP from %s",
		    kether_ntoa(prep->prep_targetaddr, ethstr));

		memcpy(&pprep, prep, sizeof(pprep));
		pprep.prep_hopcount += 1;
		pprep.prep_ttl -= 1;
		pprep.prep_metric += ms->ms_pmetric->mpm_metric(ni);
		IEEE80211_ADDR_COPY(pprep.prep_targetaddr, vap->iv_myaddr);
		hwmp_send_prep(ni, vap->iv_myaddr, broadcastaddr, &pprep);
	}
	hr = IEEE80211_MESH_ROUTE_PRIV(rt, struct ieee80211_hwmp_route);
	if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) {
		/* NB: never clobber a proxy entry */;
		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
		    "discard PREP for %s, route is marked PROXY",
		    kether_ntoa(prep->prep_targetaddr, ethstr));
		vap->iv_stats.is_hwmp_proxy++;
	} else if (prep->prep_origseq == hr->hr_origseq) {
		/*
		 * Check if we already have a path to this node.
		 * If we do, check if this path reply contains a
		 * better route.
		 */
		if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
		    (prep->prep_hopcount < rt->rt_nhops ||
		     prep->prep_metric < rt->rt_metric)) {
			IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
			    "%s path to %s, hopcount %d:%d metric %d:%d",
			    rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID ?
				"prefer" : "update",
			    kether_ntoa(prep->prep_origaddr, ethstr),
			    rt->rt_nhops, prep->prep_hopcount,
			    rt->rt_metric, prep->prep_metric);
			IEEE80211_ADDR_COPY(rt->rt_nexthop, wh->i_addr2);
			rt->rt_nhops = prep->prep_hopcount;
			rt->rt_lifetime = prep->prep_lifetime;
			rt->rt_metric = prep->prep_metric;
			rt->rt_flags |= IEEE80211_MESHRT_FLAGS_VALID;
		} else {
			IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
			    "ignore PREP for %s, hopcount %d:%d metric %d:%d",
			    kether_ntoa(prep->prep_targetaddr, ethstr),
			    rt->rt_nhops, prep->prep_hopcount,
			    rt->rt_metric, prep->prep_metric);
		}
	} else {
		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
		    "discard PREP for %s, wrong seqno %u != %u",
		    kether_ntoa(prep->prep_targetaddr, ethstr), prep->prep_origseq,
		    hr->hr_seq);
		vap->iv_stats.is_hwmp_wrongseq++;
	} 
	/*
	 * Check for frames queued awaiting path discovery.
	 * XXX probably can tell exactly and avoid remove call
	 * NB: hash may have false matches, if so they will get
	 *     stuck back on the stageq because there won't be
	 *     a path.
	 */
	m = ieee80211_ageq_remove(&ic->ic_stageq, 
	    (struct ieee80211_node *)(uintptr_t)
		ieee80211_mac_hash(ic, rt->rt_dest));
	for (; m != NULL; m = next) {
		next = m->m_nextpkt;
		m->m_nextpkt = NULL;
		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
		    "flush queued frame %p len %d", m, m->m_pkthdr.len);
		ieee80211_handoff(ifp, m);
	}
}
Exemple #25
0
static void
hwmp_recv_preq(struct ieee80211vap *vap, struct ieee80211_node *ni,
    const struct ieee80211_frame *wh, const struct ieee80211_meshpreq_ie *preq)
{
	struct ieee80211_mesh_state *ms = vap->iv_mesh;
	struct ieee80211_mesh_route *rt = NULL;
	struct ieee80211_mesh_route *rtorig = NULL;
	struct ieee80211_hwmp_route *hrorig;
	struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
	struct ieee80211_meshprep_ie prep;
#ifdef IEEE80211_DEBUG
	char ethstr[ETHER_ADDRSTRLEN + 1];
#endif

	if (ni == vap->iv_bss ||
	    ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED)
		return;
	/*
	 * Ignore PREQs from us. Could happen because someone forward it
	 * back to us.
	 */
	if (IEEE80211_ADDR_EQ(vap->iv_myaddr, preq->preq_origaddr))
		return;

	IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
	    "received PREQ, source %s", kether_ntoa(preq->preq_origaddr, ethstr));

	/*
	 * Acceptance criteria: if the PREQ is not for us and
	 * forwarding is disabled, discard this PREQ.
	 */
	if (!IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0)) &&
	    !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) {
		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_HWMP,
		    preq->preq_origaddr, NULL, "%s", "not accepting PREQ");
		return;
	}
	rtorig = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
	if (rtorig == NULL)
		rtorig = ieee80211_mesh_rt_add(vap, preq->preq_origaddr);
	if (rtorig == NULL) {
		/* XXX stat */
		return;
	}
	hrorig = IEEE80211_MESH_ROUTE_PRIV(rtorig, struct ieee80211_hwmp_route);
	/*
	 * Sequence number validation.
	 */
	if (HWMP_SEQ_LEQ(preq->preq_id, hrorig->hr_preqid) &&
	    HWMP_SEQ_LEQ(preq->preq_origseq, hrorig->hr_seq)) {
		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
		    "discard PREQ from %s, old seq no %u <= %u",
		    kether_ntoa(preq->preq_origaddr, ethstr),
		    preq->preq_origseq, hrorig->hr_seq);
		return;
	}
	hrorig->hr_preqid = preq->preq_id;
	hrorig->hr_seq = preq->preq_origseq;

	/*
	 * Check if the PREQ is addressed to us.
	 */
	if (IEEE80211_ADDR_EQ(vap->iv_myaddr, PREQ_TADDR(0))) {
		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
		    "reply to %s", kether_ntoa(preq->preq_origaddr, ethstr));
		/*
		 * Build and send a PREP frame.
		 */
		prep.prep_flags = 0;
		prep.prep_hopcount = 0;
		prep.prep_ttl = ms->ms_ttl;
		IEEE80211_ADDR_COPY(prep.prep_targetaddr, vap->iv_myaddr);
		prep.prep_targetseq = ++hs->hs_seq;
		prep.prep_lifetime = preq->preq_lifetime;
		prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
		IEEE80211_ADDR_COPY(prep.prep_origaddr, preq->preq_origaddr);
		prep.prep_origseq = preq->preq_origseq;
		hwmp_send_prep(ni, vap->iv_myaddr, wh->i_addr2, &prep);
		/*
		 * Build the reverse path, if we don't have it already.
		 */
		rt = ieee80211_mesh_rt_find(vap, preq->preq_origaddr);
		if (rt == NULL)
			hwmp_discover(vap, preq->preq_origaddr, NULL);
		else if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0)
			hwmp_discover(vap, rt->rt_dest, NULL);
		return;
	}
	/*
	 * Proactive PREQ: reply with a proactive PREP to the
	 * root STA if requested.
	 */
	if (IEEE80211_ADDR_EQ(PREQ_TADDR(0), broadcastaddr) &&
	    (PREQ_TFLAGS(0) &
	    ((IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF) ==
	    (IEEE80211_MESHPREQ_TFLAGS_TO|IEEE80211_MESHPREQ_TFLAGS_RF)))) {
		uint8_t rootmac[IEEE80211_ADDR_LEN];

		IEEE80211_ADDR_COPY(rootmac, preq->preq_origaddr);
		rt = ieee80211_mesh_rt_find(vap, rootmac);
		if (rt == NULL) {
			rt = ieee80211_mesh_rt_add(vap, rootmac);
			if (rt == NULL) {
				IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
				    "unable to add root mesh path to %s",
				    kether_ntoa(rootmac, ethstr));
				vap->iv_stats.is_mesh_rtaddfailed++;
				return;
			}
		}
		IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
		    "root mesh station @ %s", kether_ntoa(rootmac, ethstr));

		/*
		 * Reply with a PREP if we don't have a path to the root
		 * or if the root sent us a proactive PREQ.
		 */
		if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0 ||
		    (preq->preq_flags & IEEE80211_MESHPREQ_FLAGS_PP)) {
			prep.prep_flags = 0;
			prep.prep_hopcount = 0;
			prep.prep_ttl = ms->ms_ttl;
			IEEE80211_ADDR_COPY(prep.prep_origaddr, rootmac);
			prep.prep_origseq = preq->preq_origseq;
			prep.prep_lifetime = preq->preq_lifetime;
			prep.prep_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
			IEEE80211_ADDR_COPY(prep.prep_targetaddr,
			    vap->iv_myaddr);
			prep.prep_targetseq = ++hs->hs_seq;
			hwmp_send_prep(vap->iv_bss, vap->iv_myaddr,
			    broadcastaddr, &prep);
		}
		hwmp_discover(vap, rootmac, NULL);
		return;
	}
	rt = ieee80211_mesh_rt_find(vap, PREQ_TADDR(0));

	/*
	 * Forwarding and Intermediate reply for PREQs with 1 target.
	 */
	if (preq->preq_tcount == 1) {
		struct ieee80211_meshpreq_ie ppreq; /* propagated PREQ */

		memcpy(&ppreq, preq, sizeof(ppreq));
		/*
		 * We have a valid route to this node.
		 */
		if (rt != NULL &&
		    (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)) {
			if (preq->preq_ttl > 1 &&
			    preq->preq_hopcount < hs->hs_maxhops) {
				IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
				    "forward PREQ from %s",
				    kether_ntoa(preq->preq_origaddr, ethstr));
				/*
				 * Propagate the original PREQ.
				 */
				ppreq.preq_hopcount += 1;
				ppreq.preq_ttl -= 1;
				ppreq.preq_metric +=
				    ms->ms_pmetric->mpm_metric(ni);
				/*
				 * Set TO and unset RF bits because we are going
				 * to send a PREP next.
				 */
				ppreq.preq_targets[0].target_flags |=
				    IEEE80211_MESHPREQ_TFLAGS_TO;
				ppreq.preq_targets[0].target_flags &=
				    ~IEEE80211_MESHPREQ_TFLAGS_RF;
				hwmp_send_preq(ni, vap->iv_myaddr,
				    broadcastaddr, &ppreq);
			}
			/*
			 * Check if we can send an intermediate Path Reply,
			 * i.e., Target Only bit is not set.
			 */
	    		if (!(PREQ_TFLAGS(0) & IEEE80211_MESHPREQ_TFLAGS_TO)) {
				struct ieee80211_meshprep_ie prep;

				IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
				    "intermediate reply for PREQ from %s",
				    kether_ntoa(preq->preq_origaddr, ethstr));
				prep.prep_flags = 0;
				prep.prep_hopcount = rt->rt_nhops + 1;
				prep.prep_ttl = ms->ms_ttl;
				IEEE80211_ADDR_COPY(&prep.prep_targetaddr,
				    PREQ_TADDR(0));
				prep.prep_targetseq = hrorig->hr_seq;
				prep.prep_lifetime = preq->preq_lifetime;
				prep.prep_metric = rt->rt_metric +
				    ms->ms_pmetric->mpm_metric(ni);
				IEEE80211_ADDR_COPY(&prep.prep_origaddr,
				    preq->preq_origaddr);
				prep.prep_origseq = hrorig->hr_seq;
				hwmp_send_prep(ni, vap->iv_myaddr,
				    broadcastaddr, &prep);
			}
		/*
		 * We have no information about this path,
		 * propagate the PREQ.
		 */
		} else if (preq->preq_ttl > 1 &&
		    preq->preq_hopcount < hs->hs_maxhops) {
			if (rt == NULL) {
				rt = ieee80211_mesh_rt_add(vap, PREQ_TADDR(0));
				if (rt == NULL) {
					IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
					    ni, "unable to add PREQ path to %s",
					    kether_ntoa(PREQ_TADDR(0), ethstr));
					vap->iv_stats.is_mesh_rtaddfailed++;
					return;
				}
			}
			rt->rt_metric = preq->preq_metric;
			rt->rt_lifetime = preq->preq_lifetime;
			hrorig = IEEE80211_MESH_ROUTE_PRIV(rt,
			    struct ieee80211_hwmp_route);
			hrorig->hr_seq = preq->preq_origseq;
			hrorig->hr_preqid = preq->preq_id;

			IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni,
			    "forward PREQ from %s",
			    kether_ntoa(preq->preq_origaddr, ethstr));
			ppreq.preq_hopcount += 1;
			ppreq.preq_ttl -= 1;
			ppreq.preq_metric += ms->ms_pmetric->mpm_metric(ni);
			hwmp_send_preq(ni, vap->iv_myaddr, broadcastaddr,
			    &ppreq);
		}
	}

}
Exemple #26
0
static struct ieee80211_node *
hwmp_discover(struct ieee80211vap *vap,
    const uint8_t dest[IEEE80211_ADDR_LEN], struct mbuf *m)
{
	struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
	struct ieee80211_mesh_state *ms = vap->iv_mesh;
	struct ieee80211_mesh_route *rt = NULL;
	struct ieee80211_hwmp_route *hr;
	struct ieee80211_meshpreq_ie preq;
	struct ieee80211_node *ni;
	int sendpreq = 0;
#ifdef IEEE80211_DEBUG
	char ethstr[ETHER_ADDRSTRLEN + 1];
#endif

	KASSERT(vap->iv_opmode == IEEE80211_M_MBSS,
	    ("not a mesh vap, opmode %d", vap->iv_opmode));

	KASSERT(!IEEE80211_ADDR_EQ(vap->iv_myaddr, dest),
	    ("%s: discovering self!", __func__));

	ni = NULL;
	if (!IEEE80211_IS_MULTICAST(dest)) {
		rt = ieee80211_mesh_rt_find(vap, dest);
		if (rt == NULL) {
			rt = ieee80211_mesh_rt_add(vap, dest);
			if (rt == NULL) {
				IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP,
				    ni, "unable to add discovery path to %s",
				    kether_ntoa(dest, ethstr));
				vap->iv_stats.is_mesh_rtaddfailed++;
				goto done;
			}
		}
		hr = IEEE80211_MESH_ROUTE_PRIV(rt,
		    struct ieee80211_hwmp_route);
		if ((rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID) == 0) {
			if (hr->hr_origseq == 0)
				hr->hr_origseq = ++hs->hs_seq;
			rt->rt_metric = IEEE80211_MESHLMETRIC_INITIALVAL;
			rt->rt_lifetime =
			    ticks_to_msecs(ieee80211_hwmp_pathtimeout);
			/* XXX check preq retries */
			sendpreq = 1;
			if (m != NULL) {
				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP,
				    dest, "%s",
				    "start path discovery (src <none>)");
			} else {
				IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_HWMP,
				    dest,
				    "start path discovery (src %s)",
				    kether_ntoa(
					    mtod(m, struct ether_header *)->ether_shost,
					    ethstr));
			}
			/*
			 * Try to discover the path for this node.
			 */
			preq.preq_flags = 0;
			preq.preq_hopcount = 0;
			preq.preq_ttl = ms->ms_ttl;
			preq.preq_id = ++hs->hs_preqid;
			IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr);
			preq.preq_origseq = hr->hr_origseq;
			preq.preq_lifetime = rt->rt_lifetime;
			preq.preq_metric = rt->rt_metric;
			preq.preq_tcount = 1;
			IEEE80211_ADDR_COPY(PREQ_TADDR(0), dest);
			PREQ_TFLAGS(0) = 0;
			if (ieee80211_hwmp_targetonly)
				PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_TO;
			if (ieee80211_hwmp_replyforward)
				PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_RF;
			PREQ_TFLAGS(0) |= IEEE80211_MESHPREQ_TFLAGS_USN;
			PREQ_TSEQ(0) = 0;
			/* XXX check return value */
			hwmp_send_preq(vap->iv_bss, vap->iv_myaddr,
			    broadcastaddr, &preq);
		}
		if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_VALID)
			ni = ieee80211_find_txnode(vap, rt->rt_nexthop);
	} else {
Exemple #27
0
 /*
  * processes data frames.
  * ieee80211_wow_magic_parser parses the wbuf to check if match magic packet.
  */
void 
ieee80211_wow_magic_parser(struct ieee80211_node *ni, wbuf_t wbuf)
{
    struct ieee80211vap *vap = ni->ni_vap;
    a_uint8_t    i_addr[IEEE80211_ADDR_LEN];
    a_int32_t    left_len = wbuf_get_pktlen(wbuf);
    a_uint8_t    *cur_ptr;
    a_uint32_t   dup_cnt, is_match = FALSE, is_bcast = FALSE;

    //wow_dump_pkt(wbuf->data, wbuf->len);

    if (left_len < IEEE80211_WOW_MAGIC_PKTLEN)
        return;
        
    cur_ptr = wbuf_header(wbuf);
    IEEE80211_ADDR_COPY(i_addr, vap->iv_myaddr);

    /* parse whole pkt */
    while (cur_ptr && (left_len>0) && (!is_match)) {
        
        /* left len is less than magic pkt size, give up */
        if (left_len < IEEE80211_WOW_MAGIC_PKTLEN)
            break;

        /* to skip continuous 0xFF and to match last 6 bytes of 0xFF */
        while (IEEE80211_IS_BROADCAST(cur_ptr) && (left_len>=IEEE80211_WOW_MAGIC_PKTLEN)) {
            is_bcast = TRUE;
            cur_ptr += IEEE80211_ADDR_LEN;
            left_len -= IEEE80211_ADDR_LEN;
        }

        /* 6 bytes of 0xFF matched, to check if 16 duplications of the IEEE address */
        if (is_bcast) {
            
            dup_cnt = 0;
            
            /* if 0xFF exists at head, skip it */
            while ((cur_ptr[0]==0xFF) && (left_len>=IEEE80211_WOW_MAGIC_DUPLEN)) {
                cur_ptr++;
                left_len--;
            }

            /* left len is less than duplication size, give up */
            if (left_len < IEEE80211_WOW_MAGIC_DUPLEN)
                break;
            
            /* to check if 16 duplications of the IEEE address */
            while (cur_ptr && (left_len>=IEEE80211_ADDR_LEN) && IEEE80211_ADDR_EQ(cur_ptr, i_addr)) {
                cur_ptr += IEEE80211_ADDR_LEN;
                left_len -= IEEE80211_ADDR_LEN;
                dup_cnt++;
                
                if (dup_cnt >= IEEE80211_WOW_MAGIC_DUPCNT) {
                    is_match = TRUE;
                    break;
                }
            }

            /* not match magic pkt, keep parsing */
            is_bcast = FALSE;

        } else {
            cur_ptr++;
            left_len--;
        }        
    }
    
    if (is_match) {
        adf_os_print("Magic packet received...\n");
        ieee80211_wow_set_gpio(vap);
    }
}
int
ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
	struct ieee80211com *ic = (void *)ifp;
	struct ifreq *ifr = (struct ifreq *)data;
	int i, error = 0;
	struct ieee80211_nwid nwid;
	struct ieee80211_wpapsk *psk;
	struct ieee80211_wmmparams *wmm;
	struct ieee80211_power *power;
	struct ieee80211_bssid *bssid;
	struct ieee80211chanreq *chanreq;
	struct ieee80211_channel *chan;
	struct ieee80211_txpower *txpower;
	static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	};
	struct ieee80211_nodereq *nr, nrbuf;
	struct ieee80211_nodereq_all *na;
	struct ieee80211_node *ni;
	u_int32_t flags;

	switch (cmd) {
	case SIOCSIFADDR:
	case SIOCGIFADDR:
		error = ether_ioctl(ifp, &ic->ic_ac, cmd, data);
		break;
	case SIOCSIFMEDIA:
	case SIOCGIFMEDIA:
		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
		break;
	case SIOCS80211NWID:
		if ((error = suser(curproc, 0)) != 0)
			break;
		if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
			break;
		if (nwid.i_len > IEEE80211_NWID_LEN) {
			error = EINVAL;
			break;
		}
		memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
		ic->ic_des_esslen = nwid.i_len;
		memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len);
		error = ENETRESET;
		break;
	case SIOCG80211NWID:
		memset(&nwid, 0, sizeof(nwid));
		switch (ic->ic_state) {
		case IEEE80211_S_INIT:
		case IEEE80211_S_SCAN:
			nwid.i_len = ic->ic_des_esslen;
			memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len);
			break;
		default:
			nwid.i_len = ic->ic_bss->ni_esslen;
			memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
			break;
		}
		error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
		break;
	case SIOCS80211NWKEY:
		if ((error = suser(curproc, 0)) != 0)
			break;
		error = ieee80211_ioctl_setnwkeys(ic, (void *)data);
		break;
	case SIOCG80211NWKEY:
		error = ieee80211_ioctl_getnwkeys(ic, (void *)data);
		break;
	case SIOCS80211WMMPARMS:
		if ((error = suser(curproc, 0)) != 0)
			break;
		if (!(ic->ic_flags & IEEE80211_C_QOS)) {
			error = ENODEV;
			break;
		}
		wmm = (struct ieee80211_wmmparams *)data;
		if (wmm->i_enabled)
			ic->ic_flags |= IEEE80211_F_QOS;
		else
			ic->ic_flags &= ~IEEE80211_F_QOS;
		error = ENETRESET;
		break;
	case SIOCG80211WMMPARMS:
		wmm = (struct ieee80211_wmmparams *)data;
		wmm->i_enabled = (ic->ic_flags & IEEE80211_F_QOS) ? 1 : 0;
		break;
	case SIOCS80211WPAPARMS:
		if ((error = suser(curproc, 0)) != 0)
			break;
		error = ieee80211_ioctl_setwpaparms(ic, (void *)data);
		break;
	case SIOCG80211WPAPARMS:
		error = ieee80211_ioctl_getwpaparms(ic, (void *)data);
		break;
	case SIOCS80211WPAPSK:
		if ((error = suser(curproc, 0)) != 0)
			break;
		psk = (struct ieee80211_wpapsk *)data;
		if (psk->i_enabled) {
			ic->ic_flags |= IEEE80211_F_PSK;
			memcpy(ic->ic_psk, psk->i_psk, sizeof(ic->ic_psk));
		} else {
			ic->ic_flags &= ~IEEE80211_F_PSK;
			memset(ic->ic_psk, 0, sizeof(ic->ic_psk));
		}
		error = ENETRESET;
		break;
	case SIOCG80211WPAPSK:
		psk = (struct ieee80211_wpapsk *)data;
		if (ic->ic_flags & IEEE80211_F_PSK) {
			psk->i_enabled = 1;
			/* do not show any keys to non-root user */
			if (suser(curproc, 0) != 0) {
				psk->i_enabled = 2;
				memset(psk->i_psk, 0, sizeof(psk->i_psk));
				break;	/* return ok but w/o key */
			}
			memcpy(psk->i_psk, ic->ic_psk, sizeof(psk->i_psk));
		} else
			psk->i_enabled = 0;
		break;
	case SIOCS80211POWER:
		if ((error = suser(curproc, 0)) != 0)
			break;
		power = (struct ieee80211_power *)data;
		ic->ic_lintval = power->i_maxsleep;
		if (power->i_enabled != 0) {
			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
				error = EINVAL;
			else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
				ic->ic_flags |= IEEE80211_F_PMGTON;
				error = ENETRESET;
			}
		} else {
			if (ic->ic_flags & IEEE80211_F_PMGTON) {
				ic->ic_flags &= ~IEEE80211_F_PMGTON;
				error = ENETRESET;
			}
		}
		break;
	case SIOCG80211POWER:
		power = (struct ieee80211_power *)data;
		power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
		power->i_maxsleep = ic->ic_lintval;
		break;
	case SIOCS80211BSSID:
		if ((error = suser(curproc, 0)) != 0)
			break;
		bssid = (struct ieee80211_bssid *)data;
		if (IEEE80211_ADDR_EQ(bssid->i_bssid, empty_macaddr))
			ic->ic_flags &= ~IEEE80211_F_DESBSSID;
		else {
			ic->ic_flags |= IEEE80211_F_DESBSSID;
			IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid);
		}
		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
			break;
		switch (ic->ic_state) {
		case IEEE80211_S_INIT:
		case IEEE80211_S_SCAN:
			error = ENETRESET;
			break;
		default:
			if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
			    !IEEE80211_ADDR_EQ(ic->ic_des_bssid,
			    ic->ic_bss->ni_bssid))
				error = ENETRESET;
			break;
		}
		break;
	case SIOCG80211BSSID:
		bssid = (struct ieee80211_bssid *)data;
		switch (ic->ic_state) {
		case IEEE80211_S_INIT:
		case IEEE80211_S_SCAN:
			if (ic->ic_opmode == IEEE80211_M_HOSTAP)
				IEEE80211_ADDR_COPY(bssid->i_bssid,
				    ic->ic_myaddr);
			else if (ic->ic_flags & IEEE80211_F_DESBSSID)
				IEEE80211_ADDR_COPY(bssid->i_bssid,
				    ic->ic_des_bssid);
			else
				memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
			break;
		default:
			IEEE80211_ADDR_COPY(bssid->i_bssid,
			    ic->ic_bss->ni_bssid);
			break;
		}
		break;
	case SIOCS80211CHANNEL:
		if ((error = suser(curproc, 0)) != 0)
			break;
		chanreq = (struct ieee80211chanreq *)data;
		if (chanreq->i_channel == IEEE80211_CHAN_ANY)
			ic->ic_des_chan = IEEE80211_CHAN_ANYC;
		else if (chanreq->i_channel > IEEE80211_CHAN_MAX ||
		    isclr(ic->ic_chan_active, chanreq->i_channel)) {
			error = EINVAL;
			break;
		} else
			ic->ic_ibss_chan = ic->ic_des_chan =
			    &ic->ic_channels[chanreq->i_channel];
		switch (ic->ic_state) {
		case IEEE80211_S_INIT:
		case IEEE80211_S_SCAN:
			error = ENETRESET;
			break;
		default:
			if (ic->ic_opmode == IEEE80211_M_STA) {
				if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
				    ic->ic_bss->ni_chan != ic->ic_des_chan)
					error = ENETRESET;
			} else {
				if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
					error = ENETRESET;
			}
			break;
		}
		break;
	case SIOCG80211CHANNEL:
		chanreq = (struct ieee80211chanreq *)data;
		switch (ic->ic_state) {
		case IEEE80211_S_INIT:
		case IEEE80211_S_SCAN:
			if (ic->ic_opmode == IEEE80211_M_STA)
				chan = ic->ic_des_chan;
			else
				chan = ic->ic_ibss_chan;
			break;
		default:
			chan = ic->ic_bss->ni_chan;
			break;
		}
		chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
		break;
#if 0
	case SIOCG80211ZSTATS:
#endif
	case SIOCG80211STATS:
		ifr = (struct ifreq *)data;
		copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
#if 0
		if (cmd == SIOCG80211ZSTATS)
			memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
#endif
		break;
	case SIOCS80211TXPOWER:
		if ((error = suser(curproc, 0)) != 0)
			break;
		txpower = (struct ieee80211_txpower *)data;
		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) {
			error = EINVAL;
			break;
		}
		if (IEEE80211_TXPOWER_MIN > txpower->i_val ||
		    txpower->i_val > IEEE80211_TXPOWER_MAX) {
			error = EINVAL;
			break;
		}
		ic->ic_txpower = txpower->i_val;
		error = ENETRESET;
		break;
	case SIOCG80211TXPOWER:
		txpower = (struct ieee80211_txpower *)data;
		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
			error = EINVAL;
		else
			txpower->i_val = ic->ic_txpower;
		break;
	case SIOCSIFMTU:
		ifr = (struct ifreq *)data;
		if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
		    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
			error = EINVAL;
		else
			ifp->if_mtu = ifr->ifr_mtu;
		break;
	case SIOCS80211SCAN:
		if ((error = suser(curproc, 0)) != 0)
			break;
		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
			break;
		if ((ifp->if_flags & IFF_UP) == 0) {
			error = ENETDOWN;
			break;
		}
		if ((ic->ic_scan_lock & IEEE80211_SCAN_REQUEST) == 0) {
			if (ic->ic_scan_lock & IEEE80211_SCAN_LOCKED)
				ic->ic_scan_lock |= IEEE80211_SCAN_RESUME;
			ic->ic_scan_lock |= IEEE80211_SCAN_REQUEST;
			if (ic->ic_state != IEEE80211_S_SCAN)
				ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
		}
		/* Let the userspace process wait for completion */
		error = tsleep(&ic->ic_scan_lock, PCATCH, "80211scan",
		    hz * IEEE80211_SCAN_TIMEOUT);
		break;
	case SIOCG80211NODE:
		nr = (struct ieee80211_nodereq *)data;
		ni = ieee80211_find_node(ic, nr->nr_macaddr);
		if (ni == NULL) {
			error = ENOENT;
			break;
		}
		ieee80211_node2req(ic, ni, nr);
		break;
	case SIOCS80211NODE:
		if ((error = suser(curproc, 0)) != 0)
			break;
		if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
			error = EINVAL;
			break;
		}
		nr = (struct ieee80211_nodereq *)data;

		ni = ieee80211_find_node(ic, nr->nr_macaddr);
		if (ni == NULL)
			ni = ieee80211_alloc_node(ic, nr->nr_macaddr);
		if (ni == NULL) {
			error = ENOENT;
			break;
		}

		if (nr->nr_flags & IEEE80211_NODEREQ_COPY)
			ieee80211_req2node(ic, nr, ni);
		break;
	case SIOCS80211DELNODE:
		if ((error = suser(curproc, 0)) != 0)
			break;
		nr = (struct ieee80211_nodereq *)data;
		ni = ieee80211_find_node(ic, nr->nr_macaddr);
		if (ni == NULL)
			error = ENOENT;
		else if (ni == ic->ic_bss)
			error = EPERM;
		else {
			if (ni->ni_state == IEEE80211_STA_COLLECT)
				break;

			/* Disassociate station. */
			if (ni->ni_state == IEEE80211_STA_ASSOC)
				IEEE80211_SEND_MGMT(ic, ni,
				    IEEE80211_FC0_SUBTYPE_DISASSOC,
				    IEEE80211_REASON_ASSOC_LEAVE);

			/* Deauth station. */
			if (ni->ni_state >= IEEE80211_STA_AUTH)
				IEEE80211_SEND_MGMT(ic, ni,
				    IEEE80211_FC0_SUBTYPE_DEAUTH,
				    IEEE80211_REASON_AUTH_LEAVE);

			ieee80211_release_node(ic, ni);
		}
		break;
	case SIOCG80211ALLNODES:
		na = (struct ieee80211_nodereq_all *)data;
		na->na_nodes = i = 0;
		ni = RB_MIN(ieee80211_tree, &ic->ic_tree);
		while (ni && na->na_size >=
		    i + sizeof(struct ieee80211_nodereq)) {
			ieee80211_node2req(ic, ni, &nrbuf);
			error = copyout(&nrbuf, (caddr_t)na->na_node + i,
			    sizeof(struct ieee80211_nodereq));
			if (error)
				break;
			i += sizeof(struct ieee80211_nodereq);
			na->na_nodes++;
			ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni);
		}
		break;
	case SIOCG80211FLAGS:
		flags = ic->ic_flags;
		if (ic->ic_opmode != IEEE80211_M_HOSTAP)
			flags &= ~IEEE80211_F_HOSTAPMASK;
		ifr->ifr_flags = flags >> IEEE80211_F_USERSHIFT;
		break;
	case SIOCS80211FLAGS:
		if ((error = suser(curproc, 0)) != 0)
			break;
		flags = (u_int32_t)ifr->ifr_flags << IEEE80211_F_USERSHIFT;
		if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
		    (flags & IEEE80211_F_HOSTAPMASK)) {
			error = EINVAL;
			break;
		}
		ic->ic_flags = (ic->ic_flags & ~IEEE80211_F_USERMASK) | flags;
		error = ENETRESET;
		break;
	default:
		error = ENOTTY;
		break;
	}
	return error;
}
Exemple #29
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
		 */
	}
Exemple #30
0
int
ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni)
{
	u_int8_t rate;
	int fail;

	fail = 0;
	if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
		fail |= 0x01;
	if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
	    ni->ni_chan != ic->ic_des_chan)
		fail |= 0x01;
#ifndef IEEE80211_STA_ONLY
	if (ic->ic_opmode == IEEE80211_M_IBSS) {
		if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
			fail |= 0x02;
	} else
#endif
	{
		if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
			fail |= 0x02;
	}
	if (ic->ic_flags & (IEEE80211_F_WEPON | IEEE80211_F_RSNON)) {
		if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
			fail |= 0x04;
	} else {
		if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
			fail |= 0x04;
	}

	rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DONEGO);
	if (rate & IEEE80211_RATE_BASIC)
		fail |= 0x08;
	if (ic->ic_des_esslen != 0 &&
	    (ni->ni_esslen != ic->ic_des_esslen ||
	     memcmp(ni->ni_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0))
		fail |= 0x10;
	if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
	    !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid))
		fail |= 0x20;

	if (ic->ic_flags & IEEE80211_F_RSNON) {
		/*
		 * If at least one RSN IE field from the AP's RSN IE fails
		 * to overlap with any value the STA supports, the STA shall
		 * decline to associate with that AP.
		 */
		if ((ni->ni_rsnprotos & ic->ic_rsnprotos) == 0)
			fail |= 0x40;
		if ((ni->ni_rsnakms & ic->ic_rsnakms) == 0)
			fail |= 0x40;
		if ((ni->ni_rsnakms & ic->ic_rsnakms &
		     ~(IEEE80211_AKM_PSK | IEEE80211_AKM_SHA256_PSK)) == 0) {
			/* AP only supports PSK AKMPs */
			if (!(ic->ic_flags & IEEE80211_F_PSK))
				fail |= 0x40;
		}
		if (ni->ni_rsngroupcipher != IEEE80211_CIPHER_WEP40 &&
		    ni->ni_rsngroupcipher != IEEE80211_CIPHER_TKIP &&
		    ni->ni_rsngroupcipher != IEEE80211_CIPHER_CCMP &&
		    ni->ni_rsngroupcipher != IEEE80211_CIPHER_WEP104)
			fail |= 0x40;
		if ((ni->ni_rsnciphers & ic->ic_rsnciphers) == 0)
			fail |= 0x40;

		/* we only support BIP as the IGTK cipher */
		if ((ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC) &&
		    ni->ni_rsngroupmgmtcipher != IEEE80211_CIPHER_BIP)
			fail |= 0x40;

		/* we do not support MFP but AP requires it */
		if (!(ic->ic_caps & IEEE80211_C_MFP) &&
		    (ni->ni_rsncaps & IEEE80211_RSNCAP_MFPR))
			fail |= 0x40;

		/* we require MFP but AP does not support it */
		if ((ic->ic_caps & IEEE80211_C_MFP) &&
		    (ic->ic_flags & IEEE80211_F_MFPR) &&
		    !(ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC))
			fail |= 0x40;
	}

#ifdef IEEE80211_DEBUG
	if (ic->ic_if.if_flags & IFF_DEBUG) {
		printf(" %c %s", fail ? '-' : '+',
		    ether_sprintf(ni->ni_macaddr));
		printf(" %s%c", ether_sprintf(ni->ni_bssid),
		    fail & 0x20 ? '!' : ' ');
		printf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan),
			fail & 0x01 ? '!' : ' ');
		printf(" %+4d", ni->ni_rssi);
		printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2,
		    fail & 0x08 ? '!' : ' ');
		printf(" %4s%c",
		    (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
		    (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
		    "????",
		    fail & 0x02 ? '!' : ' ');
		printf(" %7s%c ",
		    (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ?
		    "privacy" : "no",
		    fail & 0x04 ? '!' : ' ');
		printf(" %3s%c ",
		    (ic->ic_flags & IEEE80211_F_RSNON) ?
		    "rsn" : "no",
		    fail & 0x40 ? '!' : ' ');
		ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
		printf("%s\n", fail & 0x10 ? "!" : "");
	}
#endif
	return fail;
}