hostapd: backport BSSID black/whitelists
[openwrt.git] / package / network / services / hostapd / patches / 710-Add-network-specific-BSSID-black-and-white-lists.patch
1 Add network specific BSSID black and white lists
2
3 This change adds the configuration options "bssid_whitelist" and
4 "bssid_blacklist" used to limit the AP selection of a network to a
5 specified (finite) set or discard certain APs.
6
7 This can be useful for environments where multiple networks operate
8 using the same SSID and roaming between those is not desired. It is also
9 useful to ignore a faulty or otherwise unwanted AP.
10
11 In many applications it is useful not just to enumerate a group of well
12 known access points, but to use a address/mask notation to match an
13 entire set of addresses (ca:ff:ee:00:00:00/ff:ff:ff:00:00:00).
14
15 This change expands the data structures used by MAC lists to include a
16 mask indicating the significant (non-masked) portions of an address and
17 extends the list parser to recognize mask suffixes.
18
19 Signed-off-by: Stefan Tomanek <stefan.tomanek@wertarbyte.de>
20 ---
21  src/utils/common.c                 |  86 ++++++++++++--
22  src/utils/common.h                 |   3 +
23  wpa_supplicant/config.c            | 223 ++++++++++++++++++++++++-------------
24  wpa_supplicant/config_ssid.h       |  12 ++
25  wpa_supplicant/events.c            |  45 ++++++++
26  wpa_supplicant/p2p_supplicant.c    |  40 ++++---
27  wpa_supplicant/wpa_supplicant.conf |  15 +++
28  7 files changed, 323 insertions(+), 101 deletions(-)
29
30 diff --git a/src/utils/common.c b/src/utils/common.c
31 index 9902004..dd6e4aa 100644
32 --- a/src/utils/common.c
33 +++ b/src/utils/common.c
34 @@ -36,6 +36,25 @@ int hex2byte(const char *hex)
35  }
36  
37  
38 +static const char * hwaddr_parse(const char *txt, u8 *addr)
39 +{
40 +       size_t i;
41 +
42 +       for (i = 0; i < ETH_ALEN; i++) {
43 +               int a;
44 +
45 +               a = hex2byte(txt);
46 +               if (a < 0)
47 +                       return NULL;
48 +               txt += 2;
49 +               addr[i] = a;
50 +               if (i < ETH_ALEN - 1 && *txt++ != ':')
51 +                       return NULL;
52 +       }
53 +       return txt;
54 +}
55 +
56 +
57  /**
58   * hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format)
59   * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
60 @@ -44,25 +63,46 @@ int hex2byte(const char *hex)
61   */
62  int hwaddr_aton(const char *txt, u8 *addr)
63  {
64 -       int i;
65 +       return hwaddr_parse(txt, addr) ? 0 : -1;
66 +}
67  
68 -       for (i = 0; i < 6; i++) {
69 -               int a, b;
70  
71 -               a = hex2num(*txt++);
72 -               if (a < 0)
73 -                       return -1;
74 -               b = hex2num(*txt++);
75 -               if (b < 0)
76 -                       return -1;
77 -               *addr++ = (a << 4) | b;
78 -               if (i < 5 && *txt++ != ':')
79 +/**
80 + * hwaddr_masked_aton - Convert ASCII string with optional mask to MAC address (colon-delimited format)
81 + * @txt: MAC address with optional mask as a string (e.g., "00:11:22:33:44:55/ff:ff:ff:ff:00:00")
82 + * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
83 + * @mask: Buffer for the MAC address mask (ETH_ALEN = 6 bytes)
84 + * @maskable: Flag to indicate whether a mask is allowed
85 + * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
86 + */
87 +int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable)
88 +{
89 +       const char *r;
90 +
91 +       /* parse address part */
92 +       r = hwaddr_parse(txt, addr);
93 +       if (!r)
94 +               return -1;
95 +
96 +       /* check for optional mask */
97 +       if (*r == '\0' || isspace(*r)) {
98 +               /* no mask specified, assume default */
99 +               os_memset(mask, 0xff, ETH_ALEN);
100 +       } else if (maskable && *r == '/') {
101 +               /* mask specified and allowed */
102 +               r = hwaddr_parse(r + 1, mask);
103 +               /* parser error? */
104 +               if (!r)
105                         return -1;
106 +       } else {
107 +               /* mask specified but not allowed or trailing garbage */
108 +               return -1;
109         }
110  
111         return 0;
112  }
113  
114 +
115  /**
116   * hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format)
117   * @txt: MAC address as a string (e.g., "001122334455")
118 @@ -144,6 +184,30 @@ int hexstr2bin(const char *hex, u8 *buf, size_t len)
119  }
120  
121  
122 +int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask)
123 +{
124 +       size_t i;
125 +       int print_mask = 0;
126 +       int res;
127 +
128 +       for (i = 0; i < ETH_ALEN; i++) {
129 +               if (mask[i] != 0xff) {
130 +                       print_mask = 1;
131 +                       break;
132 +               }
133 +       }
134 +
135 +       if (print_mask)
136 +               res = os_snprintf(buf, len, MACSTR "/" MACSTR,
137 +                                 MAC2STR(addr), MAC2STR(mask));
138 +       else
139 +               res = os_snprintf(buf, len, MACSTR, MAC2STR(addr));
140 +       if (os_snprintf_error(len, res))
141 +               return -1;
142 +       return res;
143 +}
144 +
145 +
146  /**
147   * inc_byte_array - Increment arbitrary length byte array by one
148   * @counter: Pointer to byte array
149 diff --git a/src/utils/common.h b/src/utils/common.h
150 index 14d9ad1..1127074 100644
151 --- a/src/utils/common.h
152 +++ b/src/utils/common.h
153 @@ -468,6 +468,7 @@ typedef u64 __bitwise le64;
154  #endif /* __must_check */
155  
156  int hwaddr_aton(const char *txt, u8 *addr);
157 +int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable);
158  int hwaddr_compact_aton(const char *txt, u8 *addr);
159  int hwaddr_aton2(const char *txt, u8 *addr);
160  int hex2byte(const char *hex);
161 @@ -478,6 +479,8 @@ int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
162  int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
163                                size_t len);
164  
165 +int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask);
166 +
167  #ifdef CONFIG_NATIVE_WINDOWS
168  void wpa_unicode2ascii_inplace(TCHAR *str);
169  TCHAR * wpa_strdup_tchar(const char *str);
170 diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
171 index 8d1e1e0..7f742cb 100644
172 --- a/wpa_supplicant/config.c
173 +++ b/wpa_supplicant/config.c
174 @@ -235,6 +235,99 @@ static char * wpa_config_write_int(const struct parse_data *data,
175  #endif /* NO_CONFIG_WRITE */
176  
177  
178 +static int wpa_config_parse_addr_list(const struct parse_data *data,
179 +                                     int line, const char *value,
180 +                                     u8 **list, size_t *num, char *name,
181 +                                     u8 abort_on_error, u8 masked)
182 +{
183 +       const char *pos;
184 +       u8 *buf, *n, addr[2 * ETH_ALEN];
185 +       size_t count;
186 +
187 +       buf = NULL;
188 +       count = 0;
189 +
190 +       pos = value;
191 +       while (pos && *pos) {
192 +               while (*pos == ' ')
193 +                       pos++;
194 +
195 +               if (hwaddr_masked_aton(pos, addr, &addr[ETH_ALEN], masked)) {
196 +                       if (abort_on_error || count == 0) {
197 +                               wpa_printf(MSG_ERROR,
198 +                                          "Line %d: Invalid %s address '%s'",
199 +                                          line, name, value);
200 +                               os_free(buf);
201 +                               return -1;
202 +                       }
203 +                       /* continue anyway since this could have been from a
204 +                        * truncated configuration file line */
205 +                       wpa_printf(MSG_INFO,
206 +                                  "Line %d: Ignore likely truncated %s address '%s'",
207 +                                  line, name, pos);
208 +               } else {
209 +                       n = os_realloc_array(buf, count + 1, 2 * ETH_ALEN);
210 +                       if (n == NULL) {
211 +                               os_free(buf);
212 +                               return -1;
213 +                       }
214 +                       buf = n;
215 +                       os_memmove(buf + 2 * ETH_ALEN, buf,
216 +                                  count * 2 * ETH_ALEN);
217 +                       os_memcpy(buf, addr, 2 * ETH_ALEN);
218 +                       count++;
219 +                       wpa_printf(MSG_MSGDUMP,
220 +                                  "%s: addr=" MACSTR " mask=" MACSTR,
221 +                                  name, MAC2STR(addr),
222 +                                  MAC2STR(&addr[ETH_ALEN]));
223 +               }
224 +
225 +               pos = os_strchr(pos, ' ');
226 +       }
227 +
228 +       os_free(*list);
229 +       *list = buf;
230 +       *num = count;
231 +
232 +       return 0;
233 +}
234 +
235 +
236 +#ifndef NO_CONFIG_WRITE
237 +static char * wpa_config_write_addr_list(const struct parse_data *data,
238 +                                        const u8 *list, size_t num, char *name)
239 +{
240 +       char *value, *end, *pos;
241 +       int res;
242 +       size_t i;
243 +
244 +       if (list == NULL || num == 0)
245 +               return NULL;
246 +
247 +       value = os_malloc(2 * 20 * num);
248 +       if (value == NULL)
249 +               return NULL;
250 +       pos = value;
251 +       end = value + 2 * 20 * num;
252 +
253 +       for (i = num; i > 0; i--) {
254 +               const u8 *a = list + (i - 1) * 2 * ETH_ALEN;
255 +               const u8 *m = a + ETH_ALEN;
256 +
257 +               if (i < num)
258 +                       *pos++ = ' ';
259 +               res = hwaddr_mask_txt(pos, end - pos, a, m);
260 +               if (res < 0) {
261 +                       os_free(value);
262 +                       return NULL;
263 +               }
264 +               pos += res;
265 +       }
266 +
267 +       return value;
268 +}
269 +#endif /* NO_CONFIG_WRITE */
270 +
271  static int wpa_config_parse_bssid(const struct parse_data *data,
272                                   struct wpa_ssid *ssid, int line,
273                                   const char *value)
274 @@ -280,6 +373,50 @@ static char * wpa_config_write_bssid(const struct parse_data *data,
275  #endif /* NO_CONFIG_WRITE */
276  
277  
278 +static int wpa_config_parse_bssid_blacklist(const struct parse_data *data,
279 +                                           struct wpa_ssid *ssid, int line,
280 +                                           const char *value)
281 +{
282 +       return wpa_config_parse_addr_list(data, line, value,
283 +                                         &ssid->bssid_blacklist,
284 +                                         &ssid->num_bssid_blacklist,
285 +                                         "bssid_blacklist", 1, 1);
286 +}
287 +
288 +
289 +#ifndef NO_CONFIG_WRITE
290 +static char * wpa_config_write_bssid_blacklist(const struct parse_data *data,
291 +                                              struct wpa_ssid *ssid)
292 +{
293 +       return wpa_config_write_addr_list(data, ssid->bssid_blacklist,
294 +                                         ssid->num_bssid_blacklist,
295 +                                         "bssid_blacklist");
296 +}
297 +#endif /* NO_CONFIG_WRITE */
298 +
299 +
300 +static int wpa_config_parse_bssid_whitelist(const struct parse_data *data,
301 +                                           struct wpa_ssid *ssid, int line,
302 +                                           const char *value)
303 +{
304 +       return wpa_config_parse_addr_list(data, line, value,
305 +                                         &ssid->bssid_whitelist,
306 +                                         &ssid->num_bssid_whitelist,
307 +                                         "bssid_whitelist", 1, 1);
308 +}
309 +
310 +
311 +#ifndef NO_CONFIG_WRITE
312 +static char * wpa_config_write_bssid_whitelist(const struct parse_data *data,
313 +                                              struct wpa_ssid *ssid)
314 +{
315 +       return wpa_config_write_addr_list(data, ssid->bssid_whitelist,
316 +                                         ssid->num_bssid_whitelist,
317 +                                         "bssid_whitelist");
318 +}
319 +#endif /* NO_CONFIG_WRITE */
320 +
321 +
322  static int wpa_config_parse_psk(const struct parse_data *data,
323                                 struct wpa_ssid *ssid, int line,
324                                 const char *value)
325 @@ -1435,53 +1572,10 @@ static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
326                                             struct wpa_ssid *ssid, int line,
327                                             const char *value)
328  {
329 -       const char *pos;
330 -       u8 *buf, *n, addr[ETH_ALEN];
331 -       size_t count;
332 -
333 -       buf = NULL;
334 -       count = 0;
335 -
336 -       pos = value;
337 -       while (pos && *pos) {
338 -               while (*pos == ' ')
339 -                       pos++;
340 -
341 -               if (hwaddr_aton(pos, addr)) {
342 -                       if (count == 0) {
343 -                               wpa_printf(MSG_ERROR, "Line %d: Invalid "
344 -                                          "p2p_client_list address '%s'.",
345 -                                          line, value);
346 -                               os_free(buf);
347 -                               return -1;
348 -                       }
349 -                       /* continue anyway since this could have been from a
350 -                        * truncated configuration file line */
351 -                       wpa_printf(MSG_INFO, "Line %d: Ignore likely "
352 -                                  "truncated p2p_client_list address '%s'",
353 -                                  line, pos);
354 -               } else {
355 -                       n = os_realloc_array(buf, count + 1, ETH_ALEN);
356 -                       if (n == NULL) {
357 -                               os_free(buf);
358 -                               return -1;
359 -                       }
360 -                       buf = n;
361 -                       os_memmove(buf + ETH_ALEN, buf, count * ETH_ALEN);
362 -                       os_memcpy(buf, addr, ETH_ALEN);
363 -                       count++;
364 -                       wpa_hexdump(MSG_MSGDUMP, "p2p_client_list",
365 -                                   addr, ETH_ALEN);
366 -               }
367 -
368 -               pos = os_strchr(pos, ' ');
369 -       }
370 -
371 -       os_free(ssid->p2p_client_list);
372 -       ssid->p2p_client_list = buf;
373 -       ssid->num_p2p_clients = count;
374 -
375 -       return 0;
376 +       return wpa_config_parse_addr_list(data, line, value,
377 +                                         &ssid->p2p_client_list,
378 +                                         &ssid->num_p2p_clients,
379 +                                         "p2p_client_list", 0, 0);
380  }
381  
382  
383 @@ -1489,34 +1583,9 @@ static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
384  static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
385                                                struct wpa_ssid *ssid)
386  {
387 -       char *value, *end, *pos;
388 -       int res;
389 -       size_t i;
390 -
391 -       if (ssid->p2p_client_list == NULL || ssid->num_p2p_clients == 0)
392 -               return NULL;
393 -
394 -       value = os_malloc(20 * ssid->num_p2p_clients);
395 -       if (value == NULL)
396 -               return NULL;
397 -       pos = value;
398 -       end = value + 20 * ssid->num_p2p_clients;
399 -
400 -       for (i = ssid->num_p2p_clients; i > 0; i--) {
401 -               res = os_snprintf(pos, end - pos, MACSTR " ",
402 -                                 MAC2STR(ssid->p2p_client_list +
403 -                                         (i - 1) * ETH_ALEN));
404 -               if (res < 0 || res >= end - pos) {
405 -                       os_free(value);
406 -                       return NULL;
407 -               }
408 -               pos += res;
409 -       }
410 -
411 -       if (pos > value)
412 -               pos[-1] = '\0';
413 -
414 -       return value;
415 +       return wpa_config_write_addr_list(data, ssid->p2p_client_list,
416 +                                         ssid->num_p2p_clients,
417 +                                         "p2p_client_list");
418  }
419  #endif /* NO_CONFIG_WRITE */
420  
421 @@ -1667,6 +1736,8 @@ static const struct parse_data ssid_fields[] = {
422         { STR_RANGE(ssid, 0, MAX_SSID_LEN) },
423         { INT_RANGE(scan_ssid, 0, 1) },
424         { FUNC(bssid) },
425 +       { FUNC(bssid_blacklist) },
426 +       { FUNC(bssid_whitelist) },
427         { FUNC_KEY(psk) },
428         { FUNC(proto) },
429         { FUNC(key_mgmt) },
430 @@ -1971,6 +2042,8 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
431         os_free(ssid->freq_list);
432         os_free(ssid->bgscan);
433         os_free(ssid->p2p_client_list);
434 +       os_free(ssid->bssid_blacklist);
435 +       os_free(ssid->bssid_whitelist);
436  #ifdef CONFIG_HT_OVERRIDES
437         os_free(ssid->ht_mcs);
438  #endif /* CONFIG_HT_OVERRIDES */
439 diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
440 index a4910d0..7443207 100644
441 --- a/wpa_supplicant/config_ssid.h
442 +++ b/wpa_supplicant/config_ssid.h
443 @@ -128,6 +128,18 @@ struct wpa_ssid {
444         u8 bssid[ETH_ALEN];
445  
446         /**
447 +        * bssid_blacklist - List of inacceptable BSSIDs
448 +        */
449 +       u8 *bssid_blacklist;
450 +       size_t num_bssid_blacklist;
451 +
452 +       /**
453 +        * bssid_blacklist - List of acceptable BSSIDs
454 +        */
455 +       u8 *bssid_whitelist;
456 +       size_t num_bssid_whitelist;
457 +
458 +       /**
459          * bssid_set - Whether BSSID is configured for this network
460          */
461         int bssid_set;
462 diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
463 index 6761c1a..855653c 100644
464 --- a/wpa_supplicant/events.c
465 +++ b/wpa_supplicant/events.c
466 @@ -703,6 +703,33 @@ static int bss_is_ess(struct wpa_bss *bss)
467  }
468  
469  
470 +static int match_mac_mask(const u8 *addr_a, const u8 *addr_b, const u8 *mask)
471 +{
472 +       size_t i;
473 +
474 +       for (i = 0; i < ETH_ALEN; i++) {
475 +               if ((addr_a[i] & mask[i]) != (addr_b[i] & mask[i]))
476 +                       return 0;
477 +       }
478 +       return 1;
479 +}
480 +
481 +
482 +static int addr_in_list(const u8 *addr, const u8 *list, size_t num)
483 +{
484 +       size_t i;
485 +
486 +       for (i = 0; i < num; i++) {
487 +               const u8 *a = list + i * ETH_ALEN * 2;
488 +               const u8 *m = a + ETH_ALEN;
489 +
490 +               if (match_mac_mask(a, addr, m))
491 +                       return 1;
492 +       }
493 +       return 0;
494 +}
495 +
496 +
497  static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
498                                             int i, struct wpa_bss *bss,
499                                             struct wpa_ssid *group,
500 @@ -827,6 +854,24 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
501                         continue;
502                 }
503  
504 +               /* check blacklist */
505 +               if (ssid->num_bssid_blacklist &&
506 +                   addr_in_list(bss->bssid, ssid->bssid_blacklist,
507 +                                ssid->num_bssid_blacklist)) {
508 +                       wpa_dbg(wpa_s, MSG_DEBUG,
509 +                               "   skip - BSSID blacklisted");
510 +                       continue;
511 +               }
512 +
513 +               /* if there is a whitelist, only accept those APs */
514 +               if (ssid->num_bssid_whitelist &&
515 +                   !addr_in_list(bss->bssid, ssid->bssid_whitelist,
516 +                                 ssid->num_bssid_whitelist)) {
517 +                       wpa_dbg(wpa_s, MSG_DEBUG,
518 +                               "   skip - BSSID not in whitelist");
519 +                       continue;
520 +               }
521 +
522                 if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
523                         continue;
524  
525 diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
526 index 8cd43df..60dcb5d 100644
527 --- a/wpa_supplicant/p2p_supplicant.c
528 +++ b/wpa_supplicant/p2p_supplicant.c
529 @@ -831,7 +831,7 @@ static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s,
530                 return;
531  
532         for (i = 0; s->p2p_client_list && i < s->num_p2p_clients; i++) {
533 -               if (os_memcmp(s->p2p_client_list + i * ETH_ALEN, addr,
534 +               if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN, addr,
535                               ETH_ALEN) != 0)
536                         continue;
537  
538 @@ -839,32 +839,42 @@ static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s,
539                         return; /* already the most recent entry */
540  
541                 /* move the entry to mark it most recent */
542 -               os_memmove(s->p2p_client_list + i * ETH_ALEN,
543 -                          s->p2p_client_list + (i + 1) * ETH_ALEN,
544 -                          (s->num_p2p_clients - i - 1) * ETH_ALEN);
545 +               os_memmove(s->p2p_client_list + i * 2 * ETH_ALEN,
546 +                          s->p2p_client_list + (i + 1) * 2 * ETH_ALEN,
547 +                          (s->num_p2p_clients - i - 1) * 2 * ETH_ALEN);
548                 os_memcpy(s->p2p_client_list +
549 -                         (s->num_p2p_clients - 1) * ETH_ALEN, addr, ETH_ALEN);
550 +                         (s->num_p2p_clients - 1) * 2 * ETH_ALEN, addr,
551 +                         ETH_ALEN);
552 +               os_memset(s->p2p_client_list +
553 +                         (s->num_p2p_clients - 1) * 2 * ETH_ALEN + ETH_ALEN,
554 +                         0xff, ETH_ALEN);
555                 found = 1;
556                 break;
557         }
558  
559         if (!found && s->num_p2p_clients < P2P_MAX_STORED_CLIENTS) {
560                 n = os_realloc_array(s->p2p_client_list,
561 -                                    s->num_p2p_clients + 1, ETH_ALEN);
562 +                                    s->num_p2p_clients + 1, 2 * ETH_ALEN);
563                 if (n == NULL)
564                         return;
565 -               os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN);
566 +               os_memcpy(n + s->num_p2p_clients * 2 * ETH_ALEN, addr,
567 +                         ETH_ALEN);
568 +               os_memset(n + s->num_p2p_clients * 2 * ETH_ALEN + ETH_ALEN,
569 +                         0xff, ETH_ALEN);
570                 s->p2p_client_list = n;
571                 s->num_p2p_clients++;
572         } else if (!found && s->p2p_client_list) {
573                 /* Not enough room for an additional entry - drop the oldest
574                  * entry */
575                 os_memmove(s->p2p_client_list,
576 -                          s->p2p_client_list + ETH_ALEN,
577 -                          (s->num_p2p_clients - 1) * ETH_ALEN);
578 +                          s->p2p_client_list + 2 * ETH_ALEN,
579 +                          (s->num_p2p_clients - 1) * 2 * ETH_ALEN);
580                 os_memcpy(s->p2p_client_list +
581 -                         (s->num_p2p_clients - 1) * ETH_ALEN,
582 +                         (s->num_p2p_clients - 1) * 2 * ETH_ALEN,
583                           addr, ETH_ALEN);
584 +               os_memset(s->p2p_client_list +
585 +                         (s->num_p2p_clients - 1) * 2 * ETH_ALEN + ETH_ALEN,
586 +                         0xff, ETH_ALEN);
587         }
588  
589         if (wpa_s->parent->conf->update_config &&
590 @@ -3276,7 +3286,7 @@ static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s,
591                 return;
592  
593         for (i = 0; ssid->p2p_client_list && i < ssid->num_p2p_clients; i++) {
594 -               if (os_memcmp(ssid->p2p_client_list + i * ETH_ALEN, peer,
595 +               if (os_memcmp(ssid->p2p_client_list + i * 2 * ETH_ALEN, peer,
596                               ETH_ALEN) == 0)
597                         break;
598         }
599 @@ -3296,9 +3306,9 @@ static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s,
600                    "group %d client list%s",
601                    MAC2STR(peer), ssid->id,
602                    inv ? " due to invitation result" : "");
603 -       os_memmove(ssid->p2p_client_list + i * ETH_ALEN,
604 -                  ssid->p2p_client_list + (i + 1) * ETH_ALEN,
605 -                  (ssid->num_p2p_clients - i - 1) * ETH_ALEN);
606 +       os_memmove(ssid->p2p_client_list + i * 2 * ETH_ALEN,
607 +                  ssid->p2p_client_list + (i + 1) * 2 * ETH_ALEN,
608 +                  (ssid->num_p2p_clients - i - 1) * 2 * ETH_ALEN);
609         ssid->num_p2p_clients--;
610         if (wpa_s->parent->conf->update_config &&
611             wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
612 @@ -6925,7 +6935,7 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
613                 if (s->mode != WPAS_MODE_P2P_GO || s->p2p_client_list == NULL)
614                         continue;
615                 for (i = 0; i < s->num_p2p_clients; i++) {
616 -                       if (os_memcmp(s->p2p_client_list + i * ETH_ALEN,
617 +                       if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN,
618                                       addr, ETH_ALEN) == 0)
619                                 return s; /* peer is P2P client in persistent
620                                            * group */
621 diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
622 index 0e8a28a..4bc08db 100644
623 --- a/wpa_supplicant/wpa_supplicant.conf
624 +++ b/wpa_supplicant/wpa_supplicant.conf
625 @@ -1408,6 +1408,21 @@ network={
626         key_mgmt=NONE
627  }
628  
629 +# Example configuration blacklisting two APs - these will be ignored
630 +# for this network.
631 +network={
632 +       ssid="example"
633 +       psk="very secret passphrase"
634 +       bssid_blacklist=02:11:22:33:44:55 02:22:aa:44:55:66
635 +}
636 +
637 +# Example configuration limiting AP selection to a specific set of APs;
638 +# any other AP not matching the masked address will be ignored.
639 +network={
640 +       ssid="example"
641 +       psk="very secret passphrase"
642 +       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
643 +}
644  
645  # Example config file that will only scan on channel 36.
646  freq_list=5180
647 -- 
648 2.1.3
649