示例#1
0
/*
 * Handle a station joining an RSN network.
 */
void
ieee80211_node_join_rsn(struct ieee80211com *ic, struct ieee80211_node *ni)
{
	DPRINTF(("station %s associated using proto %d akm 0x%x "
	    "cipher 0x%x groupcipher 0x%x\n", ether_sprintf(ni->ni_macaddr),
	    ni->ni_rsnprotos, ni->ni_rsnakms, ni->ni_rsnciphers,
	    ni->ni_rsngroupcipher));

	ni->ni_rsn_state = RSNA_AUTHENTICATION;
	ic->ic_rsnsta++;

	ni->ni_key_count = 0;
	ni->ni_port_valid = 0;
	ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT;
	ni->ni_replaycnt = -1;	/* XXX */
	ni->ni_rsn_retries = 0;
	ni->ni_rsncipher = ni->ni_rsnciphers;

	ni->ni_rsn_state = RSNA_AUTHENTICATION_2;

	/* generate a new authenticator nonce (ANonce) */
	arc4random_buf(ni->ni_nonce, EAPOL_KEY_NONCE_LEN);

	if (!ieee80211_is_8021x_akm(ni->ni_rsnakms)) {
		memcpy(ni->ni_pmk, ic->ic_psk, IEEE80211_PMK_LEN);
		ni->ni_flags |= IEEE80211_NODE_PMK;
		(void)ieee80211_send_4way_msg1(ic, ni);
	} else if (ni->ni_flags & IEEE80211_NODE_PMK) {
		/* skip 802.1X auth if a cached PMK was found */
		(void)ieee80211_send_4way_msg1(ic, ni);
	} else {
		/* no cached PMK found, needs full 802.1X auth */
		ieee80211_needs_auth(ic, ni);
	}
}
/*
 * 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);
}