mac80211: update mesh path selection frame format
Make mesh path selection frames Mesh Action category, remove outdated Mesh Path Selection category and defines, use updated reason codes, add mesh_action_is_path_sel for readability, and update/correct path selection IEs. Signed-off-by: Thomas Pedersen <thomas@cozybit.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
36c704fded
commit
25d49e4d63
|
@ -629,6 +629,7 @@ struct ieee80211_rann_ie {
|
||||||
u8 rann_ttl;
|
u8 rann_ttl;
|
||||||
u8 rann_addr[6];
|
u8 rann_addr[6];
|
||||||
u32 rann_seq;
|
u32 rann_seq;
|
||||||
|
u32 rann_interval;
|
||||||
u32 rann_metric;
|
u32 rann_metric;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
@ -1269,9 +1270,6 @@ enum ieee80211_category {
|
||||||
WLAN_CATEGORY_MULTIHOP_ACTION = 14,
|
WLAN_CATEGORY_MULTIHOP_ACTION = 14,
|
||||||
WLAN_CATEGORY_SELF_PROTECTED = 15,
|
WLAN_CATEGORY_SELF_PROTECTED = 15,
|
||||||
WLAN_CATEGORY_WMM = 17,
|
WLAN_CATEGORY_WMM = 17,
|
||||||
/* TODO: remove MESH_PATH_SEL after mesh is updated
|
|
||||||
* to current 802.11s draft */
|
|
||||||
WLAN_CATEGORY_MESH_PATH_SEL = 32,
|
|
||||||
WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126,
|
WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126,
|
||||||
WLAN_CATEGORY_VENDOR_SPECIFIC = 127,
|
WLAN_CATEGORY_VENDOR_SPECIFIC = 127,
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,10 +13,6 @@
|
||||||
#include "ieee80211_i.h"
|
#include "ieee80211_i.h"
|
||||||
#include "mesh.h"
|
#include "mesh.h"
|
||||||
|
|
||||||
#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
|
|
||||||
#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
|
|
||||||
#define IEEE80211_MESH_RANN_INTERVAL (1 * HZ)
|
|
||||||
|
|
||||||
#define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01
|
#define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01
|
||||||
#define MESHCONF_CAPAB_FORWARDING 0x08
|
#define MESHCONF_CAPAB_FORWARDING 0x08
|
||||||
|
|
||||||
|
@ -27,6 +23,17 @@
|
||||||
int mesh_allocated;
|
int mesh_allocated;
|
||||||
static struct kmem_cache *rm_cache;
|
static struct kmem_cache *rm_cache;
|
||||||
|
|
||||||
|
#ifdef CONFIG_MAC80211_MESH
|
||||||
|
bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
|
||||||
|
{
|
||||||
|
return (mgmt->u.action.u.mesh_action.action_code ==
|
||||||
|
WLAN_MESH_ACTION_HWMP_PATH_SELECTION);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
|
||||||
|
{ return false; }
|
||||||
|
#endif
|
||||||
|
|
||||||
void ieee80211s_init(void)
|
void ieee80211s_init(void)
|
||||||
{
|
{
|
||||||
mesh_pathtbl_init();
|
mesh_pathtbl_init();
|
||||||
|
@ -671,8 +678,9 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WLAN_CATEGORY_MESH_PATH_SEL:
|
case WLAN_CATEGORY_MESH_ACTION:
|
||||||
mesh_rx_path_sel_frame(sdata, mgmt, len);
|
if (mesh_action_is_path_sel(mgmt))
|
||||||
|
mesh_rx_path_sel_frame(sdata, mgmt, len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,6 +166,9 @@ struct mesh_rmc {
|
||||||
u32 idx_mask;
|
u32 idx_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
|
||||||
|
#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
|
||||||
|
#define IEEE80211_MESH_RANN_INTERVAL (1 * HZ)
|
||||||
|
|
||||||
#define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */
|
#define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */
|
||||||
|
|
||||||
|
@ -177,14 +180,6 @@ struct mesh_rmc {
|
||||||
/* Maximum number of paths per interface */
|
/* Maximum number of paths per interface */
|
||||||
#define MESH_MAX_MPATHS 1024
|
#define MESH_MAX_MPATHS 1024
|
||||||
|
|
||||||
/* Pending ANA approval */
|
|
||||||
#define MESH_PATH_SEL_ACTION 0
|
|
||||||
|
|
||||||
/* PERR reason codes */
|
|
||||||
#define PEER_RCODE_UNSPECIFIED 11
|
|
||||||
#define PERR_RCODE_NO_ROUTE 12
|
|
||||||
#define PERR_RCODE_DEST_UNREACH 13
|
|
||||||
|
|
||||||
/* Public interfaces */
|
/* Public interfaces */
|
||||||
/* Various */
|
/* Various */
|
||||||
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
|
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
|
||||||
|
@ -276,6 +271,7 @@ void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata);
|
||||||
void mesh_path_restart(struct ieee80211_sub_if_data *sdata);
|
void mesh_path_restart(struct ieee80211_sub_if_data *sdata);
|
||||||
void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);
|
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 mesh_paths_generation;
|
||||||
|
|
||||||
#ifdef CONFIG_MAC80211_MESH
|
#ifdef CONFIG_MAC80211_MESH
|
||||||
|
|
|
@ -68,12 +68,12 @@ static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae)
|
||||||
#define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x)
|
#define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x)
|
||||||
#define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x)
|
#define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x)
|
||||||
#define PREP_IE_TTL(x) PREQ_IE_TTL(x)
|
#define PREP_IE_TTL(x) PREQ_IE_TTL(x)
|
||||||
#define PREP_IE_ORIG_ADDR(x) (x + 3)
|
#define PREP_IE_ORIG_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21)
|
||||||
#define PREP_IE_ORIG_SN(x) u32_field_get(x, 9, 0)
|
#define PREP_IE_ORIG_SN(x) u32_field_get(x, 27, AE_F_SET(x))
|
||||||
#define PREP_IE_LIFETIME(x) u32_field_get(x, 13, AE_F_SET(x))
|
#define PREP_IE_LIFETIME(x) u32_field_get(x, 13, AE_F_SET(x))
|
||||||
#define PREP_IE_METRIC(x) u32_field_get(x, 17, AE_F_SET(x))
|
#define PREP_IE_METRIC(x) u32_field_get(x, 17, AE_F_SET(x))
|
||||||
#define PREP_IE_TARGET_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21)
|
#define PREP_IE_TARGET_ADDR(x) (x + 3)
|
||||||
#define PREP_IE_TARGET_SN(x) u32_field_get(x, 27, AE_F_SET(x))
|
#define PREP_IE_TARGET_SN(x) u32_field_get(x, 9, 0)
|
||||||
|
|
||||||
#define PERR_IE_TTL(x) (*(x))
|
#define PERR_IE_TTL(x) (*(x))
|
||||||
#define PERR_IE_TARGET_FLAGS(x) (*(x + 2))
|
#define PERR_IE_TARGET_FLAGS(x) (*(x + 2))
|
||||||
|
@ -132,8 +132,9 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
|
||||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||||
/* BSSID == SA */
|
/* BSSID == SA */
|
||||||
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
|
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
|
||||||
mgmt->u.action.category = WLAN_CATEGORY_MESH_PATH_SEL;
|
mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
|
||||||
mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
|
mgmt->u.action.u.mesh_action.action_code =
|
||||||
|
WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case MPATH_PREQ:
|
case MPATH_PREQ:
|
||||||
|
@ -163,29 +164,37 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
|
||||||
*pos++ = flags;
|
*pos++ = flags;
|
||||||
*pos++ = hop_count;
|
*pos++ = hop_count;
|
||||||
*pos++ = ttl;
|
*pos++ = ttl;
|
||||||
if (action == MPATH_PREQ) {
|
if (action == MPATH_PREP) {
|
||||||
memcpy(pos, &preq_id, 4);
|
|
||||||
pos += 4;
|
|
||||||
}
|
|
||||||
memcpy(pos, orig_addr, ETH_ALEN);
|
|
||||||
pos += ETH_ALEN;
|
|
||||||
memcpy(pos, &orig_sn, 4);
|
|
||||||
pos += 4;
|
|
||||||
if (action != MPATH_RANN) {
|
|
||||||
memcpy(pos, &lifetime, 4);
|
|
||||||
pos += 4;
|
|
||||||
}
|
|
||||||
memcpy(pos, &metric, 4);
|
|
||||||
pos += 4;
|
|
||||||
if (action == MPATH_PREQ) {
|
|
||||||
/* destination count */
|
|
||||||
*pos++ = 1;
|
|
||||||
*pos++ = target_flags;
|
|
||||||
}
|
|
||||||
if (action != MPATH_RANN) {
|
|
||||||
memcpy(pos, target, ETH_ALEN);
|
memcpy(pos, target, ETH_ALEN);
|
||||||
pos += ETH_ALEN;
|
pos += ETH_ALEN;
|
||||||
memcpy(pos, &target_sn, 4);
|
memcpy(pos, &target_sn, 4);
|
||||||
|
pos += 4;
|
||||||
|
} else {
|
||||||
|
if (action == MPATH_PREQ) {
|
||||||
|
memcpy(pos, &preq_id, 4);
|
||||||
|
pos += 4;
|
||||||
|
}
|
||||||
|
memcpy(pos, orig_addr, ETH_ALEN);
|
||||||
|
pos += ETH_ALEN;
|
||||||
|
memcpy(pos, &orig_sn, 4);
|
||||||
|
pos += 4;
|
||||||
|
}
|
||||||
|
memcpy(pos, &lifetime, 4); /* interval for RANN */
|
||||||
|
pos += 4;
|
||||||
|
memcpy(pos, &metric, 4);
|
||||||
|
pos += 4;
|
||||||
|
if (action == MPATH_PREQ) {
|
||||||
|
*pos++ = 1; /* destination count */
|
||||||
|
*pos++ = target_flags;
|
||||||
|
memcpy(pos, target, ETH_ALEN);
|
||||||
|
pos += ETH_ALEN;
|
||||||
|
memcpy(pos, &target_sn, 4);
|
||||||
|
pos += 4;
|
||||||
|
} else if (action == MPATH_PREP) {
|
||||||
|
memcpy(pos, orig_addr, ETH_ALEN);
|
||||||
|
pos += ETH_ALEN;
|
||||||
|
memcpy(pos, &orig_sn, 4);
|
||||||
|
pos += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
ieee80211_tx_skb(sdata, skb);
|
ieee80211_tx_skb(sdata, skb);
|
||||||
|
@ -224,9 +233,11 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
|
||||||
|
|
||||||
memcpy(mgmt->da, ra, ETH_ALEN);
|
memcpy(mgmt->da, ra, ETH_ALEN);
|
||||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||||
/* BSSID is left zeroed, wildcard value */
|
/* BSSID == SA */
|
||||||
mgmt->u.action.category = WLAN_CATEGORY_MESH_PATH_SEL;
|
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
|
||||||
mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
|
mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
|
||||||
|
mgmt->u.action.u.mesh_action.action_code =
|
||||||
|
WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
|
||||||
ie_len = 15;
|
ie_len = 15;
|
||||||
pos = skb_put(skb, 2 + ie_len);
|
pos = skb_put(skb, 2 + ie_len);
|
||||||
*pos++ = WLAN_EID_PERR;
|
*pos++ = WLAN_EID_PERR;
|
||||||
|
@ -683,6 +694,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
|
||||||
u8 ttl, flags, hopcount;
|
u8 ttl, flags, hopcount;
|
||||||
u8 *orig_addr;
|
u8 *orig_addr;
|
||||||
u32 orig_sn, metric;
|
u32 orig_sn, metric;
|
||||||
|
u32 interval = cpu_to_le32(IEEE80211_MESH_RANN_INTERVAL);
|
||||||
|
|
||||||
ttl = rann->rann_ttl;
|
ttl = rann->rann_ttl;
|
||||||
if (ttl <= 1) {
|
if (ttl <= 1) {
|
||||||
|
@ -715,7 +727,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
|
||||||
mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
|
mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
|
||||||
cpu_to_le32(orig_sn),
|
cpu_to_le32(orig_sn),
|
||||||
0, NULL, 0, broadcast_addr,
|
0, NULL, 0, broadcast_addr,
|
||||||
hopcount, ttl, 0,
|
hopcount, ttl, interval,
|
||||||
cpu_to_le32(metric + mpath->metric),
|
cpu_to_le32(metric + mpath->metric),
|
||||||
0, sdata);
|
0, sdata);
|
||||||
mpath->sn = orig_sn;
|
mpath->sn = orig_sn;
|
||||||
|
@ -1006,10 +1018,11 @@ void
|
||||||
mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
|
mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
|
||||||
{
|
{
|
||||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||||
|
u32 interval = cpu_to_le32(IEEE80211_MESH_RANN_INTERVAL);
|
||||||
|
|
||||||
mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr,
|
mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr,
|
||||||
cpu_to_le32(++ifmsh->sn),
|
cpu_to_le32(++ifmsh->sn),
|
||||||
0, NULL, 0, broadcast_addr,
|
0, NULL, 0, broadcast_addr,
|
||||||
0, sdata->u.mesh.mshcfg.element_ttl,
|
0, sdata->u.mesh.mshcfg.element_ttl,
|
||||||
0, 0, 0, sdata);
|
interval, 0, 0, sdata);
|
||||||
}
|
}
|
||||||
|
|
|
@ -539,6 +539,7 @@ void mesh_plink_broken(struct sta_info *sta)
|
||||||
struct hlist_node *p;
|
struct hlist_node *p;
|
||||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||||
int i;
|
int i;
|
||||||
|
__le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_DEST_UNREACHABLE);
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
tbl = rcu_dereference(mesh_paths);
|
tbl = rcu_dereference(mesh_paths);
|
||||||
|
@ -553,8 +554,7 @@ void mesh_plink_broken(struct sta_info *sta)
|
||||||
spin_unlock_bh(&mpath->state_lock);
|
spin_unlock_bh(&mpath->state_lock);
|
||||||
mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl,
|
mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl,
|
||||||
mpath->dst, cpu_to_le32(mpath->sn),
|
mpath->dst, cpu_to_le32(mpath->sn),
|
||||||
cpu_to_le16(PERR_RCODE_DEST_UNREACH),
|
reason, bcast, sdata);
|
||||||
bcast, sdata);
|
|
||||||
} else
|
} else
|
||||||
spin_unlock_bh(&mpath->state_lock);
|
spin_unlock_bh(&mpath->state_lock);
|
||||||
}
|
}
|
||||||
|
@ -699,6 +699,7 @@ void mesh_path_discard_frame(struct sk_buff *skb,
|
||||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||||
struct mesh_path *mpath;
|
struct mesh_path *mpath;
|
||||||
u32 sn = 0;
|
u32 sn = 0;
|
||||||
|
__le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);
|
||||||
|
|
||||||
if (memcmp(hdr->addr4, sdata->vif.addr, ETH_ALEN) != 0) {
|
if (memcmp(hdr->addr4, sdata->vif.addr, ETH_ALEN) != 0) {
|
||||||
u8 *ra, *da;
|
u8 *ra, *da;
|
||||||
|
@ -709,8 +710,7 @@ void mesh_path_discard_frame(struct sk_buff *skb,
|
||||||
if (mpath)
|
if (mpath)
|
||||||
sn = ++mpath->sn;
|
sn = ++mpath->sn;
|
||||||
mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, skb->data,
|
mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, skb->data,
|
||||||
cpu_to_le32(sn),
|
cpu_to_le32(sn), reason, ra, sdata);
|
||||||
cpu_to_le16(PERR_RCODE_NO_ROUTE), ra, sdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
|
|
@ -2241,9 +2241,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
||||||
case WLAN_CATEGORY_MESH_ACTION:
|
case WLAN_CATEGORY_MESH_ACTION:
|
||||||
if (!ieee80211_vif_is_mesh(&sdata->vif))
|
if (!ieee80211_vif_is_mesh(&sdata->vif))
|
||||||
break;
|
break;
|
||||||
goto queue;
|
if (mesh_action_is_path_sel(mgmt) &&
|
||||||
case WLAN_CATEGORY_MESH_PATH_SEL:
|
(!mesh_path_sel_is_hwmp(sdata)))
|
||||||
if (!mesh_path_sel_is_hwmp(sdata))
|
|
||||||
break;
|
break;
|
||||||
goto queue;
|
goto queue;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue