2019-04-11 20:47:47

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH v4 0/3] wireless: Add support to probe unexercised mesh link

Consider below mesh topology.

MP1
/ \
/ \
MP2 --- MP3

Assume that even though MP1 & MP3 have direct mesh links, the path was
established via MP2. (MP1 <-> MP2 <-> MP3). The 1-hop mesh link MP1 <-> MP3
never be excercised till the current path is terminated. As of now, there
is no option to send data frame to pick other than primary path. So mesh
link metric between MP1 & MP3 never be updated. This series allows user
to send data to 1-hop mesh peers through unexercised mesh path.

-Rajkumar

v4: Rebased on mac80211-next top and fixed compile errors
v3: Rebased the changes on TOT

Rajkumar Manoharan (3):
cfg80211: add support to probe unexercised mesh link
mac80211: add option for setting control flags
mac80211: probe unexercised mesh links

include/net/cfg80211.h | 5 ++++
include/net/mac80211.h | 2 ++
include/uapi/linux/nl80211.h | 16 +++++++++++++
net/mac80211/cfg.c | 1 +
net/mac80211/ieee80211_i.h | 5 +++-
net/mac80211/mesh_hwmp.c | 4 ++++
net/mac80211/tdls.c | 2 +-
net/mac80211/tx.c | 54 ++++++++++++++++++++++++++++++++++++++------
net/wireless/nl80211.c | 53 +++++++++++++++++++++++++++++++++++++++++++
net/wireless/rdev-ops.h | 13 +++++++++++
net/wireless/trace.h | 18 +++++++++++++++
11 files changed, 164 insertions(+), 9 deletions(-)

--
1.9.1



2019-04-11 20:47:50

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH v4 1/3] cfg80211: add support to probe unexercised mesh link

Adding support to allow mesh HWMP to measure link metrics on unexercised
direct mesh path by sending some data frames to other mesh points which
are not currently selected as a primary traffic path but only 1 hop away.
The absence of the primary path to the chosen node makes it necessary to
apply some form of marking on a chosen packet stream so that the packets
can be properly steered to the selected node for testing, and not by the
regular mesh path lookup.

Tested-by: Pradeep Kumar Chitrapu <[email protected]>
Signed-off-by: Rajkumar Manoharan <[email protected]>
---
v4: Rebased and fixed compile warnings

include/net/cfg80211.h | 5 +++++
include/uapi/linux/nl80211.h | 17 ++++++++++++++
net/wireless/nl80211.c | 53 ++++++++++++++++++++++++++++++++++++++++++++
net/wireless/rdev-ops.h | 13 +++++++++++
net/wireless/trace.h | 18 +++++++++++++++
5 files changed, 106 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 944de1802210..298301525f9f 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3501,6 +3501,9 @@ struct cfg80211_update_owe_info {
* @update_owe_info: Provide updated OWE info to driver. Driver implementing SME
* but offloading OWE processing to the user space will get the updated
* DH IE through this interface.
+ *
+ * @probe_mesh_link: Probe direct Mesh peer's link quality by sending data frame
+ * and overrule HWMP path selection algorithm.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -3817,6 +3820,8 @@ struct cfg80211_ops {
struct cfg80211_pmsr_request *request);
int (*update_owe_info)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_update_owe_info *owe_info);
+ int (*probe_mesh_link)(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *buf, size_t len);
};

/*
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 25f70dd2b583..6f09d1500960 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1070,6 +1070,21 @@
* OWE AKM by the host drivers that implement SME but rely
* on the user space for the cryptographic/DH IE processing in AP mode.
*
+ * @NL80211_CMD_PROBE_MESH_LINK: The requirement for mesh link metric
+ * refreshing, is that from one mesh point we be able to send some data
+ * frames to other mesh points which are not currently selected as a
+ * primary traffic path, but which are only 1 hop away. The absence of
+ * the primary path to the chosen node makes it necessary to apply some
+ * form of marking on a chosen packet stream so that the packets can be
+ * properly steered to the selected node for testing, and not by the
+ * regular mesh path lookup. Further, the packets must be of type data
+ * so that the rate control (often embedded in firmware) is used for
+ * rate selection.
+ *
+ * Here attribute %NL80211_ATTR_MAC is used to specify connected mesh
+ * peer MAC address and %NL80211_ATTR_FRAME is used to specify the frame
+ * content. The frame is ethernet data.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1292,6 +1307,8 @@ enum nl80211_commands {

NL80211_CMD_UPDATE_OWE_INFO,

+ NL80211_CMD_PROBE_MESH_LINK,
+
/* add new commands above here */

/* used to define NL80211_CMD_MAX below */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 846d25d2dc82..2cdc1a55d724 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -13405,6 +13405,52 @@ static int nl80211_update_owe_info(struct sk_buff *skb, struct genl_info *info)
return rdev_update_owe_info(rdev, dev, &owe_info);
}

+static int nl80211_probe_mesh_link(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];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct station_info sinfo = {};
+ const u8 *buf;
+ size_t len;
+ u8 *dest;
+ int err;
+
+ if (!rdev->ops->probe_mesh_link || !rdev->ops->get_station)
+ return -EOPNOTSUPP;
+
+ if (!info->attrs[NL80211_ATTR_MAC] ||
+ !info->attrs[NL80211_ATTR_FRAME]) {
+ GENL_SET_ERR_MSG(info, "Frame or MAC missing");
+ return -EINVAL;
+ }
+
+ wdev_lock(wdev);
+ if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
+ wdev_unlock(wdev);
+ err = -EOPNOTSUPP;
+ return err;
+ }
+ wdev_unlock(wdev);
+
+ dest = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
+ len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
+
+ if (len < sizeof(struct ethhdr))
+ return -EINVAL;
+
+ if (!ether_addr_equal(buf, dest) || is_multicast_ether_addr(buf) ||
+ !ether_addr_equal(buf + ETH_ALEN, dev->dev_addr))
+ return -EINVAL;
+
+ err = rdev_get_station(rdev, dev, dest, &sinfo);
+ if (err)
+ return err;
+
+ return rdev_probe_mesh_link(rdev, dev, dest, buf, len);
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -14242,6 +14288,13 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_PROBE_MESH_LINK,
+ .doit = nl80211_probe_mesh_link,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
};

static struct genl_family nl80211_fam __ro_after_init = {
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 18437a9deb54..e853a4fe6f97 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1286,4 +1286,17 @@ static inline int rdev_update_owe_info(struct cfg80211_registered_device *rdev,
return ret;
}

+static inline int
+rdev_probe_mesh_link(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *dest,
+ const void *buf, size_t len)
+{
+ int ret;
+
+ trace_rdev_probe_mesh_link(&rdev->wiphy, dev, dest, buf, len);
+ ret = rdev->ops->probe_mesh_link(&rdev->wiphy, dev, buf, len);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
#endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 488ef2ce8231..2abfff925aac 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -3421,6 +3421,24 @@
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer))
);

+TRACE_EVENT(rdev_probe_mesh_link,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ const u8 *dest, const u8 *buf, size_t len),
+ TP_ARGS(wiphy, netdev, dest, buf, len),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ MAC_ENTRY(dest)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ MAC_ASSIGN(dest, dest);
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT,
+ WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dest))
+);
+
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */

#undef TRACE_INCLUDE_PATH
--
1.9.1


2019-04-11 20:47:51

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH v4 2/3] mac80211: add option for setting control flags

Allows setting of control flags of skb cb - if needed -
when calling ieee80211_subif_start_xmit().

Tested-by: Pradeep Kumar Chitrapu <[email protected]>
Signed-off-by: Rajkumar Manoharan <[email protected]>
---
net/mac80211/ieee80211_i.h | 3 ++-
net/mac80211/tdls.c | 2 +-
net/mac80211/tx.c | 18 +++++++++++-------
3 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 861bf8312177..8a99bcfe81ec 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1762,7 +1762,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev);
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev,
- u32 info_flags);
+ u32 info_flags,
+ u32 ctrl_flags);
void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
struct sk_buff_head *skbs);
struct sk_buff *
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index d30690d79a58..24c37f91ca46 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -1056,7 +1056,7 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata,

/* disable bottom halves when entering the Tx path */
local_bh_disable();
- __ieee80211_subif_start_xmit(skb, dev, flags);
+ __ieee80211_subif_start_xmit(skb, dev, flags, 0);
local_bh_enable();

return ret;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 1e82ba7c34e3..ffe35fc89351 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2432,6 +2432,7 @@ static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
* @sdata: virtual interface to build the header for
* @skb: the skb to build the header in
* @info_flags: skb flags to set
+ * @ctrl_flags: info control flags to set
*
* This function takes the skb with 802.3 header and reformats the header to
* the appropriate IEEE 802.11 header based on which interface the packet is
@@ -2447,7 +2448,7 @@ static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
*/
static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, u32 info_flags,
- struct sta_info *sta)
+ struct sta_info *sta, u32 ctrl_flags)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info;
@@ -2824,6 +2825,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
info->flags = info_flags;
info->ack_frame_id = info_id;
info->band = band;
+ info->control.flags = ctrl_flags;

return skb;
free:
@@ -3805,7 +3807,8 @@ void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)

void __ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev,
- u32 info_flags)
+ u32 info_flags,
+ u32 ctrl_flags)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
@@ -3879,7 +3882,8 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
skb->prev = NULL;
skb->next = NULL;

- skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
+ skb = ieee80211_build_hdr(sdata, skb, info_flags,
+ sta, ctrl_flags);
if (IS_ERR(skb))
goto out;

@@ -4019,9 +4023,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
__skb_queue_head_init(&queue);
ieee80211_convert_to_unicast(skb, dev, &queue);
while ((skb = __skb_dequeue(&queue)))
- __ieee80211_subif_start_xmit(skb, dev, 0);
+ __ieee80211_subif_start_xmit(skb, dev, 0, 0);
} else {
- __ieee80211_subif_start_xmit(skb, dev, 0);
+ __ieee80211_subif_start_xmit(skb, dev, 0, 0);
}

return NETDEV_TX_OK;
@@ -4046,7 +4050,7 @@ struct sk_buff *
goto out;
}

- skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
+ skb = ieee80211_build_hdr(sdata, skb, info_flags, sta, 0);
if (IS_ERR(skb))
goto out;

@@ -5084,7 +5088,7 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
skb_reset_mac_header(skb);

local_bh_disable();
- __ieee80211_subif_start_xmit(skb, skb->dev, flags);
+ __ieee80211_subif_start_xmit(skb, skb->dev, flags, 0);
local_bh_enable();

return 0;
--
1.9.1


2019-04-11 20:47:54

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH v4 3/3] mac80211: probe unexercised mesh links

The requirement for mesh link metric refreshing, is that from one
mesh point we be able to send some data frames to other mesh points
which are not currently selected as a primary traffic path, but which
are only 1 hop away. The absence of the primary path to the chosen node
makes it necessary to apply some form of marking on a chosen packet
stream so that the packets can be properly steered to the selected node
for testing, and not by the regular mesh path lookup.

Tested-by: Pradeep Kumar Chitrapu <[email protected]>
Signed-off-by: Rajkumar Manoharan <[email protected]>
---
v2: fix addr1 for injected frames
v3: bugfix in filling DA

include/net/mac80211.h | 2 ++
net/mac80211/cfg.c | 1 +
net/mac80211/ieee80211_i.h | 2 ++
net/mac80211/mesh_hwmp.c | 4 ++++
net/mac80211/tx.c | 36 ++++++++++++++++++++++++++++++++++++
5 files changed, 45 insertions(+)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index d66fbfe8d55d..76a443f32fc8 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -807,6 +807,7 @@ enum mac80211_tx_info_flags {
* @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information
* @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame
* @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xmit path
+ * @IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP: This frame skips mesh path lookup
*
* These flags are used in tx_info->control.flags.
*/
@@ -816,6 +817,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_CTRL_RATE_INJECT = BIT(2),
IEEE80211_TX_CTRL_AMSDU = BIT(3),
IEEE80211_TX_CTRL_FAST_XMIT = BIT(4),
+ IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP = BIT(5),
};

/*
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index ba6e4080d63d..52e6a091b7e4 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -4035,4 +4035,5 @@ static int ieee80211_get_txq_stats(struct wiphy *wiphy,
.get_ftm_responder_stats = ieee80211_get_ftm_responder_stats,
.start_pmsr = ieee80211_start_pmsr,
.abort_pmsr = ieee80211_abort_pmsr,
+ .probe_mesh_link = ieee80211_probe_mesh_link,
};
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8a99bcfe81ec..1cd6a8bb17f2 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1780,6 +1780,8 @@ void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb,
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len,
const u8 *dest, __be16 proto, bool unencrypted);
+int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *buf, size_t len);

/* HT */
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 2c5929c0fa62..bf8e13cd5fd1 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -1135,6 +1135,10 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
if (ieee80211_is_qos_nullfunc(hdr->frame_control))
return 0;

+ /* Allow injected packets to bypass mesh routing */
+ if (info->control.flags & IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP)
+ return 0;
+
if (!mesh_nexthop_lookup(sdata, skb))
return 0;

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index ffe35fc89351..2b16a2527a6a 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2607,6 +2607,13 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
goto free;
}
band = chanctx_conf->def.chan->band;
+
+ /* For injected frames, fill RA right away as nexthop lookup
+ * will be skipped.
+ */
+ if ((ctrl_flags & IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP) &&
+ is_zero_ether_addr(hdr.addr1))
+ memcpy(hdr.addr1, skb->data, ETH_ALEN);
break;
#endif
case NL80211_IFTYPE_STATION:
@@ -5093,3 +5100,32 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,

return 0;
}
+
+int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *buf, size_t len)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
+ struct sk_buff *skb;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + len +
+ 30 + /* header size */
+ 18); /* 11s header size */
+ if (!skb)
+ return -ENOMEM;
+
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ skb_put_data(skb, buf, len);
+
+ skb->dev = dev;
+ skb->protocol = htons(ETH_P_802_3);
+ skb_reset_network_header(skb);
+ skb_reset_mac_header(skb);
+
+ local_bh_disable();
+ __ieee80211_subif_start_xmit(skb, skb->dev, 0,
+ IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP);
+ local_bh_enable();
+
+ return 0;
+}
--
1.9.1