From 3c4ca36330c0cd08e201b12044ca5f8fc64a36ab Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Thu, 23 May 2013 14:38:20 +0300 Subject: [PATCH] hostapd: Support MAC address based access control list Enable MAC address based ACL for the drivers which advertise this capabilty with NL80211_ATTR_MAC_ACL_MAX. Either of blacklist or whitelist is supported, though, not simultaneously. Signed-hostap: Vivek Natarajan --- src/ap/ap_drv_ops.h | 8 +++++ src/ap/hostapd.c | 68 ++++++++++++++++++++++++++++++++++++ src/drivers/driver.h | 22 ++++++++++++ src/drivers/driver_nl80211.c | 59 +++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+) diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index ceb7e68e8..70fab5537 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -173,6 +173,14 @@ static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd, return hapd->driver->sta_clear_stats(hapd->drv_priv, addr); } +static inline int hostapd_drv_set_acl(struct hostapd_data *hapd, + struct hostapd_acl_params *params) +{ + if (hapd->driver == NULL || hapd->driver->set_acl == NULL) + return 0; + return hapd->driver->set_acl(hapd->drv_priv, params); +} + static inline int hostapd_drv_set_ap(struct hostapd_data *hapd, struct wpa_driver_ap_params *params) { diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index a0ac38c4c..f1ec48a42 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -837,6 +837,72 @@ static void hostapd_tx_queue_params(struct hostapd_iface *iface) } +static int hostapd_set_acl_list(struct hostapd_data *hapd, + struct mac_acl_entry *mac_acl, + int n_entries, u8 accept_acl) +{ + struct hostapd_acl_params *acl_params; + int i, err; + + acl_params = os_zalloc(sizeof(*acl_params) + + (n_entries * sizeof(acl_params->mac_acl[0]))); + if (!acl_params) + return -ENOMEM; + + for (i = 0; i < n_entries; i++) + os_memcpy(acl_params->mac_acl[i].addr, mac_acl[i].addr, + ETH_ALEN); + + acl_params->acl_policy = accept_acl; + acl_params->num_mac_acl = n_entries; + + err = hostapd_drv_set_acl(hapd, acl_params); + + os_free(acl_params); + + return err; +} + + +static void hostapd_set_acl(struct hostapd_data *hapd) +{ + struct hostapd_config *conf = hapd->iconf; + int err; + u8 accept_acl; + + if (!(conf->bss->num_accept_mac || conf->bss->num_deny_mac)) + return; + + if (conf->bss->macaddr_acl == DENY_UNLESS_ACCEPTED) { + if (conf->bss->num_accept_mac) { + accept_acl = 1; + err = hostapd_set_acl_list(hapd, conf->bss->accept_mac, + conf->bss->num_accept_mac, + accept_acl); + if (err) { + wpa_printf(MSG_DEBUG, "Failed to set accept acl"); + return; + } + } else { + wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file"); + } + } else if (conf->bss->macaddr_acl == ACCEPT_UNLESS_DENIED) { + if (conf->bss->num_deny_mac) { + accept_acl = 0; + err = hostapd_set_acl_list(hapd, conf->bss->deny_mac, + conf->bss->num_deny_mac, + accept_acl); + if (err) { + wpa_printf(MSG_DEBUG, "Failed to set deny acl"); + return; + } + } else { + wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file"); + } + } +} + + static int setup_interface(struct hostapd_iface *iface) { struct hostapd_data *hapd = iface->bss[0]; @@ -962,6 +1028,8 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) ap_list_init(iface); + hostapd_set_acl(hapd); + if (hostapd_driver_commit(hapd) < 0) { wpa_printf(MSG_ERROR, "%s: Failed to commit driver " "configuration", __func__); diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 59102a466..03fc2b3fd 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -906,6 +906,8 @@ struct wpa_driver_capa { #define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING 0x00000008 unsigned int probe_resp_offloads; + unsigned int max_acl_mac_addrs; + /** * extended_capa - extended capabilities in driver/device * @@ -966,6 +968,16 @@ struct hostapd_freq_params { int bandwidth; }; +struct mac_address { + u8 addr[ETH_ALEN]; +}; + +struct hostapd_acl_params { + u8 acl_policy; + unsigned int num_mac_acl; + struct mac_address mac_acl[0]; +}; + enum wpa_driver_if_type { /** * WPA_IF_STATION - Station mode interface @@ -1595,6 +1607,16 @@ struct wpa_driver_ops { */ int (*set_ap)(void *priv, struct wpa_driver_ap_params *params); + /** + * set_acl - Set ACL in AP mode + * @priv: Private driver interface data + * @params: Parameters to configure ACL + * Returns: 0 on success, -1 on failure + * + * This is used only for the drivers which support MAC address ACL. + */ + int (*set_acl)(void *priv, struct hostapd_acl_params *params); + /** * hapd_init - Initialize driver interface (hostapd only) * @hapd: Pointer to hostapd context diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 736fa524e..5d2666772 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -2862,6 +2862,10 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) capa->max_match_sets = nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]); + if (tb[NL80211_ATTR_MAC_ACL_MAX]) + capa->max_acl_mac_addrs = + nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]); + wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]); wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]); wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]); @@ -5813,6 +5817,60 @@ static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble, } +static int wpa_driver_nl80211_set_acl(void *priv, + struct hostapd_acl_params *params) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + struct nlattr *acl; + unsigned int i; + int ret = 0; + + if (!(drv->capa.max_acl_mac_addrs)) + return -ENOTSUP; + + if (params->num_mac_acl > drv->capa.max_acl_mac_addrs) + return -ENOTSUP; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)", + params->acl_policy ? "Accept" : "Deny", params->num_mac_acl); + + nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_MAC_ACL); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + NLA_PUT_U32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ? + NL80211_ACL_POLICY_DENY_UNLESS_LISTED : + NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED); + + acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS); + if (acl == NULL) + goto nla_put_failure; + + for (i = 0; i < params->num_mac_acl; i++) + NLA_PUT(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr); + + nla_nest_end(msg, acl); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)", + ret, strerror(-ret)); + } + +nla_put_failure: + nlmsg_free(msg); + + return ret; +} + + static int wpa_driver_nl80211_set_ap(void *priv, struct wpa_driver_ap_params *params) { @@ -9882,6 +9940,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .set_supp_port = wpa_driver_nl80211_set_supp_port, .set_country = wpa_driver_nl80211_set_country, .set_ap = wpa_driver_nl80211_set_ap, + .set_acl = wpa_driver_nl80211_set_acl, .if_add = wpa_driver_nl80211_if_add, .if_remove = driver_nl80211_if_remove, .send_mlme = driver_nl80211_send_mlme,