aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorVasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com>2013-01-18 00:48:45 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-01-25 12:36:44 -0500
commit77765eaf5cfb6b8dd98ec8b54b411d74ff6095f1 (patch)
tree2b32fca883ee0c5a149290b3df3d97b21cb85549 /net/wireless/nl80211.c
parent6d45a74b1f2e42e41c9931bfb35cdb789d0bb3ea (diff)
cfg80211/nl80211: add API for MAC address ACLs
Add API to enable drivers to implement MAC address based access control in AP/P2P GO mode. Capable drivers advertise this capability by setting the maximum number of MAC addresses in such a list in wiphy->max_acl_mac_addrs. An initial ACL may be given to the NL80211_CMD_START_AP command and/or changed later with NL80211_CMD_SET_MAC_ACL. Black- and whitelists are supported, but not simultaneously. Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com> [rewrite commit log, many cleanups] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 33de80364c5c..b5978ab4ad7a 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -365,6 +365,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
365 [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, 365 [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
366 [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 }, 366 [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
367 [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, 367 [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 },
368 [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
369 [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
368}; 370};
369 371
370/* policy for the key attributes */ 372/* policy for the key attributes */
@@ -1268,6 +1270,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag
1268 dev->wiphy.ht_capa_mod_mask)) 1270 dev->wiphy.ht_capa_mod_mask))
1269 goto nla_put_failure; 1271 goto nla_put_failure;
1270 1272
1273 if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
1274 dev->wiphy.max_acl_mac_addrs &&
1275 nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
1276 dev->wiphy.max_acl_mac_addrs))
1277 goto nla_put_failure;
1278
1271 return genlmsg_end(msg, hdr); 1279 return genlmsg_end(msg, hdr);
1272 1280
1273 nla_put_failure: 1281 nla_put_failure:
@@ -2491,6 +2499,97 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
2491 return err; 2499 return err;
2492} 2500}
2493 2501
2502/* This function returns an error or the number of nested attributes */
2503static int validate_acl_mac_addrs(struct nlattr *nl_attr)
2504{
2505 struct nlattr *attr;
2506 int n_entries = 0, tmp;
2507
2508 nla_for_each_nested(attr, nl_attr, tmp) {
2509 if (nla_len(attr) != ETH_ALEN)
2510 return -EINVAL;
2511
2512 n_entries++;
2513 }
2514
2515 return n_entries;
2516}
2517
2518/*
2519 * This function parses ACL information and allocates memory for ACL data.
2520 * On successful return, the calling function is responsible to free the
2521 * ACL buffer returned by this function.
2522 */
2523static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
2524 struct genl_info *info)
2525{
2526 enum nl80211_acl_policy acl_policy;
2527 struct nlattr *attr;
2528 struct cfg80211_acl_data *acl;
2529 int i = 0, n_entries, tmp;
2530
2531 if (!wiphy->max_acl_mac_addrs)
2532 return ERR_PTR(-EOPNOTSUPP);
2533
2534 if (!info->attrs[NL80211_ATTR_ACL_POLICY])
2535 return ERR_PTR(-EINVAL);
2536
2537 acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
2538 if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
2539 acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
2540 return ERR_PTR(-EINVAL);
2541
2542 if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
2543 return ERR_PTR(-EINVAL);
2544
2545 n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
2546 if (n_entries < 0)
2547 return ERR_PTR(n_entries);
2548
2549 if (n_entries > wiphy->max_acl_mac_addrs)
2550 return ERR_PTR(-ENOTSUPP);
2551
2552 acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries),
2553 GFP_KERNEL);
2554 if (!acl)
2555 return ERR_PTR(-ENOMEM);
2556
2557 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
2558 memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
2559 i++;
2560 }
2561
2562 acl->n_acl_entries = n_entries;
2563 acl->acl_policy = acl_policy;
2564
2565 return acl;
2566}
2567
2568static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
2569{
2570 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2571 struct net_device *dev = info->user_ptr[1];
2572 struct cfg80211_acl_data *acl;
2573 int err;
2574
2575 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2576 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2577 return -EOPNOTSUPP;
2578
2579 if (!dev->ieee80211_ptr->beacon_interval)
2580 return -EINVAL;
2581
2582 acl = parse_acl_data(&rdev->wiphy, info);
2583 if (IS_ERR(acl))
2584 return PTR_ERR(acl);
2585
2586 err = rdev_set_mac_acl(rdev, dev, acl);
2587
2588 kfree(acl);
2589
2590 return err;
2591}
2592
2494static int nl80211_parse_beacon(struct genl_info *info, 2593static int nl80211_parse_beacon(struct genl_info *info,
2495 struct cfg80211_beacon_data *bcn) 2594 struct cfg80211_beacon_data *bcn)
2496{ 2595{
@@ -2734,6 +2833,12 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
2734 if (err) 2833 if (err)
2735 return err; 2834 return err;
2736 2835
2836 if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
2837 params.acl = parse_acl_data(&rdev->wiphy, info);
2838 if (IS_ERR(params.acl))
2839 return PTR_ERR(params.acl);
2840 }
2841
2737 err = rdev_start_ap(rdev, dev, &params); 2842 err = rdev_start_ap(rdev, dev, &params);
2738 if (!err) { 2843 if (!err) {
2739 wdev->preset_chandef = params.chandef; 2844 wdev->preset_chandef = params.chandef;
@@ -2742,6 +2847,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
2742 wdev->ssid_len = params.ssid_len; 2847 wdev->ssid_len = params.ssid_len;
2743 memcpy(wdev->ssid, params.ssid, wdev->ssid_len); 2848 memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
2744 } 2849 }
2850
2851 kfree(params.acl);
2852
2745 return err; 2853 return err;
2746} 2854}
2747 2855
@@ -7876,6 +7984,14 @@ static struct genl_ops nl80211_ops[] = {
7876 .internal_flags = NL80211_FLAG_NEED_NETDEV | 7984 .internal_flags = NL80211_FLAG_NEED_NETDEV |
7877 NL80211_FLAG_NEED_RTNL, 7985 NL80211_FLAG_NEED_RTNL,
7878 }, 7986 },
7987 {
7988 .cmd = NL80211_CMD_SET_MAC_ACL,
7989 .doit = nl80211_set_mac_acl,
7990 .policy = nl80211_policy,
7991 .flags = GENL_ADMIN_PERM,
7992 .internal_flags = NL80211_FLAG_NEED_NETDEV |
7993 NL80211_FLAG_NEED_RTNL,
7994 },
7879}; 7995};
7880 7996
7881static struct genl_multicast_group nl80211_mlme_mcgrp = { 7997static struct genl_multicast_group nl80211_mlme_mcgrp = {