@@ -1605,8 +1605,8 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
return -ENOENT;
}
- mpath = mesh_path_lookup(sdata, dst);
- if (!mpath) {
+ mpath = mesh_path_lookup(mbss(sdata), dst);
+ if (!mpath || mpath->sdata != sdata) {
rcu_read_unlock();
return -ENOENT;
}
@@ -1669,8 +1669,8 @@ static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
rcu_read_lock();
- mpath = mesh_path_lookup(sdata, dst);
- if (!mpath) {
+ mpath = mesh_path_lookup(mbss(sdata), dst);
+ if (!mpath || mpath->sdata != sdata) {
rcu_read_unlock();
return -ENOENT;
}
@@ -258,14 +258,14 @@ void ieee80211_mps_frame_release(struct sta_info *sta,
struct ieee802_11_elems *elems);
/* Mesh paths */
-int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata,
+int mesh_nexthop_lookup(struct mesh_local_bss *mbss,
struct sk_buff *skb);
int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata);
-struct mesh_path *mesh_path_lookup(struct ieee80211_sub_if_data *sdata,
+struct mesh_path *mesh_path_lookup(struct mesh_local_bss *mbss,
const u8 *dst);
-struct mesh_path *mpp_path_lookup(struct ieee80211_sub_if_data *sdata,
+struct mesh_path *mpp_path_lookup(struct mesh_local_bss *mbss,
const u8 *dst);
int mpp_path_add(struct ieee80211_sub_if_data *sdata,
const u8 *dst, const u8 *mpp);
@@ -101,14 +101,14 @@ enum mpath_frame_type {
static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
- const u8 *orig_addr, __le32 orig_sn,
- u8 target_flags, const u8 *target,
- __le32 target_sn, const u8 *da,
- u8 hop_count, u8 ttl,
- __le32 lifetime, __le32 metric,
- __le32 preq_id,
- struct ieee80211_sub_if_data *sdata)
+static int __mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
+ const u8 *orig_addr, __le32 orig_sn,
+ u8 target_flags, const u8 *target,
+ __le32 target_sn, const u8 *da,
+ u8 hop_count, u8 ttl,
+ __le32 lifetime, __le32 metric,
+ __le32 preq_id,
+ struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
@@ -201,6 +201,38 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
return 0;
}
+static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
+ const u8 *orig_addr, __le32 orig_sn,
+ u8 target_flags, const u8 *target,
+ __le32 target_sn, const u8 *da,
+ u8 hop_count, u8 ttl,
+ __le32 lifetime, __le32 metric,
+ __le32 preq_id,
+ struct ieee80211_sub_if_data *sdata)
+{
+ struct mesh_local_bss *mbss = mbss(sdata);
+ struct ieee80211_sub_if_data *tmp_sdata;
+ bool broadcast = is_broadcast_ether_addr(da);
+ struct sta_info *sta;
+ int ret = 0;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(tmp_sdata, &mbss->if_list, u.mesh.if_list) {
+ if (!broadcast) {
+ /* find right outgoing interface */
+ sta = sta_info_get(tmp_sdata, da);
+ if (!sta)
+ continue;
+ }
+ ret = __mesh_path_sel_frame_tx(action, flags, orig_addr,
+ orig_sn, target_flags, target, target_sn,
+ da, hop_count, ttl, lifetime, metric,
+ preq_id, tmp_sdata);
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
/* Headroom is not adjusted. Caller should ensure that skb has sufficient
* headroom in case the frame is encrypted. */
@@ -302,6 +334,8 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
ifmsh->next_perr = TU_TO_EXP_TIME(
ifmsh->mshcfg.dot11MeshHWMPperrMinInterval);
ieee80211_add_pending_skb(local, skb);
+ if (is_multicast_ether_addr(mgmt->da))
+ mesh_bss_forward_tx(sdata, skb);
return 0;
}
@@ -376,6 +410,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
const u8 *hwmp_ie, enum mpath_frame_type action)
{
struct ieee80211_local *local = sdata->local;
+ struct mesh_local_bss *mbss = mbss(sdata);
struct mesh_path *mpath;
struct sta_info *sta;
bool fresh_info;
@@ -423,14 +458,14 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
new_metric = MAX_METRIC;
exp_time = TU_TO_EXP_TIME(orig_lifetime);
- if (ether_addr_equal(orig_addr, sdata->vif.addr)) {
+ if (mesh_bss_matches_addr(mbss, orig_addr)) {
/* This MP is the originator, we are not interested in this
* frame, except for updating transmitter's path info.
*/
process = false;
fresh_info = false;
} else {
- mpath = mesh_path_lookup(sdata, orig_addr);
+ mpath = mesh_path_lookup(mbss, orig_addr);
if (mpath) {
spin_lock_bh(&mpath->state_lock);
if (mpath->flags & MESH_PATH_FIXED)
@@ -477,7 +512,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
else {
fresh_info = true;
- mpath = mesh_path_lookup(sdata, ta);
+ mpath = mesh_path_lookup(mbss, ta);
if (mpath) {
spin_lock_bh(&mpath->state_lock);
if ((mpath->flags & MESH_PATH_FIXED) ||
@@ -515,6 +550,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
const u8 *preq_elem, u32 metric)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct mesh_local_bss *mbss = mbss(sdata);
struct mesh_path *mpath = NULL;
const u8 *target_addr, *orig_addr;
const u8 *da;
@@ -537,7 +573,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
mhwmp_dbg(sdata, "received PREQ from %pM\n", orig_addr);
- if (ether_addr_equal(target_addr, sdata->vif.addr)) {
+ if (mesh_bss_matches_addr(mbss, target_addr)) {
mhwmp_dbg(sdata, "PREQ is for us\n");
forward = false;
reply = true;
@@ -551,7 +587,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
} else if (is_broadcast_ether_addr(target_addr) &&
(target_flags & IEEE80211_PREQ_TO_FLAG)) {
rcu_read_lock();
- mpath = mesh_path_lookup(sdata, orig_addr);
+ mpath = mesh_path_lookup(mbss, orig_addr);
if (mpath) {
if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) {
reply = true;
@@ -566,7 +602,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();
} else {
rcu_read_lock();
- mpath = mesh_path_lookup(sdata, target_addr);
+ mpath = mesh_path_lookup(mbss, target_addr);
if (mpath) {
if ((!(mpath->flags & MESH_PATH_SN_VALID)) ||
SN_LT(mpath->sn, target_sn)) {
@@ -646,12 +682,12 @@ next_hop_deref_protected(struct mesh_path *mpath)
lockdep_is_held(&mpath->state_lock));
}
-
static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
const u8 *prep_elem, u32 metric)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct mesh_local_bss *mbss = mbss(sdata);
struct mesh_path *mpath;
const u8 *target_addr, *orig_addr;
u8 ttl, hopcount, flags;
@@ -662,7 +698,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
PREP_IE_TARGET_ADDR(prep_elem));
orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
- if (ether_addr_equal(orig_addr, sdata->vif.addr))
+ if (mesh_bss_matches_addr(mbss, orig_addr))
/* destination, no forwarding required */
return;
@@ -676,7 +712,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
}
rcu_read_lock();
- mpath = mesh_path_lookup(sdata, orig_addr);
+ mpath = mesh_path_lookup(mbss, orig_addr);
if (mpath)
spin_lock_bh(&mpath->state_lock);
else
@@ -734,7 +770,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
target_rcode = PERR_IE_TARGET_RCODE(perr_elem);
rcu_read_lock();
- mpath = mesh_path_lookup(sdata, target_addr);
+ mpath = mesh_path_lookup(mbss(sdata), target_addr);
if (mpath) {
struct sta_info *sta;
@@ -766,6 +802,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_local *local = sdata->local;
+ struct mesh_local_bss *mbss = mbss(sdata);
struct sta_info *sta;
struct mesh_path *mpath;
u8 ttl, flags, hopcount;
@@ -784,7 +821,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
metric = le32_to_cpu(rann->rann_metric);
/* Ignore our own RANNs */
- if (ether_addr_equal(orig_addr, sdata->vif.addr))
+ if (mesh_bss_matches_addr(mbss, orig_addr))
return;
mhwmp_dbg(sdata,
@@ -800,7 +837,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
metric_txsta = airtime_link_metric_get(local, sta);
- mpath = mesh_path_lookup(sdata, orig_addr);
+ mpath = mesh_path_lookup(mbss, orig_addr);
if (!mpath) {
mpath = mesh_path_add(sdata, orig_addr);
if (IS_ERR(mpath)) {
@@ -982,6 +1019,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct mesh_local_bss *mbss = mbss(sdata);
struct mesh_preq_queue *preq_node;
struct mesh_path *mpath;
u8 ttl, target_flags;
@@ -1003,7 +1041,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
rcu_read_lock();
- mpath = mesh_path_lookup(sdata, preq_node->dst);
+ mpath = mesh_path_lookup(mbss, preq_node->dst);
if (!mpath)
goto enddiscovery;
@@ -1078,6 +1116,7 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct mesh_local_bss *mbss = mbss(sdata);
struct mesh_path *mpath;
struct sk_buff *skb_to_free = NULL;
u8 *target_addr = hdr->addr3;
@@ -1088,12 +1127,12 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
return 0;
rcu_read_lock();
- err = mesh_nexthop_lookup(sdata, skb);
+ err = mesh_nexthop_lookup(mbss, skb);
if (!err)
goto endlookup;
/* no nexthop found, start resolving */
- mpath = mesh_path_lookup(sdata, target_addr);
+ mpath = mesh_path_lookup(mbss, target_addr);
if (!mpath) {
mpath = mesh_path_add(sdata, target_addr);
if (IS_ERR(mpath)) {
@@ -1122,46 +1161,54 @@ endlookup:
}
/**
- * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame. Calling
- * this function is considered "using" the associated mpath, so preempt a path
- * refresh if this mpath expires soon.
+ * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame and
+ * insert the correct outgoing interface on the skb cb. Calling this function
+ * is considered "using" the associated mpath, so preempt a path refresh if
+ * this mpath expires soon.
*
* @skb: 802.11 frame to be sent
- * @sdata: network subif the frame will be sent through
+ * @mbss: MBSS in which to find a path
*
* Returns: 0 if the next hop was found. Nonzero otherwise.
*/
-int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata,
+int mesh_nexthop_lookup(struct mesh_local_bss *mbss,
struct sk_buff *skb)
{
+ struct ieee80211_sub_if_data *sdata = NULL;
struct mesh_path *mpath;
struct sta_info *next_hop;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_tx_info *info;
u8 *target_addr = hdr->addr3;
int err = -ENOENT;
rcu_read_lock();
- mpath = mesh_path_lookup(sdata, target_addr);
+ mpath = mesh_path_lookup(mbss, target_addr);
if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE))
goto endlookup;
- if (time_after(jiffies,
- mpath->exp_time -
- msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
- ether_addr_equal(sdata->vif.addr, hdr->addr4) &&
- !(mpath->flags & MESH_PATH_RESOLVING) &&
- !(mpath->flags & MESH_PATH_FIXED))
- mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
-
next_hop = rcu_dereference(mpath->next_hop);
if (next_hop) {
+ info = IEEE80211_SKB_CB(skb);
+ sdata = mpath->sdata;
+ info->control.vif = &sdata->vif;
memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
ieee80211_mps_set_frame_flags(sdata, next_hop, hdr);
err = 0;
}
+ if (sdata &&
+ time_after(jiffies,
+ mpath->exp_time -
+ msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
+ ether_addr_equal(sdata->vif.addr, hdr->addr4) &&
+ !(mpath->flags & MESH_PATH_RESOLVING) &&
+ !(mpath->flags & MESH_PATH_FIXED))
+ mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
+
+
endlookup:
rcu_read_unlock();
return err;
@@ -184,11 +184,11 @@ errcopy:
return -ENOMEM;
}
-static u32 mesh_table_hash(const u8 *addr, struct ieee80211_sub_if_data *sdata,
+static u32 mesh_table_hash(struct mesh_local_bss *mbss, const u8 *addr,
struct mesh_table *tbl)
{
- /* Use last four bytes of hw addr and interface index as hash index */
- return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex,
+ /* Use last four bytes of hw addr and first four of meshid */
+ return jhash_2words(*(u32 *)(addr+2), *(u32 *) mbss->mesh_id,
tbl->hash_rnd) & tbl->hash_mask;
}
@@ -328,15 +328,14 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath,
spin_unlock_irqrestore(&from_mpath->frame_queue.lock, flags);
}
-
-static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
- struct ieee80211_sub_if_data *sdata)
+static struct mesh_path *__mpath_lookup(struct mesh_table *tbl, const u8 *dst,
+ struct ieee80211_sub_if_data *sdata)
{
struct mesh_path *mpath;
struct hlist_head *bucket;
struct mpath_node *node;
- bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)];
+ bucket = &tbl->hash_buckets[mesh_table_hash(mbss(sdata), dst, tbl)];
hlist_for_each_entry_rcu(node, bucket, list) {
mpath = node->mpath;
if (mpath->sdata == sdata &&
@@ -352,9 +351,25 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
return NULL;
}
+static struct mesh_path *mpath_lookup(struct mesh_table *tbl,
+ struct mesh_local_bss *mbss,
+ const u8 *dst)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct mesh_path *mpath;
+
+ list_for_each_entry_rcu(sdata, &mbss->if_list, u.mesh.if_list) {
+ mpath = __mpath_lookup(tbl, dst, sdata);
+ if (mpath)
+ return mpath;
+ }
+ return NULL;
+}
+
/**
* mesh_path_lookup - look up a path in the mesh path table
- * @sdata: local subif
+ *
+ * @mbss: MBSS where this destination might be found
* @dst: hardware address (ETH_ALEN length) of destination
*
* Returns: pointer to the mesh path structure, or NULL if not found
@@ -362,15 +377,15 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
* Locking: must be called within a read rcu section.
*/
struct mesh_path *
-mesh_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
+mesh_path_lookup(struct mesh_local_bss *mbss, const u8 *dst)
{
- return mpath_lookup(rcu_dereference(mesh_paths), dst, sdata);
+ return mpath_lookup(rcu_dereference(mesh_paths), mbss, dst);
}
struct mesh_path *
-mpp_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
+mpp_path_lookup(struct mesh_local_bss *mbss, const u8 *dst)
{
- return mpath_lookup(rcu_dereference(mpp_paths), dst, sdata);
+ return mpath_lookup(rcu_dereference(mpp_paths), mbss, dst);
}
@@ -519,7 +534,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
read_lock_bh(&pathtbl_resize_lock);
tbl = resize_dereference_mesh_paths();
- hash_idx = mesh_table_hash(dst, sdata, tbl);
+ hash_idx = mesh_table_hash(mbss(sdata), dst, tbl);
bucket = &tbl->hash_buckets[hash_idx];
spin_lock(&tbl->hashwlock[hash_idx]);
@@ -669,7 +684,7 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
tbl = resize_dereference_mpp_paths();
- hash_idx = mesh_table_hash(dst, sdata, tbl);
+ hash_idx = mesh_table_hash(mbss(sdata), dst, tbl);
bucket = &tbl->hash_buckets[hash_idx];
spin_lock(&tbl->hashwlock[hash_idx]);
@@ -862,7 +877,7 @@ int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
read_lock_bh(&pathtbl_resize_lock);
tbl = resize_dereference_mesh_paths();
- hash_idx = mesh_table_hash(addr, sdata, tbl);
+ hash_idx = mesh_table_hash(mbss(sdata), addr, tbl);
bucket = &tbl->hash_buckets[hash_idx];
spin_lock(&tbl->hashwlock[hash_idx]);
@@ -1028,7 +1043,7 @@ static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
node = hlist_entry(p, struct mpath_node, list);
mpath = node->mpath;
new_node->mpath = mpath;
- hash_idx = mesh_table_hash(mpath->dst, mpath->sdata, newtbl);
+ hash_idx = mesh_table_hash(mbss(mpath->sdata), mpath->dst, newtbl);
hlist_add_head(&new_node->list,
&newtbl->hash_buckets[hash_idx]);
return 0;
@@ -2006,6 +2006,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
struct sk_buff *skb = rx->skb, *fwd_skb;
struct ieee80211_local *local = rx->local;
struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct mesh_local_bss *mbss = mbss(sdata);
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
__le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);
@@ -2059,7 +2060,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
}
rcu_read_lock();
- mppath = mpp_path_lookup(sdata, proxied_addr);
+ mppath = mpp_path_lookup(mbss, proxied_addr);
if (!mppath) {
mpp_path_add(sdata, proxied_addr, mpp_addr);
} else {
@@ -2110,7 +2111,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
/* update power mode indication when forwarding */
ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
- } else if (!mesh_nexthop_lookup(sdata, fwd_skb)) {
+ } else if (!mesh_nexthop_lookup(mbss, fwd_skb)) {
/* mesh power mode flags updated in mesh_nexthop_lookup */
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
} else {
@@ -1799,7 +1799,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct sta_info *next_hop;
bool mpp_lookup = true;
- mpath = mesh_path_lookup(sdata, skb->data);
+ mpath = mesh_path_lookup(mbss(sdata), skb->data);
if (mpath) {
mpp_lookup = false;
next_hop = rcu_dereference(mpath->next_hop);
@@ -1810,7 +1810,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
}
if (mpp_lookup)
- mppath = mpp_path_lookup(sdata, skb->data);
+ mppath = mpp_path_lookup(mbss(sdata),
+ skb->data);
if (mppath && mpath)
mesh_path_del(mpath->sdata, mpath->dst);