diff options
-rw-r--r-- | include/linux/ieee80211.h | 2 | ||||
-rw-r--r-- | include/linux/nl80211.h | 11 | ||||
-rw-r--r-- | include/net/cfg80211.h | 28 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 120 |
4 files changed, 161 insertions, 0 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index afa8e0ac27a7..d9724a28c0c2 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -1266,6 +1266,8 @@ enum ieee80211_sa_query_action { | |||
1266 | 1266 | ||
1267 | #define WLAN_MAX_KEY_LEN 32 | 1267 | #define WLAN_MAX_KEY_LEN 32 |
1268 | 1268 | ||
1269 | #define WLAN_PMKID_LEN 16 | ||
1270 | |||
1269 | /** | 1271 | /** |
1270 | * ieee80211_get_qos_ctl - get pointer to qos control bytes | 1272 | * ieee80211_get_qos_ctl - get pointer to qos control bytes |
1271 | * @hdr: the frame | 1273 | * @hdr: the frame |
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 45db17f81aa3..da8ea2e19273 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -349,6 +349,10 @@ enum nl80211_commands { | |||
349 | NL80211_CMD_GET_SURVEY, | 349 | NL80211_CMD_GET_SURVEY, |
350 | NL80211_CMD_NEW_SURVEY_RESULTS, | 350 | NL80211_CMD_NEW_SURVEY_RESULTS, |
351 | 351 | ||
352 | NL80211_CMD_SET_PMKSA, | ||
353 | NL80211_CMD_DEL_PMKSA, | ||
354 | NL80211_CMD_FLUSH_PMKSA, | ||
355 | |||
352 | /* add new commands above here */ | 356 | /* add new commands above here */ |
353 | 357 | ||
354 | /* used to define NL80211_CMD_MAX below */ | 358 | /* used to define NL80211_CMD_MAX below */ |
@@ -598,6 +602,10 @@ enum nl80211_commands { | |||
598 | * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute | 602 | * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute |
599 | * containing info as possible, see &enum survey_info. | 603 | * containing info as possible, see &enum survey_info. |
600 | * | 604 | * |
605 | * @NL80211_ATTR_PMKID: PMK material for PMKSA caching. | ||
606 | * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can | ||
607 | * cache, a wiphy attribute. | ||
608 | * | ||
601 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 609 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
602 | * @__NL80211_ATTR_AFTER_LAST: internal use | 610 | * @__NL80211_ATTR_AFTER_LAST: internal use |
603 | */ | 611 | */ |
@@ -732,6 +740,9 @@ enum nl80211_attrs { | |||
732 | 740 | ||
733 | NL80211_ATTR_SURVEY_INFO, | 741 | NL80211_ATTR_SURVEY_INFO, |
734 | 742 | ||
743 | NL80211_ATTR_PMKID, | ||
744 | NL80211_ATTR_MAX_NUM_PMKIDS, | ||
745 | |||
735 | /* add attributes here, update the policy in nl80211.c */ | 746 | /* add attributes here, update the policy in nl80211.c */ |
736 | 747 | ||
737 | __NL80211_ATTR_AFTER_LAST, | 748 | __NL80211_ATTR_AFTER_LAST, |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a6492e9bca97..0884b9a0f778 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -871,6 +871,19 @@ struct cfg80211_bitrate_mask { | |||
871 | u32 fixed; /* fixed bitrate, 0 == not fixed */ | 871 | u32 fixed; /* fixed bitrate, 0 == not fixed */ |
872 | u32 maxrate; /* in kbps, 0 == no limit */ | 872 | u32 maxrate; /* in kbps, 0 == no limit */ |
873 | }; | 873 | }; |
874 | /** | ||
875 | * struct cfg80211_pmksa - PMK Security Association | ||
876 | * | ||
877 | * This structure is passed to the set/del_pmksa() method for PMKSA | ||
878 | * caching. | ||
879 | * | ||
880 | * @bssid: The AP's BSSID. | ||
881 | * @pmkid: The PMK material itself. | ||
882 | */ | ||
883 | struct cfg80211_pmksa { | ||
884 | u8 *bssid; | ||
885 | u8 *pmkid; | ||
886 | }; | ||
874 | 887 | ||
875 | /** | 888 | /** |
876 | * struct cfg80211_ops - backend description for wireless configuration | 889 | * struct cfg80211_ops - backend description for wireless configuration |
@@ -976,6 +989,13 @@ struct cfg80211_bitrate_mask { | |||
976 | * @dump_survey: get site survey information. | 989 | * @dump_survey: get site survey information. |
977 | * | 990 | * |
978 | * @testmode_cmd: run a test mode command | 991 | * @testmode_cmd: run a test mode command |
992 | * | ||
993 | * @set_pmksa: Cache a PMKID for a BSSID. This is mostly useful for fullmac | ||
994 | * devices running firmwares capable of generating the (re) association | ||
995 | * RSN IE. It allows for faster roaming between WPA2 BSSIDs. | ||
996 | * @del_pmksa: Delete a cached PMKID. | ||
997 | * @flush_pmksa: Flush all cached PMKIDs. | ||
998 | * | ||
979 | */ | 999 | */ |
980 | struct cfg80211_ops { | 1000 | struct cfg80211_ops { |
981 | int (*suspend)(struct wiphy *wiphy); | 1001 | int (*suspend)(struct wiphy *wiphy); |
@@ -1097,6 +1117,12 @@ struct cfg80211_ops { | |||
1097 | int (*dump_survey)(struct wiphy *wiphy, struct net_device *netdev, | 1117 | int (*dump_survey)(struct wiphy *wiphy, struct net_device *netdev, |
1098 | int idx, struct survey_info *info); | 1118 | int idx, struct survey_info *info); |
1099 | 1119 | ||
1120 | int (*set_pmksa)(struct wiphy *wiphy, struct net_device *netdev, | ||
1121 | struct cfg80211_pmksa *pmksa); | ||
1122 | int (*del_pmksa)(struct wiphy *wiphy, struct net_device *netdev, | ||
1123 | struct cfg80211_pmksa *pmksa); | ||
1124 | int (*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev); | ||
1125 | |||
1100 | /* some temporary stuff to finish wext */ | 1126 | /* some temporary stuff to finish wext */ |
1101 | int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, | 1127 | int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, |
1102 | bool enabled, int timeout); | 1128 | bool enabled, int timeout); |
@@ -1195,6 +1221,8 @@ struct wiphy { | |||
1195 | char fw_version[ETHTOOL_BUSINFO_LEN]; | 1221 | char fw_version[ETHTOOL_BUSINFO_LEN]; |
1196 | u32 hw_version; | 1222 | u32 hw_version; |
1197 | 1223 | ||
1224 | u8 max_num_pmkids; | ||
1225 | |||
1198 | /* If multiple wiphys are registered and you're handed e.g. | 1226 | /* If multiple wiphys are registered and you're handed e.g. |
1199 | * a regular netdev with assigned ieee80211_ptr, you won't | 1227 | * a regular netdev with assigned ieee80211_ptr, you won't |
1200 | * know whether it points to a wiphy your driver has registered | 1228 | * know whether it points to a wiphy your driver has registered |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 149539ade15e..a6028433e3a0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -139,6 +139,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
139 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, | 139 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, |
140 | [NL80211_ATTR_PID] = { .type = NLA_U32 }, | 140 | [NL80211_ATTR_PID] = { .type = NLA_U32 }, |
141 | [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, | 141 | [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, |
142 | [NL80211_ATTR_PMKID] = { .type = NLA_BINARY, | ||
143 | .len = WLAN_PMKID_LEN }, | ||
142 | }; | 144 | }; |
143 | 145 | ||
144 | /* policy for the attributes */ | 146 | /* policy for the attributes */ |
@@ -450,6 +452,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
450 | sizeof(u32) * dev->wiphy.n_cipher_suites, | 452 | sizeof(u32) * dev->wiphy.n_cipher_suites, |
451 | dev->wiphy.cipher_suites); | 453 | dev->wiphy.cipher_suites); |
452 | 454 | ||
455 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, | ||
456 | dev->wiphy.max_num_pmkids); | ||
457 | |||
453 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); | 458 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); |
454 | if (!nl_modes) | 459 | if (!nl_modes) |
455 | goto nla_put_failure; | 460 | goto nla_put_failure; |
@@ -561,6 +566,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
561 | CMD(deauth, DEAUTHENTICATE); | 566 | CMD(deauth, DEAUTHENTICATE); |
562 | CMD(disassoc, DISASSOCIATE); | 567 | CMD(disassoc, DISASSOCIATE); |
563 | CMD(join_ibss, JOIN_IBSS); | 568 | CMD(join_ibss, JOIN_IBSS); |
569 | CMD(set_pmksa, SET_PMKSA); | ||
570 | CMD(del_pmksa, DEL_PMKSA); | ||
571 | CMD(flush_pmksa, FLUSH_PMKSA); | ||
564 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | 572 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { |
565 | i++; | 573 | i++; |
566 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | 574 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); |
@@ -4221,6 +4229,99 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) | |||
4221 | return err; | 4229 | return err; |
4222 | } | 4230 | } |
4223 | 4231 | ||
4232 | static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) | ||
4233 | { | ||
4234 | struct cfg80211_registered_device *rdev; | ||
4235 | int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev, | ||
4236 | struct cfg80211_pmksa *pmksa) = NULL; | ||
4237 | int err; | ||
4238 | struct net_device *dev; | ||
4239 | struct cfg80211_pmksa pmksa; | ||
4240 | |||
4241 | memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); | ||
4242 | |||
4243 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
4244 | return -EINVAL; | ||
4245 | |||
4246 | if (!info->attrs[NL80211_ATTR_PMKID]) | ||
4247 | return -EINVAL; | ||
4248 | |||
4249 | rtnl_lock(); | ||
4250 | |||
4251 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4252 | if (err) | ||
4253 | goto out_rtnl; | ||
4254 | |||
4255 | pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); | ||
4256 | pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
4257 | |||
4258 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
4259 | err = -EOPNOTSUPP; | ||
4260 | goto out; | ||
4261 | } | ||
4262 | |||
4263 | switch (info->genlhdr->cmd) { | ||
4264 | case NL80211_CMD_SET_PMKSA: | ||
4265 | rdev_ops = rdev->ops->set_pmksa; | ||
4266 | break; | ||
4267 | case NL80211_CMD_DEL_PMKSA: | ||
4268 | rdev_ops = rdev->ops->del_pmksa; | ||
4269 | break; | ||
4270 | default: | ||
4271 | WARN_ON(1); | ||
4272 | break; | ||
4273 | } | ||
4274 | |||
4275 | if (!rdev_ops) { | ||
4276 | err = -EOPNOTSUPP; | ||
4277 | goto out; | ||
4278 | } | ||
4279 | |||
4280 | err = rdev_ops(&rdev->wiphy, dev, &pmksa); | ||
4281 | |||
4282 | out: | ||
4283 | cfg80211_unlock_rdev(rdev); | ||
4284 | dev_put(dev); | ||
4285 | out_rtnl: | ||
4286 | rtnl_unlock(); | ||
4287 | |||
4288 | return err; | ||
4289 | } | ||
4290 | |||
4291 | static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) | ||
4292 | { | ||
4293 | struct cfg80211_registered_device *rdev; | ||
4294 | int err; | ||
4295 | struct net_device *dev; | ||
4296 | |||
4297 | rtnl_lock(); | ||
4298 | |||
4299 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4300 | if (err) | ||
4301 | goto out_rtnl; | ||
4302 | |||
4303 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
4304 | err = -EOPNOTSUPP; | ||
4305 | goto out; | ||
4306 | } | ||
4307 | |||
4308 | if (!rdev->ops->flush_pmksa) { | ||
4309 | err = -EOPNOTSUPP; | ||
4310 | goto out; | ||
4311 | } | ||
4312 | |||
4313 | err = rdev->ops->flush_pmksa(&rdev->wiphy, dev); | ||
4314 | |||
4315 | out: | ||
4316 | cfg80211_unlock_rdev(rdev); | ||
4317 | dev_put(dev); | ||
4318 | out_rtnl: | ||
4319 | rtnl_unlock(); | ||
4320 | |||
4321 | return err; | ||
4322 | |||
4323 | } | ||
4324 | |||
4224 | static struct genl_ops nl80211_ops[] = { | 4325 | static struct genl_ops nl80211_ops[] = { |
4225 | { | 4326 | { |
4226 | .cmd = NL80211_CMD_GET_WIPHY, | 4327 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -4465,6 +4566,25 @@ static struct genl_ops nl80211_ops[] = { | |||
4465 | .policy = nl80211_policy, | 4566 | .policy = nl80211_policy, |
4466 | .dumpit = nl80211_dump_survey, | 4567 | .dumpit = nl80211_dump_survey, |
4467 | }, | 4568 | }, |
4569 | { | ||
4570 | .cmd = NL80211_CMD_SET_PMKSA, | ||
4571 | .doit = nl80211_setdel_pmksa, | ||
4572 | .policy = nl80211_policy, | ||
4573 | .flags = GENL_ADMIN_PERM, | ||
4574 | }, | ||
4575 | { | ||
4576 | .cmd = NL80211_CMD_DEL_PMKSA, | ||
4577 | .doit = nl80211_setdel_pmksa, | ||
4578 | .policy = nl80211_policy, | ||
4579 | .flags = GENL_ADMIN_PERM, | ||
4580 | }, | ||
4581 | { | ||
4582 | .cmd = NL80211_CMD_FLUSH_PMKSA, | ||
4583 | .doit = nl80211_flush_pmksa, | ||
4584 | .policy = nl80211_policy, | ||
4585 | .flags = GENL_ADMIN_PERM, | ||
4586 | }, | ||
4587 | |||
4468 | }; | 4588 | }; |
4469 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 4589 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
4470 | .name = "mlme", | 4590 | .name = "mlme", |