static struct wlantest_tdls * get_tdls(struct wlantest *wt, const u8 *linkid, int create_new, const u8 *bssid) { struct wlantest_bss *bss; struct wlantest_sta *init, *resp; struct wlantest_tdls *tdls; bss = bss_find(wt, linkid); if (bss == NULL && bssid) { bss = bss_find(wt, bssid); if (bss) add_note(wt, MSG_INFO, "TDLS: Incorrect BSSID " MACSTR " in LinkId?! (init=" MACSTR " resp=" MACSTR ")", MAC2STR(linkid), MAC2STR(linkid + ETH_ALEN), MAC2STR(linkid + 2 * ETH_ALEN)); } if (bss == NULL) return NULL; init = sta_find(bss, linkid + ETH_ALEN); if (init == NULL) return NULL; resp = sta_find(bss, linkid + 2 * ETH_ALEN); if (resp == NULL) return NULL; dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) { if (tdls->init == init && tdls->resp == resp) return tdls; } if (!create_new) return NULL; add_note(wt, MSG_DEBUG, "Add new TDLS link context: initiator " MACSTR " responder " MACSTR " BSSID " MACSTR, MAC2STR(linkid + ETH_ALEN), MAC2STR(linkid + 2 * ETH_ALEN), MAC2STR(bssid)); tdls = os_zalloc(sizeof(*tdls)); if (tdls == NULL) return NULL; tdls->init = init; tdls->resp = resp; dl_list_add(&bss->tdls, &tdls->list); return tdls; }
static struct wlantest_bss * ctrl_get_bss(struct wlantest *wt, int sock, u8 *cmd, size_t clen) { struct wlantest_bss *bss; u8 *pos; size_t len; pos = attr_get(cmd, clen, WLANTEST_ATTR_BSSID, &len); if (pos == NULL || len != ETH_ALEN) { ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); return NULL; } bss = bss_find(wt, pos); if (bss == NULL) { ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); return NULL; } return bss; }
static void rx_data_tdls_setup_confirm_failure(struct wlantest *wt, const u8 *bssid, const u8 *src, u8 dialog_token, u16 status) { struct wlantest_bss *bss; struct wlantest_tdls *tdls; struct wlantest_sta *sta; if (status == WLAN_STATUS_SUCCESS) { add_note(wt, MSG_INFO, "TDLS: Invalid TDLS Setup Confirm from " MACSTR, MAC2STR(src)); return; } bss = bss_find(wt, bssid); if (!bss) return; sta = sta_find(bss, src); if (!sta) return; dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) { if (tdls->init == sta) { if (dialog_token != tdls->dialog_token) { add_note(wt, MSG_DEBUG, "TDLS: Dialog token " "mismatch in TDLS Setup Confirm " "(failure)"); break; } add_note(wt, MSG_DEBUG, "TDLS: Found matching TDLS " "setup session based on dialog token"); tdls->counters[ WLANTEST_TDLS_COUNTER_SETUP_CONF_FAIL]++; break; } } }
struct wlantest_bss * bss_get(struct wlantest *wt, const u8 *bssid) { struct wlantest_bss *bss; if (bssid[0] & 0x01) return NULL; /* Skip group addressed frames */ bss = bss_find(wt, bssid); if (bss) return bss; bss = os_zalloc(sizeof(*bss)); if (bss == NULL) return NULL; dl_list_init(&bss->sta); dl_list_init(&bss->pmk); dl_list_init(&bss->tdls); os_memcpy(bss->bssid, bssid, ETH_ALEN); dl_list_add(&wt->bss, &bss->list); wpa_printf(MSG_DEBUG, "Discovered new BSS - " MACSTR, MAC2STR(bss->bssid)); return bss; }
static void ctrl_inject(struct wlantest *wt, int sock, u8 *cmd, size_t clen) { u8 *bssid, *sta_addr; struct wlantest_bss *bss; struct wlantest_sta *sta; int frame, sender_ap, prot; int ret = 0; bssid = attr_get_macaddr(cmd, clen, WLANTEST_ATTR_BSSID); sta_addr = attr_get_macaddr(cmd, clen, WLANTEST_ATTR_STA_ADDR); frame = attr_get_int(cmd, clen, WLANTEST_ATTR_INJECT_FRAME); sender_ap = attr_get_int(cmd, clen, WLANTEST_ATTR_INJECT_SENDER_AP); if (sender_ap < 0) sender_ap = 0; prot = attr_get_int(cmd, clen, WLANTEST_ATTR_INJECT_PROTECTION); if (bssid == NULL || sta_addr == NULL || frame < 0 || prot < 0) { wpa_printf(MSG_INFO, "Invalid inject command parameters"); ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); return; } bss = bss_find(wt, bssid); if (bss == NULL) { wpa_printf(MSG_INFO, "BSS not found for inject command"); ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); return; } if (is_broadcast_ether_addr(sta_addr)) { if (!sender_ap) { wpa_printf(MSG_INFO, "Invalid broadcast inject " "command without sender_ap set"); ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); return; } sta = NULL; } else { sta = sta_find(bss, sta_addr); if (sta == NULL) { wpa_printf(MSG_INFO, "Station not found for inject " "command"); ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); return; } } switch (frame) { case WLANTEST_FRAME_AUTH: ret = ctrl_inject_auth(wt, bss, sta, sender_ap, prot); break; case WLANTEST_FRAME_ASSOCREQ: ret = ctrl_inject_assocreq(wt, bss, sta, sender_ap, prot); break; case WLANTEST_FRAME_REASSOCREQ: ret = ctrl_inject_reassocreq(wt, bss, sta, sender_ap, prot); break; case WLANTEST_FRAME_DEAUTH: ret = ctrl_inject_deauth(wt, bss, sta, sender_ap, prot); break; case WLANTEST_FRAME_DISASSOC: ret = ctrl_inject_disassoc(wt, bss, sta, sender_ap, prot); break; case WLANTEST_FRAME_SAQUERYREQ: ret = ctrl_inject_saqueryreq(wt, bss, sta, sender_ap, prot); break; default: wpa_printf(MSG_INFO, "Unsupported inject command frame %d", frame); ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); return; } if (ret) wpa_printf(MSG_INFO, "Failed to inject frame"); else wpa_printf(MSG_INFO, "Frame injected successfully"); ctrl_send_simple(wt, sock, ret == 0 ? WLANTEST_CTRL_SUCCESS : WLANTEST_CTRL_FAILURE); }
static void ctrl_send_(struct wlantest *wt, int sock, u8 *cmd, size_t clen) { struct wlantest_bss *bss; struct wlantest_sta *sta; u8 *bssid, *sta_addr; int prot; u8 *frame; size_t frame_len; int ret = 0; struct ieee80211_hdr *hdr; u16 fc; frame = attr_get(cmd, clen, WLANTEST_ATTR_FRAME, &frame_len); prot = attr_get_int(cmd, clen, WLANTEST_ATTR_INJECT_PROTECTION); if (frame == NULL || frame_len < 24 || prot < 0) { wpa_printf(MSG_INFO, "Invalid send command parameters"); ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); return; } hdr = (struct ieee80211_hdr *) frame; fc = le_to_host16(hdr->frame_control); switch (WLAN_FC_GET_TYPE(fc)) { case WLAN_FC_TYPE_MGMT: bssid = hdr->addr3; if (os_memcmp(hdr->addr2, hdr->addr3, ETH_ALEN) == 0) sta_addr = hdr->addr1; else sta_addr = hdr->addr2; break; case WLAN_FC_TYPE_DATA: switch (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) { case 0: bssid = hdr->addr3; sta_addr = hdr->addr2; break; case WLAN_FC_TODS: bssid = hdr->addr1; sta_addr = hdr->addr2; break; case WLAN_FC_FROMDS: bssid = hdr->addr2; sta_addr = hdr->addr1; break; default: wpa_printf(MSG_INFO, "Unsupported inject frame"); ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); return; } break; default: wpa_printf(MSG_INFO, "Unsupported inject frame"); ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); return; } bss = bss_find(wt, bssid); if (bss == NULL) { wpa_printf(MSG_INFO, "Unknown BSSID"); ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); return; } sta = sta_find(bss, sta_addr); if (sta == NULL) { wpa_printf(MSG_INFO, "Unknown STA address"); ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); return; } ret = wlantest_inject(wt, bss, sta, frame, frame_len, prot); if (ret) wpa_printf(MSG_INFO, "Failed to inject frame"); else wpa_printf(MSG_INFO, "Frame injected successfully"); ctrl_send_simple(wt, sock, ret == 0 ? WLANTEST_CTRL_SUCCESS : WLANTEST_CTRL_FAILURE); }
static void rx_data_bss_prot(struct wlantest *wt, const struct ieee80211_hdr *hdr, size_t hdrlen, const u8 *qos, const u8 *dst, const u8 *src, const u8 *data, size_t len) { struct wlantest_bss *bss, *bss2; struct wlantest_sta *sta, *sta2; int keyid; u16 fc = le_to_host16(hdr->frame_control); u8 *decrypted; size_t dlen; int tid; u8 pn[6], *rsc; struct wlantest_tdls *tdls = NULL, *found; const u8 *tk = NULL; int ptk_iter_done = 0; int try_ptk_iter = 0; int replay = 0; if (hdr->addr1[0] & 0x01) { rx_data_bss_prot_group(wt, hdr, hdrlen, qos, dst, src, data, len); return; } if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == (WLAN_FC_TODS | WLAN_FC_FROMDS)) { bss = bss_find(wt, hdr->addr1); if (bss) { sta = sta_find(bss, hdr->addr2); if (sta) { sta->counters[ WLANTEST_STA_COUNTER_PROT_DATA_TX]++; } if (!sta || !sta->ptk_set) { bss2 = bss_find(wt, hdr->addr2); if (bss2) { sta2 = sta_find(bss2, hdr->addr1); if (sta2 && (!sta || sta2->ptk_set)) { bss = bss2; sta = sta2; } } } } else { bss = bss_find(wt, hdr->addr2); if (!bss) return; sta = sta_find(bss, hdr->addr1); } } else if (fc & WLAN_FC_TODS) { bss = bss_get(wt, hdr->addr1); if (bss == NULL) return; sta = sta_get(bss, hdr->addr2); if (sta) sta->counters[WLANTEST_STA_COUNTER_PROT_DATA_TX]++; } else if (fc & WLAN_FC_FROMDS) { bss = bss_get(wt, hdr->addr2); if (bss == NULL) return; sta = sta_get(bss, hdr->addr1); } else { bss = bss_get(wt, hdr->addr3); if (bss == NULL) return; sta = sta_find(bss, hdr->addr2); sta2 = sta_find(bss, hdr->addr1); if (sta == NULL || sta2 == NULL) return; found = NULL; dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) { if ((tdls->init == sta && tdls->resp == sta2) || (tdls->init == sta2 && tdls->resp == sta)) { found = tdls; if (tdls->link_up) break; } } if (found) { if (!found->link_up) add_note(wt, MSG_DEBUG, "TDLS: Link not up, but Data " "frame seen"); tk = found->tpk.tk; tdls = found; } } if ((sta == NULL || (!sta->ptk_set && sta->pairwise_cipher != WPA_CIPHER_WEP40)) && tk == NULL) { add_note(wt, MSG_MSGDUMP, "No PTK known to decrypt the frame"); if (dl_list_empty(&wt->ptk)) return; try_ptk_iter = 1; } if (len < 4) { add_note(wt, MSG_INFO, "Too short encrypted data frame"); return; } if (sta == NULL) return; if (sta->pairwise_cipher & (WPA_CIPHER_TKIP | WPA_CIPHER_CCMP) && !(data[3] & 0x20)) { add_note(wt, MSG_INFO, "Expected TKIP/CCMP frame from " MACSTR " did not have ExtIV bit set to 1", MAC2STR(src)); return; } if (tk == NULL && sta->pairwise_cipher == WPA_CIPHER_TKIP) { if (data[3] & 0x1f) { add_note(wt, MSG_INFO, "TKIP frame from " MACSTR " used non-zero reserved bit", MAC2STR(hdr->addr2)); } if (data[1] != ((data[0] | 0x20) & 0x7f)) { add_note(wt, MSG_INFO, "TKIP frame from " MACSTR " used incorrect WEPSeed[1] (was 0x%x, " "expected 0x%x)", MAC2STR(hdr->addr2), data[1], (data[0] | 0x20) & 0x7f); } } else if (tk || sta->pairwise_cipher == WPA_CIPHER_CCMP) { if (data[2] != 0 || (data[3] & 0x1f) != 0) { add_note(wt, MSG_INFO, "CCMP frame from " MACSTR " used non-zero reserved bit", MAC2STR(hdr->addr2)); } } keyid = data[3] >> 6; if (keyid != 0) { add_note(wt, MSG_INFO, "Unexpected non-zero KeyID %d in " "individually addressed Data frame from " MACSTR, keyid, MAC2STR(hdr->addr2)); } if (qos) { tid = qos[0] & 0x0f; if (fc & WLAN_FC_TODS) sta->tx_tid[tid]++; else sta->rx_tid[tid]++; } else { tid = 0; if (fc & WLAN_FC_TODS) sta->tx_tid[16]++; else sta->rx_tid[16]++; } if (tk) { if (os_memcmp(hdr->addr2, tdls->init->addr, ETH_ALEN) == 0) rsc = tdls->rsc_init[tid]; else rsc = tdls->rsc_resp[tid]; } else if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == (WLAN_FC_TODS | WLAN_FC_FROMDS)) { if (os_memcmp(sta->addr, hdr->addr2, ETH_ALEN) == 0) rsc = sta->rsc_tods[tid]; else rsc = sta->rsc_fromds[tid]; } else if (fc & WLAN_FC_TODS) rsc = sta->rsc_tods[tid]; else rsc = sta->rsc_fromds[tid]; if (tk == NULL && sta->pairwise_cipher == WPA_CIPHER_TKIP) tkip_get_pn(pn, data); else if (sta->pairwise_cipher == WPA_CIPHER_WEP40) goto skip_replay_det; else ccmp_get_pn(pn, data); if (os_memcmp(pn, rsc, 6) <= 0) { u16 seq_ctrl = le_to_host16(hdr->seq_ctrl); add_note(wt, MSG_INFO, "CCMP/TKIP replay detected: A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u%s", MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3), WLAN_GET_SEQ_SEQ(seq_ctrl), WLAN_GET_SEQ_FRAG(seq_ctrl), (le_to_host16(hdr->frame_control) & WLAN_FC_RETRY) ? " Retry" : ""); wpa_hexdump(MSG_INFO, "RX PN", pn, 6); wpa_hexdump(MSG_INFO, "RSC", rsc, 6); replay = 1; } skip_replay_det: if (tk) { if (sta->pairwise_cipher == WPA_CIPHER_CCMP_256) decrypted = ccmp_256_decrypt(tk, hdr, data, len, &dlen); else if (sta->pairwise_cipher == WPA_CIPHER_GCMP || sta->pairwise_cipher == WPA_CIPHER_GCMP_256) decrypted = gcmp_decrypt(tk, sta->ptk.tk_len, hdr, data, len, &dlen); else decrypted = ccmp_decrypt(tk, hdr, data, len, &dlen); } else if (sta->pairwise_cipher == WPA_CIPHER_TKIP) { decrypted = tkip_decrypt(sta->ptk.tk, hdr, data, len, &dlen); } else if (sta->pairwise_cipher == WPA_CIPHER_WEP40) { decrypted = wep_decrypt(wt, hdr, data, len, &dlen); } else if (sta->ptk_set) { if (sta->pairwise_cipher == WPA_CIPHER_CCMP_256) decrypted = ccmp_256_decrypt(sta->ptk.tk, hdr, data, len, &dlen); else if (sta->pairwise_cipher == WPA_CIPHER_GCMP || sta->pairwise_cipher == WPA_CIPHER_GCMP_256) decrypted = gcmp_decrypt(sta->ptk.tk, sta->ptk.tk_len, hdr, data, len, &dlen); else decrypted = ccmp_decrypt(sta->ptk.tk, hdr, data, len, &dlen); } else { decrypted = try_all_ptk(wt, sta->pairwise_cipher, hdr, data, len, &dlen); ptk_iter_done = 1; } if (!decrypted && !ptk_iter_done) { decrypted = try_all_ptk(wt, sta->pairwise_cipher, hdr, data, len, &dlen); if (decrypted) { add_note(wt, MSG_DEBUG, "Current PTK did not work, but found a match from all known PTKs"); } } if (decrypted) { u16 fc = le_to_host16(hdr->frame_control); const u8 *peer_addr = NULL; if (!(fc & (WLAN_FC_FROMDS | WLAN_FC_TODS))) peer_addr = hdr->addr1; if (!replay) os_memcpy(rsc, pn, 6); rx_data_process(wt, bss->bssid, sta->addr, dst, src, decrypted, dlen, 1, peer_addr); write_pcap_decrypted(wt, (const u8 *) hdr, hdrlen, decrypted, dlen); } else if (!try_ptk_iter) add_note(wt, MSG_DEBUG, "Failed to decrypt frame"); os_free(decrypted); }