diff options
author | Johannes Berg <johannes.berg@intel.com> | 2010-12-09 13:58:59 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-12-13 15:23:28 -0500 |
commit | dbd2fd656f2060abfd3a16257f8b51ec60f6d2ed (patch) | |
tree | 71e61430bd8593f2ad8f1c741b5a8a8be4a9d690 /net/wireless/nl80211.c | |
parent | 897bed8b4320774e56f282cdc1cceb4d77442797 (diff) |
cfg80211/nl80211: separate unicast/multicast default TX keys
Allow userspace to specify that a given key
is default only for unicast and/or multicast
transmissions. Only WEP keys are for both,
WPA/RSN keys set here are GTKs for multicast
only. For more future flexibility, allow to
specify all combiations.
Wireless extensions can only set both so use
nl80211; WEP keys (connect keys) must be set
as default for both (but 802.1X WEP is still
possible).
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 125 |
1 files changed, 107 insertions, 18 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 73a7f6d354c9..53f044370cde 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -171,6 +171,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
171 | [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 }, | 171 | [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 }, |
172 | [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 }, | 172 | [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 }, |
173 | [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG }, | 173 | [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG }, |
174 | [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, | ||
174 | }; | 175 | }; |
175 | 176 | ||
176 | /* policy for the key attributes */ | 177 | /* policy for the key attributes */ |
@@ -182,6 +183,14 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { | |||
182 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, | 183 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, |
183 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, | 184 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, |
184 | [NL80211_KEY_TYPE] = { .type = NLA_U32 }, | 185 | [NL80211_KEY_TYPE] = { .type = NLA_U32 }, |
186 | [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, | ||
187 | }; | ||
188 | |||
189 | /* policy for the key default flags */ | ||
190 | static const struct nla_policy | ||
191 | nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = { | ||
192 | [NL80211_KEY_DEFAULT_TYPE_UNICAST] = { .type = NLA_FLAG }, | ||
193 | [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG }, | ||
185 | }; | 194 | }; |
186 | 195 | ||
187 | /* ifidx get helper */ | 196 | /* ifidx get helper */ |
@@ -314,6 +323,7 @@ struct key_parse { | |||
314 | int idx; | 323 | int idx; |
315 | int type; | 324 | int type; |
316 | bool def, defmgmt; | 325 | bool def, defmgmt; |
326 | bool def_uni, def_multi; | ||
317 | }; | 327 | }; |
318 | 328 | ||
319 | static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) | 329 | static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) |
@@ -327,6 +337,13 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) | |||
327 | k->def = !!tb[NL80211_KEY_DEFAULT]; | 337 | k->def = !!tb[NL80211_KEY_DEFAULT]; |
328 | k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT]; | 338 | k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT]; |
329 | 339 | ||
340 | if (k->def) { | ||
341 | k->def_uni = true; | ||
342 | k->def_multi = true; | ||
343 | } | ||
344 | if (k->defmgmt) | ||
345 | k->def_multi = true; | ||
346 | |||
330 | if (tb[NL80211_KEY_IDX]) | 347 | if (tb[NL80211_KEY_IDX]) |
331 | k->idx = nla_get_u8(tb[NL80211_KEY_IDX]); | 348 | k->idx = nla_get_u8(tb[NL80211_KEY_IDX]); |
332 | 349 | ||
@@ -349,6 +366,19 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) | |||
349 | return -EINVAL; | 366 | return -EINVAL; |
350 | } | 367 | } |
351 | 368 | ||
369 | if (tb[NL80211_KEY_DEFAULT_TYPES]) { | ||
370 | struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES]; | ||
371 | int err = nla_parse_nested(kdt, | ||
372 | NUM_NL80211_KEY_DEFAULT_TYPES - 1, | ||
373 | tb[NL80211_KEY_DEFAULT_TYPES], | ||
374 | nl80211_key_default_policy); | ||
375 | if (err) | ||
376 | return err; | ||
377 | |||
378 | k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST]; | ||
379 | k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST]; | ||
380 | } | ||
381 | |||
352 | return 0; | 382 | return 0; |
353 | } | 383 | } |
354 | 384 | ||
@@ -373,12 +403,32 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k) | |||
373 | k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; | 403 | k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; |
374 | k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; | 404 | k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; |
375 | 405 | ||
406 | if (k->def) { | ||
407 | k->def_uni = true; | ||
408 | k->def_multi = true; | ||
409 | } | ||
410 | if (k->defmgmt) | ||
411 | k->def_multi = true; | ||
412 | |||
376 | if (info->attrs[NL80211_ATTR_KEY_TYPE]) { | 413 | if (info->attrs[NL80211_ATTR_KEY_TYPE]) { |
377 | k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); | 414 | k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); |
378 | if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) | 415 | if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) |
379 | return -EINVAL; | 416 | return -EINVAL; |
380 | } | 417 | } |
381 | 418 | ||
419 | if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) { | ||
420 | struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES]; | ||
421 | int err = nla_parse_nested( | ||
422 | kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1, | ||
423 | info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES], | ||
424 | nl80211_key_default_policy); | ||
425 | if (err) | ||
426 | return err; | ||
427 | |||
428 | k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST]; | ||
429 | k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST]; | ||
430 | } | ||
431 | |||
382 | return 0; | 432 | return 0; |
383 | } | 433 | } |
384 | 434 | ||
@@ -401,6 +451,11 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) | |||
401 | if (k->def && k->defmgmt) | 451 | if (k->def && k->defmgmt) |
402 | return -EINVAL; | 452 | return -EINVAL; |
403 | 453 | ||
454 | if (k->defmgmt) { | ||
455 | if (k->def_uni || !k->def_multi) | ||
456 | return -EINVAL; | ||
457 | } | ||
458 | |||
404 | if (k->idx != -1) { | 459 | if (k->idx != -1) { |
405 | if (k->defmgmt) { | 460 | if (k->defmgmt) { |
406 | if (k->idx < 4 || k->idx > 5) | 461 | if (k->idx < 4 || k->idx > 5) |
@@ -450,6 +505,8 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, | |||
450 | goto error; | 505 | goto error; |
451 | def = 1; | 506 | def = 1; |
452 | result->def = parse.idx; | 507 | result->def = parse.idx; |
508 | if (!parse.def_uni || !parse.def_multi) | ||
509 | goto error; | ||
453 | } else if (parse.defmgmt) | 510 | } else if (parse.defmgmt) |
454 | goto error; | 511 | goto error; |
455 | err = cfg80211_validate_key_settings(rdev, &parse.p, | 512 | err = cfg80211_validate_key_settings(rdev, &parse.p, |
@@ -1586,8 +1643,6 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1586 | struct key_parse key; | 1643 | struct key_parse key; |
1587 | int err; | 1644 | int err; |
1588 | struct net_device *dev = info->user_ptr[1]; | 1645 | struct net_device *dev = info->user_ptr[1]; |
1589 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, | ||
1590 | u8 key_index); | ||
1591 | 1646 | ||
1592 | err = nl80211_parse_key(info, &key); | 1647 | err = nl80211_parse_key(info, &key); |
1593 | if (err) | 1648 | if (err) |
@@ -1600,27 +1655,61 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1600 | if (!key.def && !key.defmgmt) | 1655 | if (!key.def && !key.defmgmt) |
1601 | return -EINVAL; | 1656 | return -EINVAL; |
1602 | 1657 | ||
1603 | if (key.def) | 1658 | wdev_lock(dev->ieee80211_ptr); |
1604 | func = rdev->ops->set_default_key; | ||
1605 | else | ||
1606 | func = rdev->ops->set_default_mgmt_key; | ||
1607 | 1659 | ||
1608 | if (!func) | 1660 | if (key.def) { |
1609 | return -EOPNOTSUPP; | 1661 | if (!rdev->ops->set_default_key) { |
1662 | err = -EOPNOTSUPP; | ||
1663 | goto out; | ||
1664 | } | ||
1610 | 1665 | ||
1611 | wdev_lock(dev->ieee80211_ptr); | 1666 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
1612 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1667 | if (err) |
1613 | if (!err) | 1668 | goto out; |
1614 | err = func(&rdev->wiphy, dev, key.idx); | 1669 | |
1670 | if (!(rdev->wiphy.flags & | ||
1671 | WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS)) { | ||
1672 | if (!key.def_uni || !key.def_multi) { | ||
1673 | err = -EOPNOTSUPP; | ||
1674 | goto out; | ||
1675 | } | ||
1676 | } | ||
1677 | |||
1678 | err = rdev->ops->set_default_key(&rdev->wiphy, dev, key.idx, | ||
1679 | key.def_uni, key.def_multi); | ||
1680 | |||
1681 | if (err) | ||
1682 | goto out; | ||
1615 | 1683 | ||
1616 | #ifdef CONFIG_CFG80211_WEXT | 1684 | #ifdef CONFIG_CFG80211_WEXT |
1617 | if (!err) { | 1685 | dev->ieee80211_ptr->wext.default_key = key.idx; |
1618 | if (func == rdev->ops->set_default_key) | 1686 | #endif |
1619 | dev->ieee80211_ptr->wext.default_key = key.idx; | 1687 | } else { |
1620 | else | 1688 | if (key.def_uni || !key.def_multi) { |
1621 | dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; | 1689 | err = -EINVAL; |
1622 | } | 1690 | goto out; |
1691 | } | ||
1692 | |||
1693 | if (!rdev->ops->set_default_mgmt_key) { | ||
1694 | err = -EOPNOTSUPP; | ||
1695 | goto out; | ||
1696 | } | ||
1697 | |||
1698 | err = nl80211_key_allowed(dev->ieee80211_ptr); | ||
1699 | if (err) | ||
1700 | goto out; | ||
1701 | |||
1702 | err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, | ||
1703 | dev, key.idx); | ||
1704 | if (err) | ||
1705 | goto out; | ||
1706 | |||
1707 | #ifdef CONFIG_CFG80211_WEXT | ||
1708 | dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; | ||
1623 | #endif | 1709 | #endif |
1710 | } | ||
1711 | |||
1712 | out: | ||
1624 | wdev_unlock(dev->ieee80211_ptr); | 1713 | wdev_unlock(dev->ieee80211_ptr); |
1625 | 1714 | ||
1626 | return err; | 1715 | return err; |