diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 276 |
1 files changed, 230 insertions, 46 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c3f80e565365..9b62710891a2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -123,7 +123,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
123 | .len = NL80211_MAX_SUPP_RATES }, | 123 | .len = NL80211_MAX_SUPP_RATES }, |
124 | [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 }, | 124 | [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 }, |
125 | 125 | ||
126 | [NL80211_ATTR_MESH_PARAMS] = { .type = NLA_NESTED }, | 126 | [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED }, |
127 | 127 | ||
128 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, | 128 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, |
129 | .len = NL80211_HT_CAPABILITY_LEN }, | 129 | .len = NL80211_HT_CAPABILITY_LEN }, |
@@ -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, |
@@ -548,7 +605,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
548 | if (dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) | 605 | if (dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) |
549 | NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE); | 606 | NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE); |
550 | 607 | ||
551 | if (dev->ops->get_antenna) { | 608 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, |
609 | dev->wiphy.available_antennas_tx); | ||
610 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, | ||
611 | dev->wiphy.available_antennas_rx); | ||
612 | |||
613 | if ((dev->wiphy.available_antennas_tx || | ||
614 | dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) { | ||
552 | u32 tx_ant = 0, rx_ant = 0; | 615 | u32 tx_ant = 0, rx_ant = 0; |
553 | int res; | 616 | int res; |
554 | res = dev->ops->get_antenna(&dev->wiphy, &tx_ant, &rx_ant); | 617 | res = dev->ops->get_antenna(&dev->wiphy, &tx_ant, &rx_ant); |
@@ -662,7 +725,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
662 | CMD(add_beacon, NEW_BEACON); | 725 | CMD(add_beacon, NEW_BEACON); |
663 | CMD(add_station, NEW_STATION); | 726 | CMD(add_station, NEW_STATION); |
664 | CMD(add_mpath, NEW_MPATH); | 727 | CMD(add_mpath, NEW_MPATH); |
665 | CMD(update_mesh_params, SET_MESH_PARAMS); | 728 | CMD(update_mesh_config, SET_MESH_CONFIG); |
666 | CMD(change_bss, SET_BSS); | 729 | CMD(change_bss, SET_BSS); |
667 | CMD(auth, AUTHENTICATE); | 730 | CMD(auth, AUTHENTICATE); |
668 | CMD(assoc, ASSOCIATE); | 731 | CMD(assoc, ASSOCIATE); |
@@ -698,6 +761,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
698 | 761 | ||
699 | nla_nest_end(msg, nl_cmds); | 762 | nla_nest_end(msg, nl_cmds); |
700 | 763 | ||
764 | if (dev->ops->remain_on_channel) | ||
765 | NLA_PUT_U32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, | ||
766 | dev->wiphy.max_remain_on_channel_duration); | ||
767 | |||
701 | /* for now at least assume all drivers have it */ | 768 | /* for now at least assume all drivers have it */ |
702 | if (dev->ops->mgmt_tx) | 769 | if (dev->ops->mgmt_tx) |
703 | NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); | 770 | NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); |
@@ -1046,7 +1113,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1046 | if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] && | 1113 | if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] && |
1047 | info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) { | 1114 | info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) { |
1048 | u32 tx_ant, rx_ant; | 1115 | u32 tx_ant, rx_ant; |
1049 | if (!rdev->ops->set_antenna) { | 1116 | if ((!rdev->wiphy.available_antennas_tx && |
1117 | !rdev->wiphy.available_antennas_rx) || | ||
1118 | !rdev->ops->set_antenna) { | ||
1050 | result = -EOPNOTSUPP; | 1119 | result = -EOPNOTSUPP; |
1051 | goto bad_res; | 1120 | goto bad_res; |
1052 | } | 1121 | } |
@@ -1054,6 +1123,17 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1054 | tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]); | 1123 | tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]); |
1055 | rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]); | 1124 | rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]); |
1056 | 1125 | ||
1126 | /* reject antenna configurations which don't match the | ||
1127 | * available antenna masks, except for the "all" mask */ | ||
1128 | if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) || | ||
1129 | (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx))) { | ||
1130 | result = -EINVAL; | ||
1131 | goto bad_res; | ||
1132 | } | ||
1133 | |||
1134 | tx_ant = tx_ant & rdev->wiphy.available_antennas_tx; | ||
1135 | rx_ant = rx_ant & rdev->wiphy.available_antennas_rx; | ||
1136 | |||
1057 | result = rdev->ops->set_antenna(&rdev->wiphy, tx_ant, rx_ant); | 1137 | result = rdev->ops->set_antenna(&rdev->wiphy, tx_ant, rx_ant); |
1058 | if (result) | 1138 | if (result) |
1059 | goto bad_res; | 1139 | goto bad_res; |
@@ -1575,8 +1655,6 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1575 | struct key_parse key; | 1655 | struct key_parse key; |
1576 | int err; | 1656 | int err; |
1577 | struct net_device *dev = info->user_ptr[1]; | 1657 | struct net_device *dev = info->user_ptr[1]; |
1578 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, | ||
1579 | u8 key_index); | ||
1580 | 1658 | ||
1581 | err = nl80211_parse_key(info, &key); | 1659 | err = nl80211_parse_key(info, &key); |
1582 | if (err) | 1660 | if (err) |
@@ -1589,27 +1667,61 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1589 | if (!key.def && !key.defmgmt) | 1667 | if (!key.def && !key.defmgmt) |
1590 | return -EINVAL; | 1668 | return -EINVAL; |
1591 | 1669 | ||
1592 | if (key.def) | 1670 | wdev_lock(dev->ieee80211_ptr); |
1593 | func = rdev->ops->set_default_key; | ||
1594 | else | ||
1595 | func = rdev->ops->set_default_mgmt_key; | ||
1596 | 1671 | ||
1597 | if (!func) | 1672 | if (key.def) { |
1598 | return -EOPNOTSUPP; | 1673 | if (!rdev->ops->set_default_key) { |
1674 | err = -EOPNOTSUPP; | ||
1675 | goto out; | ||
1676 | } | ||
1599 | 1677 | ||
1600 | wdev_lock(dev->ieee80211_ptr); | 1678 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
1601 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1679 | if (err) |
1602 | if (!err) | 1680 | goto out; |
1603 | err = func(&rdev->wiphy, dev, key.idx); | 1681 | |
1682 | if (!(rdev->wiphy.flags & | ||
1683 | WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS)) { | ||
1684 | if (!key.def_uni || !key.def_multi) { | ||
1685 | err = -EOPNOTSUPP; | ||
1686 | goto out; | ||
1687 | } | ||
1688 | } | ||
1689 | |||
1690 | err = rdev->ops->set_default_key(&rdev->wiphy, dev, key.idx, | ||
1691 | key.def_uni, key.def_multi); | ||
1692 | |||
1693 | if (err) | ||
1694 | goto out; | ||
1604 | 1695 | ||
1605 | #ifdef CONFIG_CFG80211_WEXT | 1696 | #ifdef CONFIG_CFG80211_WEXT |
1606 | if (!err) { | 1697 | dev->ieee80211_ptr->wext.default_key = key.idx; |
1607 | if (func == rdev->ops->set_default_key) | ||
1608 | dev->ieee80211_ptr->wext.default_key = key.idx; | ||
1609 | else | ||
1610 | dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; | ||
1611 | } | ||
1612 | #endif | 1698 | #endif |
1699 | } else { | ||
1700 | if (key.def_uni || !key.def_multi) { | ||
1701 | err = -EINVAL; | ||
1702 | goto out; | ||
1703 | } | ||
1704 | |||
1705 | if (!rdev->ops->set_default_mgmt_key) { | ||
1706 | err = -EOPNOTSUPP; | ||
1707 | goto out; | ||
1708 | } | ||
1709 | |||
1710 | err = nl80211_key_allowed(dev->ieee80211_ptr); | ||
1711 | if (err) | ||
1712 | goto out; | ||
1713 | |||
1714 | err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, | ||
1715 | dev, key.idx); | ||
1716 | if (err) | ||
1717 | goto out; | ||
1718 | |||
1719 | #ifdef CONFIG_CFG80211_WEXT | ||
1720 | dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; | ||
1721 | #endif | ||
1722 | } | ||
1723 | |||
1724 | out: | ||
1613 | wdev_unlock(dev->ieee80211_ptr); | 1725 | wdev_unlock(dev->ieee80211_ptr); |
1614 | 1726 | ||
1615 | return err; | 1727 | return err; |
@@ -2569,7 +2681,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2569 | return r; | 2681 | return r; |
2570 | } | 2682 | } |
2571 | 2683 | ||
2572 | static int nl80211_get_mesh_params(struct sk_buff *skb, | 2684 | static int nl80211_get_mesh_config(struct sk_buff *skb, |
2573 | struct genl_info *info) | 2685 | struct genl_info *info) |
2574 | { | 2686 | { |
2575 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2687 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -2584,7 +2696,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2584 | if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) | 2696 | if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) |
2585 | return -EOPNOTSUPP; | 2697 | return -EOPNOTSUPP; |
2586 | 2698 | ||
2587 | if (!rdev->ops->get_mesh_params) | 2699 | if (!rdev->ops->get_mesh_config) |
2588 | return -EOPNOTSUPP; | 2700 | return -EOPNOTSUPP; |
2589 | 2701 | ||
2590 | wdev_lock(wdev); | 2702 | wdev_lock(wdev); |
@@ -2592,7 +2704,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2592 | if (!wdev->mesh_id_len) | 2704 | if (!wdev->mesh_id_len) |
2593 | memcpy(&cur_params, &default_mesh_config, sizeof(cur_params)); | 2705 | memcpy(&cur_params, &default_mesh_config, sizeof(cur_params)); |
2594 | else | 2706 | else |
2595 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, | 2707 | err = rdev->ops->get_mesh_config(&rdev->wiphy, dev, |
2596 | &cur_params); | 2708 | &cur_params); |
2597 | wdev_unlock(wdev); | 2709 | wdev_unlock(wdev); |
2598 | 2710 | ||
@@ -2604,10 +2716,10 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2604 | if (!msg) | 2716 | if (!msg) |
2605 | return -ENOMEM; | 2717 | return -ENOMEM; |
2606 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 2718 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
2607 | NL80211_CMD_GET_MESH_PARAMS); | 2719 | NL80211_CMD_GET_MESH_CONFIG); |
2608 | if (!hdr) | 2720 | if (!hdr) |
2609 | goto nla_put_failure; | 2721 | goto nla_put_failure; |
2610 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS); | 2722 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG); |
2611 | if (!pinfoattr) | 2723 | if (!pinfoattr) |
2612 | goto nla_put_failure; | 2724 | goto nla_put_failure; |
2613 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 2725 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
@@ -2669,7 +2781,15 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
2669 | [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 }, | 2781 | [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 }, |
2670 | }; | 2782 | }; |
2671 | 2783 | ||
2672 | static int nl80211_parse_mesh_params(struct genl_info *info, | 2784 | static const struct nla_policy |
2785 | nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = { | ||
2786 | [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, | ||
2787 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, | ||
2788 | [NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE] = { .type = NLA_BINARY, | ||
2789 | .len = IEEE80211_MAX_DATA_LEN }, | ||
2790 | }; | ||
2791 | |||
2792 | static int nl80211_parse_mesh_config(struct genl_info *info, | ||
2673 | struct mesh_config *cfg, | 2793 | struct mesh_config *cfg, |
2674 | u32 *mask_out) | 2794 | u32 *mask_out) |
2675 | { | 2795 | { |
@@ -2685,10 +2805,10 @@ do {\ | |||
2685 | } while (0);\ | 2805 | } while (0);\ |
2686 | 2806 | ||
2687 | 2807 | ||
2688 | if (!info->attrs[NL80211_ATTR_MESH_PARAMS]) | 2808 | if (!info->attrs[NL80211_ATTR_MESH_CONFIG]) |
2689 | return -EINVAL; | 2809 | return -EINVAL; |
2690 | if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX, | 2810 | if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX, |
2691 | info->attrs[NL80211_ATTR_MESH_PARAMS], | 2811 | info->attrs[NL80211_ATTR_MESH_CONFIG], |
2692 | nl80211_meshconf_params_policy)) | 2812 | nl80211_meshconf_params_policy)) |
2693 | return -EINVAL; | 2813 | return -EINVAL; |
2694 | 2814 | ||
@@ -2735,15 +2855,51 @@ do {\ | |||
2735 | dot11MeshHWMPRootMode, mask, | 2855 | dot11MeshHWMPRootMode, mask, |
2736 | NL80211_MESHCONF_HWMP_ROOTMODE, | 2856 | NL80211_MESHCONF_HWMP_ROOTMODE, |
2737 | nla_get_u8); | 2857 | nla_get_u8); |
2738 | |||
2739 | if (mask_out) | 2858 | if (mask_out) |
2740 | *mask_out = mask; | 2859 | *mask_out = mask; |
2860 | |||
2741 | return 0; | 2861 | return 0; |
2742 | 2862 | ||
2743 | #undef FILL_IN_MESH_PARAM_IF_SET | 2863 | #undef FILL_IN_MESH_PARAM_IF_SET |
2744 | } | 2864 | } |
2745 | 2865 | ||
2746 | static int nl80211_update_mesh_params(struct sk_buff *skb, | 2866 | static int nl80211_parse_mesh_setup(struct genl_info *info, |
2867 | struct mesh_setup *setup) | ||
2868 | { | ||
2869 | struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1]; | ||
2870 | |||
2871 | if (!info->attrs[NL80211_ATTR_MESH_SETUP]) | ||
2872 | return -EINVAL; | ||
2873 | if (nla_parse_nested(tb, NL80211_MESH_SETUP_ATTR_MAX, | ||
2874 | info->attrs[NL80211_ATTR_MESH_SETUP], | ||
2875 | nl80211_mesh_setup_params_policy)) | ||
2876 | return -EINVAL; | ||
2877 | |||
2878 | if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL]) | ||
2879 | setup->path_sel_proto = | ||
2880 | (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ? | ||
2881 | IEEE80211_PATH_PROTOCOL_VENDOR : | ||
2882 | IEEE80211_PATH_PROTOCOL_HWMP; | ||
2883 | |||
2884 | if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC]) | ||
2885 | setup->path_metric = | ||
2886 | (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])) ? | ||
2887 | IEEE80211_PATH_METRIC_VENDOR : | ||
2888 | IEEE80211_PATH_METRIC_AIRTIME; | ||
2889 | |||
2890 | if (tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE]) { | ||
2891 | struct nlattr *ieattr = | ||
2892 | tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE]; | ||
2893 | if (!is_valid_ie_attr(ieattr)) | ||
2894 | return -EINVAL; | ||
2895 | setup->vendor_ie = nla_data(ieattr); | ||
2896 | setup->vendor_ie_len = nla_len(ieattr); | ||
2897 | } | ||
2898 | |||
2899 | return 0; | ||
2900 | } | ||
2901 | |||
2902 | static int nl80211_update_mesh_config(struct sk_buff *skb, | ||
2747 | struct genl_info *info) | 2903 | struct genl_info *info) |
2748 | { | 2904 | { |
2749 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2905 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -2756,10 +2912,10 @@ static int nl80211_update_mesh_params(struct sk_buff *skb, | |||
2756 | if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) | 2912 | if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) |
2757 | return -EOPNOTSUPP; | 2913 | return -EOPNOTSUPP; |
2758 | 2914 | ||
2759 | if (!rdev->ops->update_mesh_params) | 2915 | if (!rdev->ops->update_mesh_config) |
2760 | return -EOPNOTSUPP; | 2916 | return -EOPNOTSUPP; |
2761 | 2917 | ||
2762 | err = nl80211_parse_mesh_params(info, &cfg, &mask); | 2918 | err = nl80211_parse_mesh_config(info, &cfg, &mask); |
2763 | if (err) | 2919 | if (err) |
2764 | return err; | 2920 | return err; |
2765 | 2921 | ||
@@ -2768,7 +2924,7 @@ static int nl80211_update_mesh_params(struct sk_buff *skb, | |||
2768 | err = -ENOLINK; | 2924 | err = -ENOLINK; |
2769 | 2925 | ||
2770 | if (!err) | 2926 | if (!err) |
2771 | err = rdev->ops->update_mesh_params(&rdev->wiphy, dev, | 2927 | err = rdev->ops->update_mesh_config(&rdev->wiphy, dev, |
2772 | mask, &cfg); | 2928 | mask, &cfg); |
2773 | 2929 | ||
2774 | wdev_unlock(wdev); | 2930 | wdev_unlock(wdev); |
@@ -4128,7 +4284,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
4128 | * We should be on that channel for at least one jiffie, | 4284 | * We should be on that channel for at least one jiffie, |
4129 | * and more than 5 seconds seems excessive. | 4285 | * and more than 5 seconds seems excessive. |
4130 | */ | 4286 | */ |
4131 | if (!duration || !msecs_to_jiffies(duration) || duration > 5000) | 4287 | if (!duration || !msecs_to_jiffies(duration) || |
4288 | duration > rdev->wiphy.max_remain_on_channel_duration) | ||
4132 | return -EINVAL; | 4289 | return -EINVAL; |
4133 | 4290 | ||
4134 | if (!rdev->ops->remain_on_channel) | 4291 | if (!rdev->ops->remain_on_channel) |
@@ -4296,6 +4453,7 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4296 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 4453 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && |
4297 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 4454 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
4298 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 4455 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
4456 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | ||
4299 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 4457 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
4300 | return -EOPNOTSUPP; | 4458 | return -EOPNOTSUPP; |
4301 | 4459 | ||
@@ -4336,6 +4494,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4336 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 4494 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && |
4337 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 4495 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
4338 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 4496 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
4497 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | ||
4339 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 4498 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
4340 | return -EOPNOTSUPP; | 4499 | return -EOPNOTSUPP; |
4341 | 4500 | ||
@@ -4562,14 +4721,16 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | |||
4562 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 4721 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4563 | struct net_device *dev = info->user_ptr[1]; | 4722 | struct net_device *dev = info->user_ptr[1]; |
4564 | struct mesh_config cfg; | 4723 | struct mesh_config cfg; |
4724 | struct mesh_setup setup; | ||
4565 | int err; | 4725 | int err; |
4566 | 4726 | ||
4567 | /* start with default */ | 4727 | /* start with default */ |
4568 | memcpy(&cfg, &default_mesh_config, sizeof(cfg)); | 4728 | memcpy(&cfg, &default_mesh_config, sizeof(cfg)); |
4729 | memcpy(&setup, &default_mesh_setup, sizeof(setup)); | ||
4569 | 4730 | ||
4570 | if (info->attrs[NL80211_ATTR_MESH_PARAMS]) { | 4731 | if (info->attrs[NL80211_ATTR_MESH_CONFIG]) { |
4571 | /* and parse parameters if given */ | 4732 | /* and parse parameters if given */ |
4572 | err = nl80211_parse_mesh_params(info, &cfg, NULL); | 4733 | err = nl80211_parse_mesh_config(info, &cfg, NULL); |
4573 | if (err) | 4734 | if (err) |
4574 | return err; | 4735 | return err; |
4575 | } | 4736 | } |
@@ -4578,10 +4739,17 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | |||
4578 | !nla_len(info->attrs[NL80211_ATTR_MESH_ID])) | 4739 | !nla_len(info->attrs[NL80211_ATTR_MESH_ID])) |
4579 | return -EINVAL; | 4740 | return -EINVAL; |
4580 | 4741 | ||
4581 | return cfg80211_join_mesh(rdev, dev, | 4742 | setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); |
4582 | nla_data(info->attrs[NL80211_ATTR_MESH_ID]), | 4743 | setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
4583 | nla_len(info->attrs[NL80211_ATTR_MESH_ID]), | 4744 | |
4584 | &cfg); | 4745 | if (info->attrs[NL80211_ATTR_MESH_SETUP]) { |
4746 | /* parse additional setup parameters if given */ | ||
4747 | err = nl80211_parse_mesh_setup(info, &setup); | ||
4748 | if (err) | ||
4749 | return err; | ||
4750 | } | ||
4751 | |||
4752 | return cfg80211_join_mesh(rdev, dev, &setup, &cfg); | ||
4585 | } | 4753 | } |
4586 | 4754 | ||
4587 | static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | 4755 | static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) |
@@ -4847,16 +5015,16 @@ static struct genl_ops nl80211_ops[] = { | |||
4847 | .flags = GENL_ADMIN_PERM, | 5015 | .flags = GENL_ADMIN_PERM, |
4848 | }, | 5016 | }, |
4849 | { | 5017 | { |
4850 | .cmd = NL80211_CMD_GET_MESH_PARAMS, | 5018 | .cmd = NL80211_CMD_GET_MESH_CONFIG, |
4851 | .doit = nl80211_get_mesh_params, | 5019 | .doit = nl80211_get_mesh_config, |
4852 | .policy = nl80211_policy, | 5020 | .policy = nl80211_policy, |
4853 | /* can be retrieved by unprivileged users */ | 5021 | /* can be retrieved by unprivileged users */ |
4854 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 5022 | .internal_flags = NL80211_FLAG_NEED_NETDEV | |
4855 | NL80211_FLAG_NEED_RTNL, | 5023 | NL80211_FLAG_NEED_RTNL, |
4856 | }, | 5024 | }, |
4857 | { | 5025 | { |
4858 | .cmd = NL80211_CMD_SET_MESH_PARAMS, | 5026 | .cmd = NL80211_CMD_SET_MESH_CONFIG, |
4859 | .doit = nl80211_update_mesh_params, | 5027 | .doit = nl80211_update_mesh_config, |
4860 | .policy = nl80211_policy, | 5028 | .policy = nl80211_policy, |
4861 | .flags = GENL_ADMIN_PERM, | 5029 | .flags = GENL_ADMIN_PERM, |
4862 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 5030 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
@@ -5368,6 +5536,22 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, | |||
5368 | NL80211_CMD_DISASSOCIATE, gfp); | 5536 | NL80211_CMD_DISASSOCIATE, gfp); |
5369 | } | 5537 | } |
5370 | 5538 | ||
5539 | void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev, | ||
5540 | struct net_device *netdev, const u8 *buf, | ||
5541 | size_t len, gfp_t gfp) | ||
5542 | { | ||
5543 | nl80211_send_mlme_event(rdev, netdev, buf, len, | ||
5544 | NL80211_CMD_UNPROT_DEAUTHENTICATE, gfp); | ||
5545 | } | ||
5546 | |||
5547 | void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev, | ||
5548 | struct net_device *netdev, const u8 *buf, | ||
5549 | size_t len, gfp_t gfp) | ||
5550 | { | ||
5551 | nl80211_send_mlme_event(rdev, netdev, buf, len, | ||
5552 | NL80211_CMD_UNPROT_DISASSOCIATE, gfp); | ||
5553 | } | ||
5554 | |||
5371 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, | 5555 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, |
5372 | struct net_device *netdev, int cmd, | 5556 | struct net_device *netdev, int cmd, |
5373 | const u8 *addr, gfp_t gfp) | 5557 | const u8 *addr, gfp_t gfp) |