/* * Send 4-Way Handshake Message 2 to the authenticator. */ int ieee80211_send_4way_msg2(struct ieee80211com *ic, struct ieee80211_node *ni, const u_int8_t *replaycnt, const struct ieee80211_ptk *tptk) { struct ieee80211_eapol_key *key; struct mbuf *m; u_int16_t info; u_int8_t *frm; m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA, (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) ? 2 + IEEE80211_WPAIE_MAXLEN : 2 + IEEE80211_RSNIE_MAXLEN); if (m == NULL) return ENOMEM; key = mtod(m, struct ieee80211_eapol_key *); memset(key, 0, sizeof(*key)); info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYMIC; BE_WRITE_2(key->info, info); /* copy key replay counter from Message 1/4 */ memcpy(key->replaycnt, replaycnt, 8); /* copy the supplicant's nonce (SNonce) */ memcpy(key->nonce, ic->ic_nonce, EAPOL_KEY_NONCE_LEN); frm = (u_int8_t *)&key[1]; /* add the WPA/RSN IE used in the (Re)Association Request */ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) { int keylen; frm = ieee80211_add_wpa(frm, ic, ni); /* WPA sets the key length field here */ keylen = ieee80211_cipher_keylen(ni->ni_rsncipher); BE_WRITE_2(key->keylen, keylen); } else /* RSN */ frm = ieee80211_add_rsn(frm, ic, ni); 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, 2, 4, "4-way", ether_sprintf(ni->ni_macaddr)); return ieee80211_send_eapol_key(ic, m, ni, tptk); }
/* * 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); }
static u_int8_t * ieee80211_beacon_init(struct ieee80211_node *ni, struct ieee80211_beacon_offsets *bo, u_int8_t *frm) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; u_int16_t capinfo; struct ieee80211_rateset *rs = &ni->ni_rates; KASSERT(ic->ic_bsschan != IEEE80211_CHAN_ANYC, ("no bss chan")); /* XXX timestamp is set by hardware/driver */ memset(frm, 0, 8); frm += 8; /* beacon interval */ *(__le16 *)frm = htole16(ni->ni_intval); frm += 2; /* capability information */ if (vap->iv_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (vap->iv_flags & IEEE80211_F_PRIVACY) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ic->ic_bsschan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; if (ic->ic_flags & IEEE80211_F_DOTH) capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; bo->bo_caps = (__le16 *)frm; *(__le16 *)frm = htole16(capinfo); frm += 2; /* ssid */ *frm++ = IEEE80211_ELEMID_SSID; if ((vap->iv_flags & IEEE80211_F_HIDESSID) == 0) { *frm++ = ni->ni_esslen; memcpy(frm, ni->ni_essid, ni->ni_esslen); frm += ni->ni_esslen; } else *frm++ = 0; /* supported rates */ frm = ieee80211_add_rates(frm, rs); /* XXX: better way to check this? */ /* XXX: how about DS ? */ if (!IEEE80211_IS_CHAN_FHSS(ic->ic_bsschan)) { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, ic->ic_bsschan); } bo->bo_tim = frm; /* IBSS/TIM */ if (vap->iv_opmode == IEEE80211_M_IBSS) { *frm++ = IEEE80211_ELEMID_IBSSPARMS; *frm++ = 2; *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ bo->bo_tim_len = 0; } else { struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; tie->tim_ie = IEEE80211_ELEMID_TIM; tie->tim_len = 4; /* length */ tie->tim_count = 0; /* DTIM count */ tie->tim_period = vap->iv_dtim_period; /* DTIM period */ tie->tim_bitctl = 0; /* bitmap control */ tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ frm += sizeof(struct ieee80211_tim_ie); bo->bo_tim_len = 1; } bo->bo_tim_trailer = frm; /* country */ if ((ic->ic_flags & IEEE80211_F_DOTH) || (ic->ic_flags_ext & IEEE80211_FEXT_COUNTRYIE)) { frm = ieee80211_add_country(frm, ic); } /* power constraint */ if (ic->ic_flags & IEEE80211_F_DOTH) { *frm++ = IEEE80211_ELEMID_PWRCNSTR; *frm++ = 1; *frm++ = IEEE80211_PWRCONSTRAINT_VAL(ic); } /* XXX: channel switch announcement ? */ bo->bo_chanswitch = frm; /* ERP */ if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan)) { bo->bo_erp = frm; frm = ieee80211_add_erp(frm, ic); } /* Ext. Supp. Rates */ frm = ieee80211_add_xrates(frm, rs); /* WME */ if (vap->iv_flags & IEEE80211_F_WME) { bo->bo_wme = frm; frm = ieee80211_add_wme_param(frm, &ic->ic_wme, IEEE80211_VAP_UAPSD_ENABLED(vap)); vap->iv_flags &= ~IEEE80211_F_WMEUPDATE; } /* WPA 1+2 */ if (vap->iv_flags & IEEE80211_F_WPA) frm = ieee80211_add_wpa(frm, vap); /* athAdvCaps */ bo->bo_ath_caps = frm; if (vap->iv_bss && vap->iv_bss->ni_ath_flags) frm = ieee80211_add_athAdvCap(frm, vap->iv_bss->ni_ath_flags, vap->iv_bss->ni_ath_defkeyindex); /* XR */ bo->bo_xr = frm; #ifdef ATH_SUPERG_XR if (vap->iv_xrvap && vap->iv_ath_cap & IEEE80211_ATHC_XR) /* XR */ frm = ieee80211_add_xr_param(frm, vap); #endif bo->bo_appie_buf = frm; bo->bo_appie_buf_len = 0; bo->bo_tim_trailerlen = frm - bo->bo_tim_trailer; bo->bo_chanswitch_trailerlen = frm - bo->bo_chanswitch; return frm; }