Beispiel #1
0
/*
 * Timeout inactive nodes.  Note that we cannot hold the node
 * lock while sending a frame as this would lead to a LOR.
 * Instead we use a generation number to mark nodes that we've
 * scanned and drop the lock and restart a scan if we have to
 * time out a node.  Since we are single-threaded by virtue of
 * controlling the inactivity timer we can be sure this will
 * process each node only once.
 */
void
ieee80211_clean_nodes(struct ieee80211com *ic)
{
	struct ieee80211_node *ni, *next_ni;
	u_int gen = ic->ic_scangen++;		/* NB: ok 'cuz single-threaded*/

	IEEE80211_NODE_LOCK(ic);
	for (ni = RB_MIN(ieee80211_tree, &ic->ic_tree);
	    ni != NULL; ni = next_ni) {
		next_ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni);
		if (ic->ic_nnodes <= ic->ic_max_nnodes)
			break;
		if (ni->ni_scangen == gen)	/* previously handled */
			continue;
		ni->ni_scangen = gen;
		if (ni->ni_refcnt > 0)
			continue;
		IEEE80211_DPRINTF(("station %s purged from LRU cache\n",
		    ether_sprintf(ni->ni_macaddr)));
		/*
		 * Send a deauthenticate frame.
		 */
		if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
			IEEE80211_NODE_UNLOCK(ic);
			IEEE80211_SEND_MGMT(ic, ni,
			    IEEE80211_FC0_SUBTYPE_DEAUTH,
			    IEEE80211_REASON_AUTH_EXPIRE);
			IEEE80211_NODE_LOCK(ic);
			ieee80211_node_leave(ic, ni);
		} else
			ieee80211_free_node(ic, ni);
		ic->ic_stats.is_node_timeout++;
	}
	IEEE80211_NODE_UNLOCK(ic);
}
Beispiel #2
0
static void
sta_leave(void *arg, struct ieee80211_node *ni)
{
	struct ieee80211vap *vap = arg;

	if (ni->ni_vap == vap && ni != vap->iv_bss)
		ieee80211_node_leave(ni);
}
Beispiel #3
0
void
ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni,
    int resp)
{
	int newassoc;

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

		/*
		 * It would be clever to search the bitmap
		 * more efficiently, but this will do for now.
		 */
		for (aid = 1; aid < ic->ic_max_aid; aid++) {
			if (!IEEE80211_AID_ISSET(aid,
			    ic->ic_aid_bitmap))
				break;
		}
		if (aid >= ic->ic_max_aid) {
			IEEE80211_SEND_MGMT(ic, ni, resp,
			    IEEE80211_REASON_ASSOC_TOOMANY);
			ieee80211_node_leave(ic, ni);
			return;
		}
		ni->ni_associd = aid | 0xc000;
		IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap);
		newassoc = 1;
		if (ic->ic_curmode == IEEE80211_MODE_11G)
			ieee80211_node_join_11g(ic, ni);
	} else
		newassoc = 0;

	IEEE80211_DPRINTF(("station %s %s associated at aid %d\n",
	    ether_sprintf(ni->ni_macaddr),
	    (newassoc ? "newly" : "already"),
	    ni->ni_associd & ~0xc000));

	/* give driver a chance to setup state like ni_txrate */
	if (ic->ic_newassoc)
		(*ic->ic_newassoc)(ic, ni, newassoc);
	IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS);
	ieee80211_node_newstate(ni, IEEE80211_STA_ASSOC);

#if NBRIDGE > 0
	/*
	 * If the parent interface belongs to a bridge, learn
	 * the node's address dynamically on this interface.
	 */
	if (ic->ic_if.if_bridge != NULL)
		bridge_update(&ic->ic_if,
		    (struct ether_addr *)ni->ni_macaddr, 0);
#endif
}
/*
 * Send 4-Way Handshake Message 1 to the supplicant.
 */
int
ieee80211_send_4way_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
{
	struct ieee80211_eapol_key *key;
	struct mbuf *m;
	u_int16_t info, keylen;
	u_int8_t *frm;

	ni->ni_rsn_state = RSNA_PTKSTART;
	if (++ni->ni_rsn_retries > 3) {
		IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
		    IEEE80211_REASON_4WAY_TIMEOUT);
		ieee80211_node_leave(ic, ni);
		return 0;
	}
	m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
	    (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ? 2 + 20 : 0);
	if (m == NULL)
		return ENOMEM;
	key = mtod(m, struct ieee80211_eapol_key *);
	memset(key, 0, sizeof(*key));

	info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYACK;
	BE_WRITE_2(key->info, info);

	/* copy the authenticator's nonce (ANonce) */
	memcpy(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN);

	keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
	BE_WRITE_2(key->keylen, keylen);

	frm = (u_int8_t *)&key[1];
	/* NB: WPA does not have PMKID KDE */
	if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN &&
	    ieee80211_is_8021x_akm(ni->ni_rsnakms))
		frm = ieee80211_add_pmkid_kde(frm, ni->ni_pmkid);

	m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;

	if (ic->ic_if.if_flags & IFF_DEBUG)
		printf("%s: sending msg %d/%d of the %s handshake to %s\n",
		    ic->ic_if.if_xname, 1, 4, "4-way",
		    ether_sprintf(ni->ni_macaddr));

	ni->ni_replaycnt++;
	BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);

	return ieee80211_send_eapol_key(ic, m, ni, NULL);
}
/*
 * Send Group Key Handshake Message 1 to the supplicant.
 */
int
ieee80211_send_group_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
{
	struct ieee80211_eapol_key *key;
	const struct ieee80211_key *k;
	struct mbuf *m;
	u_int16_t info;
	u_int8_t *frm;
	u_int8_t kid;

	ni->ni_rsn_gstate = RSNA_REKEYNEGOTIATING;
	if (++ni->ni_rsn_retries > 3) {
		IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
		    IEEE80211_REASON_GROUP_TIMEOUT);
		ieee80211_node_leave(ic, ni);
		return 0;
	}
	if (ni->ni_flags & IEEE80211_NODE_REKEY)
		kid = (ic->ic_def_txkey == 1) ? 2 : 1;
	else
		kid = ic->ic_def_txkey;
	k = &ic->ic_nw_keys[kid];

	m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
	    ((ni->ni_rsnprotos == IEEE80211_PROTO_WPA) ?
		k->k_len : 2 + 6 + k->k_len) +
	    ((ni->ni_flags & IEEE80211_NODE_MFP) ? 2 + 28 : 0) +
	    15);
	if (m == NULL)
		return ENOMEM;
	key = mtod(m, struct ieee80211_eapol_key *);
	memset(key, 0, sizeof(*key));

	info = EAPOL_KEY_KEYACK | EAPOL_KEY_KEYMIC | EAPOL_KEY_SECURE |
	    EAPOL_KEY_ENCRYPTED;

	ni->ni_replaycnt++;
	BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);

	frm = (u_int8_t *)&key[1];
	if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
		/* WPA does not have GTK KDE */
		BE_WRITE_2(key->keylen, k->k_len);
		memcpy(frm, k->k_key, k->k_len);
		frm += k->k_len;
		info |= (k->k_id & 0x3) << EAPOL_KEY_WPA_KID_SHIFT;
		if (ni->ni_rsncipher == IEEE80211_CIPHER_USEGROUP)
			info |= EAPOL_KEY_WPA_TX;
	} else {	/* RSN */
		frm = ieee80211_add_gtk_kde(frm, ni, k);
		if (ni->ni_flags & IEEE80211_NODE_MFP) {
			if (ni->ni_flags & IEEE80211_NODE_REKEY)
				kid = (ic->ic_igtk_kid == 4) ? 5 : 4;
			else
				kid = ic->ic_igtk_kid;
			frm = ieee80211_add_igtk_kde(frm,
			    &ic->ic_nw_keys[kid]);
		}
	}
	/* RSC = last transmit sequence number for the GTK */
	LE_WRITE_6(key->rsc, k->k_tsc);

	/* write the key info field */
	BE_WRITE_2(key->info, info);

	m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;

	if (ic->ic_if.if_flags & IFF_DEBUG)
		printf("%s: sending msg %d/%d of the %s handshake to %s\n",
		    ic->ic_if.if_xname, 1, 2, "group key",
		    ether_sprintf(ni->ni_macaddr));

	return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
}
/*
 * Send 4-Way Handshake Message 3 to the supplicant.
 */
int
ieee80211_send_4way_msg3(struct ieee80211com *ic, struct ieee80211_node *ni)
{
	struct ieee80211_eapol_key *key;
	struct ieee80211_key *k = NULL;
	struct mbuf *m;
	u_int16_t info, keylen;
	u_int8_t *frm;

	ni->ni_rsn_state = RSNA_PTKINITNEGOTIATING;
	if (++ni->ni_rsn_retries > 3) {
		IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
		    IEEE80211_REASON_4WAY_TIMEOUT);
		ieee80211_node_leave(ic, ni);
		return 0;
	}
	if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) {
		k = &ic->ic_nw_keys[ic->ic_def_txkey];
		m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
		    2 + IEEE80211_RSNIE_MAXLEN + 2 + 6 + k->k_len + 15 +
		    ((ni->ni_flags & IEEE80211_NODE_MFP) ? 2 + 28 : 0));
	} else { /* WPA */
		m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
		    2 + IEEE80211_WPAIE_MAXLEN +
		    ((ni->ni_flags & IEEE80211_NODE_MFP) ? 2 + 28 : 0));
	}
	if (m == NULL)
		return ENOMEM;
	key = mtod(m, struct ieee80211_eapol_key *);
	memset(key, 0, sizeof(*key));

	info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYACK | EAPOL_KEY_KEYMIC;
	if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP)
		info |= EAPOL_KEY_INSTALL;

	/* use same nonce as in Message 1 */
	memcpy(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN);

	ni->ni_replaycnt++;
	BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);

	keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
	BE_WRITE_2(key->keylen, keylen);

	frm = (u_int8_t *)&key[1];
	/* add the WPA/RSN IE included in Beacon/Probe Response */
	if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) {
		frm = ieee80211_add_rsn(frm, ic, ic->ic_bss);
		/* encapsulate the GTK */
		frm = ieee80211_add_gtk_kde(frm, ni, k);
		LE_WRITE_6(key->rsc, k->k_tsc);
		/* encapsulate the IGTK if MFP was negotiated */
		if (ni->ni_flags & IEEE80211_NODE_MFP) {
			frm = ieee80211_add_igtk_kde(frm,
			    &ic->ic_nw_keys[ic->ic_igtk_kid]);
		}
		/* ask that the EAPOL-Key frame be encrypted */
		info |= EAPOL_KEY_ENCRYPTED | EAPOL_KEY_SECURE;
	} else	/* WPA */
		frm = ieee80211_add_wpa(frm, ic, ic->ic_bss);

	/* write the key info field */
	BE_WRITE_2(key->info, info);

	m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;

	if (ic->ic_if.if_flags & IFF_DEBUG)
		printf("%s: sending msg %d/%d of the %s handshake to %s\n",
		    ic->ic_if.if_xname, 3, 4, "4-way",
		    ether_sprintf(ni->ni_macaddr));

	return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
}
Beispiel #7
0
void mlme_recv_auth_btamp(struct ieee80211_node *ni,
                          u_int16_t algo, u_int16_t seq, u_int16_t status_code,
                          u_int8_t *challenge, u_int8_t challenge_length, wbuf_t wbuf)
{

    struct ieee80211vap           *vap = ni->ni_vap;
    struct ieee80211_mlme_priv    *mlme_priv = vap->iv_mlme_priv;
    struct ieee80211_frame        *wh;
    u_int16_t                     indication_status = IEEE80211_STATUS_SUCCESS,response_status = IEEE80211_STATUS_SUCCESS ;
    bool                          send_auth_response=true, indicate=true;

    wh = (struct ieee80211_frame *) wbuf_header(wbuf);
    /* AP must be up and running */
    if (!mlme_priv->im_connection_up || ieee80211_vap_ready_is_clear(vap)) {
        return;
    }

    IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr2,
                       "recv auth frame with algorithm %d seq %d \n", algo, seq);

    do {

        /* Check node existance for the peer */
        if (ni == vap->iv_bss) {
            return;
        } else {
            ieee80211_ref_node(ni);
        }

        /* Validate algo */
        if (algo == IEEE80211_AUTH_ALG_OPEN) {
            if (mlme_priv->im_expected_auth_seq_number) {
                send_auth_response = false;
                indicate = false;
                if (seq == mlme_priv->im_expected_auth_seq_number) {
                    if (!OS_CANCEL_TIMER(&mlme_priv->im_timeout_timer)) {
                        IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: Timed-out already\n", __func__);
                        break;
                    }

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

                    /* Request complete */
                    mlme_priv->im_request_type = MLME_REQ_NONE;

                    /* Authentication complete (success or failure) */
                    IEEE80211_DELIVER_EVENT_MLME_AUTH_COMPLETE(vap, status_code);
                    vap->iv_mlme_priv->im_expected_auth_seq_number = 0;
                } else {
                    break;
                }
            } else {
                if (seq != IEEE80211_AUTH_OPEN_REQUEST) {
                    response_status = IEEE80211_STATUS_SEQUENCE;
                    indication_status = IEEE80211_STATUS_SEQUENCE;
                    break;
                } else {
                    indicate = true;
                    send_auth_response = true;
                }
            }
        } else if (algo == IEEE80211_AUTH_ALG_SHARED) {
            response_status = IEEE80211_STATUS_ALG;
            indication_status = IEEE80211_STATUS_ALG;
            break;
        } else {
            IEEE80211_DPRINTF(vap, IEEE80211_MSG_AUTH | IEEE80211_MSG_CRYPTO,
                              "[%s] auth: unsupported algorithm %d \n",ether_sprintf(wh->i_addr2),algo);
            vap->iv_stats.is_rx_auth_unsupported++;
            response_status = IEEE80211_STATUS_ALG;
            indication_status = IEEE80211_STATUS_ALG;
            break;
        }
    } while (FALSE);

    IEEE80211_DELIVER_EVENT_MLME_AUTH_INDICATION(vap, ni->ni_macaddr, indication_status);

    if (send_auth_response) {
        ieee80211_send_auth(ni, seq + 1, response_status, NULL, 0);
    }

    if (ni) {
        if (indication_status != IEEE80211_STATUS_SUCCESS ){
            /* auth is not success, remove the node from node table*/
            ieee80211_node_leave(ni);
        }
        /*
         * release the reference created at the begining of the case above
         * either by alloc_node or ref_node.
         */ 
        ieee80211_free_node(ni);
    }
}
Beispiel #8
0
/*
 * Timeout inactive nodes.
 *
 * If called because of a cache timeout, which happens only in hostap and ibss
 * modes, clean all inactive cached or authenticated nodes but don't de-auth
 * any associated nodes.
 *
 * Else, this function is called because a new node must be allocated but the
 * node cache is full. In this case, return as soon as a free slot was made
 * available. If acting as hostap, clean cached nodes regardless of their
 * recent activity and also allow de-authing of authenticated nodes older
 * than one cache wait interval, and de-authing of inactive associated nodes.
 */
void
ieee80211_clean_nodes(struct ieee80211com *ic, int cache_timeout)
{
	struct ieee80211_node *ni, *next_ni;
	u_int gen = ic->ic_scangen++;		/* NB: ok 'cuz single-threaded*/
	int s;
#ifndef IEEE80211_STA_ONLY
	int nnodes = 0;
	struct ifnet *ifp = &ic->ic_if;
#endif

	s = splnet();
	for (ni = RB_MIN(ieee80211_tree, &ic->ic_tree);
	    ni != NULL; ni = next_ni) {
		next_ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni);
		if (!cache_timeout && ic->ic_nnodes < ic->ic_max_nnodes)
			break;
		if (ni->ni_scangen == gen)	/* previously handled */
			continue;
#ifndef IEEE80211_STA_ONLY
		nnodes++;
#endif
		ni->ni_scangen = gen;
		if (ni->ni_refcnt > 0)
			continue;
#ifndef IEEE80211_STA_ONLY
		if ((ic->ic_opmode == IEEE80211_M_HOSTAP ||
		    ic->ic_opmode == IEEE80211_M_IBSS) &&
		    ic->ic_state == IEEE80211_S_RUN) {
			if (cache_timeout) {
				if (ni->ni_state != IEEE80211_STA_COLLECT &&
				    (ni->ni_state == IEEE80211_STA_ASSOC ||
				    ni->ni_inact < IEEE80211_INACT_MAX))
					continue;
			} else {
				if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
				    ((ni->ni_state == IEEE80211_STA_ASSOC &&
				    ni->ni_inact < IEEE80211_INACT_MAX) ||
				    (ni->ni_state == IEEE80211_STA_AUTH &&
				     ni->ni_inact == 0)))
				    	continue;

				if (ic->ic_opmode == IEEE80211_M_IBSS &&
				    ni->ni_state != IEEE80211_STA_COLLECT &&
				    ni->ni_state != IEEE80211_STA_CACHE &&
				    ni->ni_inact < IEEE80211_INACT_MAX)
					continue;
			}
		}
		if (ifp->if_flags & IFF_DEBUG)
			printf("%s: station %s purged from node cache\n",
			    ifp->if_xname, ether_sprintf(ni->ni_macaddr));
#endif
		/*
		 * If we're hostap and the node is authenticated, send
		 * a deauthentication frame. The node will be freed when
		 * the driver calls ieee80211_release_node().
		 */
#ifndef IEEE80211_STA_ONLY
		nnodes--;
		if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
		    ni->ni_state >= IEEE80211_STA_AUTH &&
		    ni->ni_state != IEEE80211_STA_COLLECT) {
			splx(s);
			IEEE80211_SEND_MGMT(ic, ni,
			    IEEE80211_FC0_SUBTYPE_DEAUTH,
			    IEEE80211_REASON_AUTH_EXPIRE);
			s = splnet();
			ieee80211_node_leave(ic, ni);
		} else
#endif
			ieee80211_free_node(ic, ni);
		ic->ic_stats.is_node_timeout++;
	}

#ifndef IEEE80211_STA_ONLY
	/* 
	 * During a cache timeout we iterate over all nodes.
	 * Check for node leaks by comparing the actual number of cached
	 * nodes with the ic_nnodes count, which is maintained while adding
	 * and removing nodes from the cache.
	 */
	if ((ifp->if_flags & IFF_DEBUG) && cache_timeout &&
	    nnodes != ic->ic_nnodes)
		printf("%s: number of cached nodes is %d, expected %d,"
		    "possible nodes leak\n", ifp->if_xname, nnodes,
		    ic->ic_nnodes);
#endif
	splx(s);
}