hostapd/wlantest/bss.c
Jouni Malinen 0d2e395d74 wlantest: Maintain only a single entry for an active direct link
The TDLS link itself is bidirectional, but there is explicit
initiator/responder roles. Remove the other direction of the link if it
exists when processing TDLS Setup Confirm to make sure that the link
counters are stored for the current TDLS entery.

This is also changing the control interface search for TDLS counters
to require initiator/responder addresses in the correct order instead
of matching entries regardless of the role.
2011-01-24 14:34:45 +02:00

303 lines
8.2 KiB
C

/*
* BSS list
* Copyright (c) 2010, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "common/defs.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "crypto/sha1.h"
#include "wlantest.h"
struct wlantest_bss * bss_find(struct wlantest *wt, const u8 *bssid)
{
struct wlantest_bss *bss;
dl_list_for_each(bss, &wt->bss, struct wlantest_bss, list) {
if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
return bss;
}
return NULL;
}
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;
}
void pmk_deinit(struct wlantest_pmk *pmk)
{
dl_list_del(&pmk->list);
os_free(pmk);
}
void tdls_deinit(struct wlantest_tdls *tdls)
{
dl_list_del(&tdls->list);
os_free(tdls);
}
void bss_deinit(struct wlantest_bss *bss)
{
struct wlantest_sta *sta, *n;
struct wlantest_pmk *pmk, *np;
struct wlantest_tdls *tdls, *nt;
dl_list_for_each_safe(sta, n, &bss->sta, struct wlantest_sta, list)
sta_deinit(sta);
dl_list_for_each_safe(pmk, np, &bss->pmk, struct wlantest_pmk, list)
pmk_deinit(pmk);
dl_list_for_each_safe(tdls, nt, &bss->tdls, struct wlantest_tdls, list)
tdls_deinit(tdls);
dl_list_del(&bss->list);
os_free(bss);
}
int bss_add_pmk_from_passphrase(struct wlantest_bss *bss,
const char *passphrase)
{
struct wlantest_pmk *pmk;
pmk = os_zalloc(sizeof(*pmk));
if (pmk == NULL)
return -1;
if (pbkdf2_sha1(passphrase, (char *) bss->ssid, bss->ssid_len, 4096,
pmk->pmk, sizeof(pmk->pmk)) < 0) {
os_free(pmk);
return -1;
}
wpa_printf(MSG_INFO, "Add possible PMK for BSSID " MACSTR
" based on passphrase '%s'",
MAC2STR(bss->bssid), passphrase);
wpa_hexdump(MSG_DEBUG, "Possible PMK", pmk->pmk, sizeof(pmk->pmk));
dl_list_add(&bss->pmk, &pmk->list);
return 0;
}
static void bss_add_pmk(struct wlantest *wt, struct wlantest_bss *bss)
{
struct wlantest_passphrase *p;
dl_list_for_each(p, &wt->passphrase, struct wlantest_passphrase, list)
{
if (!is_zero_ether_addr(p->bssid) &&
os_memcmp(p->bssid, bss->bssid, ETH_ALEN) != 0)
continue;
if (p->ssid_len &&
(p->ssid_len != bss->ssid_len ||
os_memcmp(p->ssid, bss->ssid, p->ssid_len) != 0))
continue;
if (bss_add_pmk_from_passphrase(bss, p->passphrase) < 0)
break;
}
}
void bss_update(struct wlantest *wt, struct wlantest_bss *bss,
struct ieee802_11_elems *elems)
{
struct wpa_ie_data data;
int update = 0;
if (bss->capab_info != bss->prev_capab_info)
update = 1;
if (elems->ssid == NULL || elems->ssid_len > 32) {
wpa_printf(MSG_INFO, "Invalid or missing SSID in a Beacon "
"frame for " MACSTR, MAC2STR(bss->bssid));
bss->parse_error_reported = 1;
return;
}
if (bss->ssid_len != elems->ssid_len ||
os_memcmp(bss->ssid, elems->ssid, bss->ssid_len) != 0) {
wpa_printf(MSG_DEBUG, "Store SSID '%s' for BSSID " MACSTR,
wpa_ssid_txt(elems->ssid, elems->ssid_len),
MAC2STR(bss->bssid));
os_memcpy(bss->ssid, elems->ssid, elems->ssid_len);
bss->ssid_len = elems->ssid_len;
bss_add_pmk(wt, bss);
}
if (elems->rsn_ie == NULL) {
if (bss->rsnie[0]) {
wpa_printf(MSG_INFO, "BSS " MACSTR " - RSN IE removed",
MAC2STR(bss->bssid));
bss->rsnie[0] = 0;
update = 1;
}
} else {
if (bss->rsnie[0] == 0 ||
os_memcmp(bss->rsnie, elems->rsn_ie - 2,
elems->rsn_ie_len + 2) != 0) {
wpa_printf(MSG_INFO, "BSS " MACSTR " - RSN IE "
"stored", MAC2STR(bss->bssid));
wpa_hexdump(MSG_DEBUG, "RSN IE", elems->rsn_ie - 2,
elems->rsn_ie_len + 2);
update = 1;
}
os_memcpy(bss->rsnie, elems->rsn_ie - 2,
elems->rsn_ie_len + 2);
}
if (elems->wpa_ie == NULL) {
if (bss->wpaie[0]) {
wpa_printf(MSG_INFO, "BSS " MACSTR " - WPA IE removed",
MAC2STR(bss->bssid));
bss->wpaie[0] = 0;
update = 1;
}
} else {
if (bss->wpaie[0] == 0 ||
os_memcmp(bss->wpaie, elems->wpa_ie - 2,
elems->wpa_ie_len + 2) != 0) {
wpa_printf(MSG_INFO, "BSS " MACSTR " - WPA IE "
"stored", MAC2STR(bss->bssid));
wpa_hexdump(MSG_DEBUG, "WPA IE", elems->wpa_ie - 2,
elems->wpa_ie_len + 2);
update = 1;
}
os_memcpy(bss->wpaie, elems->wpa_ie - 2,
elems->wpa_ie_len + 2);
}
if (!update)
return;
bss->prev_capab_info = bss->capab_info;
bss->proto = 0;
bss->pairwise_cipher = 0;
bss->group_cipher = 0;
bss->key_mgmt = 0;
bss->rsn_capab = 0;
bss->mgmt_group_cipher = 0;
if (bss->wpaie[0]) {
if (wpa_parse_wpa_ie_wpa(bss->wpaie, 2 + bss->wpaie[1], &data)
< 0) {
wpa_printf(MSG_INFO, "Failed to parse WPA IE from "
MACSTR, MAC2STR(bss->bssid));
} else {
bss->proto |= data.proto;
bss->pairwise_cipher |= data.pairwise_cipher;
bss->group_cipher |= data.group_cipher;
bss->key_mgmt |= data.key_mgmt;
bss->rsn_capab = data.capabilities;
bss->mgmt_group_cipher |= data.mgmt_group_cipher;
}
}
if (bss->rsnie[0]) {
if (wpa_parse_wpa_ie_rsn(bss->rsnie, 2 + bss->rsnie[1], &data)
< 0) {
wpa_printf(MSG_INFO, "Failed to parse RSN IE from "
MACSTR, MAC2STR(bss->bssid));
} else {
bss->proto |= data.proto;
bss->pairwise_cipher |= data.pairwise_cipher;
bss->group_cipher |= data.group_cipher;
bss->key_mgmt |= data.key_mgmt;
bss->rsn_capab = data.capabilities;
bss->mgmt_group_cipher |= data.mgmt_group_cipher;
}
}
if (!(bss->proto & WPA_PROTO_RSN) ||
!(bss->rsn_capab & WPA_CAPABILITY_MFPC))
bss->mgmt_group_cipher = 0;
if (!bss->wpaie[0] && !bss->rsnie[0] &&
(bss->capab_info & WLAN_CAPABILITY_PRIVACY))
bss->group_cipher = WPA_CIPHER_WEP40;
wpa_printf(MSG_INFO, "BSS " MACSTR
" proto=%s%s%s"
"pairwise=%s%s%s%s"
"group=%s%s%s%s%s%s"
"mgmt_group_cipher=%s"
"key_mgmt=%s%s%s%s%s%s%s%s"
"rsn_capab=%s%s%s%s%s",
MAC2STR(bss->bssid),
bss->proto == 0 ? "OPEN " : "",
bss->proto & WPA_PROTO_WPA ? "WPA " : "",
bss->proto & WPA_PROTO_RSN ? "WPA2 " : "",
bss->pairwise_cipher == 0 ? "N/A " : "",
bss->pairwise_cipher & WPA_CIPHER_NONE ? "NONE " : "",
bss->pairwise_cipher & WPA_CIPHER_TKIP ? "TKIP " : "",
bss->pairwise_cipher & WPA_CIPHER_CCMP ? "CCMP " : "",
bss->group_cipher == 0 ? "N/A " : "",
bss->group_cipher & WPA_CIPHER_NONE ? "NONE " : "",
bss->group_cipher & WPA_CIPHER_WEP40 ? "WEP40 " : "",
bss->group_cipher & WPA_CIPHER_WEP104 ? "WEP104 " : "",
bss->group_cipher & WPA_CIPHER_TKIP ? "TKIP " : "",
bss->group_cipher & WPA_CIPHER_CCMP ? "CCMP " : "",
bss->mgmt_group_cipher & WPA_CIPHER_AES_128_CMAC ? "BIP " :
"N/A ",
bss->key_mgmt == 0 ? "N/A " : "",
bss->key_mgmt & WPA_KEY_MGMT_IEEE8021X ? "EAP " : "",
bss->key_mgmt & WPA_KEY_MGMT_PSK ? "PSK " : "",
bss->key_mgmt & WPA_KEY_MGMT_WPA_NONE ? "WPA-NONE " : "",
bss->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X ? "FT-EAP " : "",
bss->key_mgmt & WPA_KEY_MGMT_FT_PSK ? "FT-PSK " : "",
bss->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256 ?
"EAP-SHA256 " : "",
bss->key_mgmt & WPA_KEY_MGMT_PSK_SHA256 ?
"PSK-SHA256 " : "",
bss->rsn_capab & WPA_CAPABILITY_PREAUTH ? "PREAUTH " : "",
bss->rsn_capab & WPA_CAPABILITY_NO_PAIRWISE ?
"NO_PAIRWISE " : "",
bss->rsn_capab & WPA_CAPABILITY_MFPR ? "MFPR " : "",
bss->rsn_capab & WPA_CAPABILITY_MFPC ? "MFPC " : "",
bss->rsn_capab & WPA_CAPABILITY_PEERKEY_ENABLED ?
"PEERKEY " : "");
}
void bss_flush(struct wlantest *wt)
{
struct wlantest_bss *bss, *n;
dl_list_for_each_safe(bss, n, &wt->bss, struct wlantest_bss, list)
bss_deinit(bss);
}