The following patch adds NL80211_CMD_GET_MPP as a new nl80211 command that
allows to query the content of the 'mesh proxy path' table of mac80211s via
'get' or 'dump' operation.
Signed-off-by: Henning Rogge <[email protected]>
---
include/net/cfg80211.h | 7 ++++
include/uapi/linux/nl80211.h | 6 +++
net/mac80211/cfg.c | 53 ++++++++++++++++++++++++
net/mac80211/mesh.h | 3 ++
net/mac80211/mesh_pathtbl.c | 31 ++++++++++++++
net/wireless/nl80211.c | 99 ++++++++++++++++++++++++++++++++++++++++++++
net/wireless/rdev-ops.h | 27 +++++++++++-
net/wireless/trace.h | 45 ++++++++++++++++++++
8 files changed, 270 insertions(+), 1 deletion(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 0a080c4..68fbcf5 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2139,6 +2139,8 @@ struct cfg80211_qos_map {
* @change_mpath: change a given mesh path
* @get_mpath: get a mesh path for the given parameters
* @dump_mpath: dump mesh path callback -- resume dump at index @idx
+ * @get_mpp: get a mesh proxy path for the given parameters
+ * @dump_mpp: dump mesh proxy path callback -- resume dump at index @idx
* @join_mesh: join the mesh network with the specified parameters
* (invoked with the wireless_dev mutex held)
* @leave_mesh: leave the current mesh network
@@ -2378,6 +2380,11 @@ struct cfg80211_ops {
int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev,
int idx, u8 *dst, u8 *next_hop,
struct mpath_info *pinfo);
+ int (*get_mpp)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst, u8 *mpp, struct mpath_info *pinfo);
+ int (*dump_mpp)(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *dst, u8 *mpp,
+ struct mpath_info *pinfo);
int (*get_mesh_config)(struct wiphy *wiphy,
struct net_device *dev,
struct mesh_config *conf);
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index f1db15b..80cff48 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -722,6 +722,10 @@
* QoS mapping is relevant for IP packets, it is only valid during an
* association. This is cleared on disassociation and AP restart.
*
+ * @NL80211_CMD_GET_MPP: Get mesh path attributes for mesh proxy path to
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -893,6 +897,8 @@ enum nl80211_commands {
NL80211_CMD_SET_QOS_MAP,
+ NL80211_CMD_GET_MPP,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 927b4ea..2b85eed 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1511,6 +1511,57 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
+static void mpp_set_pinfo(struct mesh_path *mpath, u8 *mpp,
+ struct mpath_info *pinfo)
+{
+ memset(pinfo, 0, sizeof(*pinfo));
+ memcpy(mpp, mpath->mpp, ETH_ALEN);
+
+ pinfo->generation = mpp_paths_generation;
+}
+
+static int ieee80211_get_mpp(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst, u8 *mpp, struct mpath_info *pinfo)
+
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct mesh_path *mpath;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ rcu_read_lock();
+ mpath = mpp_path_lookup(sdata, dst);
+ if (!mpath) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+ memcpy(dst, mpath->dst, ETH_ALEN);
+ mpp_set_pinfo(mpath, mpp, pinfo);
+ rcu_read_unlock();
+ return 0;
+}
+
+static int ieee80211_dump_mpp(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *dst, u8 *mpp,
+ struct mpath_info *pinfo)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct mesh_path *mpath;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ rcu_read_lock();
+ mpath = mpp_path_lookup_by_idx(sdata, idx);
+ if (!mpath) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+ memcpy(dst, mpath->dst, ETH_ALEN);
+ mpp_set_pinfo(mpath, mpp, pinfo);
+ rcu_read_unlock();
+ return 0;
+}
+
static int ieee80211_get_mesh_config(struct wiphy *wiphy,
struct net_device *dev,
struct mesh_config *conf)
@@ -3507,6 +3558,8 @@ const struct cfg80211_ops mac80211_config_ops = {
.change_mpath = ieee80211_change_mpath,
.get_mpath = ieee80211_get_mpath,
.dump_mpath = ieee80211_dump_mpath,
+ .get_mpp = ieee80211_get_mpp,
+ .dump_mpp = ieee80211_dump_mpp,
.update_mesh_config = ieee80211_update_mesh_config,
.get_mesh_config = ieee80211_get_mesh_config,
.join_mesh = ieee80211_join_mesh,
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index f39a19f..50c8473 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -270,6 +270,8 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
const u8 *dst, const u8 *mpp);
struct mesh_path *
mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx);
+struct mesh_path *
+mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx);
void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
void mesh_path_expire(struct ieee80211_sub_if_data *sdata);
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
@@ -317,6 +319,7 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);
bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
extern int mesh_paths_generation;
+extern int mpp_paths_generation;
#ifdef CONFIG_MAC80211_MESH
static inline
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index cf032a8..8630963 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -44,6 +44,7 @@ static struct mesh_table __rcu *mesh_paths;
static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */
int mesh_paths_generation;
+int mpp_paths_generation;
/* This lock will have the grow table function as writer and add / delete nodes
* as readers. RCU provides sufficient protection only when reading the table
@@ -410,6 +411,33 @@ mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
}
/**
+ * mpp_path_lookup_by_idx - look up a path in the proxy path table by its index
+ * @idx: index
+ * @sdata: local subif, or NULL for all entries
+ *
+ * Returns: pointer to the proxy path structure, or NULL if not found.
+ *
+ * Locking: must be called within a read rcu section.
+ */
+struct mesh_path *
+mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
+{
+ struct mesh_table *tbl = rcu_dereference(mpp_paths);
+ struct mpath_node *node;
+ int i;
+ int j = 0;
+
+ for_each_mesh_entry(tbl, node, i) {
+ if (sdata && node->mpath->sdata != sdata)
+ continue;
+ if (j++ == idx)
+ return node->mpath;
+ }
+
+ return NULL;
+}
+
+/**
* mesh_path_add_gate - add the given mpath to a mesh gate to our path table
* @mpath: gate path to add to table
*/
@@ -691,6 +719,9 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
spin_unlock(&tbl->hashwlock[hash_idx]);
read_unlock_bh(&pathtbl_resize_lock);
+
+ mpp_paths_generation++;
+
if (grow) {
set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags);
ieee80211_queue_work(&local->hw, &sdata->work);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index df7b133..1e33f2f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4581,6 +4581,96 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
return rdev_del_mpath(rdev, dev, dst);
}
+static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ int err;
+ struct net_device *dev = info->user_ptr[1];
+ struct mpath_info pinfo;
+ struct sk_buff *msg;
+ u8 *dst = NULL;
+ u8 mpp[ETH_ALEN];
+
+ memset(&pinfo, 0, sizeof(pinfo));
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ if (!rdev->ops->get_mpp)
+ return -EOPNOTSUPP;
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+ return -EOPNOTSUPP;
+
+ err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo);
+ if (err)
+ return err;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
+ dev, dst, mpp, &pinfo) < 0) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ return genlmsg_reply(msg, info);
+}
+
+static int nl80211_dump_mpp(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ struct mpath_info pinfo;
+ struct cfg80211_registered_device *rdev;
+ struct wireless_dev *wdev;
+ u8 dst[ETH_ALEN];
+ u8 mpp[ETH_ALEN];
+ int path_idx = cb->args[2];
+ int err;
+
+ err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
+ if (err)
+ return err;
+
+ if (!rdev->ops->dump_mpp) {
+ err = -EOPNOTSUPP;
+ goto out_err;
+ }
+
+ if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
+ err = -EOPNOTSUPP;
+ goto out_err;
+ }
+
+ while (1) {
+ err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst,
+ mpp, &pinfo);
+ if (err == -ENOENT)
+ break;
+ if (err)
+ goto out_err;
+
+ if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+ wdev->netdev, dst, mpp,
+ &pinfo) < 0)
+ goto out;
+
+ path_idx++;
+ }
+
+ out:
+ cb->args[2] = path_idx;
+ err = skb->len;
+ out_err:
+ nl80211_finish_wdev_dump(rdev);
+ return err;
+}
+
static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -9603,6 +9693,15 @@ static const struct genl_ops nl80211_ops[] = {
NL80211_FLAG_NEED_RTNL,
},
{
+ .cmd = NL80211_CMD_GET_MPP,
+ .doit = nl80211_get_mpp,
+ .dumpit = nl80211_dump_mpp,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
.cmd = NL80211_CMD_SET_MPATH,
.doit = nl80211_set_mpath,
.policy = nl80211_policy,
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 56c2240..e5560d5 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -263,6 +263,18 @@ static inline int rdev_get_mpath(struct cfg80211_registered_device *rdev,
}
+static inline int rdev_get_mpp(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, u8 *dst, u8 *mpp,
+ struct mpath_info *pinfo)
+{
+ int ret;
+
+ trace_rdev_get_mpp(&rdev->wiphy, dev, dst, mpp);
+ ret = rdev->ops->get_mpp(&rdev->wiphy, dev, dst, mpp, pinfo);
+ trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
+ return ret;
+}
+
static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev,
struct net_device *dev, int idx, u8 *dst,
u8 *next_hop, struct mpath_info *pinfo)
@@ -271,7 +283,20 @@ static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev,
int ret;
trace_rdev_dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop);
ret = rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop,
- pinfo);
+ pinfo);
+ trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
+ return ret;
+}
+
+static inline int rdev_dump_mpp(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, int idx, u8 *dst,
+ u8 *mpp, struct mpath_info *pinfo)
+
+{
+ int ret;
+
+ trace_rdev_dump_mpp(&rdev->wiphy, dev, idx, dst, mpp);
+ ret = rdev->ops->dump_mpp(&rdev->wiphy, dev, idx, dst, mpp, pinfo);
trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
return ret;
}
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 0c524cd..57ab727 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -801,6 +801,51 @@ TRACE_EVENT(rdev_dump_mpath,
MAC_PR_ARG(next_hop))
);
+TRACE_EVENT(rdev_get_mpp,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ u8 *dst, u8 *mpp),
+ TP_ARGS(wiphy, netdev, dst, mpp),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ MAC_ENTRY(dst)
+ MAC_ENTRY(mpp)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ MAC_ASSIGN(dst, dst);
+ MAC_ASSIGN(mpp, mpp);
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", destination: " MAC_PR_FMT
+ ", mpp: " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG,
+ MAC_PR_ARG(dst), MAC_PR_ARG(mpp))
+);
+
+TRACE_EVENT(rdev_dump_mpp,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx,
+ u8 *dst, u8 *mpp),
+ TP_ARGS(wiphy, netdev, idx, mpp, dst),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ MAC_ENTRY(dst)
+ MAC_ENTRY(mpp)
+ __field(int, idx)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ MAC_ASSIGN(dst, dst);
+ MAC_ASSIGN(mpp, mpp);
+ __entry->idx = idx;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: "
+ MAC_PR_FMT ", mpp: " MAC_PR_FMT,
+ WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx, MAC_PR_ARG(dst),
+ MAC_PR_ARG(mpp))
+);
+
TRACE_EVENT(rdev_return_int_mpath_info,
TP_PROTO(struct wiphy *wiphy, int ret, struct mpath_info *pinfo),
TP_ARGS(wiphy, ret, pinfo),
--
1.9.1
Tested with ath9k and working fine for me.
----
ChunYeow
On Mon, Sep 1, 2014 at 8:03 PM, Henning Rogge <[email protected]> wrote:
> Hi,
>
> I forgot to add that the patch applies to the head of
> wireless-testing. I have also tested it on OpenWRT Barrier Breaker on
> a Ubiquiti Bullet M5 with the ath9k driver.
>
> Henning Rogge
>
> On Mon, Sep 1, 2014 at 1:26 PM, Henning Rogge <[email protected]> wrote:
>> The following patch adds NL80211_CMD_GET_MPP as a new nl80211 command that
>> allows to query the content of the 'mesh proxy path' table of mac80211s via
>> 'get' or 'dump' operation.
>>
>> Signed-off-by: Henning Rogge <[email protected]>
>> ---
>> include/net/cfg80211.h | 7 ++++
>> include/uapi/linux/nl80211.h | 6 +++
>> net/mac80211/cfg.c | 53 ++++++++++++++++++++++++
>> net/mac80211/mesh.h | 3 ++
>> net/mac80211/mesh_pathtbl.c | 31 ++++++++++++++
>> net/wireless/nl80211.c | 99 ++++++++++++++++++++++++++++++++++++++++++++
>> net/wireless/rdev-ops.h | 27 +++++++++++-
>> net/wireless/trace.h | 45 ++++++++++++++++++++
>> 8 files changed, 270 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
>> index 0a080c4..68fbcf5 100644
>> --- a/include/net/cfg80211.h
>> +++ b/include/net/cfg80211.h
>> @@ -2139,6 +2139,8 @@ struct cfg80211_qos_map {
>> * @change_mpath: change a given mesh path
>> * @get_mpath: get a mesh path for the given parameters
>> * @dump_mpath: dump mesh path callback -- resume dump at index @idx
>> + * @get_mpp: get a mesh proxy path for the given parameters
>> + * @dump_mpp: dump mesh proxy path callback -- resume dump at index @idx
>> * @join_mesh: join the mesh network with the specified parameters
>> * (invoked with the wireless_dev mutex held)
>> * @leave_mesh: leave the current mesh network
>> @@ -2378,6 +2380,11 @@ struct cfg80211_ops {
>> int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev,
>> int idx, u8 *dst, u8 *next_hop,
>> struct mpath_info *pinfo);
>> + int (*get_mpp)(struct wiphy *wiphy, struct net_device *dev,
>> + u8 *dst, u8 *mpp, struct mpath_info *pinfo);
>> + int (*dump_mpp)(struct wiphy *wiphy, struct net_device *dev,
>> + int idx, u8 *dst, u8 *mpp,
>> + struct mpath_info *pinfo);
>> int (*get_mesh_config)(struct wiphy *wiphy,
>> struct net_device *dev,
>> struct mesh_config *conf);
>> diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
>> index f1db15b..80cff48 100644
>> --- a/include/uapi/linux/nl80211.h
>> +++ b/include/uapi/linux/nl80211.h
>> @@ -722,6 +722,10 @@
>> * QoS mapping is relevant for IP packets, it is only valid during an
>> * association. This is cleared on disassociation and AP restart.
>> *
>> + * @NL80211_CMD_GET_MPP: Get mesh path attributes for mesh proxy path to
>> + * destination %NL80211_ATTR_MAC on the interface identified by
>> + * %NL80211_ATTR_IFINDEX.
>> + *
>> * @NL80211_CMD_MAX: highest used command number
>> * @__NL80211_CMD_AFTER_LAST: internal use
>> */
>> @@ -893,6 +897,8 @@ enum nl80211_commands {
>>
>> NL80211_CMD_SET_QOS_MAP,
>>
>> + NL80211_CMD_GET_MPP,
>> +
>> /* add new commands above here */
>>
>> /* used to define NL80211_CMD_MAX below */
>> diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
>> index 927b4ea..2b85eed 100644
>> --- a/net/mac80211/cfg.c
>> +++ b/net/mac80211/cfg.c
>> @@ -1511,6 +1511,57 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
>> return 0;
>> }
>>
>> +static void mpp_set_pinfo(struct mesh_path *mpath, u8 *mpp,
>> + struct mpath_info *pinfo)
>> +{
>> + memset(pinfo, 0, sizeof(*pinfo));
>> + memcpy(mpp, mpath->mpp, ETH_ALEN);
>> +
>> + pinfo->generation = mpp_paths_generation;
>> +}
>> +
>> +static int ieee80211_get_mpp(struct wiphy *wiphy, struct net_device *dev,
>> + u8 *dst, u8 *mpp, struct mpath_info *pinfo)
>> +
>> +{
>> + struct ieee80211_sub_if_data *sdata;
>> + struct mesh_path *mpath;
>> +
>> + sdata = IEEE80211_DEV_TO_SUB_IF(dev);
>> +
>> + rcu_read_lock();
>> + mpath = mpp_path_lookup(sdata, dst);
>> + if (!mpath) {
>> + rcu_read_unlock();
>> + return -ENOENT;
>> + }
>> + memcpy(dst, mpath->dst, ETH_ALEN);
>> + mpp_set_pinfo(mpath, mpp, pinfo);
>> + rcu_read_unlock();
>> + return 0;
>> +}
>> +
>> +static int ieee80211_dump_mpp(struct wiphy *wiphy, struct net_device *dev,
>> + int idx, u8 *dst, u8 *mpp,
>> + struct mpath_info *pinfo)
>> +{
>> + struct ieee80211_sub_if_data *sdata;
>> + struct mesh_path *mpath;
>> +
>> + sdata = IEEE80211_DEV_TO_SUB_IF(dev);
>> +
>> + rcu_read_lock();
>> + mpath = mpp_path_lookup_by_idx(sdata, idx);
>> + if (!mpath) {
>> + rcu_read_unlock();
>> + return -ENOENT;
>> + }
>> + memcpy(dst, mpath->dst, ETH_ALEN);
>> + mpp_set_pinfo(mpath, mpp, pinfo);
>> + rcu_read_unlock();
>> + return 0;
>> +}
>> +
>> static int ieee80211_get_mesh_config(struct wiphy *wiphy,
>> struct net_device *dev,
>> struct mesh_config *conf)
>> @@ -3507,6 +3558,8 @@ const struct cfg80211_ops mac80211_config_ops = {
>> .change_mpath = ieee80211_change_mpath,
>> .get_mpath = ieee80211_get_mpath,
>> .dump_mpath = ieee80211_dump_mpath,
>> + .get_mpp = ieee80211_get_mpp,
>> + .dump_mpp = ieee80211_dump_mpp,
>> .update_mesh_config = ieee80211_update_mesh_config,
>> .get_mesh_config = ieee80211_get_mesh_config,
>> .join_mesh = ieee80211_join_mesh,
>> diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
>> index f39a19f..50c8473 100644
>> --- a/net/mac80211/mesh.h
>> +++ b/net/mac80211/mesh.h
>> @@ -270,6 +270,8 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
>> const u8 *dst, const u8 *mpp);
>> struct mesh_path *
>> mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx);
>> +struct mesh_path *
>> +mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx);
>> void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
>> void mesh_path_expire(struct ieee80211_sub_if_data *sdata);
>> void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
>> @@ -317,6 +319,7 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);
>>
>> bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
>> extern int mesh_paths_generation;
>> +extern int mpp_paths_generation;
>>
>> #ifdef CONFIG_MAC80211_MESH
>> static inline
>> diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
>> index cf032a8..8630963 100644
>> --- a/net/mac80211/mesh_pathtbl.c
>> +++ b/net/mac80211/mesh_pathtbl.c
>> @@ -44,6 +44,7 @@ static struct mesh_table __rcu *mesh_paths;
>> static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */
>>
>> int mesh_paths_generation;
>> +int mpp_paths_generation;
>>
>> /* This lock will have the grow table function as writer and add / delete nodes
>> * as readers. RCU provides sufficient protection only when reading the table
>> @@ -410,6 +411,33 @@ mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
>> }
>>
>> /**
>> + * mpp_path_lookup_by_idx - look up a path in the proxy path table by its index
>> + * @idx: index
>> + * @sdata: local subif, or NULL for all entries
>> + *
>> + * Returns: pointer to the proxy path structure, or NULL if not found.
>> + *
>> + * Locking: must be called within a read rcu section.
>> + */
>> +struct mesh_path *
>> +mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
>> +{
>> + struct mesh_table *tbl = rcu_dereference(mpp_paths);
>> + struct mpath_node *node;
>> + int i;
>> + int j = 0;
>> +
>> + for_each_mesh_entry(tbl, node, i) {
>> + if (sdata && node->mpath->sdata != sdata)
>> + continue;
>> + if (j++ == idx)
>> + return node->mpath;
>> + }
>> +
>> + return NULL;
>> +}
>> +
>> +/**
>> * mesh_path_add_gate - add the given mpath to a mesh gate to our path table
>> * @mpath: gate path to add to table
>> */
>> @@ -691,6 +719,9 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
>>
>> spin_unlock(&tbl->hashwlock[hash_idx]);
>> read_unlock_bh(&pathtbl_resize_lock);
>> +
>> + mpp_paths_generation++;
>> +
>> if (grow) {
>> set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags);
>> ieee80211_queue_work(&local->hw, &sdata->work);
>> diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
>> index df7b133..1e33f2f 100644
>> --- a/net/wireless/nl80211.c
>> +++ b/net/wireless/nl80211.c
>> @@ -4581,6 +4581,96 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
>> return rdev_del_mpath(rdev, dev, dst);
>> }
>>
>> +static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info)
>> +{
>> + struct cfg80211_registered_device *rdev = info->user_ptr[0];
>> + int err;
>> + struct net_device *dev = info->user_ptr[1];
>> + struct mpath_info pinfo;
>> + struct sk_buff *msg;
>> + u8 *dst = NULL;
>> + u8 mpp[ETH_ALEN];
>> +
>> + memset(&pinfo, 0, sizeof(pinfo));
>> +
>> + if (!info->attrs[NL80211_ATTR_MAC])
>> + return -EINVAL;
>> +
>> + dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
>> +
>> + if (!rdev->ops->get_mpp)
>> + return -EOPNOTSUPP;
>> +
>> + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
>> + return -EOPNOTSUPP;
>> +
>> + err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo);
>> + if (err)
>> + return err;
>> +
>> + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
>> + if (!msg)
>> + return -ENOMEM;
>> +
>> + if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
>> + dev, dst, mpp, &pinfo) < 0) {
>> + nlmsg_free(msg);
>> + return -ENOBUFS;
>> + }
>> +
>> + return genlmsg_reply(msg, info);
>> +}
>> +
>> +static int nl80211_dump_mpp(struct sk_buff *skb,
>> + struct netlink_callback *cb)
>> +{
>> + struct mpath_info pinfo;
>> + struct cfg80211_registered_device *rdev;
>> + struct wireless_dev *wdev;
>> + u8 dst[ETH_ALEN];
>> + u8 mpp[ETH_ALEN];
>> + int path_idx = cb->args[2];
>> + int err;
>> +
>> + err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
>> + if (err)
>> + return err;
>> +
>> + if (!rdev->ops->dump_mpp) {
>> + err = -EOPNOTSUPP;
>> + goto out_err;
>> + }
>> +
>> + if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
>> + err = -EOPNOTSUPP;
>> + goto out_err;
>> + }
>> +
>> + while (1) {
>> + err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst,
>> + mpp, &pinfo);
>> + if (err == -ENOENT)
>> + break;
>> + if (err)
>> + goto out_err;
>> +
>> + if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
>> + cb->nlh->nlmsg_seq, NLM_F_MULTI,
>> + wdev->netdev, dst, mpp,
>> + &pinfo) < 0)
>> + goto out;
>> +
>> + path_idx++;
>> + }
>> +
>> + out:
>> + cb->args[2] = path_idx;
>> + err = skb->len;
>> + out_err:
>> + nl80211_finish_wdev_dump(rdev);
>> + return err;
>> +}
>> +
>> static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
>> {
>> struct cfg80211_registered_device *rdev = info->user_ptr[0];
>> @@ -9603,6 +9693,15 @@ static const struct genl_ops nl80211_ops[] = {
>> NL80211_FLAG_NEED_RTNL,
>> },
>> {
>> + .cmd = NL80211_CMD_GET_MPP,
>> + .doit = nl80211_get_mpp,
>> + .dumpit = nl80211_dump_mpp,
>> + .policy = nl80211_policy,
>> + .flags = GENL_ADMIN_PERM,
>> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
>> + NL80211_FLAG_NEED_RTNL,
>> + },
>> + {
>> .cmd = NL80211_CMD_SET_MPATH,
>> .doit = nl80211_set_mpath,
>> .policy = nl80211_policy,
>> diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
>> index 56c2240..e5560d5 100644
>> --- a/net/wireless/rdev-ops.h
>> +++ b/net/wireless/rdev-ops.h
>> @@ -263,6 +263,18 @@ static inline int rdev_get_mpath(struct cfg80211_registered_device *rdev,
>>
>> }
>>
>> +static inline int rdev_get_mpp(struct cfg80211_registered_device *rdev,
>> + struct net_device *dev, u8 *dst, u8 *mpp,
>> + struct mpath_info *pinfo)
>> +{
>> + int ret;
>> +
>> + trace_rdev_get_mpp(&rdev->wiphy, dev, dst, mpp);
>> + ret = rdev->ops->get_mpp(&rdev->wiphy, dev, dst, mpp, pinfo);
>> + trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
>> + return ret;
>> +}
>> +
>> static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev,
>> struct net_device *dev, int idx, u8 *dst,
>> u8 *next_hop, struct mpath_info *pinfo)
>> @@ -271,7 +283,20 @@ static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev,
>> int ret;
>> trace_rdev_dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop);
>> ret = rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop,
>> - pinfo);
>> + pinfo);
>> + trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
>> + return ret;
>> +}
>> +
>> +static inline int rdev_dump_mpp(struct cfg80211_registered_device *rdev,
>> + struct net_device *dev, int idx, u8 *dst,
>> + u8 *mpp, struct mpath_info *pinfo)
>> +
>> +{
>> + int ret;
>> +
>> + trace_rdev_dump_mpp(&rdev->wiphy, dev, idx, dst, mpp);
>> + ret = rdev->ops->dump_mpp(&rdev->wiphy, dev, idx, dst, mpp, pinfo);
>> trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
>> return ret;
>> }
>> diff --git a/net/wireless/trace.h b/net/wireless/trace.h
>> index 0c524cd..57ab727 100644
>> --- a/net/wireless/trace.h
>> +++ b/net/wireless/trace.h
>> @@ -801,6 +801,51 @@ TRACE_EVENT(rdev_dump_mpath,
>> MAC_PR_ARG(next_hop))
>> );
>>
>> +TRACE_EVENT(rdev_get_mpp,
>> + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
>> + u8 *dst, u8 *mpp),
>> + TP_ARGS(wiphy, netdev, dst, mpp),
>> + TP_STRUCT__entry(
>> + WIPHY_ENTRY
>> + NETDEV_ENTRY
>> + MAC_ENTRY(dst)
>> + MAC_ENTRY(mpp)
>> + ),
>> + TP_fast_assign(
>> + WIPHY_ASSIGN;
>> + NETDEV_ASSIGN;
>> + MAC_ASSIGN(dst, dst);
>> + MAC_ASSIGN(mpp, mpp);
>> + ),
>> + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", destination: " MAC_PR_FMT
>> + ", mpp: " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG,
>> + MAC_PR_ARG(dst), MAC_PR_ARG(mpp))
>> +);
>> +
>> +TRACE_EVENT(rdev_dump_mpp,
>> + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx,
>> + u8 *dst, u8 *mpp),
>> + TP_ARGS(wiphy, netdev, idx, mpp, dst),
>> + TP_STRUCT__entry(
>> + WIPHY_ENTRY
>> + NETDEV_ENTRY
>> + MAC_ENTRY(dst)
>> + MAC_ENTRY(mpp)
>> + __field(int, idx)
>> + ),
>> + TP_fast_assign(
>> + WIPHY_ASSIGN;
>> + NETDEV_ASSIGN;
>> + MAC_ASSIGN(dst, dst);
>> + MAC_ASSIGN(mpp, mpp);
>> + __entry->idx = idx;
>> + ),
>> + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: "
>> + MAC_PR_FMT ", mpp: " MAC_PR_FMT,
>> + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx, MAC_PR_ARG(dst),
>> + MAC_PR_ARG(mpp))
>> +);
>> +
>> TRACE_EVENT(rdev_return_int_mpath_info,
>> TP_PROTO(struct wiphy *wiphy, int ret, struct mpath_info *pinfo),
>> TP_ARGS(wiphy, ret, pinfo),
>> --
>> 1.9.1
>>
>>
On Wed, 2014-09-03 at 14:12 +0200, Henning Rogge wrote:
> On Wed, Sep 3, 2014 at 1:52 PM, Johannes Berg <[email protected]> wrote:
> > On Mon, 2014-09-01 at 13:26 +0200, Henning Rogge wrote:
> >> The following patch adds NL80211_CMD_GET_MPP as a new nl80211 command that
> >> allows to query the content of the 'mesh proxy path' table of mac80211s via
> >> 'get' or 'dump' operation.
> >
> > For review and merging, and to make it more obvious to you as well when
> > writing commit logs/documentation/etc I'd prefer if you'd split this up
> > into separate cfg80211 and mac80211 patches.
>
> Just to make sure I got the split right...
>
> First patch to define the two new cfg80211_ops and the necessary
> nl80211/tracing helper functions, second patch that implements
> get_mpp() and dump_mpp() functions?
Right. That way you have one patch that defines the API etc., and
another that implements it, and it's easier to review and document the
APIs in the right places etc.
I don't always insist on this, but it's a pretty big patch so I'd prefer
it this way (and it also should be almost trivial to split)
> >> + int (*get_mpp)(struct wiphy *wiphy, struct net_device *dev,
> >> + u8 *dst, u8 *mpp, struct mpath_info *pinfo);
> >> + int (*dump_mpp)(struct wiphy *wiphy, struct net_device *dev,
> >> + int idx, u8 *dst, u8 *mpp,
> >> + struct mpath_info *pinfo);
> >
> > Should dst/mpp be const? Or are those output parameters?
>
> Yes, similar to the get_mpath/dump_mpath cfg80211_ops these are output
> parameters. Same thing for pinfo.
Yeah I figured pinfo was, wasn't sure about the others :)
> > Should it really be mpath_info? I thought this was some other thing?
> > Probably just need more documentation :)
>
> mpath and mpp use the same storage object (struct mesh_path), so I
> reused the mpath_info struct. As far as I can see its just a "transfer
> object" between for cfg80211 that temporarily stores data from the
> cfg80211_ops for nl80211 messages.
Indeed, it is.
> Shall I create a new struct for the two new cfg80211_ops?
No need, I just wasn't sure it really needed the same data so figured
I'd ask.
> See
I guess you got cut off there :)
johannes
On Wed, Sep 3, 2014 at 2:25 PM, Johannes Berg <[email protected]> wrote:
>> First patch to define the two new cfg80211_ops and the necessary
>> nl80211/tracing helper functions, second patch that implements
>> get_mpp() and dump_mpp() functions?
>
> Right. That way you have one patch that defines the API etc., and
> another that implements it, and it's easier to review and document the
> APIs in the right places etc.
>
> I don't always insist on this, but it's a pretty big patch so I'd prefer
> it this way (and it also should be almost trivial to split)
Yes, should be easy. I will come back to the list with a "v2" set of patches.
>> mpath and mpp use the same storage object (struct mesh_path), so I
>> reused the mpath_info struct. As far as I can see its just a "transfer
>> object" between for cfg80211 that temporarily stores data from the
>> cfg80211_ops for nl80211 messages.
>
> Indeed, it is.
>
>> Shall I create a new struct for the two new cfg80211_ops?
>
> No need, I just wasn't sure it really needed the same data so figured
> I'd ask.
At the moment I don't use much of the mpath_info field... but I think
the mpp operations will always use a subset of the mpath fields, so we
can reuse the nl80211 encoding function by reusing the struct. If this
changes it would be trivial to switch to a different struct, because
its not visible from userspace.
Henning
On Mon, 2014-09-01 at 13:26 +0200, Henning Rogge wrote:
> The following patch adds NL80211_CMD_GET_MPP as a new nl80211 command that
> allows to query the content of the 'mesh proxy path' table of mac80211s via
> 'get' or 'dump' operation.
Is this really something that should be a generic nl80211 operation,
rather than say debugfs?
Could this be useful to other devices implementing the 11s, or is it
more of a mac80211 implementation detail?
johannes
On Tue, Sep 2, 2014 at 10:03 AM, Johannes Berg
<[email protected]> wrote:
> On Mon, 2014-09-01 at 13:26 +0200, Henning Rogge wrote:
>> The following patch adds NL80211_CMD_GET_MPP as a new nl80211 command that
>> allows to query the content of the 'mesh proxy path' table of mac80211s via
>> 'get' or 'dump' operation.
>
> Is this really something that should be a generic nl80211 operation,
> rather than say debugfs?
No, this should be (in my opinion) a nl80211 operation.
It is directly comparable to "station get/dump" and "mpath get/dump".
> Could this be useful to other devices implementing the 11s, or is it
> more of a mac80211 implementation detail?
Yes, this could be relevant to all 11s implementations. Without this
data you cannot determine where your data packages will be going
(similar to the routing table/fib, just layer-2).
In my case I need this feature to correlate the layer-2 data I got
from a "station dump" with the mac addresses of bridged devices.
I am trying to implement a DLEP-style radio/router system (see
http://tools.ietf.org/html/draft-ietf-manet-dlep-06), which combines a
IP router with a bridged radio (both connected via ethernet). The
routers can talk directly to each other, but to map the layer-2 data
from the radio (which refers to the wifi MAC addresses) to the router
communication, I need the mapping table.
Henning Rogge
On Mon, 2014-09-01 at 13:26 +0200, Henning Rogge wrote:
> The following patch adds NL80211_CMD_GET_MPP as a new nl80211 command that
> allows to query the content of the 'mesh proxy path' table of mac80211s via
> 'get' or 'dump' operation.
For review and merging, and to make it more obvious to you as well when
writing commit logs/documentation/etc I'd prefer if you'd split this up
into separate cfg80211 and mac80211 patches.
> + int (*get_mpp)(struct wiphy *wiphy, struct net_device *dev,
> + u8 *dst, u8 *mpp, struct mpath_info *pinfo);
> + int (*dump_mpp)(struct wiphy *wiphy, struct net_device *dev,
> + int idx, u8 *dst, u8 *mpp,
> + struct mpath_info *pinfo);
Should dst/mpp be const? Or are those output parameters?
Should it really be mpath_info? I thought this was some other thing?
Probably just need more documentation :)
johannes
On Wed, 2014-09-03 at 14:32 +0200, Henning Rogge wrote:
> > No need, I just wasn't sure it really needed the same data so figured
> > I'd ask.
>
> At the moment I don't use much of the mpath_info field... but I think
> the mpp operations will always use a subset of the mpath fields, so we
> can reuse the nl80211 encoding function by reusing the struct. If this
> changes it would be trivial to switch to a different struct, because
> its not visible from userspace.
Makes sense I guess. Thanks for the explanation.
johannes
Hi,
I forgot to add that the patch applies to the head of
wireless-testing. I have also tested it on OpenWRT Barrier Breaker on
a Ubiquiti Bullet M5 with the ath9k driver.
Henning Rogge
On Mon, Sep 1, 2014 at 1:26 PM, Henning Rogge <[email protected]> wrote:
> The following patch adds NL80211_CMD_GET_MPP as a new nl80211 command that
> allows to query the content of the 'mesh proxy path' table of mac80211s via
> 'get' or 'dump' operation.
>
> Signed-off-by: Henning Rogge <[email protected]>
> ---
> include/net/cfg80211.h | 7 ++++
> include/uapi/linux/nl80211.h | 6 +++
> net/mac80211/cfg.c | 53 ++++++++++++++++++++++++
> net/mac80211/mesh.h | 3 ++
> net/mac80211/mesh_pathtbl.c | 31 ++++++++++++++
> net/wireless/nl80211.c | 99 ++++++++++++++++++++++++++++++++++++++++++++
> net/wireless/rdev-ops.h | 27 +++++++++++-
> net/wireless/trace.h | 45 ++++++++++++++++++++
> 8 files changed, 270 insertions(+), 1 deletion(-)
>
> diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
> index 0a080c4..68fbcf5 100644
> --- a/include/net/cfg80211.h
> +++ b/include/net/cfg80211.h
> @@ -2139,6 +2139,8 @@ struct cfg80211_qos_map {
> * @change_mpath: change a given mesh path
> * @get_mpath: get a mesh path for the given parameters
> * @dump_mpath: dump mesh path callback -- resume dump at index @idx
> + * @get_mpp: get a mesh proxy path for the given parameters
> + * @dump_mpp: dump mesh proxy path callback -- resume dump at index @idx
> * @join_mesh: join the mesh network with the specified parameters
> * (invoked with the wireless_dev mutex held)
> * @leave_mesh: leave the current mesh network
> @@ -2378,6 +2380,11 @@ struct cfg80211_ops {
> int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev,
> int idx, u8 *dst, u8 *next_hop,
> struct mpath_info *pinfo);
> + int (*get_mpp)(struct wiphy *wiphy, struct net_device *dev,
> + u8 *dst, u8 *mpp, struct mpath_info *pinfo);
> + int (*dump_mpp)(struct wiphy *wiphy, struct net_device *dev,
> + int idx, u8 *dst, u8 *mpp,
> + struct mpath_info *pinfo);
> int (*get_mesh_config)(struct wiphy *wiphy,
> struct net_device *dev,
> struct mesh_config *conf);
> diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
> index f1db15b..80cff48 100644
> --- a/include/uapi/linux/nl80211.h
> +++ b/include/uapi/linux/nl80211.h
> @@ -722,6 +722,10 @@
> * QoS mapping is relevant for IP packets, it is only valid during an
> * association. This is cleared on disassociation and AP restart.
> *
> + * @NL80211_CMD_GET_MPP: Get mesh path attributes for mesh proxy path to
> + * destination %NL80211_ATTR_MAC on the interface identified by
> + * %NL80211_ATTR_IFINDEX.
> + *
> * @NL80211_CMD_MAX: highest used command number
> * @__NL80211_CMD_AFTER_LAST: internal use
> */
> @@ -893,6 +897,8 @@ enum nl80211_commands {
>
> NL80211_CMD_SET_QOS_MAP,
>
> + NL80211_CMD_GET_MPP,
> +
> /* add new commands above here */
>
> /* used to define NL80211_CMD_MAX below */
> diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
> index 927b4ea..2b85eed 100644
> --- a/net/mac80211/cfg.c
> +++ b/net/mac80211/cfg.c
> @@ -1511,6 +1511,57 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
> return 0;
> }
>
> +static void mpp_set_pinfo(struct mesh_path *mpath, u8 *mpp,
> + struct mpath_info *pinfo)
> +{
> + memset(pinfo, 0, sizeof(*pinfo));
> + memcpy(mpp, mpath->mpp, ETH_ALEN);
> +
> + pinfo->generation = mpp_paths_generation;
> +}
> +
> +static int ieee80211_get_mpp(struct wiphy *wiphy, struct net_device *dev,
> + u8 *dst, u8 *mpp, struct mpath_info *pinfo)
> +
> +{
> + struct ieee80211_sub_if_data *sdata;
> + struct mesh_path *mpath;
> +
> + sdata = IEEE80211_DEV_TO_SUB_IF(dev);
> +
> + rcu_read_lock();
> + mpath = mpp_path_lookup(sdata, dst);
> + if (!mpath) {
> + rcu_read_unlock();
> + return -ENOENT;
> + }
> + memcpy(dst, mpath->dst, ETH_ALEN);
> + mpp_set_pinfo(mpath, mpp, pinfo);
> + rcu_read_unlock();
> + return 0;
> +}
> +
> +static int ieee80211_dump_mpp(struct wiphy *wiphy, struct net_device *dev,
> + int idx, u8 *dst, u8 *mpp,
> + struct mpath_info *pinfo)
> +{
> + struct ieee80211_sub_if_data *sdata;
> + struct mesh_path *mpath;
> +
> + sdata = IEEE80211_DEV_TO_SUB_IF(dev);
> +
> + rcu_read_lock();
> + mpath = mpp_path_lookup_by_idx(sdata, idx);
> + if (!mpath) {
> + rcu_read_unlock();
> + return -ENOENT;
> + }
> + memcpy(dst, mpath->dst, ETH_ALEN);
> + mpp_set_pinfo(mpath, mpp, pinfo);
> + rcu_read_unlock();
> + return 0;
> +}
> +
> static int ieee80211_get_mesh_config(struct wiphy *wiphy,
> struct net_device *dev,
> struct mesh_config *conf)
> @@ -3507,6 +3558,8 @@ const struct cfg80211_ops mac80211_config_ops = {
> .change_mpath = ieee80211_change_mpath,
> .get_mpath = ieee80211_get_mpath,
> .dump_mpath = ieee80211_dump_mpath,
> + .get_mpp = ieee80211_get_mpp,
> + .dump_mpp = ieee80211_dump_mpp,
> .update_mesh_config = ieee80211_update_mesh_config,
> .get_mesh_config = ieee80211_get_mesh_config,
> .join_mesh = ieee80211_join_mesh,
> diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
> index f39a19f..50c8473 100644
> --- a/net/mac80211/mesh.h
> +++ b/net/mac80211/mesh.h
> @@ -270,6 +270,8 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
> const u8 *dst, const u8 *mpp);
> struct mesh_path *
> mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx);
> +struct mesh_path *
> +mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx);
> void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
> void mesh_path_expire(struct ieee80211_sub_if_data *sdata);
> void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
> @@ -317,6 +319,7 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);
>
> bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
> extern int mesh_paths_generation;
> +extern int mpp_paths_generation;
>
> #ifdef CONFIG_MAC80211_MESH
> static inline
> diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
> index cf032a8..8630963 100644
> --- a/net/mac80211/mesh_pathtbl.c
> +++ b/net/mac80211/mesh_pathtbl.c
> @@ -44,6 +44,7 @@ static struct mesh_table __rcu *mesh_paths;
> static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */
>
> int mesh_paths_generation;
> +int mpp_paths_generation;
>
> /* This lock will have the grow table function as writer and add / delete nodes
> * as readers. RCU provides sufficient protection only when reading the table
> @@ -410,6 +411,33 @@ mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
> }
>
> /**
> + * mpp_path_lookup_by_idx - look up a path in the proxy path table by its index
> + * @idx: index
> + * @sdata: local subif, or NULL for all entries
> + *
> + * Returns: pointer to the proxy path structure, or NULL if not found.
> + *
> + * Locking: must be called within a read rcu section.
> + */
> +struct mesh_path *
> +mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
> +{
> + struct mesh_table *tbl = rcu_dereference(mpp_paths);
> + struct mpath_node *node;
> + int i;
> + int j = 0;
> +
> + for_each_mesh_entry(tbl, node, i) {
> + if (sdata && node->mpath->sdata != sdata)
> + continue;
> + if (j++ == idx)
> + return node->mpath;
> + }
> +
> + return NULL;
> +}
> +
> +/**
> * mesh_path_add_gate - add the given mpath to a mesh gate to our path table
> * @mpath: gate path to add to table
> */
> @@ -691,6 +719,9 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
>
> spin_unlock(&tbl->hashwlock[hash_idx]);
> read_unlock_bh(&pathtbl_resize_lock);
> +
> + mpp_paths_generation++;
> +
> if (grow) {
> set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags);
> ieee80211_queue_work(&local->hw, &sdata->work);
> diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
> index df7b133..1e33f2f 100644
> --- a/net/wireless/nl80211.c
> +++ b/net/wireless/nl80211.c
> @@ -4581,6 +4581,96 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
> return rdev_del_mpath(rdev, dev, dst);
> }
>
> +static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info)
> +{
> + struct cfg80211_registered_device *rdev = info->user_ptr[0];
> + int err;
> + struct net_device *dev = info->user_ptr[1];
> + struct mpath_info pinfo;
> + struct sk_buff *msg;
> + u8 *dst = NULL;
> + u8 mpp[ETH_ALEN];
> +
> + memset(&pinfo, 0, sizeof(pinfo));
> +
> + if (!info->attrs[NL80211_ATTR_MAC])
> + return -EINVAL;
> +
> + dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
> +
> + if (!rdev->ops->get_mpp)
> + return -EOPNOTSUPP;
> +
> + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
> + return -EOPNOTSUPP;
> +
> + err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo);
> + if (err)
> + return err;
> +
> + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
> + if (!msg)
> + return -ENOMEM;
> +
> + if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
> + dev, dst, mpp, &pinfo) < 0) {
> + nlmsg_free(msg);
> + return -ENOBUFS;
> + }
> +
> + return genlmsg_reply(msg, info);
> +}
> +
> +static int nl80211_dump_mpp(struct sk_buff *skb,
> + struct netlink_callback *cb)
> +{
> + struct mpath_info pinfo;
> + struct cfg80211_registered_device *rdev;
> + struct wireless_dev *wdev;
> + u8 dst[ETH_ALEN];
> + u8 mpp[ETH_ALEN];
> + int path_idx = cb->args[2];
> + int err;
> +
> + err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
> + if (err)
> + return err;
> +
> + if (!rdev->ops->dump_mpp) {
> + err = -EOPNOTSUPP;
> + goto out_err;
> + }
> +
> + if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
> + err = -EOPNOTSUPP;
> + goto out_err;
> + }
> +
> + while (1) {
> + err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst,
> + mpp, &pinfo);
> + if (err == -ENOENT)
> + break;
> + if (err)
> + goto out_err;
> +
> + if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
> + cb->nlh->nlmsg_seq, NLM_F_MULTI,
> + wdev->netdev, dst, mpp,
> + &pinfo) < 0)
> + goto out;
> +
> + path_idx++;
> + }
> +
> + out:
> + cb->args[2] = path_idx;
> + err = skb->len;
> + out_err:
> + nl80211_finish_wdev_dump(rdev);
> + return err;
> +}
> +
> static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
> {
> struct cfg80211_registered_device *rdev = info->user_ptr[0];
> @@ -9603,6 +9693,15 @@ static const struct genl_ops nl80211_ops[] = {
> NL80211_FLAG_NEED_RTNL,
> },
> {
> + .cmd = NL80211_CMD_GET_MPP,
> + .doit = nl80211_get_mpp,
> + .dumpit = nl80211_dump_mpp,
> + .policy = nl80211_policy,
> + .flags = GENL_ADMIN_PERM,
> + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> + NL80211_FLAG_NEED_RTNL,
> + },
> + {
> .cmd = NL80211_CMD_SET_MPATH,
> .doit = nl80211_set_mpath,
> .policy = nl80211_policy,
> diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
> index 56c2240..e5560d5 100644
> --- a/net/wireless/rdev-ops.h
> +++ b/net/wireless/rdev-ops.h
> @@ -263,6 +263,18 @@ static inline int rdev_get_mpath(struct cfg80211_registered_device *rdev,
>
> }
>
> +static inline int rdev_get_mpp(struct cfg80211_registered_device *rdev,
> + struct net_device *dev, u8 *dst, u8 *mpp,
> + struct mpath_info *pinfo)
> +{
> + int ret;
> +
> + trace_rdev_get_mpp(&rdev->wiphy, dev, dst, mpp);
> + ret = rdev->ops->get_mpp(&rdev->wiphy, dev, dst, mpp, pinfo);
> + trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
> + return ret;
> +}
> +
> static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev,
> struct net_device *dev, int idx, u8 *dst,
> u8 *next_hop, struct mpath_info *pinfo)
> @@ -271,7 +283,20 @@ static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev,
> int ret;
> trace_rdev_dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop);
> ret = rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop,
> - pinfo);
> + pinfo);
> + trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
> + return ret;
> +}
> +
> +static inline int rdev_dump_mpp(struct cfg80211_registered_device *rdev,
> + struct net_device *dev, int idx, u8 *dst,
> + u8 *mpp, struct mpath_info *pinfo)
> +
> +{
> + int ret;
> +
> + trace_rdev_dump_mpp(&rdev->wiphy, dev, idx, dst, mpp);
> + ret = rdev->ops->dump_mpp(&rdev->wiphy, dev, idx, dst, mpp, pinfo);
> trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
> return ret;
> }
> diff --git a/net/wireless/trace.h b/net/wireless/trace.h
> index 0c524cd..57ab727 100644
> --- a/net/wireless/trace.h
> +++ b/net/wireless/trace.h
> @@ -801,6 +801,51 @@ TRACE_EVENT(rdev_dump_mpath,
> MAC_PR_ARG(next_hop))
> );
>
> +TRACE_EVENT(rdev_get_mpp,
> + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
> + u8 *dst, u8 *mpp),
> + TP_ARGS(wiphy, netdev, dst, mpp),
> + TP_STRUCT__entry(
> + WIPHY_ENTRY
> + NETDEV_ENTRY
> + MAC_ENTRY(dst)
> + MAC_ENTRY(mpp)
> + ),
> + TP_fast_assign(
> + WIPHY_ASSIGN;
> + NETDEV_ASSIGN;
> + MAC_ASSIGN(dst, dst);
> + MAC_ASSIGN(mpp, mpp);
> + ),
> + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", destination: " MAC_PR_FMT
> + ", mpp: " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG,
> + MAC_PR_ARG(dst), MAC_PR_ARG(mpp))
> +);
> +
> +TRACE_EVENT(rdev_dump_mpp,
> + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx,
> + u8 *dst, u8 *mpp),
> + TP_ARGS(wiphy, netdev, idx, mpp, dst),
> + TP_STRUCT__entry(
> + WIPHY_ENTRY
> + NETDEV_ENTRY
> + MAC_ENTRY(dst)
> + MAC_ENTRY(mpp)
> + __field(int, idx)
> + ),
> + TP_fast_assign(
> + WIPHY_ASSIGN;
> + NETDEV_ASSIGN;
> + MAC_ASSIGN(dst, dst);
> + MAC_ASSIGN(mpp, mpp);
> + __entry->idx = idx;
> + ),
> + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: "
> + MAC_PR_FMT ", mpp: " MAC_PR_FMT,
> + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx, MAC_PR_ARG(dst),
> + MAC_PR_ARG(mpp))
> +);
> +
> TRACE_EVENT(rdev_return_int_mpath_info,
> TP_PROTO(struct wiphy *wiphy, int ret, struct mpath_info *pinfo),
> TP_ARGS(wiphy, ret, pinfo),
> --
> 1.9.1
>
>
On Wed, Sep 3, 2014 at 1:52 PM, Johannes Berg <[email protected]> wrote:
> On Mon, 2014-09-01 at 13:26 +0200, Henning Rogge wrote:
>> The following patch adds NL80211_CMD_GET_MPP as a new nl80211 command that
>> allows to query the content of the 'mesh proxy path' table of mac80211s via
>> 'get' or 'dump' operation.
>
> For review and merging, and to make it more obvious to you as well when
> writing commit logs/documentation/etc I'd prefer if you'd split this up
> into separate cfg80211 and mac80211 patches.
Just to make sure I got the split right...
First patch to define the two new cfg80211_ops and the necessary
nl80211/tracing helper functions, second patch that implements
get_mpp() and dump_mpp() functions?
>> + int (*get_mpp)(struct wiphy *wiphy, struct net_device *dev,
>> + u8 *dst, u8 *mpp, struct mpath_info *pinfo);
>> + int (*dump_mpp)(struct wiphy *wiphy, struct net_device *dev,
>> + int idx, u8 *dst, u8 *mpp,
>> + struct mpath_info *pinfo);
>
> Should dst/mpp be const? Or are those output parameters?
Yes, similar to the get_mpath/dump_mpath cfg80211_ops these are output
parameters. Same thing for pinfo.
> Should it really be mpath_info? I thought this was some other thing?
> Probably just need more documentation :)
mpath and mpp use the same storage object (struct mesh_path), so I
reused the mpath_info struct. As far as I can see its just a "transfer
object" between for cfg80211 that temporarily stores data from the
cfg80211_ops for nl80211 messages.
Shall I create a new struct for the two new cfg80211_ops?
See