aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-12-14 06:20:27 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-12-15 14:45:45 -0500
commitbdd90d5e36a55271beb957b3d7ca3e29b2a90207 (patch)
tree79243e73e6c64217bc676507504b72a2d59fc096
parentd83023daa219486e9aa139d423308a045bf0438b (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>
-rw-r--r--include/linux/nl80211.h6
-rw-r--r--include/net/cfg80211.h7
-rw-r--r--net/mac80211/cfg.c8
-rw-r--r--net/wireless/nl80211.c199
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, &params)) 2585 if (parse_station_flags(info, &params))
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, &params); 2672 err = rdev->ops->change_station(&rdev->wiphy, dev, mac_addr, &params);
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, &params)) 2731 if (parse_station_flags(info, &params))
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, &params); 2801 err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, &params);
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;