diff --git a/package/network/services/hostapd/files/netifd.sh b/package/network/services/hostapd/files/netifd.sh index 83fb129fe1..3a64689428 100644 --- a/package/network/services/hostapd/files/netifd.sh +++ b/package/network/services/hostapd/files/netifd.sh @@ -153,6 +153,9 @@ hostapd_common_add_bss_config() { config_add_string macfilter 'macfile:file' config_add_array 'maclist:list(macaddr)' + config_add_array bssid_blacklist + config_add_array bssid_whitelist + config_add_int mcast_rate config_add_array basic_rate config_add_array supported_rates @@ -580,6 +583,12 @@ wpa_supplicant_add_network() { [ -n "$bssid" ] && append network_data "bssid=$bssid" "$N$T" [ -n "$beacon_int" ] && append network_data "beacon_int=$beacon_int" "$N$T" + local bssid_blacklist bssid_whitelist + json_get_values bssid_blacklist bssid_blacklist + json_get_values bssid_whitelist bssid_whitelist + + [ -n "$bssid_blacklist" ] && append network_data "bssid_blacklist=$bssid_blacklist" "$N$T" + [ -n "$bssid_whitelist" ] && append network_data "bssid_whitelist=$bssid_whitelist" "$N$T" [ -n "$basic_rate" ] && { local br rate_list= diff --git a/package/network/services/hostapd/patches/700-Add-os_snprintf_error-helper.patch b/package/network/services/hostapd/patches/700-Add-os_snprintf_error-helper.patch new file mode 100644 index 0000000000..51ad1c4d70 --- /dev/null +++ b/package/network/services/hostapd/patches/700-Add-os_snprintf_error-helper.patch @@ -0,0 +1,29 @@ +Add os_snprintf_error() helper + +This can be used to check os_snprintf() return value more consistently. + +Signed-off-by: Jouni Malinen +--- + src/utils/os.h | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/utils/os.h b/src/utils/os.h +index b9247d8..77250d6 100644 +--- a/src/utils/os.h ++++ b/src/utils/os.h +@@ -549,6 +549,12 @@ char * os_strdup(const char *s); + #endif /* OS_NO_C_LIB_DEFINES */ + + ++static inline int os_snprintf_error(size_t size, int res) ++{ ++ return res < 0 || (unsigned int) res >= size; ++} ++ ++ + static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size) + { + if (size && nmemb > (~(size_t) 0) / size) +-- +2.1.3 + diff --git a/package/network/services/hostapd/patches/710-Add-network-specific-BSSID-black-and-white-lists.patch b/package/network/services/hostapd/patches/710-Add-network-specific-BSSID-black-and-white-lists.patch new file mode 100644 index 0000000000..5b42158a4b --- /dev/null +++ b/package/network/services/hostapd/patches/710-Add-network-specific-BSSID-black-and-white-lists.patch @@ -0,0 +1,649 @@ +Add network specific BSSID black and white lists + +This change adds the configuration options "bssid_whitelist" and +"bssid_blacklist" used to limit the AP selection of a network to a +specified (finite) set or discard certain APs. + +This can be useful for environments where multiple networks operate +using the same SSID and roaming between those is not desired. It is also +useful to ignore a faulty or otherwise unwanted AP. + +In many applications it is useful not just to enumerate a group of well +known access points, but to use a address/mask notation to match an +entire set of addresses (ca:ff:ee:00:00:00/ff:ff:ff:00:00:00). + +This change expands the data structures used by MAC lists to include a +mask indicating the significant (non-masked) portions of an address and +extends the list parser to recognize mask suffixes. + +Signed-off-by: Stefan Tomanek +--- + src/utils/common.c | 86 ++++++++++++-- + src/utils/common.h | 3 + + wpa_supplicant/config.c | 223 ++++++++++++++++++++++++------------- + wpa_supplicant/config_ssid.h | 12 ++ + wpa_supplicant/events.c | 45 ++++++++ + wpa_supplicant/p2p_supplicant.c | 40 ++++--- + wpa_supplicant/wpa_supplicant.conf | 15 +++ + 7 files changed, 323 insertions(+), 101 deletions(-) + +diff --git a/src/utils/common.c b/src/utils/common.c +index 9902004..dd6e4aa 100644 +--- a/src/utils/common.c ++++ b/src/utils/common.c +@@ -36,6 +36,25 @@ int hex2byte(const char *hex) + } + + ++static const char * hwaddr_parse(const char *txt, u8 *addr) ++{ ++ size_t i; ++ ++ for (i = 0; i < ETH_ALEN; i++) { ++ int a; ++ ++ a = hex2byte(txt); ++ if (a < 0) ++ return NULL; ++ txt += 2; ++ addr[i] = a; ++ if (i < ETH_ALEN - 1 && *txt++ != ':') ++ return NULL; ++ } ++ return txt; ++} ++ ++ + /** + * hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format) + * @txt: MAC address as a string (e.g., "00:11:22:33:44:55") +@@ -44,25 +63,46 @@ int hex2byte(const char *hex) + */ + int hwaddr_aton(const char *txt, u8 *addr) + { +- int i; ++ return hwaddr_parse(txt, addr) ? 0 : -1; ++} + +- for (i = 0; i < 6; i++) { +- int a, b; + +- a = hex2num(*txt++); +- if (a < 0) +- return -1; +- b = hex2num(*txt++); +- if (b < 0) +- return -1; +- *addr++ = (a << 4) | b; +- if (i < 5 && *txt++ != ':') ++/** ++ * hwaddr_masked_aton - Convert ASCII string with optional mask to MAC address (colon-delimited format) ++ * @txt: MAC address with optional mask as a string (e.g., "00:11:22:33:44:55/ff:ff:ff:ff:00:00") ++ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) ++ * @mask: Buffer for the MAC address mask (ETH_ALEN = 6 bytes) ++ * @maskable: Flag to indicate whether a mask is allowed ++ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) ++ */ ++int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable) ++{ ++ const char *r; ++ ++ /* parse address part */ ++ r = hwaddr_parse(txt, addr); ++ if (!r) ++ return -1; ++ ++ /* check for optional mask */ ++ if (*r == '\0' || isspace(*r)) { ++ /* no mask specified, assume default */ ++ os_memset(mask, 0xff, ETH_ALEN); ++ } else if (maskable && *r == '/') { ++ /* mask specified and allowed */ ++ r = hwaddr_parse(r + 1, mask); ++ /* parser error? */ ++ if (!r) + return -1; ++ } else { ++ /* mask specified but not allowed or trailing garbage */ ++ return -1; + } + + return 0; + } + ++ + /** + * hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format) + * @txt: MAC address as a string (e.g., "001122334455") +@@ -144,6 +184,30 @@ int hexstr2bin(const char *hex, u8 *buf, size_t len) + } + + ++int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask) ++{ ++ size_t i; ++ int print_mask = 0; ++ int res; ++ ++ for (i = 0; i < ETH_ALEN; i++) { ++ if (mask[i] != 0xff) { ++ print_mask = 1; ++ break; ++ } ++ } ++ ++ if (print_mask) ++ res = os_snprintf(buf, len, MACSTR "/" MACSTR, ++ MAC2STR(addr), MAC2STR(mask)); ++ else ++ res = os_snprintf(buf, len, MACSTR, MAC2STR(addr)); ++ if (os_snprintf_error(len, res)) ++ return -1; ++ return res; ++} ++ ++ + /** + * inc_byte_array - Increment arbitrary length byte array by one + * @counter: Pointer to byte array +diff --git a/src/utils/common.h b/src/utils/common.h +index 14d9ad1..1127074 100644 +--- a/src/utils/common.h ++++ b/src/utils/common.h +@@ -468,6 +468,7 @@ typedef u64 __bitwise le64; + #endif /* __must_check */ + + int hwaddr_aton(const char *txt, u8 *addr); ++int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable); + int hwaddr_compact_aton(const char *txt, u8 *addr); + int hwaddr_aton2(const char *txt, u8 *addr); + int hex2byte(const char *hex); +@@ -478,6 +479,8 @@ int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); + int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, + size_t len); + ++int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask); ++ + #ifdef CONFIG_NATIVE_WINDOWS + void wpa_unicode2ascii_inplace(TCHAR *str); + TCHAR * wpa_strdup_tchar(const char *str); +diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c +index 8d1e1e0..7f742cb 100644 +--- a/wpa_supplicant/config.c ++++ b/wpa_supplicant/config.c +@@ -235,6 +235,99 @@ static char * wpa_config_write_int(const struct parse_data *data, + #endif /* NO_CONFIG_WRITE */ + + ++static int wpa_config_parse_addr_list(const struct parse_data *data, ++ int line, const char *value, ++ u8 **list, size_t *num, char *name, ++ u8 abort_on_error, u8 masked) ++{ ++ const char *pos; ++ u8 *buf, *n, addr[2 * ETH_ALEN]; ++ size_t count; ++ ++ buf = NULL; ++ count = 0; ++ ++ pos = value; ++ while (pos && *pos) { ++ while (*pos == ' ') ++ pos++; ++ ++ if (hwaddr_masked_aton(pos, addr, &addr[ETH_ALEN], masked)) { ++ if (abort_on_error || count == 0) { ++ wpa_printf(MSG_ERROR, ++ "Line %d: Invalid %s address '%s'", ++ line, name, value); ++ os_free(buf); ++ return -1; ++ } ++ /* continue anyway since this could have been from a ++ * truncated configuration file line */ ++ wpa_printf(MSG_INFO, ++ "Line %d: Ignore likely truncated %s address '%s'", ++ line, name, pos); ++ } else { ++ n = os_realloc_array(buf, count + 1, 2 * ETH_ALEN); ++ if (n == NULL) { ++ os_free(buf); ++ return -1; ++ } ++ buf = n; ++ os_memmove(buf + 2 * ETH_ALEN, buf, ++ count * 2 * ETH_ALEN); ++ os_memcpy(buf, addr, 2 * ETH_ALEN); ++ count++; ++ wpa_printf(MSG_MSGDUMP, ++ "%s: addr=" MACSTR " mask=" MACSTR, ++ name, MAC2STR(addr), ++ MAC2STR(&addr[ETH_ALEN])); ++ } ++ ++ pos = os_strchr(pos, ' '); ++ } ++ ++ os_free(*list); ++ *list = buf; ++ *num = count; ++ ++ return 0; ++} ++ ++ ++#ifndef NO_CONFIG_WRITE ++static char * wpa_config_write_addr_list(const struct parse_data *data, ++ const u8 *list, size_t num, char *name) ++{ ++ char *value, *end, *pos; ++ int res; ++ size_t i; ++ ++ if (list == NULL || num == 0) ++ return NULL; ++ ++ value = os_malloc(2 * 20 * num); ++ if (value == NULL) ++ return NULL; ++ pos = value; ++ end = value + 2 * 20 * num; ++ ++ for (i = num; i > 0; i--) { ++ const u8 *a = list + (i - 1) * 2 * ETH_ALEN; ++ const u8 *m = a + ETH_ALEN; ++ ++ if (i < num) ++ *pos++ = ' '; ++ res = hwaddr_mask_txt(pos, end - pos, a, m); ++ if (res < 0) { ++ os_free(value); ++ return NULL; ++ } ++ pos += res; ++ } ++ ++ return value; ++} ++#endif /* NO_CONFIG_WRITE */ ++ + static int wpa_config_parse_bssid(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +@@ -280,6 +373,50 @@ static char * wpa_config_write_bssid(const struct parse_data *data, + #endif /* NO_CONFIG_WRITE */ + + ++static int wpa_config_parse_bssid_blacklist(const struct parse_data *data, ++ struct wpa_ssid *ssid, int line, ++ const char *value) ++{ ++ return wpa_config_parse_addr_list(data, line, value, ++ &ssid->bssid_blacklist, ++ &ssid->num_bssid_blacklist, ++ "bssid_blacklist", 1, 1); ++} ++ ++ ++#ifndef NO_CONFIG_WRITE ++static char * wpa_config_write_bssid_blacklist(const struct parse_data *data, ++ struct wpa_ssid *ssid) ++{ ++ return wpa_config_write_addr_list(data, ssid->bssid_blacklist, ++ ssid->num_bssid_blacklist, ++ "bssid_blacklist"); ++} ++#endif /* NO_CONFIG_WRITE */ ++ ++ ++static int wpa_config_parse_bssid_whitelist(const struct parse_data *data, ++ struct wpa_ssid *ssid, int line, ++ const char *value) ++{ ++ return wpa_config_parse_addr_list(data, line, value, ++ &ssid->bssid_whitelist, ++ &ssid->num_bssid_whitelist, ++ "bssid_whitelist", 1, 1); ++} ++ ++ ++#ifndef NO_CONFIG_WRITE ++static char * wpa_config_write_bssid_whitelist(const struct parse_data *data, ++ struct wpa_ssid *ssid) ++{ ++ return wpa_config_write_addr_list(data, ssid->bssid_whitelist, ++ ssid->num_bssid_whitelist, ++ "bssid_whitelist"); ++} ++#endif /* NO_CONFIG_WRITE */ ++ ++ + static int wpa_config_parse_psk(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +@@ -1435,53 +1572,10 @@ static int wpa_config_parse_p2p_client_list(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) + { +- const char *pos; +- u8 *buf, *n, addr[ETH_ALEN]; +- size_t count; +- +- buf = NULL; +- count = 0; +- +- pos = value; +- while (pos && *pos) { +- while (*pos == ' ') +- pos++; +- +- if (hwaddr_aton(pos, addr)) { +- if (count == 0) { +- wpa_printf(MSG_ERROR, "Line %d: Invalid " +- "p2p_client_list address '%s'.", +- line, value); +- os_free(buf); +- return -1; +- } +- /* continue anyway since this could have been from a +- * truncated configuration file line */ +- wpa_printf(MSG_INFO, "Line %d: Ignore likely " +- "truncated p2p_client_list address '%s'", +- line, pos); +- } else { +- n = os_realloc_array(buf, count + 1, ETH_ALEN); +- if (n == NULL) { +- os_free(buf); +- return -1; +- } +- buf = n; +- os_memmove(buf + ETH_ALEN, buf, count * ETH_ALEN); +- os_memcpy(buf, addr, ETH_ALEN); +- count++; +- wpa_hexdump(MSG_MSGDUMP, "p2p_client_list", +- addr, ETH_ALEN); +- } +- +- pos = os_strchr(pos, ' '); +- } +- +- os_free(ssid->p2p_client_list); +- ssid->p2p_client_list = buf; +- ssid->num_p2p_clients = count; +- +- return 0; ++ return wpa_config_parse_addr_list(data, line, value, ++ &ssid->p2p_client_list, ++ &ssid->num_p2p_clients, ++ "p2p_client_list", 0, 0); + } + + +@@ -1489,34 +1583,9 @@ static int wpa_config_parse_p2p_client_list(const struct parse_data *data, + static char * wpa_config_write_p2p_client_list(const struct parse_data *data, + struct wpa_ssid *ssid) + { +- char *value, *end, *pos; +- int res; +- size_t i; +- +- if (ssid->p2p_client_list == NULL || ssid->num_p2p_clients == 0) +- return NULL; +- +- value = os_malloc(20 * ssid->num_p2p_clients); +- if (value == NULL) +- return NULL; +- pos = value; +- end = value + 20 * ssid->num_p2p_clients; +- +- for (i = ssid->num_p2p_clients; i > 0; i--) { +- res = os_snprintf(pos, end - pos, MACSTR " ", +- MAC2STR(ssid->p2p_client_list + +- (i - 1) * ETH_ALEN)); +- if (res < 0 || res >= end - pos) { +- os_free(value); +- return NULL; +- } +- pos += res; +- } +- +- if (pos > value) +- pos[-1] = '\0'; +- +- return value; ++ return wpa_config_write_addr_list(data, ssid->p2p_client_list, ++ ssid->num_p2p_clients, ++ "p2p_client_list"); + } + #endif /* NO_CONFIG_WRITE */ + +@@ -1667,6 +1736,8 @@ static const struct parse_data ssid_fields[] = { + { STR_RANGE(ssid, 0, MAX_SSID_LEN) }, + { INT_RANGE(scan_ssid, 0, 1) }, + { FUNC(bssid) }, ++ { FUNC(bssid_blacklist) }, ++ { FUNC(bssid_whitelist) }, + { FUNC_KEY(psk) }, + { FUNC(proto) }, + { FUNC(key_mgmt) }, +@@ -1971,6 +2042,8 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid) + os_free(ssid->freq_list); + os_free(ssid->bgscan); + os_free(ssid->p2p_client_list); ++ os_free(ssid->bssid_blacklist); ++ os_free(ssid->bssid_whitelist); + #ifdef CONFIG_HT_OVERRIDES + os_free(ssid->ht_mcs); + #endif /* CONFIG_HT_OVERRIDES */ +diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h +index a4910d0..7443207 100644 +--- a/wpa_supplicant/config_ssid.h ++++ b/wpa_supplicant/config_ssid.h +@@ -128,6 +128,18 @@ struct wpa_ssid { + u8 bssid[ETH_ALEN]; + + /** ++ * bssid_blacklist - List of inacceptable BSSIDs ++ */ ++ u8 *bssid_blacklist; ++ size_t num_bssid_blacklist; ++ ++ /** ++ * bssid_blacklist - List of acceptable BSSIDs ++ */ ++ u8 *bssid_whitelist; ++ size_t num_bssid_whitelist; ++ ++ /** + * bssid_set - Whether BSSID is configured for this network + */ + int bssid_set; +diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c +index 6761c1a..855653c 100644 +--- a/wpa_supplicant/events.c ++++ b/wpa_supplicant/events.c +@@ -703,6 +703,33 @@ static int bss_is_ess(struct wpa_bss *bss) + } + + ++static int match_mac_mask(const u8 *addr_a, const u8 *addr_b, const u8 *mask) ++{ ++ size_t i; ++ ++ for (i = 0; i < ETH_ALEN; i++) { ++ if ((addr_a[i] & mask[i]) != (addr_b[i] & mask[i])) ++ return 0; ++ } ++ return 1; ++} ++ ++ ++static int addr_in_list(const u8 *addr, const u8 *list, size_t num) ++{ ++ size_t i; ++ ++ for (i = 0; i < num; i++) { ++ const u8 *a = list + i * ETH_ALEN * 2; ++ const u8 *m = a + ETH_ALEN; ++ ++ if (match_mac_mask(a, addr, m)) ++ return 1; ++ } ++ return 0; ++} ++ ++ + static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, + int i, struct wpa_bss *bss, + struct wpa_ssid *group, +@@ -827,6 +854,24 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, + continue; + } + ++ /* check blacklist */ ++ if (ssid->num_bssid_blacklist && ++ addr_in_list(bss->bssid, ssid->bssid_blacklist, ++ ssid->num_bssid_blacklist)) { ++ wpa_dbg(wpa_s, MSG_DEBUG, ++ " skip - BSSID blacklisted"); ++ continue; ++ } ++ ++ /* if there is a whitelist, only accept those APs */ ++ if (ssid->num_bssid_whitelist && ++ !addr_in_list(bss->bssid, ssid->bssid_whitelist, ++ ssid->num_bssid_whitelist)) { ++ wpa_dbg(wpa_s, MSG_DEBUG, ++ " skip - BSSID not in whitelist"); ++ continue; ++ } ++ + if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss)) + continue; + +diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c +index 8cd43df..60dcb5d 100644 +--- a/wpa_supplicant/p2p_supplicant.c ++++ b/wpa_supplicant/p2p_supplicant.c +@@ -831,7 +831,7 @@ static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s, + return; + + for (i = 0; s->p2p_client_list && i < s->num_p2p_clients; i++) { +- if (os_memcmp(s->p2p_client_list + i * ETH_ALEN, addr, ++ if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN, addr, + ETH_ALEN) != 0) + continue; + +@@ -839,32 +839,42 @@ static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s, + return; /* already the most recent entry */ + + /* move the entry to mark it most recent */ +- os_memmove(s->p2p_client_list + i * ETH_ALEN, +- s->p2p_client_list + (i + 1) * ETH_ALEN, +- (s->num_p2p_clients - i - 1) * ETH_ALEN); ++ os_memmove(s->p2p_client_list + i * 2 * ETH_ALEN, ++ s->p2p_client_list + (i + 1) * 2 * ETH_ALEN, ++ (s->num_p2p_clients - i - 1) * 2 * ETH_ALEN); + os_memcpy(s->p2p_client_list + +- (s->num_p2p_clients - 1) * ETH_ALEN, addr, ETH_ALEN); ++ (s->num_p2p_clients - 1) * 2 * ETH_ALEN, addr, ++ ETH_ALEN); ++ os_memset(s->p2p_client_list + ++ (s->num_p2p_clients - 1) * 2 * ETH_ALEN + ETH_ALEN, ++ 0xff, ETH_ALEN); + found = 1; + break; + } + + if (!found && s->num_p2p_clients < P2P_MAX_STORED_CLIENTS) { + n = os_realloc_array(s->p2p_client_list, +- s->num_p2p_clients + 1, ETH_ALEN); ++ s->num_p2p_clients + 1, 2 * ETH_ALEN); + if (n == NULL) + return; +- os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN); ++ os_memcpy(n + s->num_p2p_clients * 2 * ETH_ALEN, addr, ++ ETH_ALEN); ++ os_memset(n + s->num_p2p_clients * 2 * ETH_ALEN + ETH_ALEN, ++ 0xff, ETH_ALEN); + s->p2p_client_list = n; + s->num_p2p_clients++; + } else if (!found && s->p2p_client_list) { + /* Not enough room for an additional entry - drop the oldest + * entry */ + os_memmove(s->p2p_client_list, +- s->p2p_client_list + ETH_ALEN, +- (s->num_p2p_clients - 1) * ETH_ALEN); ++ s->p2p_client_list + 2 * ETH_ALEN, ++ (s->num_p2p_clients - 1) * 2 * ETH_ALEN); + os_memcpy(s->p2p_client_list + +- (s->num_p2p_clients - 1) * ETH_ALEN, ++ (s->num_p2p_clients - 1) * 2 * ETH_ALEN, + addr, ETH_ALEN); ++ os_memset(s->p2p_client_list + ++ (s->num_p2p_clients - 1) * 2 * ETH_ALEN + ETH_ALEN, ++ 0xff, ETH_ALEN); + } + + if (wpa_s->parent->conf->update_config && +@@ -3276,7 +3286,7 @@ static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s, + return; + + for (i = 0; ssid->p2p_client_list && i < ssid->num_p2p_clients; i++) { +- if (os_memcmp(ssid->p2p_client_list + i * ETH_ALEN, peer, ++ if (os_memcmp(ssid->p2p_client_list + i * 2 * ETH_ALEN, peer, + ETH_ALEN) == 0) + break; + } +@@ -3296,9 +3306,9 @@ static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s, + "group %d client list%s", + MAC2STR(peer), ssid->id, + inv ? " due to invitation result" : ""); +- os_memmove(ssid->p2p_client_list + i * ETH_ALEN, +- ssid->p2p_client_list + (i + 1) * ETH_ALEN, +- (ssid->num_p2p_clients - i - 1) * ETH_ALEN); ++ os_memmove(ssid->p2p_client_list + i * 2 * ETH_ALEN, ++ ssid->p2p_client_list + (i + 1) * 2 * ETH_ALEN, ++ (ssid->num_p2p_clients - i - 1) * 2 * ETH_ALEN); + ssid->num_p2p_clients--; + if (wpa_s->parent->conf->update_config && + wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf)) +@@ -6925,7 +6935,7 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s, + if (s->mode != WPAS_MODE_P2P_GO || s->p2p_client_list == NULL) + continue; + for (i = 0; i < s->num_p2p_clients; i++) { +- if (os_memcmp(s->p2p_client_list + i * ETH_ALEN, ++ if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN, + addr, ETH_ALEN) == 0) + return s; /* peer is P2P client in persistent + * group */ +diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf +index 0e8a28a..4bc08db 100644 +--- a/wpa_supplicant/wpa_supplicant.conf ++++ b/wpa_supplicant/wpa_supplicant.conf +@@ -1408,6 +1408,21 @@ network={ + key_mgmt=NONE + } + ++# Example configuration blacklisting two APs - these will be ignored ++# for this network. ++network={ ++ ssid="example" ++ psk="very secret passphrase" ++ bssid_blacklist=02:11:22:33:44:55 02:22:aa:44:55:66 ++} ++ ++# Example configuration limiting AP selection to a specific set of APs; ++# any other AP not matching the masked address will be ignored. ++network={ ++ ssid="example" ++ psk="very secret passphrase" ++ bssid_whitelist=02:55:ae:bc:00:00/ff:ff:ff:ff:00:00 00:00:77:66:55:44/00:00:ff:ff:ff:ff ++} + + # Example config file that will only scan on channel 36. + freq_list=5180 +-- +2.1.3 +