From 3988046de5383abddc6207b160eb199acecc04b5 Mon Sep 17 00:00:00 2001 From: Tamizh chelvam Date: Thu, 11 Jan 2018 15:29:03 +0530 Subject: [PATCH] hostapd: Dynamic MAC ACL management over control interface Previously, MAC ACL could be modified only through file operations (modify accept/deny_mac_file and reload it to hostapd). Extend this to allow MAC ACL to be modified and displayed through new control interface commands: ACCEPT_ACL [argument] DENY_ACL [argument] subcmd: ADD_MAC [ VLAN_ID=]|DEL_MAC |SHOW|CLEAR Signed-off-by: Tamizh chelvam --- hostapd/config_file.c | 68 ++++++++++------ hostapd/config_file.h | 5 ++ hostapd/ctrl_iface.c | 180 +++++++++++++++++++++++++++++++++++------- hostapd/hostapd_cli.c | 18 +++++ 4 files changed, 218 insertions(+), 53 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 4cd34481c..cdd2b63f1 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -113,7 +113,7 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss, #endif /* CONFIG_NO_VLAN */ -static int hostapd_acl_comp(const void *a, const void *b) +int hostapd_acl_comp(const void *a, const void *b) { const struct mac_acl_entry *aa = a; const struct mac_acl_entry *bb = b; @@ -121,6 +121,44 @@ static int hostapd_acl_comp(const void *a, const void *b) } +int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num, + int vlan_id, const u8 *addr) +{ + struct mac_acl_entry *newacl; + + newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl)); + if (!newacl) { + wpa_printf(MSG_ERROR, "MAC list reallocation failed"); + return -1; + } + + *acl = newacl; + os_memcpy((*acl)[*num].addr, addr, ETH_ALEN); + os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id)); + (*acl)[*num].vlan_id.untagged = vlan_id; + (*acl)[*num].vlan_id.notempty = !!vlan_id; + (*num)++; + + return 0; +} + + +void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num, + const u8 *addr) +{ + int i = 0; + + while (i < *num) { + if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) == 0) { + os_remove_in_array(*acl, *num, sizeof(**acl), i); + (*num)--; + } else { + i++; + } + } +} + + static int hostapd_config_read_maclist(const char *fname, struct mac_acl_entry **acl, int *num) { @@ -128,7 +166,6 @@ static int hostapd_config_read_maclist(const char *fname, char buf[128], *pos; int line = 0; u8 addr[ETH_ALEN]; - struct mac_acl_entry *newacl; int vlan_id; f = fopen(fname, "r"); @@ -138,7 +175,7 @@ static int hostapd_config_read_maclist(const char *fname, } while (fgets(buf, sizeof(buf), f)) { - int i, rem = 0; + int rem = 0; line++; @@ -168,16 +205,7 @@ static int hostapd_config_read_maclist(const char *fname, } if (rem) { - i = 0; - while (i < *num) { - if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) == - 0) { - os_remove_in_array(*acl, *num, - sizeof(**acl), i); - (*num)--; - } else - i++; - } + hostapd_remove_acl_mac(acl, num, addr); continue; } vlan_id = 0; @@ -189,20 +217,8 @@ static int hostapd_config_read_maclist(const char *fname, if (*pos != '\0') vlan_id = atoi(pos); - newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl)); - if (newacl == NULL) { - wpa_printf(MSG_ERROR, "MAC list reallocation failed"); - fclose(f); + if (hostapd_add_acl_maclist(acl, num, vlan_id, addr) < 0) return -1; - } - - *acl = newacl; - os_memcpy((*acl)[*num].addr, addr, ETH_ALEN); - os_memset(&(*acl)[*num].vlan_id, 0, - sizeof((*acl)[*num].vlan_id)); - (*acl)[*num].vlan_id.untagged = vlan_id; - (*acl)[*num].vlan_id.notempty = !!vlan_id; - (*num)++; } fclose(f); diff --git a/hostapd/config_file.h b/hostapd/config_file.h index c98bdb683..9830f5a22 100644 --- a/hostapd/config_file.h +++ b/hostapd/config_file.h @@ -13,5 +13,10 @@ struct hostapd_config * hostapd_config_read(const char *fname); int hostapd_set_iface(struct hostapd_config *conf, struct hostapd_bss_config *bss, const char *field, char *value); +int hostapd_acl_comp(const void *a, const void *b); +int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num, + int vlan_id, const u8 *addr); +void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num, + const u8 *addr); #endif /* CONFIG_FILE_H */ diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index f24da81e8..0071e69df 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -1248,6 +1248,42 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, } +static void hostapd_disassoc_accept_mac(struct hostapd_data *hapd) +{ + struct sta_info *sta; + struct vlan_description vlan_id; + + if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED) + return; + + for (sta = hapd->sta_list; sta; sta = sta->next) { + if (!hostapd_maclist_found(hapd->conf->accept_mac, + hapd->conf->num_accept_mac, + sta->addr, &vlan_id) || + (vlan_id.notempty && + vlan_compare(&vlan_id, sta->vlan_desc))) + ap_sta_disconnect(hapd, sta, sta->addr, + WLAN_REASON_UNSPECIFIED); + } +} + + +static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd) +{ + struct sta_info *sta; + struct vlan_description vlan_id; + + for (sta = hapd->sta_list; sta; sta = sta->next) { + if (hostapd_maclist_found(hapd->conf->deny_mac, + hapd->conf->num_deny_mac, sta->addr, + &vlan_id) && + (!vlan_id.notempty || + !vlan_compare(&vlan_id, sta->vlan_desc))) + ap_sta_disconnect(hapd, sta, sta->addr, + WLAN_REASON_UNSPECIFIED); + } +} + static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) { char *value; @@ -1332,38 +1368,14 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) hapd->dpp_configurator_params = os_strdup(value); #endif /* CONFIG_DPP */ } else { - struct sta_info *sta; - struct vlan_description vlan_id; - ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value); if (ret) return ret; if (os_strcasecmp(cmd, "deny_mac_file") == 0) { - for (sta = hapd->sta_list; sta; sta = sta->next) { - if (hostapd_maclist_found( - hapd->conf->deny_mac, - hapd->conf->num_deny_mac, sta->addr, - &vlan_id) && - (!vlan_id.notempty || - !vlan_compare(&vlan_id, sta->vlan_desc))) - ap_sta_disconnect( - hapd, sta, sta->addr, - WLAN_REASON_UNSPECIFIED); - } - } else if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED && - os_strcasecmp(cmd, "accept_mac_file") == 0) { - for (sta = hapd->sta_list; sta; sta = sta->next) { - if (!hostapd_maclist_found( - hapd->conf->accept_mac, - hapd->conf->num_accept_mac, - sta->addr, &vlan_id) || - (vlan_id.notempty && - vlan_compare(&vlan_id, sta->vlan_desc))) - ap_sta_disconnect( - hapd, sta, sta->addr, - WLAN_REASON_UNSPECIFIED); - } + hostapd_disassoc_deny_mac(hapd); + } else if (os_strcasecmp(cmd, "accept_mac_file") == 0) { + hostapd_disassoc_accept_mac(hapd); } } @@ -2683,6 +2695,80 @@ static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf, } +static int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num, + const char *txtaddr) +{ + u8 addr[ETH_ALEN]; + struct vlan_description vlan_id; + + if (!(*num)) + return 0; + + if (hwaddr_aton(txtaddr, addr)) + return -1; + + if (hostapd_maclist_found(*acl, *num, addr, &vlan_id)) + hostapd_remove_acl_mac(acl, num, addr); + + return 0; +} + + +static void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl, + int *num) +{ + while (*num) + hostapd_remove_acl_mac(acl, num, (*acl)[0].addr); +} + + +static int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num, + char *buf, size_t buflen) +{ + int i = 0, len = 0, ret = 0; + + if (!acl) + return 0; + + while (i < num) { + ret = os_snprintf(buf + len, buflen - len, + MACSTR " VLAN_ID=%d\n", + MAC2STR(acl[i].addr), + acl[i].vlan_id.untagged); + if (ret < 0 || (size_t) ret >= buflen - len) + return len; + i++; + len += ret; + } + return len; +} + + +static int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num, + const char *cmd) +{ + u8 addr[ETH_ALEN]; + struct vlan_description vlan_id; + int ret = 0, vlanid = 0; + const char *pos; + + if (hwaddr_aton(cmd, addr)) + return -1; + + pos = os_strstr(cmd, "VLAN_ID="); + if (pos) + vlanid = atoi(pos + 8); + + if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) { + ret = hostapd_add_acl_maclist(acl, num, vlanid, addr); + if (ret != -1 && *acl) + qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp); + } + + return ret < 0 ? -1 : 0; +} + + static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, char *buf, char *reply, int reply_size, @@ -2983,6 +3069,46 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, reply_size); } else if (os_strcmp(buf, "TERMINATE") == 0) { eloop_terminate(); + } else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) { + if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) { + if (!hostapd_ctrl_iface_acl_add_mac( + &hapd->conf->accept_mac, + &hapd->conf->num_accept_mac, buf + 19)) + hostapd_disassoc_accept_mac(hapd); + else + reply_len = -1; + } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) { + hostapd_ctrl_iface_acl_del_mac( + &hapd->conf->accept_mac, + &hapd->conf->num_accept_mac, buf + 19); + } else if (os_strcmp(buf + 11, "SHOW") == 0) { + reply_len = hostapd_ctrl_iface_acl_show_mac( + hapd->conf->accept_mac, + hapd->conf->num_accept_mac, reply, reply_size); + } else if (os_strcmp(buf + 11, "CLEAR") == 0) { + hostapd_ctrl_iface_acl_clear_list( + &hapd->conf->accept_mac, + &hapd->conf->num_accept_mac); + } + } else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) { + if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) { + if (!hostapd_ctrl_iface_acl_add_mac( + &hapd->conf->deny_mac, + &hapd->conf->num_deny_mac, buf + 17)) + hostapd_disassoc_deny_mac(hapd); + } else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) { + hostapd_ctrl_iface_acl_del_mac( + &hapd->conf->deny_mac, + &hapd->conf->num_deny_mac, buf + 17); + } else if (os_strcmp(buf + 9, "SHOW") == 0) { + reply_len = hostapd_ctrl_iface_acl_show_mac( + hapd->conf->deny_mac, + hapd->conf->num_deny_mac, reply, reply_size); + } else if (os_strcmp(buf + 9, "CLEAR") == 0) { + hostapd_ctrl_iface_acl_clear_list( + &hapd->conf->deny_mac, + &hapd->conf->num_deny_mac); + } #ifdef CONFIG_DPP } else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) { res = hostapd_dpp_qr_code(hapd, buf + 12); diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index 8b99a0a50..66835823a 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1452,6 +1452,20 @@ static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc, #endif /* CONFIG_DPP */ +static int hostapd_cli_cmd_accept_macacl(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return hostapd_cli_cmd(ctrl, "ACCEPT_ACL", 1, argc, argv); +} + + +static int hostapd_cli_cmd_deny_macacl(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return hostapd_cli_cmd(ctrl, "DENY_ACL", 1, argc, argv); +} + + struct hostapd_cli_cmd { const char *cmd; int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); @@ -1614,6 +1628,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { { "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL, "*| = remove DPP pkex information" }, #endif /* CONFIG_DPP */ + { "accept_acl", hostapd_cli_cmd_accept_macacl, NULL, + "=Add/Delete/Show/Clear accept MAC ACL" }, + { "deny_acl", hostapd_cli_cmd_deny_macacl, NULL, + "=Add/Delete/Show/Clear deny MAC ACL" }, { NULL, NULL, NULL, NULL } };