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 <nataraja@qca.qualcomm.com>
This commit is contained in:
Vivek Natarajan 2013-05-23 14:38:20 +03:00 committed by Jouni Malinen
parent 376204934d
commit 3c4ca36330
4 changed files with 157 additions and 0 deletions

View file

@ -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); 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, static inline int hostapd_drv_set_ap(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params) struct wpa_driver_ap_params *params)
{ {

View file

@ -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) static int setup_interface(struct hostapd_iface *iface)
{ {
struct hostapd_data *hapd = iface->bss[0]; 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); ap_list_init(iface);
hostapd_set_acl(hapd);
if (hostapd_driver_commit(hapd) < 0) { if (hostapd_driver_commit(hapd) < 0) {
wpa_printf(MSG_ERROR, "%s: Failed to commit driver " wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
"configuration", __func__); "configuration", __func__);

View file

@ -906,6 +906,8 @@ struct wpa_driver_capa {
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING 0x00000008 #define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING 0x00000008
unsigned int probe_resp_offloads; unsigned int probe_resp_offloads;
unsigned int max_acl_mac_addrs;
/** /**
* extended_capa - extended capabilities in driver/device * extended_capa - extended capabilities in driver/device
* *
@ -966,6 +968,16 @@ struct hostapd_freq_params {
int bandwidth; 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 { enum wpa_driver_if_type {
/** /**
* WPA_IF_STATION - Station mode interface * 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); 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_init - Initialize driver interface (hostapd only)
* @hapd: Pointer to hostapd context * @hapd: Pointer to hostapd context

View file

@ -2862,6 +2862,10 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
capa->max_match_sets = capa->max_match_sets =
nla_get_u8(tb[NL80211_ATTR_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_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]); wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]); 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, static int wpa_driver_nl80211_set_ap(void *priv,
struct wpa_driver_ap_params *params) 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_supp_port = wpa_driver_nl80211_set_supp_port,
.set_country = wpa_driver_nl80211_set_country, .set_country = wpa_driver_nl80211_set_country,
.set_ap = wpa_driver_nl80211_set_ap, .set_ap = wpa_driver_nl80211_set_ap,
.set_acl = wpa_driver_nl80211_set_acl,
.if_add = wpa_driver_nl80211_if_add, .if_add = wpa_driver_nl80211_if_add,
.if_remove = driver_nl80211_if_remove, .if_remove = driver_nl80211_if_remove,
.send_mlme = driver_nl80211_send_mlme, .send_mlme = driver_nl80211_send_mlme,