@@ -1020,6 +1020,73 @@ static int add_r1kh(struct hostapd_bss_config *bss, char *value)
return 0;
}
+
+int hostapd_config_read_rxkh_file(struct hostapd_bss_config *conf,
+ const char *fname)
+{
+ FILE *f;
+ char buf[256], *pos;
+ int line = 0, errors = 0;
+
+ if (!fname)
+ return 0;
+
+ f = fopen(fname, "r");
+ if (!f) {
+ wpa_printf(MSG_ERROR, "rxkh file '%s' not found.", fname);
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ line++;
+
+ if (buf[0] == '#')
+ continue;
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ if (buf[0] == '\0')
+ continue;
+
+ pos = os_strchr(buf, '=');
+ if (pos == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
+ line, buf);
+ errors++;
+ continue;
+ }
+ *pos = '\0';
+ pos++;
+
+ if (os_strcmp(buf, "r0kh") == 0) {
+ if (add_r0kh(conf, pos) < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid r0kh '%s'",
+ line, pos);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "r1kh") == 0) {
+ if (add_r1kh(conf, pos) < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid r1kh '%s'",
+ line, pos);
+ errors++;
+ }
+ }
+ }
+
+ fclose(f);
+
+ if (errors) {
+ wpa_printf(MSG_ERROR, "%d errors in configuring rxkhs from "
+ "'%s'", errors, fname);
+ return -1;
+ }
+ return 0;
+}
#endif /* CONFIG_IEEE80211R_AP */
@@ -3098,6 +3165,18 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "rxkh_file") == 0) {
+ os_free(bss->rxkh_file);
+ bss->rxkh_file = os_strdup(pos);
+ if (!bss->rxkh_file) {
+ wpa_printf(MSG_ERROR, "Line %d: allocation failed",
+ line);
+ return 1;
+ }
+ if (hostapd_config_read_rxkh_file(bss, pos)) {
+ wpa_printf(MSG_DEBUG, "Line %d: failed to read rxkh_file '%s'",
+ line, pos);
+ }
} else if (os_strcmp(buf, "pmk_r1_push") == 0) {
bss->pmk_r1_push = atoi(pos);
} else if (os_strcmp(buf, "ft_over_ds") == 0) {
@@ -974,6 +974,74 @@ static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd,
}
+#ifdef CONFIG_IEEE80211R_AP
+static int hostapd_ctrl_iface_get_rxkhs(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+{
+ int i;
+ int ret;
+ char *pos, *end;
+ struct ft_remote_r0kh *r0kh;
+ struct ft_remote_r1kh *r1kh;
+ struct hostapd_bss_config *conf = hapd->conf;
+
+ pos = buf;
+ end = buf + buflen;
+
+ for(r0kh = conf->r0kh_list; r0kh; r0kh=r0kh->next) {
+ ret = os_snprintf(pos, end - pos, "r0kh=" MACSTR " ",
+ MAC2STR(r0kh->addr));
+ pos += ret;
+ ret = os_snprintf(pos, r0kh->id_len + 2, "%s ",
+ r0kh->id);
+ pos += ret;
+ for (i = 0; i<32; i++) {
+ ret = os_snprintf(pos, 3, "%02x", r0kh->key[i]);
+ pos += ret;
+ }
+ ret = os_snprintf(pos, 2, "\n");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ for(r1kh = conf->r1kh_list; r1kh; r1kh=r1kh->next) {
+ ret = os_snprintf(pos, end - pos, "r1kh=" MACSTR " " MACSTR " ",
+ MAC2STR(r1kh->addr), MAC2STR(r1kh->id));
+ pos += ret;
+ for (i = 0; i<32; i++) {
+ ret = os_snprintf(pos, 3, "%02x", r1kh->key[i]);
+ pos += ret;
+ }
+ ret = os_snprintf(pos, 2, "\n");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
+static int hostapd_ctrl_iface_reload_rxkhs(struct hostapd_data *hapd)
+{
+ struct hostapd_bss_config *conf = hapd->conf;
+ int err;
+
+ hostapd_config_clear_rxkhs(conf);
+
+ err = hostapd_config_setup_rxkhs(conf);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, "Reloading RXKHs failed: %d",
+ err);
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_IEEE80211R_AP */
+
+
static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
char *buf, size_t buflen)
{
@@ -3599,6 +3667,14 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strcmp(buf, "RELOAD_WPA_PSK") == 0) {
if (hostapd_ctrl_iface_reload_wpa_psk(hapd))
reply_len = -1;
+#ifdef CONFIG_IEEE80211R_AP
+ } else if (os_strcmp(buf, "GET_RXKHS") == 0) {
+ reply_len = hostapd_ctrl_iface_get_rxkhs(hapd, reply,
+ reply_size);
+ } else if (os_strcmp(buf, "RELOAD_RXKHS") == 0) {
+ if (hostapd_ctrl_iface_reload_rxkhs(hapd))
+ reply_len = -1;
+#endif /* CONFIG_IEEE80211R_AP */
} else if (os_strcmp(buf, "RELOAD_BSS") == 0) {
if (hostapd_ctrl_iface_reload_bss(hapd))
reply_len = -1;
@@ -2295,6 +2295,12 @@ own_ip_addr=127.0.0.1
# list and thus will receive push notifications.
#r1kh=00:00:00:00:00:00 00:00:00:00:00:00 00112233445566778899aabbccddeeff
+# Optionally, the list of RxKHs can be read from a text file. Format is the same
+# as specified above. File shall contain both r0kh and r1kh. Once this variable
+# is set, RxKHs can be reloaded in runtime without bringing down an interface
+# using 'reload_rxkhs' command.
+#rxkh_file=<path>
+
# Timeout (seconds) for newly discovered R0KH/R1KH (see wildcard entries above)
# Special values: 0 -> do not expire
# Warning: do not cache implies no sequence number validation with wildcards
@@ -1407,6 +1407,22 @@ static int hostapd_cli_cmd_driver_flags2(struct wpa_ctrl *ctrl, int argc,
}
+#ifdef CONFIG_IEEE80211R_AP
+static int hostapd_cli_cmd_get_rxkhs(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "GET_RXKHS");
+}
+
+static int hostapd_cli_cmd_reload_rxkhs(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "RELOAD_RXKHS");
+}
+
+#endif /* CONFIG_IEEE80211R_AP */
+
+
#ifdef CONFIG_DPP
static int hostapd_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc,
@@ -1804,6 +1820,12 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
"<addr> [req_mode=] <measurement request hexdump> = send a Beacon report request to a station" },
{ "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL,
"= reload wpa_psk_file only" },
+#ifdef CONFIG_IEEE80211R_AP
+ { "reload_rxkhs", hostapd_cli_cmd_reload_rxkhs, NULL,
+ "= reload R0KHs and R1KHs" },
+ { "get_rxkhs", hostapd_cli_cmd_get_rxkhs, NULL,
+ "= get R0KHs and R1KHs" },
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef ANDROID
{ "driver", hostapd_cli_cmd_driver, NULL,
"<driver sub command> [<hex formatted data>] = send driver command data" },
@@ -699,6 +699,36 @@ void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
}
+#ifdef CONFIG_IEEE80211R_AP
+int hostapd_config_setup_rxkhs(struct hostapd_bss_config *conf)
+{
+ return hostapd_config_read_rxkh_file(conf, conf->rxkh_file);
+}
+
+void hostapd_config_clear_rxkhs(struct hostapd_bss_config *conf)
+{
+ struct ft_remote_r0kh *r0kh, *r0kh_prev;
+ struct ft_remote_r1kh *r1kh, *r1kh_prev;
+
+ r0kh = conf->r0kh_list;
+ conf->r0kh_list = NULL;
+ while (r0kh) {
+ r0kh_prev = r0kh;
+ r0kh = r0kh->next;
+ os_free(r0kh_prev);
+ }
+
+ r1kh = conf->r1kh_list;
+ conf->r1kh_list = NULL;
+ while (r1kh) {
+ r1kh_prev = r1kh;
+ r1kh = r1kh->next;
+ os_free(r1kh_prev);
+ }
+}
+#endif /* CONFIG_IEEE80211R_AP */
+
+
static void hostapd_config_free_anqp_elem(struct hostapd_bss_config *conf)
{
struct anqp_element *elem;
@@ -831,26 +861,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->time_zone);
#ifdef CONFIG_IEEE80211R_AP
- {
- struct ft_remote_r0kh *r0kh, *r0kh_prev;
- struct ft_remote_r1kh *r1kh, *r1kh_prev;
-
- r0kh = conf->r0kh_list;
- conf->r0kh_list = NULL;
- while (r0kh) {
- r0kh_prev = r0kh;
- r0kh = r0kh->next;
- os_free(r0kh_prev);
- }
-
- r1kh = conf->r1kh_list;
- conf->r1kh_list = NULL;
- while (r1kh) {
- r1kh_prev = r1kh;
- r1kh = r1kh->next;
- os_free(r1kh_prev);
- }
- }
+ hostapd_config_clear_rxkhs(conf);
+ os_free(conf->rxkh_file);
+ conf->rxkh_file = NULL;
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_WPS
@@ -405,6 +405,7 @@ struct hostapd_bss_config {
int ft_over_ds;
int ft_psk_generate_local;
int r1_max_key_lifetime;
+ char *rxkh_file;
#endif /* CONFIG_IEEE80211R_AP */
char *ctrl_interface; /* directory for UNIX domain sockets */
@@ -1345,6 +1346,10 @@ void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr);
void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
void hostapd_config_free_eap_users(struct hostapd_eap_user *user);
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
+int hostapd_config_read_rxkh_file(struct hostapd_bss_config *conf,
+ const char *fname);
+void hostapd_config_clear_rxkhs(struct hostapd_bss_config *conf);
+int hostapd_config_setup_rxkhs(struct hostapd_bss_config *conf);
void hostapd_config_free_bss(struct hostapd_bss_config *conf);
void hostapd_config_free(struct hostapd_config *conf);
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,