Remove tcpslice(1).
[dragonfly.git] / contrib / hostapd-0.5.8 / reconfig.c
1 /*
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.
6  *
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.
10  *
11  * Alternatively, this software may be distributed under the terms of BSD
12  * license.
13  *
14  * See README and COPYING for more details.
15  */
16
17 #include "includes.h"
18
19 #include "hostapd.h"
20 #include "beacon.h"
21 #include "hw_features.h"
22 #include "driver.h"
23 #include "sta_info.h"
24 #include "radius_client.h"
25 #include "ieee802_11.h"
26 #include "iapp.h"
27 #include "ap_list.h"
28 #include "wpa.h"
29 #include "vlan_init.h"
30 #include "ieee802_11_auth.h"
31 #include "ieee802_1x.h"
32 #include "accounting.h"
33 #include "eloop.h"
34
35
36 /**
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.
42  */
43 struct hostapd_config_change {
44         struct hostapd_data *hapd;
45         struct hostapd_config *newconf, *oldconf;
46         struct hostapd_bss_config *newbss, *oldbss;
47         int mac_acl_changed;
48         int num_sta_remove; /* number of STAs that need to be removed */
49         int beacon_changed;
50         struct hostapd_iface *hapd_iface;
51         struct hostapd_data **new_hapd, **old_hapd;
52         int num_old_hapd;
53 };
54
55
56 static int hostapd_config_reload_sta(struct hostapd_data *hapd,
57                                      struct sta_info *sta, void *data)
58 {
59         struct hostapd_config_change *change = data;
60         struct hostapd_bss_config *newbss, *oldbss;
61         int deauth = 0;
62         u8 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
63
64         newbss = change->newbss;
65         oldbss = change->oldbss;
66         hapd = change->hapd;
67
68         if (sta->ssid == &oldbss->ssid) {
69                 sta->ssid = &newbss->ssid;
70
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 */
75                         deauth++;
76                 }
77         }
78         sta->ssid_probe = sta->ssid;
79
80         /*
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
87          * themselves.
88          */
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,
92                                       NULL)))
93                 deauth++;
94
95         if (newbss->ieee802_1x != oldbss->ieee802_1x &&
96             sta->ssid == &hapd->conf->ssid)
97                 deauth++;
98
99         if (newbss->wpa != oldbss->wpa)
100                 deauth++;
101
102         if (!newbss->wme_enabled && (sta->flags & WLAN_STA_WME))
103                 deauth++;
104
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))))
110                 deauth++;
111
112         if (change->num_sta_remove > 0) {
113                 deauth++;
114                 reason = WLAN_REASON_DISASSOC_AP_BUSY;
115         }
116
117         if (deauth) {
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--;
124         }
125
126         return 0;
127 }
128
129
130 static void hostapd_reconfig_tx_queue_params(struct hostapd_data *hapd,
131                                              struct hostapd_config *newconf,
132                                              struct hostapd_config *oldconf)
133 {
134         int i;
135         struct hostapd_tx_queue_params *o, *n;
136
137         for (i = 0; i < NUM_TX_QUEUES; i++) {
138                 o = &oldconf->tx_queue[i];
139                 n = &newconf->tx_queue[i];
140
141                 if (!n->configured)
142                         continue;
143
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,
147                                                 n->cwmax, n->burst))
148                         printf("Failed to set TX queue parameters for queue %d"
149                                ".\n", i);
150         }
151 }
152
153
154 static int hostapd_reconfig_wme(struct hostapd_data *hapd,
155                                 struct hostapd_config *newconf,
156                                 struct hostapd_config *oldconf)
157 {
158         int beacon_changed = 0;
159         size_t i;
160         struct hostapd_wme_ac_params *o, *n;
161
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) {
172                         beacon_changed++;
173                         hapd->parameter_set_count++;
174                 }
175         }
176
177         return beacon_changed;
178 }
179
180
181 static int rate_array_diff(int *a1, int *a2)
182 {
183         int i;
184
185         if (a1 == NULL && a2 == NULL)
186                 return 0;
187         if (a1 == NULL || a2 == NULL)
188                 return 1;
189
190         i = 0;
191         for (;;) {
192                 if (a1[i] != a2[i])
193                         return 1;
194                 if (a1[i] == -1)
195                         break;
196                 i++;
197         }
198
199         return 0;
200 }
201
202
203 static int hostapd_acl_diff(struct hostapd_bss_config *a,
204                             struct hostapd_bss_config *b)
205 {
206         int i;
207
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)
211                 return 1;
212
213         for (i = 0; i < a->num_accept_mac; i++) {
214                 if (memcmp(a->accept_mac[i], b->accept_mac[i], ETH_ALEN) != 0)
215                         return 1;
216         }
217
218         for (i = 0; i < a->num_deny_mac; i++) {
219                 if (memcmp(a->deny_mac[i], b->deny_mac[i], ETH_ALEN) != 0)
220                         return 1;
221         }
222
223         return 0;
224 }
225
226
227 /**
228  * reload_iface2 - Part 2 of reload_iface
229  * @hapd_iface: Pointer to hostapd interface data.
230  */
231 static void reload_iface2(struct hostapd_iface *hapd_iface)
232 {
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;
238
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");
242                 beacon_changed++;
243         }
244
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 "
250                                "driver\n");
251                 if (newconf->beacon_int != oldconf->beacon_int)
252                         beacon_changed++;
253         }
254
255         if (newconf->cts_protection_type != oldconf->cts_protection_type)
256                 beacon_changed++;
257
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");
262
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 "
267                        "driver\n");
268
269         hostapd_reconfig_tx_queue_params(hapd, newconf, oldconf);
270
271         if (hostapd_reconfig_wme(hapd, newconf, oldconf) > 0)
272                 beacon_changed++;
273
274         ap_list_reconfig(hapd_iface, oldconf);
275
276         hapd_iface->change->beacon_changed = beacon_changed;
277
278         hapd_iface->reload_iface_cb = NULL;
279         cb(hapd_iface, 0);
280 }
281
282
283 /**
284  * reload_iface2_handler - Handler that calls reload_face2
285  * @eloop_data: Stores the struct hostapd_iface for the interface.
286  * @user_ctx: Unused.
287  */
288 static void reload_iface2_handler(void *eloop_data, void *user_ctx)
289 {
290         struct hostapd_iface *hapd_iface = eloop_data;
291
292         reload_iface2(hapd_iface);
293 }
294
295
296 /**
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.
300  */
301 static void reload_hw_mode_done(struct hostapd_iface *hapd_iface, int status)
302 {
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;
306         hostapd_iface_cb cb;
307         int freq;
308
309         if (status) {
310                 printf("Failed to select hw_mode.\n");
311
312                 cb = hapd_iface->reload_iface_cb;
313                 hapd_iface->reload_iface_cb = NULL;
314                 cb(hapd_iface, -1);
315
316                 return;
317         }
318
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);
324
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);
328         }
329
330         change->beacon_changed++;
331
332         reload_iface2(hapd_iface);
333 }
334
335
336 /**
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.
342  */
343 static int hostapd_config_reload_iface_start(struct hostapd_iface *hapd_iface,
344                                              hostapd_iface_cb cb)
345 {
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];
350
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);
355                 return -1;
356         }
357
358         hapd_iface->reload_iface_cb = cb;
359
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");
364
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);
371
372                 if (hostapd_get_hw_features(hapd_iface)) {
373                         printf("Could not read HW feature info from the kernel"
374                                " driver.\n");
375                         hapd_iface->reload_iface_cb = NULL;
376                         return -1;
377                 }
378
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;
383                         return -1;
384                 }
385
386                 return 0;
387         }
388
389         eloop_register_timeout(0, 0, reload_iface2_handler, hapd_iface, NULL);
390         return 0;
391 }
392
393
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,
398                                  int beacon_changed)
399 {
400         struct hostapd_config_change change;
401         int encr_changed = 0;
402         struct radius_client_data *old_radius;
403
404         radius_client_flush(hapd->radius, 0);
405
406         if (hostapd_set_dtim_period(hapd, newbss->dtim_period))
407                 printf("Could not set DTIM period for kernel driver\n");
408
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");
415                 beacon_changed++;
416         }
417
418         if (newbss->ignore_broadcast_ssid != oldbss->ignore_broadcast_ssid)
419                 beacon_changed++;
420
421         if (hostapd_wep_key_cmp(&newbss->ssid.wep, &oldbss->ssid.wep)) {
422                 encr_changed++;
423                 beacon_changed++;
424         }
425
426         vlan_reconfig(hapd, oldconf, oldbss);
427
428         if (beacon_changed) {
429                 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Updating beacon frame "
430                               "information\n");
431                 ieee802_11_set_beacon(hapd);
432         }
433
434         change.hapd = 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;
443         } else
444                 change.num_sta_remove = 0;
445         ap_for_each_sta(hapd, hostapd_config_reload_sta, &change);
446
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);
452
453         ieee802_1x_reconfig(hapd, oldconf, oldbss);
454         iapp_reconfig(hapd, oldconf, oldbss);
455
456         hostapd_acl_reconfig(hapd, oldconf);
457         accounting_reconfig(hapd, oldconf);
458 }
459
460
461 /**
462  * config_reload2 - Part 2 of configuration reloading
463  * @hapd_iface:
464  */
465 static void config_reload2(struct hostapd_iface *hapd_iface, int status)
466 {
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;
477         u8 *prev_addr;
478         hostapd_iface_cb cb;
479
480         free(change);
481         hapd_iface->change = NULL;
482
483         if (status) {
484                 printf("Failed to setup new interface config\n");
485
486                 cb = hapd_iface->config_reload_cb;
487                 hapd_iface->config_reload_cb = NULL;
488
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);
495                 free(new_hapd);
496
497                 cb(hapd_iface, -2);
498
499                 return;
500         }
501
502         /*
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.
506          */
507         max_bss = oldconf->num_bss;
508         if (max_bss > newconf->num_bss)
509                 max_bss = newconf->num_bss;
510
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)
515                         break;
516         }
517         same_bssid = i;
518
519         for (i = 0; i < oldconf->num_bss; i++) {
520                 oldbss = &oldconf->bss[i];
521                 newbss = NULL;
522                 for (j = 0; j < newconf->num_bss; j++) {
523                         if (strcmp(oldbss->iface, newconf->bss[j].iface) == 0)
524                         {
525                                 newbss = &newconf->bss[j];
526                                 break;
527                         }
528                 }
529
530                 if (newbss && i < same_bssid) {
531                         hapd = hapd_iface->bss[j] = old_hapd[i];
532                         hapd->iconf = newconf;
533                         hapd->conf = newbss;
534                         hostapd_reconfig_bss(hapd, newbss, oldbss, oldconf,
535                                              beacon_changed);
536                 } else {
537                         hapd = old_hapd[i];
538                         HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
539                                       "Removing BSS (ifname %s)\n",
540                                       hapd->conf->iface);
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
546                          * being removed. */
547 #if 0
548                         hostapd_deauth_all_stas(hapd);
549                         hostapd_cleanup(hapd);
550 #endif
551
552                         free(hapd);
553                 }
554         }
555
556
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;
562                         continue;
563                 }
564
565                 newbss = &newconf->bss[j];
566
567                 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Reconfiguration: adding "
568                               "new BSS (ifname=%s)\n", newbss->iface);
569
570 #if 0
571                 hapd = hapd_iface->bss[j] =
572                         hostapd_alloc_bss_data(hapd_iface, newconf, newbss);
573 #endif
574                 if (hapd == NULL) {
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. */
579                         exit(1);
580                 }
581                 hapd->driver = hapd_iface->bss[0]->driver;
582                 hapd->iface = hapd_iface;
583                 hapd->iconf = newconf;
584                 hapd->conf = newbss;
585
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;
589
590 #if 0
591                 if (hostapd_setup_bss(hapd, j == 0)) {
592                         printf("Failed to setup new BSS\n");
593                         /* FIX */
594                         exit(1);
595                 }
596 #endif
597
598         }
599
600         free(old_hapd);
601         hostapd_config_free(oldconf);
602
603         cb = hapd_iface->config_reload_cb;
604         hapd_iface->config_reload_cb = NULL;
605
606         cb(hapd_iface, 0);
607 }
608
609
610 /**
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
619  * Returns:
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
624  */
625 int hostapd_config_reload_start(struct hostapd_iface *hapd_iface,
626                                 hostapd_iface_cb cb)
627 {
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;
632         int num_old_hapd;
633
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);
637                 return -1;
638         }
639
640         newconf = hostapd_config_read(hapd_iface->config_fname);
641         if (newconf == NULL) {
642                 printf("Failed to read new configuration file - continuing "
643                        "with old.\n");
644                 return -1;
645         }
646
647         if (strcmp(newconf->bss[0].iface, hapd_iface->conf->bss[0].iface) !=
648             0) {
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);
653                 return -1;
654         }
655
656         new_hapd = wpa_zalloc(newconf->num_bss *
657                               sizeof(struct hostapd_data *));
658         if (new_hapd == NULL) {
659                 hostapd_config_free(newconf);
660                 return -1;
661         }
662         old_hapd = hapd_iface->bss;
663         num_old_hapd = hapd_iface->num_bss;
664
665         hapd_iface->bss = new_hapd;
666         hapd_iface->num_bss = newconf->num_bss;
667         /*
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
671          * this again.
672          */
673         hapd = hapd_iface->bss[0] = old_hapd[0];
674
675         oldconf = hapd_iface->conf;
676         hapd->iconf = hapd_iface->conf = newconf;
677         hapd->conf = &newconf->bss[0];
678
679         change = wpa_zalloc(sizeof(struct hostapd_config_change));
680         if (change == NULL) {
681                 hostapd_config_free(newconf);
682                 return -1;
683         }
684
685         change->hapd = hapd;
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;
693
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");
698
699                 hapd_iface->config_reload_cb = NULL;
700                 free(change);
701                 hapd_iface->change = NULL;
702
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);
709                 free(new_hapd);
710                 return -2;
711         }
712
713         return 0;
714 }