reconfig.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  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. #include "includes.h"
  17. #include "hostapd.h"
  18. #include "beacon.h"
  19. #include "hw_features.h"
  20. #include "driver.h"
  21. #include "sta_info.h"
  22. #include "radius/radius_client.h"
  23. #include "ieee802_11.h"
  24. #include "iapp.h"
  25. #include "ap_list.h"
  26. #include "wpa.h"
  27. #include "vlan_init.h"
  28. #include "ieee802_11_auth.h"
  29. #include "ieee802_1x.h"
  30. #include "accounting.h"
  31. #include "eloop.h"
  32. /**
  33. * struct hostapd_config_change - Configuration change information
  34. * This is for two purposes:
  35. * - Storing configuration information in the hostapd_iface during
  36. * the asynchronous parts of reconfiguration.
  37. * - Passing configuration information for per-station reconfiguration.
  38. */
  39. struct hostapd_config_change {
  40. struct hostapd_data *hapd;
  41. struct hostapd_config *newconf, *oldconf;
  42. struct hostapd_bss_config *newbss, *oldbss;
  43. int mac_acl_changed;
  44. int num_sta_remove; /* number of STAs that need to be removed */
  45. int beacon_changed;
  46. struct hostapd_iface *hapd_iface;
  47. struct hostapd_data **new_hapd, **old_hapd;
  48. int num_old_hapd;
  49. };
  50. static int hostapd_config_reload_sta(struct hostapd_data *hapd,
  51. struct sta_info *sta, void *data)
  52. {
  53. struct hostapd_config_change *change = data;
  54. struct hostapd_bss_config *newbss, *oldbss;
  55. int deauth = 0;
  56. u8 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
  57. newbss = change->newbss;
  58. oldbss = change->oldbss;
  59. hapd = change->hapd;
  60. if (sta->ssid == &oldbss->ssid) {
  61. sta->ssid = &newbss->ssid;
  62. if (newbss->ssid.ssid_len != oldbss->ssid.ssid_len ||
  63. os_memcmp(newbss->ssid.ssid, oldbss->ssid.ssid,
  64. newbss->ssid.ssid_len) != 0) {
  65. /* main SSID was changed - kick STA out */
  66. deauth++;
  67. }
  68. }
  69. sta->ssid_probe = sta->ssid;
  70. /*
  71. * If MAC ACL configuration has changed, deauthenticate stations that
  72. * have been removed from accepted list or have been added to denied
  73. * list. If external RADIUS server is used for ACL, all stations are
  74. * deauthenticated and they will need to authenticate again. This
  75. * limits sudden load on the RADIUS server since the verification will
  76. * be done over the time needed for the STAs to reauthenticate
  77. * themselves.
  78. */
  79. if (change->mac_acl_changed &&
  80. (newbss->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH ||
  81. !hostapd_allowed_address(hapd, sta->addr, NULL, 0, NULL, NULL,
  82. NULL)))
  83. deauth++;
  84. if (newbss->ieee802_1x != oldbss->ieee802_1x &&
  85. sta->ssid == &hapd->conf->ssid)
  86. deauth++;
  87. if (newbss->wpa != oldbss->wpa)
  88. deauth++;
  89. if (!newbss->wme_enabled && (sta->flags & WLAN_STA_WME))
  90. deauth++;
  91. if (newbss->auth_algs != oldbss->auth_algs &&
  92. ((sta->auth_alg == WLAN_AUTH_OPEN &&
  93. !(newbss->auth_algs & WPA_AUTH_ALG_OPEN)) ||
  94. (sta->auth_alg == WLAN_AUTH_SHARED_KEY &&
  95. !(newbss->auth_algs & WPA_AUTH_ALG_SHARED))))
  96. deauth++;
  97. if (change->num_sta_remove > 0) {
  98. deauth++;
  99. reason = WLAN_REASON_DISASSOC_AP_BUSY;
  100. }
  101. if (deauth) {
  102. wpa_printf(MSG_DEBUG, "STA " MACSTR " deauthenticated during "
  103. "config reloading (reason=%d)",
  104. MAC2STR(sta->addr), reason);
  105. ieee802_11_send_deauth(hapd, sta->addr, reason);
  106. ap_sta_deauthenticate(hapd, sta, reason);
  107. change->num_sta_remove--;
  108. }
  109. return 0;
  110. }
  111. static void hostapd_reconfig_tx_queue_params(struct hostapd_data *hapd,
  112. struct hostapd_config *newconf,
  113. struct hostapd_config *oldconf)
  114. {
  115. int i;
  116. struct hostapd_tx_queue_params *o, *n;
  117. for (i = 0; i < NUM_TX_QUEUES; i++) {
  118. o = &oldconf->tx_queue[i];
  119. n = &newconf->tx_queue[i];
  120. if (!n->configured)
  121. continue;
  122. if ((n->aifs != o->aifs || n->cwmin != o->cwmin ||
  123. n->cwmax != o->cwmax || n->burst != o->burst) &&
  124. hostapd_set_tx_queue_params(hapd, i, n->aifs, n->cwmin,
  125. n->cwmax, n->burst))
  126. printf("Failed to set TX queue parameters for queue %d"
  127. ".\n", i);
  128. }
  129. }
  130. static int hostapd_reconfig_wme(struct hostapd_data *hapd,
  131. struct hostapd_config *newconf,
  132. struct hostapd_config *oldconf)
  133. {
  134. int beacon_changed = 0;
  135. size_t i;
  136. struct hostapd_wme_ac_params *o, *n;
  137. for (i = 0; i < sizeof(newconf->wme_ac_params) /
  138. sizeof(newconf->wme_ac_params[0]); i++) {
  139. o = &oldconf->wme_ac_params[i];
  140. n = &newconf->wme_ac_params[i];
  141. if (n->cwmin != o->cwmin ||
  142. n->cwmax != o->cwmax ||
  143. n->aifs != o->aifs ||
  144. n->txopLimit != o->txopLimit ||
  145. n->admission_control_mandatory !=
  146. o->admission_control_mandatory) {
  147. beacon_changed++;
  148. hapd->parameter_set_count++;
  149. }
  150. }
  151. return beacon_changed;
  152. }
  153. static int rate_array_diff(int *a1, int *a2)
  154. {
  155. int i;
  156. if (a1 == NULL && a2 == NULL)
  157. return 0;
  158. if (a1 == NULL || a2 == NULL)
  159. return 1;
  160. i = 0;
  161. for (;;) {
  162. if (a1[i] != a2[i])
  163. return 1;
  164. if (a1[i] == -1)
  165. break;
  166. i++;
  167. }
  168. return 0;
  169. }
  170. static int hostapd_acl_diff(struct hostapd_bss_config *a,
  171. struct hostapd_bss_config *b)
  172. {
  173. int i;
  174. if (a->macaddr_acl != b->macaddr_acl ||
  175. a->num_accept_mac != b->num_accept_mac ||
  176. a->num_deny_mac != b->num_deny_mac)
  177. return 1;
  178. for (i = 0; i < a->num_accept_mac; i++) {
  179. if (os_memcmp(a->accept_mac[i].addr, b->accept_mac[i].addr,
  180. ETH_ALEN) != 0)
  181. return 1;
  182. }
  183. for (i = 0; i < a->num_deny_mac; i++) {
  184. if (os_memcmp(a->deny_mac[i].addr, b->deny_mac[i].addr,
  185. ETH_ALEN) != 0)
  186. return 1;
  187. }
  188. return 0;
  189. }
  190. /**
  191. * reload_iface2 - Part 2 of reload_iface
  192. * @hapd_iface: Pointer to hostapd interface data.
  193. */
  194. static void reload_iface2(struct hostapd_iface *hapd_iface)
  195. {
  196. struct hostapd_data *hapd = hapd_iface->bss[0];
  197. struct hostapd_config *newconf = hapd_iface->change->newconf;
  198. struct hostapd_config *oldconf = hapd_iface->change->oldconf;
  199. int beacon_changed = hapd_iface->change->beacon_changed;
  200. hostapd_iface_cb cb = hapd_iface->reload_iface_cb;
  201. if (newconf->preamble != oldconf->preamble) {
  202. if (hostapd_set_preamble(hapd, hapd->iconf->preamble))
  203. printf("Could not set preamble for kernel driver\n");
  204. beacon_changed++;
  205. }
  206. if (newconf->beacon_int != oldconf->beacon_int) {
  207. /* Need to change beacon interval if it has changed or if
  208. * auto channel selection was used. */
  209. if (hostapd_set_beacon_int(hapd, newconf->beacon_int))
  210. printf("Could not set beacon interval for kernel "
  211. "driver\n");
  212. if (newconf->beacon_int != oldconf->beacon_int)
  213. beacon_changed++;
  214. }
  215. if (newconf->cts_protection_type != oldconf->cts_protection_type)
  216. beacon_changed++;
  217. if (newconf->rts_threshold > -1 &&
  218. newconf->rts_threshold != oldconf->rts_threshold &&
  219. hostapd_set_rts(hapd, newconf->rts_threshold))
  220. printf("Could not set RTS threshold for kernel driver\n");
  221. if (newconf->fragm_threshold > -1 &&
  222. newconf->fragm_threshold != oldconf->fragm_threshold &&
  223. hostapd_set_frag(hapd, newconf->fragm_threshold))
  224. printf("Could not set fragmentation threshold for kernel "
  225. "driver\n");
  226. hostapd_reconfig_tx_queue_params(hapd, newconf, oldconf);
  227. if (hostapd_reconfig_wme(hapd, newconf, oldconf) > 0)
  228. beacon_changed++;
  229. ap_list_reconfig(hapd_iface, oldconf);
  230. hapd_iface->change->beacon_changed = beacon_changed;
  231. hapd_iface->reload_iface_cb = NULL;
  232. cb(hapd_iface, 0);
  233. }
  234. /**
  235. * reload_iface2_handler - Handler that calls reload_face2
  236. * @eloop_data: Stores the struct hostapd_iface for the interface.
  237. * @user_ctx: Unused.
  238. */
  239. static void reload_iface2_handler(void *eloop_data, void *user_ctx)
  240. {
  241. struct hostapd_iface *hapd_iface = eloop_data;
  242. reload_iface2(hapd_iface);
  243. }
  244. /**
  245. * reload_hw_mode_done - Callback for after the HW mode is setup
  246. * @hapd_iface: Pointer to interface data.
  247. * @status: Status of the HW mode setup.
  248. */
  249. static void reload_hw_mode_done(struct hostapd_iface *hapd_iface, int status)
  250. {
  251. struct hostapd_data *hapd = hapd_iface->bss[0];
  252. struct hostapd_config_change *change = hapd_iface->change;
  253. struct hostapd_config *newconf = change->newconf;
  254. hostapd_iface_cb cb;
  255. int freq;
  256. if (status) {
  257. printf("Failed to select hw_mode.\n");
  258. cb = hapd_iface->reload_iface_cb;
  259. hapd_iface->reload_iface_cb = NULL;
  260. cb(hapd_iface, -1);
  261. return;
  262. }
  263. freq = hostapd_hw_get_freq(hapd, newconf->channel);
  264. wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d Frequency: %d MHz",
  265. hostapd_hw_mode_txt(newconf->hw_mode),
  266. newconf->channel, freq);
  267. if (hostapd_set_freq(hapd, newconf->hw_mode, freq)) {
  268. printf("Could not set channel %d (%d MHz) for kernel "
  269. "driver\n", newconf->channel, freq);
  270. }
  271. change->beacon_changed++;
  272. reload_iface2(hapd_iface);
  273. }
  274. /**
  275. * hostapd_config_reload_iface_start - Start interface reload
  276. * @hapd_iface: Pointer to interface data.
  277. * @cb: The function to callback when done.
  278. * Returns: 0 if it starts successfully; cb will be called when done.
  279. * -1 on failure; cb will not be called.
  280. */
  281. static int hostapd_config_reload_iface_start(struct hostapd_iface *hapd_iface,
  282. hostapd_iface_cb cb)
  283. {
  284. struct hostapd_config_change *change = hapd_iface->change;
  285. struct hostapd_config *newconf = change->newconf;
  286. struct hostapd_config *oldconf = change->oldconf;
  287. struct hostapd_data *hapd = hapd_iface->bss[0];
  288. if (hapd_iface->reload_iface_cb) {
  289. wpa_printf(MSG_DEBUG,
  290. "%s: Interface reload already in progress.",
  291. hapd_iface->bss[0]->conf->iface);
  292. return -1;
  293. }
  294. hapd_iface->reload_iface_cb = cb;
  295. if (newconf->bridge_packets != oldconf->bridge_packets &&
  296. hapd->iconf->bridge_packets != INTERNAL_BRIDGE_DO_NOT_CONTROL &&
  297. hostapd_set_internal_bridge(hapd, hapd->iconf->bridge_packets))
  298. printf("Failed to set bridge_packets for kernel driver\n");
  299. if (newconf->channel != oldconf->channel ||
  300. newconf->hw_mode != oldconf->hw_mode ||
  301. rate_array_diff(newconf->supported_rates,
  302. oldconf->supported_rates) ||
  303. rate_array_diff(newconf->basic_rates, oldconf->basic_rates)) {
  304. hostapd_free_stas(hapd);
  305. if (hostapd_get_hw_features(hapd_iface)) {
  306. printf("Could not read HW feature info from the kernel"
  307. " driver.\n");
  308. hapd_iface->reload_iface_cb = NULL;
  309. return -1;
  310. }
  311. if (hostapd_select_hw_mode_start(hapd_iface,
  312. reload_hw_mode_done)) {
  313. printf("Failed to start select hw_mode.\n");
  314. hapd_iface->reload_iface_cb = NULL;
  315. return -1;
  316. }
  317. return 0;
  318. }
  319. eloop_register_timeout(0, 0, reload_iface2_handler, hapd_iface, NULL);
  320. return 0;
  321. }
  322. static void hostapd_reconfig_bss(struct hostapd_data *hapd,
  323. struct hostapd_bss_config *newbss,
  324. struct hostapd_bss_config *oldbss,
  325. struct hostapd_config *oldconf,
  326. int beacon_changed)
  327. {
  328. struct hostapd_config_change change;
  329. int encr_changed = 0;
  330. struct radius_client_data *old_radius;
  331. radius_client_flush(hapd->radius, 0);
  332. if (hostapd_set_dtim_period(hapd, newbss->dtim_period))
  333. printf("Could not set DTIM period for kernel driver\n");
  334. if (newbss->ssid.ssid_len != oldbss->ssid.ssid_len ||
  335. os_memcmp(newbss->ssid.ssid, oldbss->ssid.ssid,
  336. newbss->ssid.ssid_len) != 0) {
  337. if (hostapd_set_ssid(hapd, (u8 *) newbss->ssid.ssid,
  338. newbss->ssid.ssid_len))
  339. printf("Could not set SSID for kernel driver\n");
  340. beacon_changed++;
  341. }
  342. if (newbss->ignore_broadcast_ssid != oldbss->ignore_broadcast_ssid)
  343. beacon_changed++;
  344. if (hostapd_wep_key_cmp(&newbss->ssid.wep, &oldbss->ssid.wep)) {
  345. encr_changed++;
  346. beacon_changed++;
  347. }
  348. vlan_reconfig(hapd, oldconf, oldbss);
  349. if (beacon_changed) {
  350. wpa_printf(MSG_DEBUG, "Updating beacon frame information");
  351. ieee802_11_set_beacon(hapd);
  352. }
  353. change.hapd = hapd;
  354. change.oldconf = oldconf;
  355. change.newconf = hapd->iconf;
  356. change.oldbss = oldbss;
  357. change.newbss = newbss;
  358. change.mac_acl_changed = hostapd_acl_diff(newbss, oldbss);
  359. if (newbss->max_num_sta != oldbss->max_num_sta &&
  360. newbss->max_num_sta < hapd->num_sta) {
  361. change.num_sta_remove = hapd->num_sta - newbss->max_num_sta;
  362. } else
  363. change.num_sta_remove = 0;
  364. ap_for_each_sta(hapd, hostapd_config_reload_sta, &change);
  365. old_radius = hapd->radius;
  366. hapd->radius = radius_client_reconfig(hapd->radius, hapd,
  367. oldbss->radius, newbss->radius);
  368. hapd->radius_client_reconfigured = old_radius != hapd->radius ||
  369. hostapd_ip_diff(&newbss->own_ip_addr, &oldbss->own_ip_addr);
  370. ieee802_1x_reconfig(hapd, oldconf, oldbss);
  371. iapp_reconfig(hapd, oldconf, oldbss);
  372. hostapd_acl_reconfig(hapd, oldconf);
  373. accounting_reconfig(hapd, oldconf);
  374. }
  375. /**
  376. * config_reload2 - Part 2 of configuration reloading
  377. * @hapd_iface:
  378. */
  379. static void config_reload2(struct hostapd_iface *hapd_iface, int status)
  380. {
  381. struct hostapd_config_change *change = hapd_iface->change;
  382. struct hostapd_data *hapd = change->hapd;
  383. struct hostapd_config *newconf = change->newconf;
  384. struct hostapd_config *oldconf = change->oldconf;
  385. int beacon_changed = change->beacon_changed;
  386. struct hostapd_data **new_hapd = change->new_hapd;
  387. struct hostapd_data **old_hapd = change->old_hapd;
  388. int num_old_hapd = change->num_old_hapd;
  389. size_t i, j, max_bss, same_bssid;
  390. struct hostapd_bss_config *newbss, *oldbss;
  391. u8 *prev_addr;
  392. hostapd_iface_cb cb;
  393. os_free(change);
  394. hapd_iface->change = NULL;
  395. if (status) {
  396. printf("Failed to setup new interface config\n");
  397. cb = hapd_iface->config_reload_cb;
  398. hapd_iface->config_reload_cb = NULL;
  399. /* Invalid configuration - cleanup and terminate hostapd */
  400. hapd_iface->bss = old_hapd;
  401. hapd_iface->num_bss = num_old_hapd;
  402. hapd_iface->conf = hapd->iconf = oldconf;
  403. hapd->conf = &oldconf->bss[0];
  404. hostapd_config_free(newconf);
  405. os_free(new_hapd);
  406. cb(hapd_iface, -2);
  407. return;
  408. }
  409. /*
  410. * If any BSSes have been removed, added, or had their BSSIDs changed,
  411. * completely remove and reinitialize such BSSes and all the BSSes
  412. * following them since their BSSID might have changed.
  413. */
  414. max_bss = oldconf->num_bss;
  415. if (max_bss > newconf->num_bss)
  416. max_bss = newconf->num_bss;
  417. for (i = 0; i < max_bss; i++) {
  418. if (os_strcmp(oldconf->bss[i].iface, newconf->bss[i].iface) !=
  419. 0 || hostapd_mac_comp(oldconf->bss[i].bssid,
  420. newconf->bss[i].bssid) != 0)
  421. break;
  422. }
  423. same_bssid = i;
  424. for (i = 0; i < oldconf->num_bss; i++) {
  425. oldbss = &oldconf->bss[i];
  426. newbss = NULL;
  427. for (j = 0; j < newconf->num_bss; j++) {
  428. if (os_strcmp(oldbss->iface, newconf->bss[j].iface) ==
  429. 0) {
  430. newbss = &newconf->bss[j];
  431. break;
  432. }
  433. }
  434. if (newbss && i < same_bssid) {
  435. hapd = hapd_iface->bss[j] = old_hapd[i];
  436. hapd->iconf = newconf;
  437. hapd->conf = newbss;
  438. hostapd_reconfig_bss(hapd, newbss, oldbss, oldconf,
  439. beacon_changed);
  440. } else {
  441. hapd = old_hapd[i];
  442. wpa_printf(MSG_DEBUG, "Removing BSS (ifname %s)",
  443. hapd->conf->iface);
  444. hostapd_free_stas(hapd);
  445. /* Send broadcast deauthentication for this BSS, but do
  446. * not clear all STAs from the driver since other BSSes
  447. * may have STA entries. The driver will remove all STA
  448. * entries for this BSS anyway when the interface is
  449. * being removed. */
  450. #if 0
  451. hostapd_deauth_all_stas(hapd);
  452. hostapd_cleanup(hapd);
  453. #endif
  454. os_free(hapd);
  455. }
  456. }
  457. prev_addr = hapd_iface->bss[0]->own_addr;
  458. hapd = hapd_iface->bss[0];
  459. for (j = 0; j < newconf->num_bss; j++) {
  460. if (hapd_iface->bss[j] != NULL) {
  461. prev_addr = hapd_iface->bss[j]->own_addr;
  462. continue;
  463. }
  464. newbss = &newconf->bss[j];
  465. wpa_printf(MSG_DEBUG, "Reconfiguration: adding new BSS "
  466. "(ifname=%s)", newbss->iface);
  467. #if 0
  468. hapd = hapd_iface->bss[j] =
  469. hostapd_alloc_bss_data(hapd_iface, newconf, newbss);
  470. if (hapd == NULL) {
  471. printf("Failed to initialize new BSS\n");
  472. /* FIX: This one is somewhat hard to recover
  473. * from.. Would need to remove this BSS from
  474. * conf and BSS list. */
  475. exit(1);
  476. }
  477. #endif
  478. hapd->driver = hapd_iface->bss[0]->driver;
  479. hapd->iface = hapd_iface;
  480. hapd->iconf = newconf;
  481. hapd->conf = newbss;
  482. os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
  483. if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
  484. prev_addr = hapd->own_addr;
  485. #if 0
  486. if (hostapd_setup_bss(hapd, j == 0)) {
  487. printf("Failed to setup new BSS\n");
  488. /* FIX */
  489. exit(1);
  490. }
  491. #endif
  492. }
  493. os_free(old_hapd);
  494. hostapd_config_free(oldconf);
  495. cb = hapd_iface->config_reload_cb;
  496. hapd_iface->config_reload_cb = NULL;
  497. cb(hapd_iface, 0);
  498. }
  499. /**
  500. * hostapd_config_reload_start - Start reconfiguration of an interface
  501. * @hapd_iface: Pointer to hostapd interface data
  502. * @cb: Function to be called back when done.
  503. * The status indicates:
  504. * 0 = success, new configuration in use;
  505. * -1 = failed to update configuraiton, old configuration in use;
  506. * -2 = failed to update configuration and failed to recover; caller
  507. * should cleanup and terminate hostapd
  508. * Returns:
  509. * 0 = reconfiguration started;
  510. * -1 = failed to update configuration, old configuration in use;
  511. * -2 = failed to update configuration and failed to recover; caller
  512. * should cleanup and terminate hostapd
  513. */
  514. int hostapd_config_reload_start(struct hostapd_iface *hapd_iface,
  515. hostapd_iface_cb cb)
  516. {
  517. struct hostapd_config *newconf, *oldconf;
  518. struct hostapd_config_change *change;
  519. struct hostapd_data *hapd = NULL;
  520. struct hostapd_data **old_hapd, **new_hapd;
  521. int num_old_hapd;
  522. if (hapd_iface->config_reload_cb) {
  523. wpa_printf(MSG_DEBUG, "%s: Config reload already in progress.",
  524. hapd_iface->bss[0]->conf->iface);
  525. return -1;
  526. }
  527. newconf = hostapd_config_read(hapd_iface->config_fname);
  528. if (newconf == NULL) {
  529. printf("Failed to read new configuration file - continuing "
  530. "with old.\n");
  531. return -1;
  532. }
  533. if (os_strcmp(newconf->bss[0].iface, hapd_iface->conf->bss[0].iface) !=
  534. 0) {
  535. printf("Interface name changing is not allowed in "
  536. "configuration reloading (%s -> %s).\n",
  537. hapd_iface->conf->bss[0].iface, newconf->bss[0].iface);
  538. hostapd_config_free(newconf);
  539. return -1;
  540. }
  541. new_hapd = os_zalloc(newconf->num_bss *
  542. sizeof(struct hostapd_data *));
  543. if (new_hapd == NULL) {
  544. hostapd_config_free(newconf);
  545. return -1;
  546. }
  547. old_hapd = hapd_iface->bss;
  548. num_old_hapd = hapd_iface->num_bss;
  549. hapd_iface->bss = new_hapd;
  550. hapd_iface->num_bss = newconf->num_bss;
  551. /*
  552. * First BSS remains the same since interface name changing was
  553. * prohibited above. Now, this is only used in
  554. * hostapd_config_reload_iface() and following loop will anyway set
  555. * this again.
  556. */
  557. hapd = hapd_iface->bss[0] = old_hapd[0];
  558. oldconf = hapd_iface->conf;
  559. hapd->iconf = hapd_iface->conf = newconf;
  560. hapd->conf = &newconf->bss[0];
  561. change = os_zalloc(sizeof(struct hostapd_config_change));
  562. if (change == NULL) {
  563. hostapd_config_free(newconf);
  564. return -1;
  565. }
  566. change->hapd = hapd;
  567. change->newconf = newconf;
  568. change->oldconf = oldconf;
  569. change->beacon_changed = 0;
  570. change->hapd_iface = hapd_iface;
  571. change->new_hapd = new_hapd;
  572. change->old_hapd = old_hapd;
  573. change->num_old_hapd = num_old_hapd;
  574. hapd_iface->config_reload_cb = cb;
  575. hapd_iface->change = change;
  576. if (hostapd_config_reload_iface_start(hapd_iface, config_reload2)) {
  577. printf("Failed to start setup of new interface config\n");
  578. hapd_iface->config_reload_cb = NULL;
  579. os_free(change);
  580. hapd_iface->change = NULL;
  581. /* Invalid configuration - cleanup and terminate hostapd */
  582. hapd_iface->bss = old_hapd;
  583. hapd_iface->num_bss = num_old_hapd;
  584. hapd_iface->conf = hapd->iconf = oldconf;
  585. hapd->conf = &oldconf->bss[0];
  586. hostapd_config_free(newconf);
  587. os_free(new_hapd);
  588. return -2;
  589. }
  590. return 0;
  591. }