diff options
-rw-r--r-- | include/linux/nl80211.h | 6 | ||||
-rw-r--r-- | include/net/cfg80211.h | 7 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 8 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 199 |
4 files changed, 131 insertions, 89 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index a18760684fc9..f795cb7dccdd 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -1536,7 +1536,11 @@ enum nl80211_iftype { | |||
1536 | * @NL80211_STA_FLAG_WME: station is WME/QoS capable | 1536 | * @NL80211_STA_FLAG_WME: station is WME/QoS capable |
1537 | * @NL80211_STA_FLAG_MFP: station uses management frame protection | 1537 | * @NL80211_STA_FLAG_MFP: station uses management frame protection |
1538 | * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated | 1538 | * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated |
1539 | * @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer | 1539 | * @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer -- this flag should |
1540 | * only be used in managed mode (even in the flags mask). Note that the | ||
1541 | * flag can't be changed, it is only valid while adding a station, and | ||
1542 | * attempts to change it will silently be ignored (rather than rejected | ||
1543 | * as errors.) | ||
1540 | * @NL80211_STA_FLAG_MAX: highest station flag number currently defined | 1544 | * @NL80211_STA_FLAG_MAX: highest station flag number currently defined |
1541 | * @__NL80211_STA_FLAG_AFTER_LAST: internal use | 1545 | * @__NL80211_STA_FLAG_AFTER_LAST: internal use |
1542 | */ | 1546 | */ |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 150c0ee714c2..5eda5933ae01 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -1346,7 +1346,12 @@ struct cfg80211_gtk_rekey_data { | |||
1346 | * | 1346 | * |
1347 | * @add_station: Add a new station. | 1347 | * @add_station: Add a new station. |
1348 | * @del_station: Remove a station; @mac may be NULL to remove all stations. | 1348 | * @del_station: Remove a station; @mac may be NULL to remove all stations. |
1349 | * @change_station: Modify a given station. | 1349 | * @change_station: Modify a given station. Note that flags changes are not much |
1350 | * validated in cfg80211, in particular the auth/assoc/authorized flags | ||
1351 | * might come to the driver in invalid combinations -- make sure to check | ||
1352 | * them, also against the existing state! Also, supported_rates changes are | ||
1353 | * not checked in station mode -- drivers need to reject (or ignore) them | ||
1354 | * for anything but TDLS peers. | ||
1350 | * @get_station: get station information for the station identified by @mac | 1355 | * @get_station: get station information for the station identified by @mac |
1351 | * @dump_station: dump station callback -- resume dump at index @idx | 1356 | * @dump_station: dump station callback -- resume dump at index @idx |
1352 | * | 1357 | * |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 393b2a4445b8..944051b43bad 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -976,6 +976,14 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
976 | return -EINVAL; | 976 | return -EINVAL; |
977 | } | 977 | } |
978 | 978 | ||
979 | /* in station mode, supported rates are only valid with TDLS */ | ||
980 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
981 | params->supported_rates && | ||
982 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { | ||
983 | rcu_read_unlock(); | ||
984 | return -EINVAL; | ||
985 | } | ||
986 | |||
979 | if (params->vlan && params->vlan != sta->sdata->dev) { | 987 | if (params->vlan && params->vlan != sta->sdata->dev) { |
980 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 988 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
981 | 989 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d86428145c32..b07c4fc4ae22 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -2579,6 +2579,9 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2579 | params.ht_capa = | 2579 | params.ht_capa = |
2580 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 2580 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); |
2581 | 2581 | ||
2582 | if (!rdev->ops->change_station) | ||
2583 | return -EOPNOTSUPP; | ||
2584 | |||
2582 | if (parse_station_flags(info, ¶ms)) | 2585 | if (parse_station_flags(info, ¶ms)) |
2583 | return -EINVAL; | 2586 | return -EINVAL; |
2584 | 2587 | ||
@@ -2590,73 +2593,84 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2590 | params.plink_state = | 2593 | params.plink_state = |
2591 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); | 2594 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); |
2592 | 2595 | ||
2593 | params.vlan = get_vlan(info, rdev); | ||
2594 | if (IS_ERR(params.vlan)) | ||
2595 | return PTR_ERR(params.vlan); | ||
2596 | |||
2597 | /* validate settings */ | ||
2598 | err = 0; | ||
2599 | |||
2600 | switch (dev->ieee80211_ptr->iftype) { | 2596 | switch (dev->ieee80211_ptr->iftype) { |
2601 | case NL80211_IFTYPE_AP: | 2597 | case NL80211_IFTYPE_AP: |
2602 | case NL80211_IFTYPE_AP_VLAN: | 2598 | case NL80211_IFTYPE_AP_VLAN: |
2603 | case NL80211_IFTYPE_P2P_GO: | 2599 | case NL80211_IFTYPE_P2P_GO: |
2604 | /* disallow mesh-specific things */ | 2600 | /* disallow mesh-specific things */ |
2605 | if (params.plink_action) | 2601 | if (params.plink_action) |
2606 | err = -EINVAL; | 2602 | return -EINVAL; |
2603 | |||
2604 | /* TDLS can't be set, ... */ | ||
2605 | if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) | ||
2606 | return -EINVAL; | ||
2607 | /* | ||
2608 | * ... but don't bother the driver with it. This works around | ||
2609 | * a hostapd/wpa_supplicant issue -- it always includes the | ||
2610 | * TLDS_PEER flag in the mask even for AP mode. | ||
2611 | */ | ||
2612 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
2613 | |||
2614 | /* accept only the listed bits */ | ||
2615 | if (params.sta_flags_mask & | ||
2616 | ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
2617 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | | ||
2618 | BIT(NL80211_STA_FLAG_WME) | | ||
2619 | BIT(NL80211_STA_FLAG_MFP))) | ||
2620 | return -EINVAL; | ||
2621 | |||
2622 | /* must be last in here for error handling */ | ||
2623 | params.vlan = get_vlan(info, rdev); | ||
2624 | if (IS_ERR(params.vlan)) | ||
2625 | return PTR_ERR(params.vlan); | ||
2607 | break; | 2626 | break; |
2608 | case NL80211_IFTYPE_P2P_CLIENT: | 2627 | case NL80211_IFTYPE_P2P_CLIENT: |
2609 | case NL80211_IFTYPE_STATION: | 2628 | case NL80211_IFTYPE_STATION: |
2610 | /* disallow things sta doesn't support */ | 2629 | /* disallow things sta doesn't support */ |
2611 | if (params.plink_action) | 2630 | if (params.plink_action) |
2612 | err = -EINVAL; | 2631 | return -EINVAL; |
2613 | if (params.vlan) | ||
2614 | err = -EINVAL; | ||
2615 | if (params.supported_rates && | ||
2616 | !(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) | ||
2617 | err = -EINVAL; | ||
2618 | if (params.ht_capa) | 2632 | if (params.ht_capa) |
2619 | err = -EINVAL; | 2633 | return -EINVAL; |
2620 | if (params.listen_interval >= 0) | 2634 | if (params.listen_interval >= 0) |
2621 | err = -EINVAL; | 2635 | return -EINVAL; |
2622 | if (params.sta_flags_mask & | 2636 | /* |
2623 | ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | 2637 | * Don't allow userspace to change the TDLS_PEER flag, |
2624 | BIT(NL80211_STA_FLAG_TDLS_PEER))) | 2638 | * but silently ignore attempts to change it since we |
2625 | err = -EINVAL; | 2639 | * don't have state here to verify that it doesn't try |
2626 | /* can't change the TDLS bit */ | 2640 | * to change the flag. |
2627 | if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) && | 2641 | */ |
2628 | (params.sta_flags_mask & BIT(NL80211_STA_FLAG_TDLS_PEER))) | 2642 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); |
2629 | err = -EINVAL; | 2643 | |
2644 | /* reject any changes other than AUTHORIZED */ | ||
2645 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) | ||
2646 | return -EINVAL; | ||
2630 | break; | 2647 | break; |
2631 | case NL80211_IFTYPE_MESH_POINT: | 2648 | case NL80211_IFTYPE_MESH_POINT: |
2632 | /* disallow things mesh doesn't support */ | 2649 | /* disallow things mesh doesn't support */ |
2633 | if (params.vlan) | 2650 | if (params.vlan) |
2634 | err = -EINVAL; | 2651 | return -EINVAL; |
2635 | if (params.ht_capa) | 2652 | if (params.ht_capa) |
2636 | err = -EINVAL; | 2653 | return -EINVAL; |
2637 | if (params.listen_interval >= 0) | 2654 | if (params.listen_interval >= 0) |
2638 | err = -EINVAL; | 2655 | return -EINVAL; |
2656 | /* | ||
2657 | * No special handling for TDLS here -- the userspace | ||
2658 | * mesh code doesn't have this bug. | ||
2659 | */ | ||
2639 | if (params.sta_flags_mask & | 2660 | if (params.sta_flags_mask & |
2640 | ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | | 2661 | ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | |
2641 | BIT(NL80211_STA_FLAG_MFP) | | 2662 | BIT(NL80211_STA_FLAG_MFP) | |
2642 | BIT(NL80211_STA_FLAG_AUTHORIZED))) | 2663 | BIT(NL80211_STA_FLAG_AUTHORIZED))) |
2643 | err = -EINVAL; | 2664 | return -EINVAL; |
2644 | break; | 2665 | break; |
2645 | default: | 2666 | default: |
2646 | err = -EINVAL; | 2667 | return -EOPNOTSUPP; |
2647 | } | 2668 | } |
2648 | 2669 | ||
2649 | if (err) | 2670 | /* be aware of params.vlan when changing code here */ |
2650 | goto out; | ||
2651 | |||
2652 | if (!rdev->ops->change_station) { | ||
2653 | err = -EOPNOTSUPP; | ||
2654 | goto out; | ||
2655 | } | ||
2656 | 2671 | ||
2657 | err = rdev->ops->change_station(&rdev->wiphy, dev, mac_addr, ¶ms); | 2672 | err = rdev->ops->change_station(&rdev->wiphy, dev, mac_addr, ¶ms); |
2658 | 2673 | ||
2659 | out: | ||
2660 | if (params.vlan) | 2674 | if (params.vlan) |
2661 | dev_put(params.vlan); | 2675 | dev_put(params.vlan); |
2662 | 2676 | ||
@@ -2711,70 +2725,81 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2711 | params.plink_action = | 2725 | params.plink_action = |
2712 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 2726 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
2713 | 2727 | ||
2728 | if (!rdev->ops->add_station) | ||
2729 | return -EOPNOTSUPP; | ||
2730 | |||
2714 | if (parse_station_flags(info, ¶ms)) | 2731 | if (parse_station_flags(info, ¶ms)) |
2715 | return -EINVAL; | 2732 | return -EINVAL; |
2716 | 2733 | ||
2717 | /* parse WME attributes if sta is WME capable */ | 2734 | switch (dev->ieee80211_ptr->iftype) { |
2718 | if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) && | 2735 | case NL80211_IFTYPE_AP: |
2719 | (params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)) && | 2736 | case NL80211_IFTYPE_AP_VLAN: |
2720 | info->attrs[NL80211_ATTR_STA_WME]) { | 2737 | case NL80211_IFTYPE_P2P_GO: |
2721 | struct nlattr *tb[NL80211_STA_WME_MAX + 1]; | 2738 | /* parse WME attributes if sta is WME capable */ |
2722 | struct nlattr *nla; | 2739 | if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) && |
2740 | (params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)) && | ||
2741 | info->attrs[NL80211_ATTR_STA_WME]) { | ||
2742 | struct nlattr *tb[NL80211_STA_WME_MAX + 1]; | ||
2743 | struct nlattr *nla; | ||
2744 | |||
2745 | nla = info->attrs[NL80211_ATTR_STA_WME]; | ||
2746 | err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla, | ||
2747 | nl80211_sta_wme_policy); | ||
2748 | if (err) | ||
2749 | return err; | ||
2723 | 2750 | ||
2724 | nla = info->attrs[NL80211_ATTR_STA_WME]; | 2751 | if (tb[NL80211_STA_WME_UAPSD_QUEUES]) |
2725 | err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla, | 2752 | params.uapsd_queues = |
2726 | nl80211_sta_wme_policy); | 2753 | nla_get_u8(tb[NL80211_STA_WME_UAPSD_QUEUES]); |
2727 | if (err) | 2754 | if (params.uapsd_queues & |
2728 | return err; | 2755 | ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) |
2756 | return -EINVAL; | ||
2729 | 2757 | ||
2730 | if (tb[NL80211_STA_WME_UAPSD_QUEUES]) | 2758 | if (tb[NL80211_STA_WME_MAX_SP]) |
2731 | params.uapsd_queues = | 2759 | params.max_sp = |
2732 | nla_get_u8(tb[NL80211_STA_WME_UAPSD_QUEUES]); | 2760 | nla_get_u8(tb[NL80211_STA_WME_MAX_SP]); |
2733 | if (params.uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) | ||
2734 | return -EINVAL; | ||
2735 | 2761 | ||
2736 | if (tb[NL80211_STA_WME_MAX_SP]) | 2762 | if (params.max_sp & |
2737 | params.max_sp = | 2763 | ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) |
2738 | nla_get_u8(tb[NL80211_STA_WME_MAX_SP]); | 2764 | return -EINVAL; |
2739 | 2765 | ||
2740 | if (params.max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) | 2766 | params.sta_modify_mask |= STATION_PARAM_APPLY_UAPSD; |
2767 | } | ||
2768 | /* TDLS peers cannot be added */ | ||
2769 | if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) | ||
2741 | return -EINVAL; | 2770 | return -EINVAL; |
2771 | /* but don't bother the driver with it */ | ||
2772 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
2742 | 2773 | ||
2743 | params.sta_modify_mask |= STATION_PARAM_APPLY_UAPSD; | 2774 | /* must be last in here for error handling */ |
2775 | params.vlan = get_vlan(info, rdev); | ||
2776 | if (IS_ERR(params.vlan)) | ||
2777 | return PTR_ERR(params.vlan); | ||
2778 | break; | ||
2779 | case NL80211_IFTYPE_MESH_POINT: | ||
2780 | /* TDLS peers cannot be added */ | ||
2781 | if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) | ||
2782 | return -EINVAL; | ||
2783 | break; | ||
2784 | case NL80211_IFTYPE_STATION: | ||
2785 | /* Only TDLS peers can be added */ | ||
2786 | if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) | ||
2787 | return -EINVAL; | ||
2788 | /* Can only add if TDLS ... */ | ||
2789 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS)) | ||
2790 | return -EOPNOTSUPP; | ||
2791 | /* ... with external setup is supported */ | ||
2792 | if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)) | ||
2793 | return -EOPNOTSUPP; | ||
2794 | break; | ||
2795 | default: | ||
2796 | return -EOPNOTSUPP; | ||
2744 | } | 2797 | } |
2745 | 2798 | ||
2746 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2799 | /* be aware of params.vlan when changing code here */ |
2747 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | ||
2748 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | ||
2749 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO && | ||
2750 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) | ||
2751 | return -EINVAL; | ||
2752 | |||
2753 | /* | ||
2754 | * Only managed stations can add TDLS peers, and only when the | ||
2755 | * wiphy supports external TDLS setup. | ||
2756 | */ | ||
2757 | if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION && | ||
2758 | !((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) && | ||
2759 | (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) && | ||
2760 | (rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))) | ||
2761 | return -EINVAL; | ||
2762 | |||
2763 | params.vlan = get_vlan(info, rdev); | ||
2764 | if (IS_ERR(params.vlan)) | ||
2765 | return PTR_ERR(params.vlan); | ||
2766 | |||
2767 | /* validate settings */ | ||
2768 | err = 0; | ||
2769 | |||
2770 | if (!rdev->ops->add_station) { | ||
2771 | err = -EOPNOTSUPP; | ||
2772 | goto out; | ||
2773 | } | ||
2774 | 2800 | ||
2775 | err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); | 2801 | err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, ¶ms); |
2776 | 2802 | ||
2777 | out: | ||
2778 | if (params.vlan) | 2803 | if (params.vlan) |
2779 | dev_put(params.vlan); | 2804 | dev_put(params.vlan); |
2780 | return err; | 2805 | return err; |