]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
hostapd: Support MAC address based access control list
authorVivek Natarajan <nataraja@qca.qualcomm.com>
Thu, 23 May 2013 11:38:20 +0000 (14:38 +0300)
committerJouni Malinen <j@w1.fi>
Fri, 24 May 2013 10:26:35 +0000 (13:26 +0300)
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>

src/ap/ap_drv_ops.h
src/ap/hostapd.c
src/drivers/driver.h
src/drivers/driver_nl80211.c

index ceb7e68e87197431983ad90912fd9b2078f25078..70fab55377a27045afc899c999bbf7e99fd7f64b 100644 (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);
 }
 
+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)
 {
index a0ac38c4c7442106f686b0a21de1d325a28b32f5..f1ec48a42a2af3ee3024df5cc73d0029fc777116 100644 (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)
 {
        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__);
index 59102a466c1c79446742364446109b0e4711b2aa..03fc2b3fd11b1b92824268bc655b3378323d28a6 100644 (file)
@@ -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
index 736fa524e605ae29a0722c26a18c797b154d9892..5d26667723a168920f353d9aac3144e361ccdd24 100644 (file)
@@ -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,