diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-12-14 06:20:27 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-12-15 14:45:45 -0500 |
commit | bdd90d5e36a55271beb957b3d7ca3e29b2a90207 (patch) | |
tree | 79243e73e6c64217bc676507504b72a2d59fc096 /net/wireless | |
parent | d83023daa219486e9aa139d423308a045bf0438b (diff) |
cfg80211: validate nl80211 station handling better
The nl80211 station handling code is a bit messy
and doesn't do a lot of validation. It seems like
this could be an issue for drivers that don't use
mac80211 to validate everything.
As cfg80211 doesn't keep station state, move the
validation of allowing supported_rates to change
for TDLS only in station mode to mac80211.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/nl80211.c | 199 |
1 files changed, 112 insertions, 87 deletions
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; |