2011-09-26 10:55:01

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 0/5] TDLS support for nl80211/mac80211 drivers

This series adds basic kernel-mode TDLS support for nl80211 based drivers.
It is based in part on patches by Kalyan C. Gaddam, cc-ed here.

Support is added for peer discovery and data path setup/teardown.
Currently not implemented: QoS/HT, peer PSM, peer U-APSD and channel
switching.

The main change from the RFC series is the addition of a Tx block
during link setup. In the new scheme of things, a STA entry is added
just before setting up a link. This allows us to throw out frames
sent to a peer while the link is being set up. This is required by
the specification, to avoid reordering of MSDUs.

User-mode support is added in a companion series.

Tested with wl12xx hardware, with a nl80211/mac80211 based driver.

Arik

Cc: Kalyan C Gaddam <[email protected]>

Arik Nemtsov (5):
nl80211: support sending TDLS commands/frames
mac80211: standardize adding supported rates IEs
mac80211: handle TDLS high-level commands and frames
nl80211/mac80211: allow adding TDLS peers as stations
mac80211: data path modification for TDLS peers

include/linux/ieee80211.h | 85 ++++++++++++
include/linux/if_ether.h | 1 +
include/linux/nl80211.h | 48 +++++++
include/net/cfg80211.h | 17 +++
include/net/mac80211.h | 5 +
net/mac80211/Kconfig | 12 ++
net/mac80211/cfg.c | 335 +++++++++++++++++++++++++++++++++++++++++++++
net/mac80211/main.c | 4 +
net/mac80211/mesh.c | 58 --------
net/mac80211/mesh.h | 4 -
net/mac80211/mesh_plink.c | 4 +-
net/mac80211/mlme.c | 7 +-
net/mac80211/sta_info.h | 5 +
net/mac80211/tx.c | 46 ++++++-
net/mac80211/util.c | 59 ++++++++
net/wireless/nl80211.c | 97 ++++++++++++-
net/wireless/util.c | 5 +-
17 files changed, 711 insertions(+), 81 deletions(-)

--
1.7.4.1



2011-09-26 10:55:10

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 3/5] mac80211: handle TDLS high-level commands and frames

Register and implement the TDLS cfg80211 callback functions.

Internally prepare and send TDLS management frames. We incorporate
local STA capabilities and supported rates with extra IEs given by
usermode. The resulting packet is either encapsulated in a data frame,
or assembled as an action frame. It is transmitted either directly or
through the AP, as mandated by the TDLS specification.

Declare support for the TDLS external setup wiphy capability. This
tells usermode to handle link setup and discovery on its own, and use the
kernel driver for sending TDLS mgmt packets.

Signed-off-by: Arik Nemtsov <[email protected]>
Cc: Kalyan C Gaddam <[email protected]>
---
include/linux/ieee80211.h | 85 ++++++++++++
include/linux/if_ether.h | 1 +
net/mac80211/Kconfig | 12 ++
net/mac80211/cfg.c | 314 +++++++++++++++++++++++++++++++++++++++++++++
net/mac80211/main.c | 4 +
5 files changed, 416 insertions(+), 0 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index b5e0a5c..f5c8ced 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -759,6 +759,12 @@ struct ieee80211_mgmt {
u8 action;
u8 smps_control;
} __attribute__ ((packed)) ht_smps;
+ struct {
+ u8 action_code;
+ u8 dialog_token;
+ __le16 capability;
+ u8 variable[0];
+ } __packed tdls_discover_resp;
} u;
} __attribute__ ((packed)) action;
} u;
@@ -805,6 +811,52 @@ struct ieee80211_pspoll {
u8 ta[6];
} __attribute__ ((packed));

+/* TDLS */
+
+/* Link-id information element */
+struct ieee80211_tdls_lnkie {
+ u8 ie_type; /* Link Identifier IE */
+ u8 ie_len;
+ u8 bssid[6];
+ u8 init_sta[6];
+ u8 resp_sta[6];
+} __packed;
+
+struct ieee80211_tdls_data {
+ u8 da[6];
+ u8 sa[6];
+ __be16 ether_type;
+ u8 payload_type;
+ u8 category;
+ u8 action_code;
+ union {
+ struct {
+ u8 dialog_token;
+ __le16 capability;
+ u8 variable[0];
+ } __packed setup_req;
+ struct {
+ __le16 status_code;
+ u8 dialog_token;
+ __le16 capability;
+ u8 variable[0];
+ } __packed setup_resp;
+ struct {
+ __le16 status_code;
+ u8 dialog_token;
+ u8 variable[0];
+ } __packed setup_cfm;
+ struct {
+ __le16 reason_code;
+ u8 variable[0];
+ } __packed teardown;
+ struct {
+ u8 dialog_token;
+ u8 variable[0];
+ } __packed discover_req;
+ } u;
+} __packed;
+
/**
* struct ieee80211_bar - HT Block Ack Request
*
@@ -1196,6 +1248,8 @@ enum ieee80211_eid {
WLAN_EID_TS_DELAY = 43,
WLAN_EID_TCLAS_PROCESSING = 44,
WLAN_EID_QOS_CAPA = 46,
+ /* 802.11z */
+ WLAN_EID_LINK_ID = 101,
/* 802.11s */
WLAN_EID_MESH_CONFIG = 113,
WLAN_EID_MESH_ID = 114,
@@ -1279,6 +1333,7 @@ enum ieee80211_category {
WLAN_CATEGORY_HT = 7,
WLAN_CATEGORY_SA_QUERY = 8,
WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9,
+ WLAN_CATEGORY_TDLS = 12,
WLAN_CATEGORY_MESH_ACTION = 13,
WLAN_CATEGORY_MULTIHOP_ACTION = 14,
WLAN_CATEGORY_SELF_PROTECTED = 15,
@@ -1342,6 +1397,36 @@ enum ieee80211_key_len {
WLAN_KEY_LEN_AES_CMAC = 16,
};

+/* Public action codes */
+enum ieee80211_pub_actioncode {
+ WLAN_PUB_ACTION_TDLS_DISCOVER_RES = 14,
+};
+
+/* TDLS action codes */
+enum ieee80211_tdls_actioncode {
+ WLAN_TDLS_SETUP_REQUEST = 0,
+ WLAN_TDLS_SETUP_RESPONSE = 1,
+ WLAN_TDLS_SETUP_CONFIRM = 2,
+ WLAN_TDLS_TEARDOWN = 3,
+ WLAN_TDLS_PEER_TRAFFIC_INDICATION = 4,
+ WLAN_TDLS_CHANNEL_SWITCH_REQUEST = 5,
+ WLAN_TDLS_CHANNEL_SWITCH_RESPONSE = 6,
+ WLAN_TDLS_PEER_PSM_REQUEST = 7,
+ WLAN_TDLS_PEER_PSM_RESPONSE = 8,
+ WLAN_TDLS_PEER_TRAFFIC_RESPONSE = 9,
+ WLAN_TDLS_DISCOVERY_REQUEST = 10,
+};
+
+/*
+ * TDLS capabililites to be enabled in the 5th byte of the
+ * @WLAN_EID_EXT_CAPABILITY information element
+ */
+#define WLAN_EXT_CAPA_TDLS_ENABLED BIT(5)
+#define WLAN_EXT_CAPA_TDLS_PROHIBITED BIT(6)
+
+/* TDLS specific payload type in the LLC/SNAP header */
+#define WLAN_TDLS_SNAP_RFTYPE 0x2
+
/**
* enum - mesh path selection protocol identifier
*
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index a3d99ff..49c38fc 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -83,6 +83,7 @@
#define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */
#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */
#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */
+#define ETH_P_TDLS 0x890D /* TDLS */
#define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */
#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index d1886b5..7d3b438 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -225,6 +225,18 @@ config MAC80211_VERBOSE_MHWMP_DEBUG

Do not select this option.

+config MAC80211_VERBOSE_TDLS_DEBUG
+ bool "Verbose TDLS debugging"
+ depends on MAC80211_DEBUG_MENU
+ ---help---
+ Selecting this option causes mac80211 to print out very
+ verbose TDLS selection debugging messages (when mac80211
+ is a TDLS STA).
+ It should not be selected on production systems as those
+ messages are remotely triggerable.
+
+ Do not select this option.
+
config MAC80211_DEBUG_COUNTERS
bool "Extra statistics for TX/RX debugging"
depends on MAC80211_DEBUG_MENU
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index b57ddf9..1adf823 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <net/net_namespace.h>
#include <linux/rcupdate.h>
+#include <linux/if_ether.h>
#include <net/cfg80211.h>
#include "ieee80211_i.h"
#include "driver-ops.h"
@@ -2120,6 +2121,317 @@ static int ieee80211_set_rekey_data(struct wiphy *wiphy,
return 0;
}

+static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb)
+{
+ u8 *pos = (void *)skb_put(skb, 7);
+
+ *pos++ = WLAN_EID_EXT_CAPABILITY;
+ *pos++ = 5; /* len */
+ *pos++ = 0x0;
+ *pos++ = 0x0;
+ *pos++ = 0x0;
+ *pos++ = 0x0;
+ *pos++ = WLAN_EXT_CAPA_TDLS_ENABLED;
+}
+
+static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ u16 capab;
+
+ capab = 0;
+ if (local->oper_channel->band != IEEE80211_BAND_2GHZ)
+ return capab;
+
+ if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
+ capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+ if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
+ capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
+
+ return capab;
+}
+
+static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, u8 *src_addr,
+ u8 *peer, u8 *bssid)
+{
+ struct ieee80211_tdls_lnkie *lnkid;
+
+ lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
+
+ lnkid->ie_type = WLAN_EID_LINK_ID;
+ lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
+
+ memcpy(lnkid->bssid, bssid, ETH_ALEN);
+ memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
+ memcpy(lnkid->resp_sta, peer, ETH_ALEN);
+}
+
+static int
+ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token,
+ u16 status_code, struct sk_buff *skb)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_tdls_data *tf;
+
+ tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
+
+ memcpy(tf->da, peer, ETH_ALEN);
+ memcpy(tf->sa, sdata->vif.addr, ETH_ALEN);
+ tf->ether_type = cpu_to_be16(ETH_P_TDLS);
+ tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
+
+ switch (action_code) {
+ case WLAN_TDLS_SETUP_REQUEST:
+ tf->category = WLAN_CATEGORY_TDLS;
+ tf->action_code = WLAN_TDLS_SETUP_REQUEST;
+
+ skb_put(skb, sizeof(tf->u.setup_req));
+ tf->u.setup_req.dialog_token = dialog_token;
+ tf->u.setup_req.capability =
+ cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
+
+ ieee80211_add_srates_ie(&sdata->vif, skb);
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb);
+ ieee80211_tdls_add_ext_capab(skb);
+ break;
+ case WLAN_TDLS_SETUP_RESPONSE:
+ tf->category = WLAN_CATEGORY_TDLS;
+ tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
+
+ skb_put(skb, sizeof(tf->u.setup_resp));
+ tf->u.setup_resp.status_code = cpu_to_le16(status_code);
+ tf->u.setup_resp.dialog_token = dialog_token;
+ tf->u.setup_resp.capability =
+ cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
+
+ ieee80211_add_srates_ie(&sdata->vif, skb);
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb);
+ ieee80211_tdls_add_ext_capab(skb);
+ break;
+ case WLAN_TDLS_SETUP_CONFIRM:
+ tf->category = WLAN_CATEGORY_TDLS;
+ tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
+
+ skb_put(skb, sizeof(tf->u.setup_cfm));
+ tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
+ tf->u.setup_cfm.dialog_token = dialog_token;
+ break;
+ case WLAN_TDLS_TEARDOWN:
+ tf->category = WLAN_CATEGORY_TDLS;
+ tf->action_code = WLAN_TDLS_TEARDOWN;
+
+ skb_put(skb, sizeof(tf->u.teardown));
+ tf->u.teardown.reason_code = cpu_to_le16(status_code);
+ break;
+ case WLAN_TDLS_DISCOVERY_REQUEST:
+ tf->category = WLAN_CATEGORY_TDLS;
+ tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
+
+ skb_put(skb, sizeof(tf->u.discover_req));
+ tf->u.discover_req.dialog_token = dialog_token;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token,
+ u16 status_code, struct sk_buff *skb)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_mgmt *mgmt;
+
+ mgmt = (void *)skb_put(skb, 24);
+ memset(mgmt, 0, 24);
+ memcpy(mgmt->da, peer, ETH_ALEN);
+ memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
+ memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
+
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION);
+
+ switch (action_code) {
+ case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
+ skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
+ mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
+ mgmt->u.action.u.tdls_discover_resp.action_code =
+ WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
+ mgmt->u.action.u.tdls_discover_resp.dialog_token =
+ dialog_token;
+ mgmt->u.action.u.tdls_discover_resp.capability =
+ cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
+
+ ieee80211_add_srates_ie(&sdata->vif, skb);
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb);
+ ieee80211_tdls_add_ext_capab(skb);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token,
+ u16 status_code, const u8 *extra_ies,
+ size_t extra_ies_len)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_tx_info *info;
+ struct sk_buff *skb = NULL;
+ bool send_direct;
+ int ret;
+
+ if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
+ return -ENOTSUPP;
+
+ /* make sure we are in managed mode, and associated */
+ if (sdata->vif.type != NL80211_IFTYPE_STATION ||
+ !sdata->u.mgd.associated)
+ return -EINVAL;
+
+#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
+ printk(KERN_DEBUG "TDLS mgmt action %d peer %pM\n", action_code, peer);
+#endif
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+ max(sizeof(struct ieee80211_mgmt),
+ sizeof(struct ieee80211_tdls_data)) +
+ 50 + /* supported rates */
+ 7 + /* ext capab */
+ extra_ies_len +
+ sizeof(struct ieee80211_tdls_lnkie));
+ if (!skb)
+ return -ENOMEM;
+
+ info = IEEE80211_SKB_CB(skb);
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ switch (action_code) {
+ case WLAN_TDLS_SETUP_REQUEST:
+ case WLAN_TDLS_SETUP_RESPONSE:
+ case WLAN_TDLS_SETUP_CONFIRM:
+ case WLAN_TDLS_TEARDOWN:
+ case WLAN_TDLS_DISCOVERY_REQUEST:
+ ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer,
+ action_code, dialog_token,
+ status_code, skb);
+ send_direct = false;
+ break;
+ case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
+ ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code,
+ dialog_token, status_code,
+ skb);
+ send_direct = true;
+ break;
+ default:
+ ret = -ENOTSUPP;
+ break;
+ }
+
+ if (ret < 0)
+ goto fail;
+
+ if (extra_ies_len)
+ memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
+
+ /* the TDLS link IE is always added last */
+ switch (action_code) {
+ case WLAN_TDLS_SETUP_REQUEST:
+ case WLAN_TDLS_SETUP_CONFIRM:
+ case WLAN_TDLS_TEARDOWN:
+ case WLAN_TDLS_DISCOVERY_REQUEST:
+ /* we are the initiator */
+ ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer,
+ sdata->u.mgd.bssid);
+ break;
+ case WLAN_TDLS_SETUP_RESPONSE:
+ case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
+ /* we are the responder */
+ ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr,
+ sdata->u.mgd.bssid);
+ break;
+ default:
+ ret = -ENOTSUPP;
+ goto fail;
+ }
+
+ if (send_direct) {
+ ieee80211_tx_skb(sdata, skb);
+ return 0;
+ }
+
+ /*
+ * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
+ * we should default to AC_VI.
+ */
+ switch (action_code) {
+ case WLAN_TDLS_SETUP_REQUEST:
+ case WLAN_TDLS_SETUP_RESPONSE:
+ skb_set_queue_mapping(skb, IEEE80211_AC_BK);
+ skb->priority = 2;
+ break;
+ default:
+ skb_set_queue_mapping(skb, IEEE80211_AC_VI);
+ skb->priority = 5;
+ break;
+ }
+
+ /* disable bottom halves when entering the Tx path */
+ local_bh_disable();
+ ret = ieee80211_subif_start_xmit(skb, dev);
+ local_bh_enable();
+
+ return ret;
+
+fail:
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, enum nl80211_tdls_operation oper)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
+ return -ENOTSUPP;
+
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return -EINVAL;
+
+#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
+ printk(KERN_DEBUG "TDLS oper %d peer %pM\n", oper, peer);
+#endif
+
+ switch (oper) {
+ case NL80211_TDLS_ENABLE_LINK:
+ break;
+ case NL80211_TDLS_DISABLE_LINK:
+ return sta_info_destroy_addr(sdata, peer);
+ case NL80211_TDLS_TEARDOWN:
+ case NL80211_TDLS_SETUP:
+ case NL80211_TDLS_DISCOVERY_REQ:
+ /* We don't support in-driver setup/teardown/discovery */
+ return -ENOTSUPP;
+ case NL80211_TDLS_DISABLE:
+ case NL80211_TDLS_ENABLE:
+ /* TODO */
+ return -ENOTSUPP;
+ default:
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -2183,4 +2495,6 @@ struct cfg80211_ops mac80211_config_ops = {
.set_ringparam = ieee80211_set_ringparam,
.get_ringparam = ieee80211_get_ringparam,
.set_rekey_data = ieee80211_set_rekey_data,
+ .tdls_oper = ieee80211_tdls_oper,
+ .tdls_mgmt = ieee80211_tdls_mgmt,
};
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index a5809a1..336ceb9 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -863,6 +863,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (local->ops->sched_scan_start)
local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;

+ /* mac80211 based drivers don't support internal TDLS setup */
+ if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)
+ local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
+
result = wiphy_register(local->hw.wiphy);
if (result < 0)
goto fail_wiphy_register;
--
1.7.4.1


2011-09-27 11:43:50

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 1/5] nl80211: support sending TDLS commands/frames

On Mon, 2011-09-26 at 13:54 +0300, Arik Nemtsov wrote:

> @@ -876,6 +884,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
> }
> CMD(set_channel, SET_CHANNEL);
> CMD(set_wds_peer, SET_WDS_PEER);
> + CMD(tdls_mgmt, TDLS_MGMT);

Should that maybe depend on the TLDS_EXTERNAL_SETUP flag to avoid
inconsistencies? Especially with mac80211 drivers?

> + CMD(tdls_oper, TDLS_OPER);

and maybe not advertise that if TDLS isn't support -- in particular so
that mac80211 drivers don't advertise it even though mac80211 might have
the hook.

> +static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
> +{
> + struct cfg80211_registered_device *rdev = info->user_ptr[0];
> + struct net_device *dev = info->user_ptr[1];
> + u8 action_code, dialog_token;
> + u16 status_code;
> + u8 *peer;
> +
> + if (!rdev->ops->tdls_mgmt)
> + return -EOPNOTSUPP;
> +
> + if (!info->attrs[NL80211_ATTR_TDLS_ACTION] ||
> + !info->attrs[NL80211_ATTR_STATUS_CODE] ||
> + !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] ||
> + !info->attrs[NL80211_ATTR_IE] ||
> + !info->attrs[NL80211_ATTR_MAC])
> + return -EINVAL;
> +
> + peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
> + action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
> + status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
> + dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
> +
> + return rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code,
> + dialog_token, status_code,
> + nla_data(info->attrs[NL80211_ATTR_IE]),
> + nla_len(info->attrs[NL80211_ATTR_IE]));
> +}

Shouldn't that return an error if TDLS_EXTERNAL_SETUP isn't set? At
least for some operations?


> +static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
> +{
> + struct cfg80211_registered_device *rdev = info->user_ptr[0];
> + struct net_device *dev = info->user_ptr[1];
> + enum nl80211_tdls_operation operation;
> + u8 *peer;
> +
> + if (!rdev->ops->tdls_oper)
> + return -EOPNOTSUPP;
> +
> + if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] ||
> + !info->attrs[NL80211_ATTR_MAC])
> + return -EINVAL;
> +
> + operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
> + peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
> +
> + return rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, operation);
> +}

Ditto here, if TDLS isn't supported it needs to return an error I think,
and if TLDS needs external setup it needs to return errors for the setup
operations I think?

johannes


2011-09-26 10:55:07

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 2/5] mac80211: standardize adding supported rates IEs

Relocate the mesh implementation of adding the (extended) supported
rates IE to util.c, anticipating its use by other parts of mac80211.

Signed-off-by: Arik Nemtsov <[email protected]>
Cc: Kalyan C Gaddam <[email protected]>
---
include/net/mac80211.h | 5 ++++
net/mac80211/mesh.c | 58 --------------------------------------------
net/mac80211/mesh.h | 4 ---
net/mac80211/mesh_plink.c | 4 +-
net/mac80211/tx.c | 4 +-
net/mac80211/util.c | 59 +++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 68 insertions(+), 66 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index c0f63fd..4dfead6 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3439,4 +3439,9 @@ void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
int rssi_max_thold);

void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif);
+
+int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb);
+
+int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif,
+ struct sk_buff *skb);
#endif /* MAC80211_H */
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index a4225ae..a7078fd 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -320,64 +320,6 @@ mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
return 0;
}

-int
-mesh_add_srates_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_supported_band *sband;
- int rate;
- u8 i, rates, *pos;
-
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- rates = sband->n_bitrates;
- if (rates > 8)
- rates = 8;
-
- if (skb_tailroom(skb) < rates + 2)
- return -ENOMEM;
-
- pos = skb_put(skb, rates + 2);
- *pos++ = WLAN_EID_SUPP_RATES;
- *pos++ = rates;
- for (i = 0; i < rates; i++) {
- rate = sband->bitrates[i].bitrate;
- *pos++ = (u8) (rate / 5);
- }
-
- return 0;
-}
-
-int
-mesh_add_ext_srates_ie(struct sk_buff *skb,
- struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_supported_band *sband;
- int rate;
- u8 i, exrates, *pos;
-
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- exrates = sband->n_bitrates;
- if (exrates > 8)
- exrates -= 8;
- else
- exrates = 0;
-
- if (skb_tailroom(skb) < exrates + 2)
- return -ENOMEM;
-
- if (exrates) {
- pos = skb_put(skb, exrates + 2);
- *pos++ = WLAN_EID_EXT_SUPP_RATES;
- *pos++ = exrates;
- for (i = 8; i < sband->n_bitrates; i++) {
- rate = sband->bitrates[i].bitrate;
- *pos++ = (u8) (rate / 5);
- }
- }
- return 0;
-}
-
int mesh_add_ds_params_ie(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata)
{
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 7118e8e..8c00e2d 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -210,10 +210,6 @@ int mesh_add_rsn_ie(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata);
int mesh_add_vendor_ies(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata);
-int mesh_add_srates_ie(struct sk_buff *skb,
- struct ieee80211_sub_if_data *sdata);
-int mesh_add_ext_srates_ie(struct sk_buff *skb,
- struct ieee80211_sub_if_data *sdata);
int mesh_add_ds_params_ie(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata);
void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 1213a23..9cc5029 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -185,8 +185,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
pos = skb_put(skb, 2);
memcpy(pos + 2, &plid, 2);
}
- if (mesh_add_srates_ie(skb, sdata) ||
- mesh_add_ext_srates_ie(skb, sdata) ||
+ if (ieee80211_add_srates_ie(&sdata->vif, skb) ||
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb) ||
mesh_add_rsn_ie(skb, sdata) ||
mesh_add_meshid_ie(skb, sdata) ||
mesh_add_meshconf_ie(skb, sdata))
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 7cd6c28..542272a 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2307,9 +2307,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
*pos++ = WLAN_EID_SSID;
*pos++ = 0x0;

- if (mesh_add_srates_ie(skb, sdata) ||
+ if (ieee80211_add_srates_ie(&sdata->vif, skb) ||
mesh_add_ds_params_ie(skb, sdata) ||
- mesh_add_ext_srates_ie(skb, sdata) ||
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb) ||
mesh_add_rsn_ie(skb, sdata) ||
mesh_add_meshid_ie(skb, sdata) ||
mesh_add_meshconf_ie(skb, sdata) ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 4b1466d..6926c99 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1353,3 +1353,62 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
_ieee80211_enable_rssi_reports(sdata, 0, 0);
}
EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
+
+int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_supported_band *sband;
+ int rate;
+ u8 i, rates, *pos;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ rates = sband->n_bitrates;
+ if (rates > 8)
+ rates = 8;
+
+ if (skb_tailroom(skb) < rates + 2)
+ return -ENOMEM;
+
+ pos = skb_put(skb, rates + 2);
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = rates;
+ for (i = 0; i < rates; i++) {
+ rate = sband->bitrates[i].bitrate;
+ *pos++ = (u8) (rate / 5);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ieee80211_add_srates_ie);
+
+int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_supported_band *sband;
+ int rate;
+ u8 i, exrates, *pos;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ exrates = sband->n_bitrates;
+ if (exrates > 8)
+ exrates -= 8;
+ else
+ exrates = 0;
+
+ if (skb_tailroom(skb) < exrates + 2)
+ return -ENOMEM;
+
+ if (exrates) {
+ pos = skb_put(skb, exrates + 2);
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos++ = exrates;
+ for (i = 8; i < sband->n_bitrates; i++) {
+ rate = sband->bitrates[i].bitrate;
+ *pos++ = (u8) (rate / 5);
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL(ieee80211_add_ext_srates_ie);
\ No newline at end of file
--
1.7.4.1


2011-09-27 21:24:52

by Arik Nemtsov

[permalink] [raw]
Subject: Re: [PATCH 4/5] nl80211/mac80211: allow adding TDLS peers as stations

On Tue, Sep 27, 2011 at 14:55, Johannes Berg <[email protected]> wrote:
> On Mon, 2011-09-26 at 13:54 +0300, Arik Nemtsov wrote:
>
>> @@ -811,6 +817,11 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
>>
>> ? ? ? sta_apply_parameters(local, sta, params);
>>
>> + ? ? if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
>> + ? ? ? ? (sta->flags & WLAN_STA_TDLS_PEER)) {
>> + ? ? ? ? ? ? return -ENOTSUPP;
>> + ? ? }
>
> I think this should maybe also make sure that the interface is in
> station mode? Otherwise it could get somewhat confusing. Also changes to
> the TDLS flag probably shouldn't be allowed.

Sure. I'll add some more guards.

>
> And this code might also be better in cfg80211, although this is only
> with external management, right?

There's a similar check in cfg80211 code, in nl80211_new_station().

>
>> --- a/net/wireless/nl80211.c
>> +++ b/net/wireless/nl80211.c
>> @@ -2521,18 +2521,18 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
>> - ? ? ? ? ? ? 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)))
>
> Why is the TDLS flag allowed to change?

I'll add some more TDLS specific guards in set_station as well.

>
>
>> + ? ? /*
>> + ? ? ?* Managed stations can only add TDLS peers, and only when the
>> + ? ? ?* wiphy supports it.
>> + ? ? ?*/
>> + ? ? 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)))
>> ? ? ? ? ? ? ? return -EINVAL;
>
> If the device does full TDLS by itself I don't think we should be
> allowed to add/remove stations?

Fair point. I'll add a EXTERNAL_SETUP check here.

>
> Maybe you need to describe the command sequences a little bit somewhere.
> I'm getting a bad feeling about adding stations without supported rates,
> and this is only when we have external management etc.
>
> Part of your argument for having the frame sending etc. in the kernel
> was that then it's more like managed mode, but all the manual station
> handling is very much unlike that.
>
> I'm beginning to think that maybe it should be handled through the TDLS
> operations instead, more implicitly?
>

As discussed on IRC, the added station is convenient for implementing
the TDLS Tx-lock during link setup. Stations are (almost)
automatically purged when disassociating, thereby clearing TDLS state.
It's also already part of the mac80211 Tx path, so no need to add
other elements.

Adding a station with no supported rates is a bit strange, but it is
clearly flagged as a TDLS peer sta and checks are in place in the Tx
path to prevent abuse.

Arik

2011-09-26 10:55:13

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 4/5] nl80211/mac80211: allow adding TDLS peers as stations

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 <[email protected]>
Cc: Kalyan C Gaddam <[email protected]>
---
include/linux/nl80211.h | 2 ++
net/mac80211/cfg.c | 11 +++++++++++
net/mac80211/mlme.c | 7 ++++---
net/mac80211/sta_info.h | 2 ++
net/wireless/nl80211.c | 20 +++++++++++++++-----
5 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 1582916..165a49c 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1421,6 +1421,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
*/
@@ -1431,6 +1432,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,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 1adf823..8a3168c 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -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);

sta->sta.uapsd_queues = params->uapsd_queues;
@@ -811,6 +817,11 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,

sta_apply_parameters(local, sta, params);

+ if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
+ (sta->flags & WLAN_STA_TDLS_PEER)) {
+ return -ENOTSUPP;
+ }
+
rate_control_rate_init(sta);

layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 1a59fb6..593a244 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -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);
@@ -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);
@@ -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);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 56a3d38..b6bd4e9 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -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,
@@ -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
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ed9e6d8..8e5184b 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2521,18 +2521,18 @@ 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)
- 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;
break;
case NL80211_IFTYPE_MESH_POINT:
@@ -2651,7 +2651,17 @@ 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;
+
+ /*
+ * Managed stations can only add TDLS peers, and only when the
+ * wiphy supports it.
+ */
+ 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)))
return -EINVAL;

err = get_vlan(info, rdev, &params.vlan);
--
1.7.4.1


2011-09-27 11:55:58

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 4/5] nl80211/mac80211: allow adding TDLS peers as stations

On Mon, 2011-09-26 at 13:54 +0300, Arik Nemtsov wrote:

> @@ -811,6 +817,11 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
>
> sta_apply_parameters(local, sta, params);
>
> + if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
> + (sta->flags & WLAN_STA_TDLS_PEER)) {
> + return -ENOTSUPP;
> + }

I think this should maybe also make sure that the interface is in
station mode? Otherwise it could get somewhat confusing. Also changes to
the TDLS flag probably shouldn't be allowed.

And this code might also be better in cfg80211, although this is only
with external management, right?

> --- a/net/wireless/nl80211.c
> +++ b/net/wireless/nl80211.c
> @@ -2521,18 +2521,18 @@ 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)
> - err = -EINVAL;

Hmm. Should this be dependent on TLDS somehow?

> 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)))

Why is the TDLS flag allowed to change?


> + /*
> + * Managed stations can only add TDLS peers, and only when the
> + * wiphy supports it.
> + */
> + 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)))
> return -EINVAL;

If the device does full TDLS by itself I don't think we should be
allowed to add/remove stations?



Maybe you need to describe the command sequences a little bit somewhere.
I'm getting a bad feeling about adding stations without supported rates,
and this is only when we have external management etc.

Part of your argument for having the frame sending etc. in the kernel
was that then it's more like managed mode, but all the manual station
handling is very much unlike that.

I'm beginning to think that maybe it should be handled through the TDLS
operations instead, more implicitly?

johannes


2011-09-27 11:50:11

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 3/5] mac80211: handle TDLS high-level commands and frames

On Mon, 2011-09-26 at 13:54 +0300, Arik Nemtsov wrote:

> +/*
> + * TDLS capabililites to be enabled in the 5th byte of the
> + * @WLAN_EID_EXT_CAPABILITY information element
> + */
> +#define WLAN_EXT_CAPA_TDLS_ENABLED BIT(5)
> +#define WLAN_EXT_CAPA_TDLS_PROHIBITED BIT(6)

Would it be useful to have the IE declared as a struct somewhere?


> +static int
> +ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
> + u8 *peer, u8 action_code, u8 dialog_token,
> + u16 status_code, struct sk_buff *skb)

All the code addition here makes me wonder if it'd be useful to move it
into a new tdls.c file and just call the right hooks from cfg.c? the cfg
file is pretty large already ... tdls wouldn't be huge, but still might
make sense?

johannes


2011-09-27 21:08:36

by Arik Nemtsov

[permalink] [raw]
Subject: Re: [PATCH 2/5] mac80211: standardize adding supported rates IEs

On Tue, Sep 27, 2011 at 14:46, Johannes Berg <[email protected]> wrote:
>> +EXPORT_SYMBOL(ieee80211_add_srates_ie);
>
>> +EXPORT_SYMBOL(ieee80211_add_ext_srates_ie);
>
> You shouldn't export these.
>
>> \ No newline at end of file
>
> And it's a good idea to have "\n" be the last character of the file :)
>

Will do.

Arik

2011-09-26 10:55:03

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 1/5] nl80211: support sending TDLS commands/frames

Add support for sending high-level TDLS commands and TDLS frames via
NL80211_CMD_TDLS_OPER and NL80211_CMD_TDLS_MGMT, respectively. Add
appropriate cfg80211 callbacks for lower level drivers.

Add wiphy capability flags for TDLS support and advertise them via
nl80211.

Signed-off-by: Arik Nemtsov <[email protected]>
Cc: Kalyan C Gaddam <[email protected]>
---
include/linux/nl80211.h | 46 ++++++++++++++++++++++++++++
include/net/cfg80211.h | 17 ++++++++++
net/wireless/nl80211.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 139 insertions(+), 1 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 460b12a..1582916 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -502,6 +502,9 @@
* @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace
* of PMKSA caching dandidates.
*
+ * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
+ * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -628,6 +631,9 @@ enum nl80211_commands {

NL80211_CMD_PMKSA_CANDIDATE,

+ NL80211_CMD_TDLS_OPER,
+ NL80211_CMD_TDLS_MGMT,
+
/* add new commands above here */

/* used to define NL80211_CMD_MAX below */
@@ -1078,6 +1084,20 @@ enum nl80211_commands {
* @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching
* candidate information, see &enum nl80211_pmksa_candidate_attr.
*
+ * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup
+ * request, link setup confirm, link teardown, etc.). Values are
+ * described in the TDLS (802.11z) specification.
+ * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a
+ * TDLS conversation between two devices.
+ * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see
+ * &enum nl80211_tdls_operation, represented as a u8.
+ * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate
+ * as a TDLS peer sta.
+ * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown
+ * procedures should be performed by sending TDLS packets via
+ * %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
+ * used for asking the driver to perform a TDLS operation.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1298,6 +1318,12 @@ enum nl80211_attrs {

NL80211_ATTR_PMKSA_CANDIDATE,

+ NL80211_ATTR_TDLS_ACTION,
+ NL80211_ATTR_TDLS_DIALOG_TOKEN,
+ NL80211_ATTR_TDLS_OPERATION,
+ NL80211_ATTR_TDLS_SUPPORT,
+ NL80211_ATTR_TDLS_EXTERNAL_SETUP,
+
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
@@ -2591,4 +2617,24 @@ enum nl80211_pmksa_candidate_attr {
MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1
};

+/**
+ * enum nl80211_tdls_operation - values for %NL80211_ATTR_TDLS_OPERATION
+ * @NL80211_TDLS_DISCOVERY_REQ: Send a TDLS discovery request
+ * @NL80211_TDLS_SETUP: Setup TDLS link
+ * @NL80211_TDLS_TEARDOWN: Teardown a TDLS link which is already established
+ * @NL80211_TDLS_ENABLE_LINK: Enable TDLS link
+ * @NL80211_TDLS_DISABLE_LINK: Disable TDLS link
+ * @NL80211_TDLS_ENABLE: (Re-)Enable TDLS operation
+ * @NL80211_TDLS_DISABLE: Disable TDLS operation
+ */
+enum nl80211_tdls_operation {
+ NL80211_TDLS_DISCOVERY_REQ,
+ NL80211_TDLS_SETUP,
+ NL80211_TDLS_TEARDOWN,
+ NL80211_TDLS_ENABLE_LINK,
+ NL80211_TDLS_DISABLE_LINK,
+ NL80211_TDLS_ENABLE,
+ NL80211_TDLS_DISABLE
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ccfdf3f..63a2e31 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1408,6 +1408,9 @@ struct cfg80211_gtk_rekey_data {
* @set_ringparam: Set tx and rx ring sizes.
*
* @get_ringparam: Get tx and rx ring current and maximum sizes.
+ *
+ * @tdls_mgmt: Transmit a TDLS management frame.
+ * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup).
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1590,6 +1593,12 @@ struct cfg80211_ops {

int (*set_rekey_data)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_gtk_rekey_data *data);
+
+ int (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token,
+ u16 status_code, const u8 *buf, size_t len);
+ int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, enum nl80211_tdls_operation oper);
};

/*
@@ -1642,6 +1651,12 @@ struct cfg80211_ops {
* @WIPHY_FLAG_SUPPORTS_FW_ROAM: The device supports roaming feature in the
* firmware.
* @WIPHY_FLAG_AP_UAPSD: The device supports uapsd on AP.
+ * @WIPHY_FLAG_SUPPORTS_TDLS: The device supports TDLS (802.11z) operation.
+ * @WIPHY_FLAG_TDLS_EXTERNAL_SETUP: The device does not handle TDLS (802.11z)
+ * link setup/discovery operations internally. Setup, discovery and
+ * teardown packets should be sent through the @NL80211_CMD_TDLS_MGMT
+ * command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be
+ * used for asking the driver/firmware to perform a TDLS operation.
*/
enum wiphy_flags {
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
@@ -1658,6 +1673,8 @@ enum wiphy_flags {
WIPHY_FLAG_ENFORCE_COMBINATIONS = BIT(12),
WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13),
WIPHY_FLAG_AP_UAPSD = BIT(14),
+ WIPHY_FLAG_SUPPORTS_TDLS = BIT(15),
+ WIPHY_FLAG_TDLS_EXTERNAL_SETUP = BIT(16),
};

/**
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c26a1da..ed9e6d8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -191,6 +191,11 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
.len = IEEE80211_MAX_DATA_LEN },
[NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
[NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
+ [NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 },
+ [NL80211_ATTR_TDLS_DIALOG_TOKEN] = { .type = NLA_U8 },
+ [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
+ [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
+ [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
};

/* policy for the key attributes */
@@ -731,9 +736,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_MESH_AUTH);
if (dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD)
NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_AP_UAPSD);
-
if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM)
NLA_PUT_FLAG(msg, NL80211_ATTR_ROAM_SUPPORT);
+ if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_SUPPORT);
+ if (dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP);

NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES,
sizeof(u32) * dev->wiphy.n_cipher_suites,
@@ -876,6 +884,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
}
CMD(set_channel, SET_CHANNEL);
CMD(set_wds_peer, SET_WDS_PEER);
+ CMD(tdls_mgmt, TDLS_MGMT);
+ CMD(tdls_oper, TDLS_OPER);
if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
CMD(sched_scan_start, START_SCHED_SCAN);

@@ -4972,6 +4982,55 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
return rdev->ops->flush_pmksa(&rdev->wiphy, dev);
}

+static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ u8 action_code, dialog_token;
+ u16 status_code;
+ u8 *peer;
+
+ if (!rdev->ops->tdls_mgmt)
+ return -EOPNOTSUPP;
+
+ if (!info->attrs[NL80211_ATTR_TDLS_ACTION] ||
+ !info->attrs[NL80211_ATTR_STATUS_CODE] ||
+ !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] ||
+ !info->attrs[NL80211_ATTR_IE] ||
+ !info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]);
+ status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
+ dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
+
+ return rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code,
+ dialog_token, status_code,
+ nla_data(info->attrs[NL80211_ATTR_IE]),
+ nla_len(info->attrs[NL80211_ATTR_IE]));
+}
+
+static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ enum nl80211_tdls_operation operation;
+ u8 *peer;
+
+ if (!rdev->ops->tdls_oper)
+ return -EOPNOTSUPP;
+
+ if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] ||
+ !info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
+ peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ return rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, operation);
+}
+
static int nl80211_remain_on_channel(struct sk_buff *skb,
struct genl_info *info)
{
@@ -6284,6 +6343,22 @@ static struct genl_ops nl80211_ops[] = {
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_TDLS_MGMT,
+ .doit = nl80211_tdls_mgmt,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL80211_CMD_TDLS_OPER,
+ .doit = nl80211_tdls_oper,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
};

static struct genl_multicast_group nl80211_mlme_mcgrp = {
--
1.7.4.1


2011-09-26 10:55:15

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 5/5] mac80211: data path modification for TDLS peers

Mark the STA entries of enabled TDLS peers with a new "peer authorized"
flag.

During link setup, allow special TDLS setup frames through the AP, but
otherwise drop all packets destined to the peer. This is required by the
TDLS (802.11z) specification in order to prevent reordering of MSDUs
between the AP and direct paths.

When setup completes and the peer is authorized, send data directly,
bypassing the AP.

In the Rx path, allow data to be received directly from TDLS peers.

Signed-off-by: Arik Nemtsov <[email protected]>
Cc: Kalyan C Gaddam <[email protected]>
---
net/mac80211/cfg.c | 10 ++++++++++
net/mac80211/sta_info.h | 5 ++++-
net/mac80211/tx.c | 42 ++++++++++++++++++++++++++++++++++++++----
net/wireless/util.c | 5 +++--
4 files changed, 55 insertions(+), 7 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 8a3168c..729f5c3 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2410,6 +2410,7 @@ fail:
static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
u8 *peer, enum nl80211_tdls_operation oper)
{
+ struct sta_info *sta;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);

if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
@@ -2424,6 +2425,15 @@ static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,

switch (oper) {
case NL80211_TDLS_ENABLE_LINK:
+ rcu_read_lock();
+ sta = sta_info_get(sdata, peer);
+ if (!sta) {
+ rcu_read_unlock();
+ return -ENOLINK;
+ }
+
+ set_sta_flags(sta, WLAN_STA_TDLS_PEER_AUTH);
+ rcu_read_unlock();
break;
case NL80211_TDLS_DISABLE_LINK:
return sta_info_destroy_addr(sdata, peer);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index b6bd4e9..c10e2e8 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -45,7 +45,9 @@
* 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.
+ * @WLAN_STA_TDLS_PEER: Station is a TDLS peer.
+ * @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct
+ * packets. This means the link is enabled.
*/
enum ieee80211_sta_info_flags {
WLAN_STA_AUTH = 1<<0,
@@ -63,6 +65,7 @@ enum ieee80211_sta_info_flags {
WLAN_STA_PSPOLL = 1<<13,
WLAN_STA_PS_DRIVER_BUF = 1<<14,
WLAN_STA_TDLS_PEER = 1<<15,
+ WLAN_STA_TDLS_PEER_AUTH = 1<<16,
};

#define STA_TID_NUM 16
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 542272a..0ca1688 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1726,6 +1726,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct sta_info *sta = NULL;
u32 sta_flags = 0;
struct sk_buff *tmp_skb;
+ bool tdls_direct = false;

if (unlikely(skb->len < ETH_HLEN)) {
ret = NETDEV_TX_OK;
@@ -1837,11 +1838,43 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
break;
#endif
case NL80211_IFTYPE_STATION:
- memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
- if (sdata->u.mgd.use_4addr &&
- cpu_to_be16(ethertype) != sdata->control_port_protocol) {
- fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
+ if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
+ rcu_read_lock();
+ sta = sta_info_get(sdata, skb->data);
+ if (sta)
+ sta_flags = get_sta_flags(sta);
+ rcu_read_unlock();
+
+ /*
+ * If the TDLS link is enabled, send everything
+ * directly. Otherwise, allow TDLS setup frames
+ * to be transmitted indirectly.
+ */
+ tdls_direct =
+ (sta_flags & WLAN_STA_TDLS_PEER) &&
+ ((sta_flags & WLAN_STA_TDLS_PEER_AUTH) ||
+ !(ethertype == ETH_P_TDLS && skb->len > 14 &&
+ skb->data[14] == WLAN_TDLS_SNAP_RFTYPE));
+ }
+
+ if (tdls_direct) {
+ /* link during setup - throw out frames to peer */
+ if (!(sta_flags & WLAN_STA_TDLS_PEER_AUTH)) {
+ ret = NETDEV_TX_OK;
+ goto fail;
+ }
+
+ /* DA SA BSSID */
+ memcpy(hdr.addr1, skb->data, ETH_ALEN);
+ memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+ memcpy(hdr.addr3, sdata->u.mgd.bssid, ETH_ALEN);
+ hdrlen = 24;
+ } else if (sdata->u.mgd.use_4addr &&
+ cpu_to_be16(ethertype) != sdata->control_port_protocol) {
+ fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
+ IEEE80211_FCTL_TODS);
/* RA TA DA SA */
+ memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
memcpy(hdr.addr3, skb->data, ETH_ALEN);
memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
@@ -1849,6 +1882,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
} else {
fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
/* BSSID SA DA */
+ memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
memcpy(hdr.addr3, skb->data, ETH_ALEN);
hdrlen = 24;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 39dbf4a..13e6596 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -392,8 +392,9 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
}
break;
case cpu_to_le16(0):
- if (iftype != NL80211_IFTYPE_ADHOC)
- return -1;
+ if (iftype != NL80211_IFTYPE_ADHOC &&
+ iftype != NL80211_IFTYPE_STATION)
+ return -1;
break;
}

--
1.7.4.1


2011-09-27 21:12:53

by Arik Nemtsov

[permalink] [raw]
Subject: Re: [PATCH 3/5] mac80211: handle TDLS high-level commands and frames

On Tue, Sep 27, 2011 at 14:50, Johannes Berg <[email protected]> wrote:
> On Mon, 2011-09-26 at 13:54 +0300, Arik Nemtsov wrote:
>
>> +/*
>> + * TDLS capabililites to be enabled in the 5th byte of the
>> + * @WLAN_EID_EXT_CAPABILITY information element
>> + */
>> +#define WLAN_EXT_CAPA_TDLS_ENABLED ? BIT(5)
>> +#define WLAN_EXT_CAPA_TDLS_PROHIBITED ? ? ? ?BIT(6)
>
> Would it be useful to have the IE declared as a struct somewhere?

It's really just a bit-mask, and a variable length one as it is. But
I'll change the name to make it more palatable. Something like
WLAN_EXT_CAPA5_TDLS_ENABLED :)

>
>
>> +static int
>> +ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?u8 *peer, u8 action_code, u8 dialog_token,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?u16 status_code, struct sk_buff *skb)
>
> All the code addition here makes me wonder if it'd be useful to move it
> into a new tdls.c file and just call the right hooks from cfg.c? the cfg
> file is pretty large already ... tdls wouldn't be huge, but still might
> make sense?

As discussed on IRC, this code is pretty much stateless, and it's not
a lot of code. We agreed we can keep it in cfg.c for now.

Arik

2011-09-27 11:46:35

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 2/5] mac80211: standardize adding supported rates IEs

On Mon, 2011-09-26 at 13:54 +0300, Arik Nemtsov wrote:
> Relocate the mesh implementation of adding the (extended) supported
> rates IE to util.c, anticipating its use by other parts of mac80211.
>
> Signed-off-by: Arik Nemtsov <[email protected]>
> Cc: Kalyan C Gaddam <[email protected]>

Thanks! :)

> +EXPORT_SYMBOL(ieee80211_add_srates_ie);

> +EXPORT_SYMBOL(ieee80211_add_ext_srates_ie);

You shouldn't export these.

> \ No newline at end of file

And it's a good idea to have "\n" be the last character of the file :)

johannes