Skip to content

Commit

Permalink
nl80211/mac80211: allow adding TDLS peers as stations
Browse files Browse the repository at this point in the history
When adding a TDLS peer STA, mark it with a new flag in both nl80211 and
mac80211. Before adding a peer, make sure the wiphy supports TDLS and
our operating mode is appropriate (managed).

In addition, make sure all peers are removed on disassociation.

A TDLS peer is first added just before link setup is initiated. In later
setup stages we have more info about peer supported rates, capabilities,
etc. This info is reported via nl80211_set_station().

Signed-off-by: Arik Nemtsov <arik@wizery.com>
Cc: Kalyan C Gaddam <chakkal@iit.edu>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Arik Nemtsov authored and John W. Linville committed Sep 30, 2011
1 parent dfe018b commit 07ba55d
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 7 deletions.
2 changes: 2 additions & 0 deletions include/linux/nl80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -1434,6 +1434,7 @@ enum nl80211_iftype {
* @NL80211_STA_FLAG_WME: station is WME/QoS capable
* @NL80211_STA_FLAG_MFP: station uses management frame protection
* @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated
* @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer
* @NL80211_STA_FLAG_MAX: highest station flag number currently defined
* @__NL80211_STA_FLAG_AFTER_LAST: internal use
*/
Expand All @@ -1444,6 +1445,7 @@ enum nl80211_sta_flags {
NL80211_STA_FLAG_WME,
NL80211_STA_FLAG_MFP,
NL80211_STA_FLAG_AUTHENTICATED,
NL80211_STA_FLAG_TDLS_PEER,

/* keep last */
__NL80211_STA_FLAG_AFTER_LAST,
Expand Down
20 changes: 20 additions & 0 deletions net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,12 @@ static void sta_apply_parameters(struct ieee80211_local *local,
if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
sta->flags |= WLAN_STA_AUTH;
}

if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
sta->flags &= ~WLAN_STA_TDLS_PEER;
if (set & BIT(NL80211_STA_FLAG_TDLS_PEER))
sta->flags |= WLAN_STA_TDLS_PEER;
}
spin_unlock_irqrestore(&sta->flaglock, flags);

if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) {
Expand Down Expand Up @@ -813,6 +819,12 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,

sta_apply_parameters(local, sta, params);

/* Only TDLS-supporting stations can add TDLS peers */
if ((sta->flags & WLAN_STA_TDLS_PEER) &&
!((wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
sdata->vif.type == NL80211_IFTYPE_STATION))
return -ENOTSUPP;

rate_control_rate_init(sta);

layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
Expand Down Expand Up @@ -865,6 +877,14 @@ static int ieee80211_change_station(struct wiphy *wiphy,
return -ENOENT;
}

/* The TDLS bit cannot be toggled after the STA was added */
if ((params->sta_flags_mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
!!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) !=
!!test_sta_flags(sta, WLAN_STA_TDLS_PEER)) {
rcu_read_unlock();
return -EINVAL;
}

if (params->vlan && params->vlan != sta->sdata->dev) {
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);

Expand Down
7 changes: 4 additions & 3 deletions net/mac80211/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -1137,8 +1137,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
ieee80211_bss_info_change_notify(sdata, changed);

/* remove AP and TDLS peers */
if (remove_sta)
sta_info_destroy_addr(sdata, bssid);
sta_info_flush(local, sdata);

del_timer_sync(&sdata->u.mgd.conn_mon_timer);
del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
Expand Down Expand Up @@ -2738,7 +2739,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
req->reason_code, cookie,
!req->local_state_change);
if (assoc_bss)
sta_info_destroy_addr(sdata, bssid);
sta_info_flush(sdata->local, sdata);

mutex_lock(&sdata->local->mtx);
ieee80211_recalc_idle(sdata->local);
Expand Down Expand Up @@ -2778,7 +2779,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
ieee80211_send_deauth_disassoc(sdata, req->bss->bssid,
IEEE80211_STYPE_DISASSOC, req->reason_code,
cookie, !req->local_state_change);
sta_info_destroy_addr(sdata, bssid);
sta_info_flush(sdata->local, sdata);

mutex_lock(&sdata->local->mtx);
ieee80211_recalc_idle(sdata->local);
Expand Down
2 changes: 2 additions & 0 deletions net/mac80211/sta_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
* station in power-save mode, reply when the driver unblocks.
* @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal
* buffers. Automatically cleared on station wake-up.
* @WLAN_STA_TDLS_PEER: station is a TDLS peer.
*/
enum ieee80211_sta_info_flags {
WLAN_STA_AUTH = 1<<0,
Expand All @@ -61,6 +62,7 @@ enum ieee80211_sta_info_flags {
WLAN_STA_PS_DRIVER = 1<<12,
WLAN_STA_PSPOLL = 1<<13,
WLAN_STA_PS_DRIVER_BUF = 1<<14,
WLAN_STA_TDLS_PEER = 1<<15,
};

#define STA_TID_NUM 16
Expand Down
26 changes: 22 additions & 4 deletions net/wireless/nl80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -2530,18 +2530,25 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
/* disallow everything but AUTHORIZED flag */
/* disallow things sta doesn't support */
if (params.plink_action)
err = -EINVAL;
if (params.vlan)
err = -EINVAL;
if (params.supported_rates)
if (params.supported_rates &&
!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
err = -EINVAL;
if (params.ht_capa)
err = -EINVAL;
if (params.listen_interval >= 0)
err = -EINVAL;
if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
if (params.sta_flags_mask &
~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
BIT(NL80211_STA_FLAG_TDLS_PEER)))
err = -EINVAL;
/* can't change the TDLS bit */
if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
(params.sta_flags_mask & BIT(NL80211_STA_FLAG_TDLS_PEER)))
err = -EINVAL;
break;
case NL80211_IFTYPE_MESH_POINT:
Expand Down Expand Up @@ -2662,7 +2669,18 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)
return -EINVAL;

/*
* Only managed stations can add TDLS peers, and only when the
* wiphy supports external TDLS setup.
*/
if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
!((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)))
return -EINVAL;

err = get_vlan(info, rdev, &params.vlan);
Expand Down

0 comments on commit 07ba55d

Please sign in to comment.