2 * hostapd / Configuration reloading
3 * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2002-2004, Instant802 Networks, Inc.
5 * Copyright (c) 2005-2006, Devicescape Software, Inc.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * Alternatively, this software may be distributed under the terms of BSD
14 * See README and COPYING for more details.
21 #include "hw_features.h"
24 #include "radius_client.h"
25 #include "ieee802_11.h"
29 #include "vlan_init.h"
30 #include "ieee802_11_auth.h"
31 #include "ieee802_1x.h"
32 #include "accounting.h"
37 * struct hostapd_config_change - Configuration change information
38 * This is for two purposes:
39 * - Storing configuration information in the hostapd_iface during
40 * the asynchronous parts of reconfiguration.
41 * - Passing configuration information for per-station reconfiguration.
43 struct hostapd_config_change
{
44 struct hostapd_data
*hapd
;
45 struct hostapd_config
*newconf
, *oldconf
;
46 struct hostapd_bss_config
*newbss
, *oldbss
;
48 int num_sta_remove
; /* number of STAs that need to be removed */
50 struct hostapd_iface
*hapd_iface
;
51 struct hostapd_data
**new_hapd
, **old_hapd
;
56 static int hostapd_config_reload_sta(struct hostapd_data
*hapd
,
57 struct sta_info
*sta
, void *data
)
59 struct hostapd_config_change
*change
= data
;
60 struct hostapd_bss_config
*newbss
, *oldbss
;
62 u8 reason
= WLAN_REASON_PREV_AUTH_NOT_VALID
;
64 newbss
= change
->newbss
;
65 oldbss
= change
->oldbss
;
68 if (sta
->ssid
== &oldbss
->ssid
) {
69 sta
->ssid
= &newbss
->ssid
;
71 if (newbss
->ssid
.ssid_len
!= oldbss
->ssid
.ssid_len
||
72 memcmp(newbss
->ssid
.ssid
, oldbss
->ssid
.ssid
,
73 newbss
->ssid
.ssid_len
) != 0) {
74 /* main SSID was changed - kick STA out */
78 sta
->ssid_probe
= sta
->ssid
;
81 * If MAC ACL configuration has changed, deauthenticate stations that
82 * have been removed from accepted list or have been added to denied
83 * list. If external RADIUS server is used for ACL, all stations are
84 * deauthenticated and they will need to authenticate again. This
85 * limits sudden load on the RADIUS server since the verification will
86 * be done over the time needed for the STAs to reauthenticate
89 if (change
->mac_acl_changed
&&
90 (newbss
->macaddr_acl
== USE_EXTERNAL_RADIUS_AUTH
||
91 !hostapd_allowed_address(hapd
, sta
->addr
, NULL
, 0, NULL
, NULL
,
95 if (newbss
->ieee802_1x
!= oldbss
->ieee802_1x
&&
96 sta
->ssid
== &hapd
->conf
->ssid
)
99 if (newbss
->wpa
!= oldbss
->wpa
)
102 if (!newbss
->wme_enabled
&& (sta
->flags
& WLAN_STA_WME
))
105 if (newbss
->auth_algs
!= oldbss
->auth_algs
&&
106 ((sta
->auth_alg
== WLAN_AUTH_OPEN
&&
107 !(newbss
->auth_algs
& HOSTAPD_AUTH_OPEN
)) ||
108 (sta
->auth_alg
== WLAN_AUTH_SHARED_KEY
&&
109 !(newbss
->auth_algs
& HOSTAPD_AUTH_SHARED_KEY
))))
112 if (change
->num_sta_remove
> 0) {
114 reason
= WLAN_REASON_DISASSOC_AP_BUSY
;
118 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
, "STA " MACSTR
119 " deauthenticated during config reloading "
120 "(reason=%d)\n", MAC2STR(sta
->addr
), reason
);
121 ieee802_11_send_deauth(hapd
, sta
->addr
, reason
);
122 ap_sta_deauthenticate(hapd
, sta
, reason
);
123 change
->num_sta_remove
--;
130 static void hostapd_reconfig_tx_queue_params(struct hostapd_data
*hapd
,
131 struct hostapd_config
*newconf
,
132 struct hostapd_config
*oldconf
)
135 struct hostapd_tx_queue_params
*o
, *n
;
137 for (i
= 0; i
< NUM_TX_QUEUES
; i
++) {
138 o
= &oldconf
->tx_queue
[i
];
139 n
= &newconf
->tx_queue
[i
];
144 if ((n
->aifs
!= o
->aifs
|| n
->cwmin
!= o
->cwmin
||
145 n
->cwmax
!= o
->cwmax
|| n
->burst
!= o
->burst
) &&
146 hostapd_set_tx_queue_params(hapd
, i
, n
->aifs
, n
->cwmin
,
148 printf("Failed to set TX queue parameters for queue %d"
154 static int hostapd_reconfig_wme(struct hostapd_data
*hapd
,
155 struct hostapd_config
*newconf
,
156 struct hostapd_config
*oldconf
)
158 int beacon_changed
= 0;
160 struct hostapd_wme_ac_params
*o
, *n
;
162 for (i
= 0; i
< sizeof(newconf
->wme_ac_params
) /
163 sizeof(newconf
->wme_ac_params
[0]); i
++) {
164 o
= &oldconf
->wme_ac_params
[i
];
165 n
= &newconf
->wme_ac_params
[i
];
166 if (n
->cwmin
!= o
->cwmin
||
167 n
->cwmax
!= o
->cwmax
||
168 n
->aifs
!= o
->aifs
||
169 n
->txopLimit
!= o
->txopLimit
||
170 n
->admission_control_mandatory
!=
171 o
->admission_control_mandatory
) {
173 hapd
->parameter_set_count
++;
177 return beacon_changed
;
181 static int rate_array_diff(int *a1
, int *a2
)
185 if (a1
== NULL
&& a2
== NULL
)
187 if (a1
== NULL
|| a2
== NULL
)
203 static int hostapd_acl_diff(struct hostapd_bss_config
*a
,
204 struct hostapd_bss_config
*b
)
208 if (a
->macaddr_acl
!= b
->macaddr_acl
||
209 a
->num_accept_mac
!= b
->num_accept_mac
||
210 a
->num_deny_mac
!= b
->num_deny_mac
)
213 for (i
= 0; i
< a
->num_accept_mac
; i
++) {
214 if (memcmp(a
->accept_mac
[i
], b
->accept_mac
[i
], ETH_ALEN
) != 0)
218 for (i
= 0; i
< a
->num_deny_mac
; i
++) {
219 if (memcmp(a
->deny_mac
[i
], b
->deny_mac
[i
], ETH_ALEN
) != 0)
228 * reload_iface2 - Part 2 of reload_iface
229 * @hapd_iface: Pointer to hostapd interface data.
231 static void reload_iface2(struct hostapd_iface
*hapd_iface
)
233 struct hostapd_data
*hapd
= hapd_iface
->bss
[0];
234 struct hostapd_config
*newconf
= hapd_iface
->change
->newconf
;
235 struct hostapd_config
*oldconf
= hapd_iface
->change
->oldconf
;
236 int beacon_changed
= hapd_iface
->change
->beacon_changed
;
237 hostapd_iface_cb cb
= hapd_iface
->reload_iface_cb
;
239 if (newconf
->preamble
!= oldconf
->preamble
) {
240 if (hostapd_set_preamble(hapd
, hapd
->iconf
->preamble
))
241 printf("Could not set preamble for kernel driver\n");
245 if (newconf
->beacon_int
!= oldconf
->beacon_int
) {
246 /* Need to change beacon interval if it has changed or if
247 * auto channel selection was used. */
248 if (hostapd_set_beacon_int(hapd
, newconf
->beacon_int
))
249 printf("Could not set beacon interval for kernel "
251 if (newconf
->beacon_int
!= oldconf
->beacon_int
)
255 if (newconf
->cts_protection_type
!= oldconf
->cts_protection_type
)
258 if (newconf
->rts_threshold
> -1 &&
259 newconf
->rts_threshold
!= oldconf
->rts_threshold
&&
260 hostapd_set_rts(hapd
, newconf
->rts_threshold
))
261 printf("Could not set RTS threshold for kernel driver\n");
263 if (newconf
->fragm_threshold
> -1 &&
264 newconf
->fragm_threshold
!= oldconf
->fragm_threshold
&&
265 hostapd_set_frag(hapd
, newconf
->fragm_threshold
))
266 printf("Could not set fragmentation threshold for kernel "
269 hostapd_reconfig_tx_queue_params(hapd
, newconf
, oldconf
);
271 if (hostapd_reconfig_wme(hapd
, newconf
, oldconf
) > 0)
274 ap_list_reconfig(hapd_iface
, oldconf
);
276 hapd_iface
->change
->beacon_changed
= beacon_changed
;
278 hapd_iface
->reload_iface_cb
= NULL
;
284 * reload_iface2_handler - Handler that calls reload_face2
285 * @eloop_data: Stores the struct hostapd_iface for the interface.
288 static void reload_iface2_handler(void *eloop_data
, void *user_ctx
)
290 struct hostapd_iface
*hapd_iface
= eloop_data
;
292 reload_iface2(hapd_iface
);
297 * reload_hw_mode_done - Callback for after the HW mode is setup
298 * @hapd_iface: Pointer to interface data.
299 * @status: Status of the HW mode setup.
301 static void reload_hw_mode_done(struct hostapd_iface
*hapd_iface
, int status
)
303 struct hostapd_data
*hapd
= hapd_iface
->bss
[0];
304 struct hostapd_config_change
*change
= hapd_iface
->change
;
305 struct hostapd_config
*newconf
= change
->newconf
;
310 printf("Failed to select hw_mode.\n");
312 cb
= hapd_iface
->reload_iface_cb
;
313 hapd_iface
->reload_iface_cb
= NULL
;
319 freq
= hostapd_hw_get_freq(hapd
, newconf
->channel
);
320 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
,
321 "Mode: %s Channel: %d Frequency: %d MHz\n",
322 hostapd_hw_mode_txt(newconf
->hw_mode
),
323 newconf
->channel
, freq
);
325 if (hostapd_set_freq(hapd
, newconf
->hw_mode
, freq
)) {
326 printf("Could not set channel %d (%d MHz) for kernel "
327 "driver\n", newconf
->channel
, freq
);
330 change
->beacon_changed
++;
332 reload_iface2(hapd_iface
);
337 * hostapd_config_reload_iface_start - Start interface reload
338 * @hapd_iface: Pointer to interface data.
339 * @cb: The function to callback when done.
340 * Returns: 0 if it starts successfully; cb will be called when done.
341 * -1 on failure; cb will not be called.
343 static int hostapd_config_reload_iface_start(struct hostapd_iface
*hapd_iface
,
346 struct hostapd_config_change
*change
= hapd_iface
->change
;
347 struct hostapd_config
*newconf
= change
->newconf
;
348 struct hostapd_config
*oldconf
= change
->oldconf
;
349 struct hostapd_data
*hapd
= hapd_iface
->bss
[0];
351 if (hapd_iface
->reload_iface_cb
) {
352 wpa_printf(MSG_DEBUG
,
353 "%s: Interface reload already in progress.",
354 hapd_iface
->bss
[0]->conf
->iface
);
358 hapd_iface
->reload_iface_cb
= cb
;
360 if (newconf
->bridge_packets
!= oldconf
->bridge_packets
&&
361 hapd
->iconf
->bridge_packets
!= INTERNAL_BRIDGE_DO_NOT_CONTROL
&&
362 hostapd_set_internal_bridge(hapd
, hapd
->iconf
->bridge_packets
))
363 printf("Failed to set bridge_packets for kernel driver\n");
365 if (newconf
->channel
!= oldconf
->channel
||
366 newconf
->hw_mode
!= oldconf
->hw_mode
||
367 rate_array_diff(newconf
->supported_rates
,
368 oldconf
->supported_rates
) ||
369 rate_array_diff(newconf
->basic_rates
, oldconf
->basic_rates
)) {
370 hostapd_free_stas(hapd
);
372 if (hostapd_get_hw_features(hapd_iface
)) {
373 printf("Could not read HW feature info from the kernel"
375 hapd_iface
->reload_iface_cb
= NULL
;
379 if (hostapd_select_hw_mode_start(hapd_iface
,
380 reload_hw_mode_done
)) {
381 printf("Failed to start select hw_mode.\n");
382 hapd_iface
->reload_iface_cb
= NULL
;
389 eloop_register_timeout(0, 0, reload_iface2_handler
, hapd_iface
, NULL
);
394 static void hostapd_reconfig_bss(struct hostapd_data
*hapd
,
395 struct hostapd_bss_config
*newbss
,
396 struct hostapd_bss_config
*oldbss
,
397 struct hostapd_config
*oldconf
,
400 struct hostapd_config_change change
;
401 int encr_changed
= 0;
402 struct radius_client_data
*old_radius
;
404 radius_client_flush(hapd
->radius
, 0);
406 if (hostapd_set_dtim_period(hapd
, newbss
->dtim_period
))
407 printf("Could not set DTIM period for kernel driver\n");
409 if (newbss
->ssid
.ssid_len
!= oldbss
->ssid
.ssid_len
||
410 memcmp(newbss
->ssid
.ssid
, oldbss
->ssid
.ssid
,
411 newbss
->ssid
.ssid_len
) != 0) {
412 if (hostapd_set_ssid(hapd
, (u8
*) newbss
->ssid
.ssid
,
413 newbss
->ssid
.ssid_len
))
414 printf("Could not set SSID for kernel driver\n");
418 if (newbss
->ignore_broadcast_ssid
!= oldbss
->ignore_broadcast_ssid
)
421 if (hostapd_wep_key_cmp(&newbss
->ssid
.wep
, &oldbss
->ssid
.wep
)) {
426 vlan_reconfig(hapd
, oldconf
, oldbss
);
428 if (beacon_changed
) {
429 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
, "Updating beacon frame "
431 ieee802_11_set_beacon(hapd
);
435 change
.oldconf
= oldconf
;
436 change
.newconf
= hapd
->iconf
;
437 change
.oldbss
= oldbss
;
438 change
.newbss
= newbss
;
439 change
.mac_acl_changed
= hostapd_acl_diff(newbss
, oldbss
);
440 if (newbss
->max_num_sta
!= oldbss
->max_num_sta
&&
441 newbss
->max_num_sta
< hapd
->num_sta
) {
442 change
.num_sta_remove
= hapd
->num_sta
- newbss
->max_num_sta
;
444 change
.num_sta_remove
= 0;
445 ap_for_each_sta(hapd
, hostapd_config_reload_sta
, &change
);
447 old_radius
= hapd
->radius
;
448 hapd
->radius
= radius_client_reconfig(hapd
->radius
, hapd
,
449 oldbss
->radius
, newbss
->radius
);
450 hapd
->radius_client_reconfigured
= old_radius
!= hapd
->radius
||
451 hostapd_ip_diff(&newbss
->own_ip_addr
, &oldbss
->own_ip_addr
);
453 ieee802_1x_reconfig(hapd
, oldconf
, oldbss
);
454 iapp_reconfig(hapd
, oldconf
, oldbss
);
456 hostapd_acl_reconfig(hapd
, oldconf
);
457 accounting_reconfig(hapd
, oldconf
);
462 * config_reload2 - Part 2 of configuration reloading
465 static void config_reload2(struct hostapd_iface
*hapd_iface
, int status
)
467 struct hostapd_config_change
*change
= hapd_iface
->change
;
468 struct hostapd_data
*hapd
= change
->hapd
;
469 struct hostapd_config
*newconf
= change
->newconf
;
470 struct hostapd_config
*oldconf
= change
->oldconf
;
471 int beacon_changed
= change
->beacon_changed
;
472 struct hostapd_data
**new_hapd
= change
->new_hapd
;
473 struct hostapd_data
**old_hapd
= change
->old_hapd
;
474 int num_old_hapd
= change
->num_old_hapd
;
475 size_t i
, j
, max_bss
, same_bssid
;
476 struct hostapd_bss_config
*newbss
, *oldbss
;
481 hapd_iface
->change
= NULL
;
484 printf("Failed to setup new interface config\n");
486 cb
= hapd_iface
->config_reload_cb
;
487 hapd_iface
->config_reload_cb
= NULL
;
489 /* Invalid configuration - cleanup and terminate hostapd */
490 hapd_iface
->bss
= old_hapd
;
491 hapd_iface
->num_bss
= num_old_hapd
;
492 hapd_iface
->conf
= hapd
->iconf
= oldconf
;
493 hapd
->conf
= &oldconf
->bss
[0];
494 hostapd_config_free(newconf
);
503 * If any BSSes have been removed, added, or had their BSSIDs changed,
504 * completely remove and reinitialize such BSSes and all the BSSes
505 * following them since their BSSID might have changed.
507 max_bss
= oldconf
->num_bss
;
508 if (max_bss
> newconf
->num_bss
)
509 max_bss
= newconf
->num_bss
;
511 for (i
= 0; i
< max_bss
; i
++) {
512 if (strcmp(oldconf
->bss
[i
].iface
, newconf
->bss
[i
].iface
) != 0
513 || hostapd_mac_comp(oldconf
->bss
[i
].bssid
,
514 newconf
->bss
[i
].bssid
) != 0)
519 for (i
= 0; i
< oldconf
->num_bss
; i
++) {
520 oldbss
= &oldconf
->bss
[i
];
522 for (j
= 0; j
< newconf
->num_bss
; j
++) {
523 if (strcmp(oldbss
->iface
, newconf
->bss
[j
].iface
) == 0)
525 newbss
= &newconf
->bss
[j
];
530 if (newbss
&& i
< same_bssid
) {
531 hapd
= hapd_iface
->bss
[j
] = old_hapd
[i
];
532 hapd
->iconf
= newconf
;
534 hostapd_reconfig_bss(hapd
, newbss
, oldbss
, oldconf
,
538 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
,
539 "Removing BSS (ifname %s)\n",
541 hostapd_free_stas(hapd
);
542 /* Send broadcast deauthentication for this BSS, but do
543 * not clear all STAs from the driver since other BSSes
544 * may have STA entries. The driver will remove all STA
545 * entries for this BSS anyway when the interface is
548 hostapd_deauth_all_stas(hapd
);
549 hostapd_cleanup(hapd
);
557 prev_addr
= hapd_iface
->bss
[0]->own_addr
;
558 hapd
= hapd_iface
->bss
[0];
559 for (j
= 0; j
< newconf
->num_bss
; j
++) {
560 if (hapd_iface
->bss
[j
] != NULL
) {
561 prev_addr
= hapd_iface
->bss
[j
]->own_addr
;
565 newbss
= &newconf
->bss
[j
];
567 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
, "Reconfiguration: adding "
568 "new BSS (ifname=%s)\n", newbss
->iface
);
571 hapd
= hapd_iface
->bss
[j
] =
572 hostapd_alloc_bss_data(hapd_iface
, newconf
, newbss
);
575 printf("Failed to initialize new BSS\n");
576 /* FIX: This one is somewhat hard to recover
577 * from.. Would need to remove this BSS from
578 * conf and BSS list. */
581 hapd
->driver
= hapd_iface
->bss
[0]->driver
;
582 hapd
->iface
= hapd_iface
;
583 hapd
->iconf
= newconf
;
586 memcpy(hapd
->own_addr
, prev_addr
, ETH_ALEN
);
587 if (hostapd_mac_comp_empty(hapd
->conf
->bssid
) == 0)
588 prev_addr
= hapd
->own_addr
;
591 if (hostapd_setup_bss(hapd
, j
== 0)) {
592 printf("Failed to setup new BSS\n");
601 hostapd_config_free(oldconf
);
603 cb
= hapd_iface
->config_reload_cb
;
604 hapd_iface
->config_reload_cb
= NULL
;
611 * hostapd_config_reload_start - Start reconfiguration of an interface
612 * @hapd_iface: Pointer to hostapd interface data
613 * @cb: Function to be called back when done.
614 * The status indicates:
615 * 0 = success, new configuration in use;
616 * -1 = failed to update configuraiton, old configuration in use;
617 * -2 = failed to update configuration and failed to recover; caller
618 * should cleanup and terminate hostapd
620 * 0 = reconfiguration started;
621 * -1 = failed to update configuration, old configuration in use;
622 * -2 = failed to update configuration and failed to recover; caller
623 * should cleanup and terminate hostapd
625 int hostapd_config_reload_start(struct hostapd_iface
*hapd_iface
,
628 struct hostapd_config
*newconf
, *oldconf
;
629 struct hostapd_config_change
*change
;
630 struct hostapd_data
*hapd
= NULL
;
631 struct hostapd_data
**old_hapd
, **new_hapd
;
634 if (hapd_iface
->config_reload_cb
) {
635 wpa_printf(MSG_DEBUG
, "%s: Config reload already in progress.",
636 hapd_iface
->bss
[0]->conf
->iface
);
640 newconf
= hostapd_config_read(hapd_iface
->config_fname
);
641 if (newconf
== NULL
) {
642 printf("Failed to read new configuration file - continuing "
647 if (strcmp(newconf
->bss
[0].iface
, hapd_iface
->conf
->bss
[0].iface
) !=
649 printf("Interface name changing is not allowed in "
650 "configuration reloading (%s -> %s).\n",
651 hapd_iface
->conf
->bss
[0].iface
, newconf
->bss
[0].iface
);
652 hostapd_config_free(newconf
);
656 new_hapd
= wpa_zalloc(newconf
->num_bss
*
657 sizeof(struct hostapd_data
*));
658 if (new_hapd
== NULL
) {
659 hostapd_config_free(newconf
);
662 old_hapd
= hapd_iface
->bss
;
663 num_old_hapd
= hapd_iface
->num_bss
;
665 hapd_iface
->bss
= new_hapd
;
666 hapd_iface
->num_bss
= newconf
->num_bss
;
668 * First BSS remains the same since interface name changing was
669 * prohibited above. Now, this is only used in
670 * hostapd_config_reload_iface() and following loop will anyway set
673 hapd
= hapd_iface
->bss
[0] = old_hapd
[0];
675 oldconf
= hapd_iface
->conf
;
676 hapd
->iconf
= hapd_iface
->conf
= newconf
;
677 hapd
->conf
= &newconf
->bss
[0];
679 change
= wpa_zalloc(sizeof(struct hostapd_config_change
));
680 if (change
== NULL
) {
681 hostapd_config_free(newconf
);
686 change
->newconf
= newconf
;
687 change
->oldconf
= oldconf
;
688 change
->beacon_changed
= 0;
689 change
->hapd_iface
= hapd_iface
;
690 change
->new_hapd
= new_hapd
;
691 change
->old_hapd
= old_hapd
;
692 change
->num_old_hapd
= num_old_hapd
;
694 hapd_iface
->config_reload_cb
= cb
;
695 hapd_iface
->change
= change
;
696 if (hostapd_config_reload_iface_start(hapd_iface
, config_reload2
)) {
697 printf("Failed to start setup of new interface config\n");
699 hapd_iface
->config_reload_cb
= NULL
;
701 hapd_iface
->change
= NULL
;
703 /* Invalid configuration - cleanup and terminate hostapd */
704 hapd_iface
->bss
= old_hapd
;
705 hapd_iface
->num_bss
= num_old_hapd
;
706 hapd_iface
->conf
= hapd
->iconf
= oldconf
;
707 hapd
->conf
= &oldconf
->bss
[0];
708 hostapd_config_free(newconf
);