Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

This commit is contained in:
John W. Linville 2013-02-18 15:27:42 -05:00
commit a9908ebf5c
15 changed files with 309 additions and 334 deletions

View File

@ -107,8 +107,8 @@
!Finclude/net/cfg80211.h key_params !Finclude/net/cfg80211.h key_params
!Finclude/net/cfg80211.h survey_info_flags !Finclude/net/cfg80211.h survey_info_flags
!Finclude/net/cfg80211.h survey_info !Finclude/net/cfg80211.h survey_info
!Finclude/net/cfg80211.h beacon_parameters !Finclude/net/cfg80211.h cfg80211_beacon_data
!Finclude/net/cfg80211.h plink_actions !Finclude/net/cfg80211.h cfg80211_ap_settings
!Finclude/net/cfg80211.h station_parameters !Finclude/net/cfg80211.h station_parameters
!Finclude/net/cfg80211.h station_info_flags !Finclude/net/cfg80211.h station_info_flags
!Finclude/net/cfg80211.h rate_info_flags !Finclude/net/cfg80211.h rate_info_flags

View File

@ -1500,13 +1500,13 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
return -ENOENT; return -ENOENT;
} }
err = mesh_path_add(dst, sdata); err = mesh_path_add(sdata, dst);
if (err) { if (err) {
rcu_read_unlock(); rcu_read_unlock();
return err; return err;
} }
mpath = mesh_path_lookup(dst, sdata); mpath = mesh_path_lookup(sdata, dst);
if (!mpath) { if (!mpath) {
rcu_read_unlock(); rcu_read_unlock();
return -ENXIO; return -ENXIO;
@ -1518,12 +1518,12 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
} }
static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
u8 *dst) u8 *dst)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (dst) if (dst)
return mesh_path_del(dst, sdata); return mesh_path_del(sdata, dst);
mesh_path_flush_by_iface(sdata); mesh_path_flush_by_iface(sdata);
return 0; return 0;
@ -1547,7 +1547,7 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
return -ENOENT; return -ENOENT;
} }
mpath = mesh_path_lookup(dst, sdata); mpath = mesh_path_lookup(sdata, dst);
if (!mpath) { if (!mpath) {
rcu_read_unlock(); rcu_read_unlock();
return -ENOENT; return -ENOENT;
@ -1611,7 +1611,7 @@ static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
rcu_read_lock(); rcu_read_lock();
mpath = mesh_path_lookup(dst, sdata); mpath = mesh_path_lookup(sdata, dst);
if (!mpath) { if (!mpath) {
rcu_read_unlock(); rcu_read_unlock();
return -ENOENT; return -ENOENT;
@ -1632,7 +1632,7 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
rcu_read_lock(); rcu_read_lock();
mpath = mesh_path_lookup_by_idx(idx, sdata); mpath = mesh_path_lookup_by_idx(sdata, idx);
if (!mpath) { if (!mpath) {
rcu_read_unlock(); rcu_read_unlock();
return -ENOENT; return -ENOENT;

View File

@ -294,7 +294,8 @@ static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata)
} }
} }
if ((sdata->vif.type != NL80211_IFTYPE_AP) || if ((sdata->vif.type != NL80211_IFTYPE_AP &&
sdata->vif.type != NL80211_IFTYPE_MESH_POINT) ||
!(sdata->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) { !(sdata->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) {
sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
return 0; return 0;
@ -695,6 +696,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
ieee80211_roc_purge(sdata); ieee80211_roc_purge(sdata);
if (sdata->vif.type == NL80211_IFTYPE_STATION)
ieee80211_mgd_stop(sdata);
/* /*
* Remove all stations associated with this interface. * Remove all stations associated with this interface.
* *
@ -782,8 +786,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
} }
} }
spin_unlock_irqrestore(&ps->bc_buf.lock, flags); spin_unlock_irqrestore(&ps->bc_buf.lock, flags);
} else if (sdata->vif.type == NL80211_IFTYPE_STATION) {
ieee80211_mgd_stop(sdata);
} }
if (going_down) if (going_down)

View File

@ -1173,8 +1173,7 @@ static void __exit ieee80211_exit(void)
rc80211_minstrel_ht_exit(); rc80211_minstrel_ht_exit();
rc80211_minstrel_exit(); rc80211_minstrel_exit();
if (mesh_allocated) ieee80211s_stop();
ieee80211s_stop();
ieee80211_iface_exit(); ieee80211_iface_exit();

View File

@ -17,7 +17,7 @@
#define TMR_RUNNING_MP 1 #define TMR_RUNNING_MP 1
#define TMR_RUNNING_MPR 2 #define TMR_RUNNING_MPR 2
int mesh_allocated; static int mesh_allocated;
static struct kmem_cache *rm_cache; static struct kmem_cache *rm_cache;
bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt) bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
@ -36,6 +36,8 @@ void ieee80211s_init(void)
void ieee80211s_stop(void) void ieee80211s_stop(void)
{ {
if (!mesh_allocated)
return;
mesh_pathtbl_unregister(); mesh_pathtbl_unregister();
kmem_cache_destroy(rm_cache); kmem_cache_destroy(rm_cache);
} }
@ -90,24 +92,22 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
(ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) && (ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) &&
(ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) && (ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) &&
(ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))) (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)))
goto mismatch; return false;
ieee80211_sta_get_rates(local, ie, ieee80211_get_sdata_band(sdata), ieee80211_sta_get_rates(local, ie, ieee80211_get_sdata_band(sdata),
&basic_rates); &basic_rates);
if (sdata->vif.bss_conf.basic_rates != basic_rates) if (sdata->vif.bss_conf.basic_rates != basic_rates)
goto mismatch; return false;
ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
ie->ht_operation, &sta_chan_def); ie->ht_operation, &sta_chan_def);
if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef, if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
&sta_chan_def)) &sta_chan_def))
goto mismatch; return false;
return true; return true;
mismatch:
return false;
} }
/** /**
@ -118,7 +118,7 @@ mismatch:
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
{ {
return (ie->mesh_config->meshconf_cap & return (ie->mesh_config->meshconf_cap &
IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS) != 0;
} }
/** /**
@ -196,11 +196,12 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
if (!sdata->u.mesh.rmc) if (!sdata->u.mesh.rmc)
return; return;
for (i = 0; i < RMC_BUCKETS; i++) for (i = 0; i < RMC_BUCKETS; i++) {
list_for_each_entry_safe(p, n, &rmc->bucket[i], list) { list_for_each_entry_safe(p, n, &rmc->bucket[i], list) {
list_del(&p->list); list_del(&p->list);
kmem_cache_free(rm_cache, p); kmem_cache_free(rm_cache, p);
} }
}
kfree(rmc); kfree(rmc);
sdata->u.mesh.rmc = NULL; sdata->u.mesh.rmc = NULL;
@ -209,6 +210,7 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
/** /**
* mesh_rmc_check - Check frame in recent multicast cache and add if absent. * mesh_rmc_check - Check frame in recent multicast cache and add if absent.
* *
* @sdata: interface
* @sa: source address * @sa: source address
* @mesh_hdr: mesh_header * @mesh_hdr: mesh_header
* *
@ -218,8 +220,8 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
* received this frame lately. If the frame is not in the cache, it is added to * received this frame lately. If the frame is not in the cache, it is added to
* it. * it.
*/ */
int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr, int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata) const u8 *sa, struct ieee80211s_hdr *mesh_hdr)
{ {
struct mesh_rmc *rmc = sdata->u.mesh.rmc; struct mesh_rmc *rmc = sdata->u.mesh.rmc;
u32 seqnum = 0; u32 seqnum = 0;
@ -233,12 +235,11 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
list_for_each_entry_safe(p, n, &rmc->bucket[idx], list) { list_for_each_entry_safe(p, n, &rmc->bucket[idx], list) {
++entries; ++entries;
if (time_after(jiffies, p->exp_time) || if (time_after(jiffies, p->exp_time) ||
(entries == RMC_QUEUE_MAX_LEN)) { entries == RMC_QUEUE_MAX_LEN) {
list_del(&p->list); list_del(&p->list);
kmem_cache_free(rm_cache, p); kmem_cache_free(rm_cache, p);
--entries; --entries;
} else if ((seqnum == p->seqnum) && } else if ((seqnum == p->seqnum) && ether_addr_equal(sa, p->sa))
(ether_addr_equal(sa, p->sa)))
return -1; return -1;
} }
@ -253,8 +254,8 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
return 0; return 0;
} }
int int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) struct sk_buff *skb)
{ {
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u8 *pos, neighbors; u8 *pos, neighbors;
@ -285,19 +286,18 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
/* Mesh capability */ /* Mesh capability */
*pos = IEEE80211_MESHCONF_CAPAB_FORWARDING; *pos = IEEE80211_MESHCONF_CAPAB_FORWARDING;
*pos |= ifmsh->accepting_plinks ? *pos |= ifmsh->accepting_plinks ?
IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
/* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */ /* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */
*pos |= ifmsh->ps_peers_deep_sleep ? *pos |= ifmsh->ps_peers_deep_sleep ?
IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00; IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00;
*pos++ |= ifmsh->adjusting_tbtt ? *pos++ |= ifmsh->adjusting_tbtt ?
IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00;
*pos++ = 0x00; *pos++ = 0x00;
return 0; return 0;
} }
int int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
mesh_add_meshid_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
{ {
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u8 *pos; u8 *pos;
@ -314,8 +314,8 @@ mesh_add_meshid_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
return 0; return 0;
} }
int mesh_add_awake_window_ie(struct sk_buff *skb, static int mesh_add_awake_window_ie(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata) struct sk_buff *skb)
{ {
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u8 *pos; u8 *pos;
@ -337,8 +337,8 @@ int mesh_add_awake_window_ie(struct sk_buff *skb,
return 0; return 0;
} }
int int mesh_add_vendor_ies(struct ieee80211_sub_if_data *sdata,
mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) struct sk_buff *skb)
{ {
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u8 offset, len; u8 offset, len;
@ -361,8 +361,7 @@ mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
return 0; return 0;
} }
int int mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
{ {
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u8 len = 0; u8 len = 0;
@ -390,8 +389,8 @@ mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
return 0; return 0;
} }
int mesh_add_ds_params_ie(struct sk_buff *skb, static int mesh_add_ds_params_ie(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata) struct sk_buff *skb)
{ {
struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
@ -417,8 +416,8 @@ int mesh_add_ds_params_ie(struct sk_buff *skb,
return 0; return 0;
} }
int mesh_add_ht_cap_ie(struct sk_buff *skb, int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata) struct sk_buff *skb)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
enum ieee80211_band band = ieee80211_get_sdata_band(sdata); enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
@ -439,8 +438,8 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb,
return 0; return 0;
} }
int mesh_add_ht_oper_ie(struct sk_buff *skb, int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata) struct sk_buff *skb)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_chanctx_conf *chanctx_conf;
@ -475,6 +474,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb,
return 0; return 0;
} }
static void ieee80211_mesh_path_timer(unsigned long data) static void ieee80211_mesh_path_timer(unsigned long data)
{ {
struct ieee80211_sub_if_data *sdata = struct ieee80211_sub_if_data *sdata =
@ -520,7 +520,7 @@ void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
/** /**
* ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
* @hdr: 802.11 frame header * @hdr: 802.11 frame header
* @fc: frame control field * @fc: frame control field
* @meshda: destination address in the mesh * @meshda: destination address in the mesh
* @meshsa: source address address in the mesh. Same as TA, as frame is * @meshsa: source address address in the mesh. Same as TA, as frame is
@ -551,8 +551,8 @@ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
/** /**
* ieee80211_new_mesh_header - create a new mesh header * ieee80211_new_mesh_header - create a new mesh header
* @meshhdr: uninitialized mesh header
* @sdata: mesh interface to be used * @sdata: mesh interface to be used
* @meshhdr: uninitialized mesh header
* @addr4or5: 1st address in the ae header, which may correspond to address 4 * @addr4or5: 1st address in the ae header, which may correspond to address 4
* (if addr6 is NULL) or address 5 (if addr6 is present). It may * (if addr6 is NULL) or address 5 (if addr6 is present). It may
* be NULL. * be NULL.
@ -561,32 +561,38 @@ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
* *
* Return the header length. * Return the header length.
*/ */
int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata, char *addr4or5, struct ieee80211s_hdr *meshhdr,
char *addr6) const char *addr4or5, const char *addr6)
{ {
int aelen = 0; if (WARN_ON(!addr4or5 && addr6))
BUG_ON(!addr4or5 && addr6); return 0;
memset(meshhdr, 0, sizeof(*meshhdr)); memset(meshhdr, 0, sizeof(*meshhdr));
meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
/* FIXME: racy -- TX on multiple queues can be concurrent */
put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum);
sdata->u.mesh.mesh_seqnum++; sdata->u.mesh.mesh_seqnum++;
if (addr4or5 && !addr6) { if (addr4or5 && !addr6) {
meshhdr->flags |= MESH_FLAGS_AE_A4; meshhdr->flags |= MESH_FLAGS_AE_A4;
aelen += ETH_ALEN;
memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN); memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
return 2 * ETH_ALEN;
} else if (addr4or5 && addr6) { } else if (addr4or5 && addr6) {
meshhdr->flags |= MESH_FLAGS_AE_A5_A6; meshhdr->flags |= MESH_FLAGS_AE_A5_A6;
aelen += 2 * ETH_ALEN;
memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN); memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
memcpy(meshhdr->eaddr2, addr6, ETH_ALEN); memcpy(meshhdr->eaddr2, addr6, ETH_ALEN);
return 3 * ETH_ALEN;
} }
return 6 + aelen;
return ETH_ALEN;
} }
static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata)
struct ieee80211_if_mesh *ifmsh)
{ {
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u32 changed; u32 changed;
ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
@ -596,7 +602,8 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
ieee80211_mbss_info_change_notify(sdata, changed); ieee80211_mbss_info_change_notify(sdata, changed);
mod_timer(&ifmsh->housekeeping_timer, mod_timer(&ifmsh->housekeeping_timer,
round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); round_jiffies(jiffies +
IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
} }
static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata) static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
@ -708,7 +715,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
*pos++ = 0x0; *pos++ = 0x0;
if (ieee80211_add_srates_ie(sdata, skb, true, band) || if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
mesh_add_ds_params_ie(skb, sdata)) mesh_add_ds_params_ie(sdata, skb))
goto out_free; goto out_free;
bcn->head_len = skb->len; bcn->head_len = skb->len;
@ -719,13 +726,13 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
bcn->tail = bcn->head + bcn->head_len; bcn->tail = bcn->head + bcn->head_len;
if (ieee80211_add_ext_srates_ie(sdata, skb, true, band) || if (ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
mesh_add_rsn_ie(skb, sdata) || mesh_add_rsn_ie(sdata, skb) ||
mesh_add_ht_cap_ie(skb, sdata) || mesh_add_ht_cap_ie(sdata, skb) ||
mesh_add_ht_oper_ie(skb, sdata) || mesh_add_ht_oper_ie(sdata, skb) ||
mesh_add_meshid_ie(skb, sdata) || mesh_add_meshid_ie(sdata, skb) ||
mesh_add_meshconf_ie(skb, sdata) || mesh_add_meshconf_ie(sdata, skb) ||
mesh_add_awake_window_ie(skb, sdata) || mesh_add_awake_window_ie(sdata, skb) ||
mesh_add_vendor_ies(skb, sdata)) mesh_add_vendor_ies(sdata, skb))
goto out_free; goto out_free;
bcn->tail_len = skb->len; bcn->tail_len = skb->len;
@ -918,7 +925,6 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_PROBE_RESP); IEEE80211_STYPE_PROBE_RESP);
memcpy(hdr->da, mgmt->sa, ETH_ALEN); memcpy(hdr->da, mgmt->sa, ETH_ALEN);
mpl_dbg(sdata, "sending probe resp. to %pM\n", hdr->da);
IEEE80211_SKB_CB(presp)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; IEEE80211_SKB_CB(presp)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
ieee80211_tx_skb(sdata, presp); ieee80211_tx_skb(sdata, presp);
out: out:
@ -1039,7 +1045,7 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
mesh_mpp_table_grow(); mesh_mpp_table_grow();
if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags))
ieee80211_mesh_housekeeping(sdata, ifmsh); ieee80211_mesh_housekeeping(sdata);
if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags)) if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags))
ieee80211_mesh_rootpath(sdata); ieee80211_mesh_rootpath(sdata);

View File

@ -26,12 +26,12 @@
* @MESH_PATH_ACTIVE: the mesh path can be used for forwarding * @MESH_PATH_ACTIVE: the mesh path can be used for forwarding
* @MESH_PATH_RESOLVING: the discovery process is running for this mesh path * @MESH_PATH_RESOLVING: the discovery process is running for this mesh path
* @MESH_PATH_SN_VALID: the mesh path contains a valid destination sequence * @MESH_PATH_SN_VALID: the mesh path contains a valid destination sequence
* number * number
* @MESH_PATH_FIXED: the mesh path has been manually set and should not be * @MESH_PATH_FIXED: the mesh path has been manually set and should not be
* modified * modified
* @MESH_PATH_RESOLVED: the mesh path can has been resolved * @MESH_PATH_RESOLVED: the mesh path can has been resolved
* @MESH_PATH_REQ_QUEUED: there is an unsent path request for this destination * @MESH_PATH_REQ_QUEUED: there is an unsent path request for this destination
* already queued up, waiting for the discovery process to start. * already queued up, waiting for the discovery process to start.
* *
* MESH_PATH_RESOLVED is used by the mesh path timer to * MESH_PATH_RESOLVED is used by the mesh path timer to
* decide when to stop or cancel the mesh path discovery. * decide when to stop or cancel the mesh path discovery.
@ -73,16 +73,16 @@ enum mesh_deferred_task_flags {
* @dst: mesh path destination mac address * @dst: mesh path destination mac address
* @sdata: mesh subif * @sdata: mesh subif
* @next_hop: mesh neighbor to which frames for this destination will be * @next_hop: mesh neighbor to which frames for this destination will be
* forwarded * forwarded
* @timer: mesh path discovery timer * @timer: mesh path discovery timer
* @frame_queue: pending queue for frames sent to this destination while the * @frame_queue: pending queue for frames sent to this destination while the
* path is unresolved * path is unresolved
* @sn: target sequence number * @sn: target sequence number
* @metric: current metric to this destination * @metric: current metric to this destination
* @hop_count: hops to destination * @hop_count: hops to destination
* @exp_time: in jiffies, when the path will expire or when it expired * @exp_time: in jiffies, when the path will expire or when it expired
* @discovery_timeout: timeout (lapse in jiffies) used for the last discovery * @discovery_timeout: timeout (lapse in jiffies) used for the last discovery
* retry * retry
* @discovery_retries: number of discovery retries * @discovery_retries: number of discovery retries
* @flags: mesh path flags, as specified on &enum mesh_path_flags * @flags: mesh path flags, as specified on &enum mesh_path_flags
* @state_lock: mesh path state lock used to protect changes to the * @state_lock: mesh path state lock used to protect changes to the
@ -206,38 +206,33 @@ struct mesh_rmc {
/* Various */ /* Various */
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
const u8 *da, const u8 *sa); const u8 *da, const u8 *sa);
int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata, char *addr4or5, struct ieee80211s_hdr *meshhdr,
char *addr6); const char *addr4or5, const char *addr6);
int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata); const u8 *addr, struct ieee80211s_hdr *mesh_hdr);
bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *ie); struct ieee802_11_elems *ie);
void mesh_ids_set_default(struct ieee80211_if_mesh *mesh); void mesh_ids_set_default(struct ieee80211_if_mesh *mesh);
void mesh_mgmt_ies_add(struct sk_buff *skb, void mesh_mgmt_ies_add(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata); struct sk_buff *skb);
int mesh_add_meshconf_ie(struct sk_buff *skb, int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata); struct sk_buff *skb);
int mesh_add_meshid_ie(struct sk_buff *skb, int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata); struct sk_buff *skb);
int mesh_add_rsn_ie(struct sk_buff *skb, int mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata); struct sk_buff *skb);
int mesh_add_awake_window_ie(struct sk_buff *skb, int mesh_add_vendor_ies(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata); struct sk_buff *skb);
int mesh_add_vendor_ies(struct sk_buff *skb, int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata); struct sk_buff *skb);
int mesh_add_ds_params_ie(struct sk_buff *skb, int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata); struct sk_buff *skb);
int mesh_add_ht_cap_ie(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata);
int mesh_add_ht_oper_ie(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata);
void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
void ieee80211s_init(void); void ieee80211s_init(void);
void ieee80211s_update_metric(struct ieee80211_local *local, void ieee80211s_update_metric(struct ieee80211_local *local,
struct sta_info *sta, struct sk_buff *skb); struct sta_info *sta, struct sk_buff *skb);
void ieee80211s_stop(void);
void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
@ -263,31 +258,32 @@ void ieee80211_mps_frame_release(struct sta_info *sta,
struct ieee802_11_elems *elems); struct ieee802_11_elems *elems);
/* Mesh paths */ /* Mesh paths */
int mesh_nexthop_lookup(struct sk_buff *skb, int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata); struct sk_buff *skb);
int mesh_nexthop_resolve(struct sk_buff *skb, int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata); struct sk_buff *skb);
void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata); void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata);
struct mesh_path *mesh_path_lookup(const u8 *dst, struct mesh_path *mesh_path_lookup(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata); const u8 *dst);
struct mesh_path *mpp_path_lookup(u8 *dst, struct mesh_path *mpp_path_lookup(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata); const u8 *dst);
int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata); int mpp_path_add(struct ieee80211_sub_if_data *sdata,
struct mesh_path *mesh_path_lookup_by_idx(int idx, const u8 *dst, const u8 *mpp);
struct ieee80211_sub_if_data *sdata); struct mesh_path *
mesh_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_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
void mesh_path_expire(struct ieee80211_sub_if_data *sdata); void mesh_path_expire(struct ieee80211_sub_if_data *sdata);
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len); struct ieee80211_mgmt *mgmt, size_t len);
int mesh_path_add(const u8 *dst, struct ieee80211_sub_if_data *sdata); int mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst);
int mesh_path_add_gate(struct mesh_path *mpath); int mesh_path_add_gate(struct mesh_path *mpath);
int mesh_path_send_to_gates(struct mesh_path *mpath); int mesh_path_send_to_gates(struct mesh_path *mpath);
int mesh_gate_num(struct ieee80211_sub_if_data *sdata); int mesh_gate_num(struct ieee80211_sub_if_data *sdata);
/* Mesh plinks */ /* Mesh plinks */
void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
u8 *hw_addr, u8 *hw_addr, struct ieee802_11_elems *ie);
struct ieee802_11_elems *ie);
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie); bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie);
u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
void mesh_plink_broken(struct sta_info *sta); void mesh_plink_broken(struct sta_info *sta);
@ -304,19 +300,19 @@ void mesh_sta_cleanup(struct sta_info *sta);
void mesh_mpath_table_grow(void); void mesh_mpath_table_grow(void);
void mesh_mpp_table_grow(void); void mesh_mpp_table_grow(void);
/* Mesh paths */ /* Mesh paths */
int mesh_path_error_tx(u8 ttl, const u8 *target, __le32 target_sn, int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
__le16 target_rcode, const u8 *ra, u8 ttl, const u8 *target, __le32 target_sn,
struct ieee80211_sub_if_data *sdata); __le16 target_rcode, const u8 *ra);
void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
void mesh_path_flush_pending(struct mesh_path *mpath); void mesh_path_flush_pending(struct mesh_path *mpath);
void mesh_path_tx_pending(struct mesh_path *mpath); void mesh_path_tx_pending(struct mesh_path *mpath);
int mesh_pathtbl_init(void); int mesh_pathtbl_init(void);
void mesh_pathtbl_unregister(void); void mesh_pathtbl_unregister(void);
int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata); int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr);
void mesh_path_timer(unsigned long data); void mesh_path_timer(unsigned long data);
void mesh_path_flush_by_nexthop(struct sta_info *sta); void mesh_path_flush_by_nexthop(struct sta_info *sta);
void mesh_path_discard_frame(struct sk_buff *skb, void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata); struct sk_buff *skb);
void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); 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);
@ -325,8 +321,6 @@ 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
extern int mesh_allocated;
static inline static inline
u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
{ {
@ -371,8 +365,8 @@ void mesh_plink_quiesce(struct sta_info *sta);
void mesh_plink_restart(struct sta_info *sta); void mesh_plink_restart(struct sta_info *sta);
void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata); void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata);
void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata); void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata);
void ieee80211s_stop(void);
#else #else
#define mesh_allocated 0
static inline void static inline void
ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {} ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {}
static inline void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) static inline void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
@ -385,6 +379,7 @@ static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
{ return false; } { return false; }
static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata) static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
{} {}
static inline void ieee80211s_stop(void) {}
#endif #endif
#endif /* IEEE80211S_H */ #endif /* IEEE80211S_H */

View File

@ -238,9 +238,9 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata,
* also acquires in the TX path. To avoid a deadlock we don't transmit the * also acquires in the TX path. To avoid a deadlock we don't transmit the
* frame directly but add it to the pending queue instead. * frame directly but add it to the pending queue instead.
*/ */
int mesh_path_error_tx(u8 ttl, const u8 *target, __le32 target_sn, int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
__le16 target_rcode, const u8 *ra, u8 ttl, const u8 *target, __le32 target_sn,
struct ieee80211_sub_if_data *sdata) __le16 target_rcode, const u8 *ra)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct sk_buff *skb; struct sk_buff *skb;
@ -430,7 +430,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
process = false; process = false;
fresh_info = false; fresh_info = false;
} else { } else {
mpath = mesh_path_lookup(orig_addr, sdata); mpath = mesh_path_lookup(sdata, orig_addr);
if (mpath) { if (mpath) {
spin_lock_bh(&mpath->state_lock); spin_lock_bh(&mpath->state_lock);
if (mpath->flags & MESH_PATH_FIXED) if (mpath->flags & MESH_PATH_FIXED)
@ -445,8 +445,8 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
} }
} }
} else { } else {
mesh_path_add(orig_addr, sdata); mesh_path_add(sdata, orig_addr);
mpath = mesh_path_lookup(orig_addr, sdata); mpath = mesh_path_lookup(sdata, orig_addr);
if (!mpath) { if (!mpath) {
rcu_read_unlock(); rcu_read_unlock();
return 0; return 0;
@ -478,7 +478,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
else { else {
fresh_info = true; fresh_info = true;
mpath = mesh_path_lookup(ta, sdata); mpath = mesh_path_lookup(sdata, ta);
if (mpath) { if (mpath) {
spin_lock_bh(&mpath->state_lock); spin_lock_bh(&mpath->state_lock);
if ((mpath->flags & MESH_PATH_FIXED) || if ((mpath->flags & MESH_PATH_FIXED) ||
@ -486,8 +486,8 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
(last_hop_metric > mpath->metric))) (last_hop_metric > mpath->metric)))
fresh_info = false; fresh_info = false;
} else { } else {
mesh_path_add(ta, sdata); mesh_path_add(sdata, ta);
mpath = mesh_path_lookup(ta, sdata); mpath = mesh_path_lookup(sdata, ta);
if (!mpath) { if (!mpath) {
rcu_read_unlock(); rcu_read_unlock();
return 0; return 0;
@ -553,7 +553,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
} else if (is_broadcast_ether_addr(target_addr) && } else if (is_broadcast_ether_addr(target_addr) &&
(target_flags & IEEE80211_PREQ_TO_FLAG)) { (target_flags & IEEE80211_PREQ_TO_FLAG)) {
rcu_read_lock(); rcu_read_lock();
mpath = mesh_path_lookup(orig_addr, sdata); mpath = mesh_path_lookup(sdata, orig_addr);
if (mpath) { if (mpath) {
if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) { if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) {
reply = true; reply = true;
@ -568,7 +568,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock(); rcu_read_unlock();
} else { } else {
rcu_read_lock(); rcu_read_lock();
mpath = mesh_path_lookup(target_addr, sdata); mpath = mesh_path_lookup(sdata, target_addr);
if (mpath) { if (mpath) {
if ((!(mpath->flags & MESH_PATH_SN_VALID)) || if ((!(mpath->flags & MESH_PATH_SN_VALID)) ||
SN_LT(mpath->sn, target_sn)) { SN_LT(mpath->sn, target_sn)) {
@ -678,7 +678,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
} }
rcu_read_lock(); rcu_read_lock();
mpath = mesh_path_lookup(orig_addr, sdata); mpath = mesh_path_lookup(sdata, orig_addr);
if (mpath) if (mpath)
spin_lock_bh(&mpath->state_lock); spin_lock_bh(&mpath->state_lock);
else else
@ -736,7 +736,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
target_rcode = PERR_IE_TARGET_RCODE(perr_elem); target_rcode = PERR_IE_TARGET_RCODE(perr_elem);
rcu_read_lock(); rcu_read_lock();
mpath = mesh_path_lookup(target_addr, sdata); mpath = mesh_path_lookup(sdata, target_addr);
if (mpath) { if (mpath) {
struct sta_info *sta; struct sta_info *sta;
@ -751,9 +751,10 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
spin_unlock_bh(&mpath->state_lock); spin_unlock_bh(&mpath->state_lock);
if (!ifmsh->mshcfg.dot11MeshForwarding) if (!ifmsh->mshcfg.dot11MeshForwarding)
goto endperr; goto endperr;
mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn), mesh_path_error_tx(sdata, ttl, target_addr,
cpu_to_le32(target_sn),
cpu_to_le16(target_rcode), cpu_to_le16(target_rcode),
broadcast_addr, sdata); broadcast_addr);
} else } else
spin_unlock_bh(&mpath->state_lock); spin_unlock_bh(&mpath->state_lock);
} }
@ -801,10 +802,10 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
metric_txsta = airtime_link_metric_get(local, sta); metric_txsta = airtime_link_metric_get(local, sta);
mpath = mesh_path_lookup(orig_addr, sdata); mpath = mesh_path_lookup(sdata, orig_addr);
if (!mpath) { if (!mpath) {
mesh_path_add(orig_addr, sdata); mesh_path_add(sdata, orig_addr);
mpath = mesh_path_lookup(orig_addr, sdata); mpath = mesh_path_lookup(sdata, orig_addr);
if (!mpath) { if (!mpath) {
rcu_read_unlock(); rcu_read_unlock();
sdata->u.mesh.mshstats.dropped_frames_no_route++; sdata->u.mesh.mshstats.dropped_frames_no_route++;
@ -861,8 +862,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, struct ieee80211_mgmt *mgmt, size_t len)
size_t len)
{ {
struct ieee802_11_elems elems; struct ieee802_11_elems elems;
size_t baselen; size_t baselen;
@ -1006,7 +1006,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
rcu_read_lock(); rcu_read_lock();
mpath = mesh_path_lookup(preq_node->dst, sdata); mpath = mesh_path_lookup(sdata, preq_node->dst);
if (!mpath) if (!mpath)
goto enddiscovery; goto enddiscovery;
@ -1076,8 +1076,8 @@ enddiscovery:
* Returns: 0 if the next hop was found and -ENOENT if the frame was queued. * Returns: 0 if the next hop was found and -ENOENT if the frame was queued.
* skb is freeed here if no mpath could be allocated. * skb is freeed here if no mpath could be allocated.
*/ */
int mesh_nexthop_resolve(struct sk_buff *skb, int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata) struct sk_buff *skb)
{ {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@ -1091,17 +1091,17 @@ int mesh_nexthop_resolve(struct sk_buff *skb,
return 0; return 0;
rcu_read_lock(); rcu_read_lock();
err = mesh_nexthop_lookup(skb, sdata); err = mesh_nexthop_lookup(sdata, skb);
if (!err) if (!err)
goto endlookup; goto endlookup;
/* no nexthop found, start resolving */ /* no nexthop found, start resolving */
mpath = mesh_path_lookup(target_addr, sdata); mpath = mesh_path_lookup(sdata, target_addr);
if (!mpath) { if (!mpath) {
mesh_path_add(target_addr, sdata); mesh_path_add(sdata, target_addr);
mpath = mesh_path_lookup(target_addr, sdata); mpath = mesh_path_lookup(sdata, target_addr);
if (!mpath) { if (!mpath) {
mesh_path_discard_frame(skb, sdata); mesh_path_discard_frame(sdata, skb);
err = -ENOSPC; err = -ENOSPC;
goto endlookup; goto endlookup;
} }
@ -1118,12 +1118,13 @@ int mesh_nexthop_resolve(struct sk_buff *skb,
skb_queue_tail(&mpath->frame_queue, skb); skb_queue_tail(&mpath->frame_queue, skb);
err = -ENOENT; err = -ENOENT;
if (skb_to_free) if (skb_to_free)
mesh_path_discard_frame(skb_to_free, sdata); mesh_path_discard_frame(sdata, skb_to_free);
endlookup: endlookup:
rcu_read_unlock(); rcu_read_unlock();
return err; return err;
} }
/** /**
* mesh_nexthop_lookup - put the appropriate next hop on a mesh frame. Calling * 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 * this function is considered "using" the associated mpath, so preempt a path
@ -1134,8 +1135,8 @@ endlookup:
* *
* Returns: 0 if the next hop was found. Nonzero otherwise. * Returns: 0 if the next hop was found. Nonzero otherwise.
*/ */
int mesh_nexthop_lookup(struct sk_buff *skb, int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata) struct sk_buff *skb)
{ {
struct mesh_path *mpath; struct mesh_path *mpath;
struct sta_info *next_hop; struct sta_info *next_hop;
@ -1144,7 +1145,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
int err = -ENOENT; int err = -ENOENT;
rcu_read_lock(); rcu_read_lock();
mpath = mesh_path_lookup(target_addr, sdata); mpath = mesh_path_lookup(sdata, target_addr);
if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE)) if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE))
goto endlookup; goto endlookup;
@ -1203,8 +1204,7 @@ void mesh_path_timer(unsigned long data)
} }
} }
void 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 = ifmsh->mshcfg.dot11MeshHWMPRannInterval; u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;

View File

@ -24,9 +24,12 @@
/* Keep the mean chain length below this constant */ /* Keep the mean chain length below this constant */
#define MEAN_CHAIN_LEN 2 #define MEAN_CHAIN_LEN 2
#define MPATH_EXPIRED(mpath) ((mpath->flags & MESH_PATH_ACTIVE) && \ static inline bool mpath_expired(struct mesh_path *mpath)
time_after(jiffies, mpath->exp_time) && \ {
!(mpath->flags & MESH_PATH_FIXED)) return (mpath->flags & MESH_PATH_ACTIVE) &&
time_after(jiffies, mpath->exp_time) &&
!(mpath->flags & MESH_PATH_FIXED);
}
struct mpath_node { struct mpath_node {
struct hlist_node list; struct hlist_node list;
@ -185,8 +188,8 @@ static u32 mesh_table_hash(const u8 *addr, struct ieee80211_sub_if_data *sdata,
struct mesh_table *tbl) struct mesh_table *tbl)
{ {
/* Use last four bytes of hw addr and interface index as hash index */ /* Use last four bytes of hw addr and interface index as hash index */
return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex, tbl->hash_rnd) return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex,
& tbl->hash_mask; tbl->hash_rnd) & tbl->hash_mask;
} }
@ -339,7 +342,7 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
mpath = node->mpath; mpath = node->mpath;
if (mpath->sdata == sdata && if (mpath->sdata == sdata &&
ether_addr_equal(dst, mpath->dst)) { ether_addr_equal(dst, mpath->dst)) {
if (MPATH_EXPIRED(mpath)) { if (mpath_expired(mpath)) {
spin_lock_bh(&mpath->state_lock); spin_lock_bh(&mpath->state_lock);
mpath->flags &= ~MESH_PATH_ACTIVE; mpath->flags &= ~MESH_PATH_ACTIVE;
spin_unlock_bh(&mpath->state_lock); spin_unlock_bh(&mpath->state_lock);
@ -352,20 +355,21 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
/** /**
* mesh_path_lookup - look up a path in the mesh path table * mesh_path_lookup - look up a path in the mesh path table
* @dst: hardware address (ETH_ALEN length) of destination
* @sdata: local subif * @sdata: local subif
* @dst: hardware address (ETH_ALEN length) of destination
* *
* Returns: pointer to the mesh path structure, or NULL if not found * Returns: pointer to the mesh path structure, or NULL if not found
* *
* Locking: must be called within a read rcu section. * Locking: must be called within a read rcu section.
*/ */
struct mesh_path *mesh_path_lookup(const u8 *dst, struct mesh_path *
struct ieee80211_sub_if_data *sdata) mesh_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
{ {
return mpath_lookup(rcu_dereference(mesh_paths), dst, sdata); return mpath_lookup(rcu_dereference(mesh_paths), dst, sdata);
} }
struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) struct mesh_path *
mpp_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
{ {
return mpath_lookup(rcu_dereference(mpp_paths), dst, sdata); return mpath_lookup(rcu_dereference(mpp_paths), dst, sdata);
} }
@ -380,7 +384,8 @@ struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
* *
* Locking: must be called within a read rcu section. * Locking: must be called within a read rcu section.
*/ */
struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data *sdata) struct mesh_path *
mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
{ {
struct mesh_table *tbl = rcu_dereference(mesh_paths); struct mesh_table *tbl = rcu_dereference(mesh_paths);
struct mpath_node *node; struct mpath_node *node;
@ -392,7 +397,7 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data
if (sdata && node->mpath->sdata != sdata) if (sdata && node->mpath->sdata != sdata)
continue; continue;
if (j++ == idx) { if (j++ == idx) {
if (MPATH_EXPIRED(node->mpath)) { if (mpath_expired(node->mpath)) {
spin_lock_bh(&node->mpath->state_lock); spin_lock_bh(&node->mpath->state_lock);
node->mpath->flags &= ~MESH_PATH_ACTIVE; node->mpath->flags &= ~MESH_PATH_ACTIVE;
spin_unlock_bh(&node->mpath->state_lock); spin_unlock_bh(&node->mpath->state_lock);
@ -436,11 +441,10 @@ int mesh_path_add_gate(struct mesh_path *mpath)
spin_lock_bh(&tbl->gates_lock); spin_lock_bh(&tbl->gates_lock);
hlist_add_head_rcu(&new_gate->list, tbl->known_gates); hlist_add_head_rcu(&new_gate->list, tbl->known_gates);
spin_unlock_bh(&tbl->gates_lock); spin_unlock_bh(&tbl->gates_lock);
rcu_read_unlock();
mpath_dbg(mpath->sdata, mpath_dbg(mpath->sdata,
"Mesh path: Recorded new gate: %pM. %d known gates\n", "Mesh path: Recorded new gate: %pM. %d known gates\n",
mpath->dst, mpath->sdata->u.mesh.num_gates); mpath->dst, mpath->sdata->u.mesh.num_gates);
return 0; err = 0;
err_rcu: err_rcu:
rcu_read_unlock(); rcu_read_unlock();
return err; return err;
@ -451,30 +455,27 @@ err_rcu:
* @tbl: table which holds our list of known gates * @tbl: table which holds our list of known gates
* @mpath: gate mpath * @mpath: gate mpath
* *
* Returns: 0 on success
*
* Locking: must be called inside rcu_read_lock() section * Locking: must be called inside rcu_read_lock() section
*/ */
static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath) static void mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)
{ {
struct mpath_node *gate; struct mpath_node *gate;
struct hlist_node *p, *q; struct hlist_node *p, *q;
hlist_for_each_entry_safe(gate, p, q, tbl->known_gates, list) hlist_for_each_entry_safe(gate, p, q, tbl->known_gates, list) {
if (gate->mpath == mpath) { if (gate->mpath != mpath)
spin_lock_bh(&tbl->gates_lock); continue;
hlist_del_rcu(&gate->list); spin_lock_bh(&tbl->gates_lock);
kfree_rcu(gate, rcu); hlist_del_rcu(&gate->list);
spin_unlock_bh(&tbl->gates_lock); kfree_rcu(gate, rcu);
mpath->sdata->u.mesh.num_gates--; spin_unlock_bh(&tbl->gates_lock);
mpath->is_gate = false; mpath->sdata->u.mesh.num_gates--;
mpath_dbg(mpath->sdata, mpath->is_gate = false;
"Mesh path: Deleted gate: %pM. %d known gates\n", mpath_dbg(mpath->sdata,
mpath->dst, mpath->sdata->u.mesh.num_gates); "Mesh path: Deleted gate: %pM. %d known gates\n",
break; mpath->dst, mpath->sdata->u.mesh.num_gates);
} break;
}
return 0;
} }
/** /**
@ -488,14 +489,14 @@ int mesh_gate_num(struct ieee80211_sub_if_data *sdata)
/** /**
* mesh_path_add - allocate and add a new path to the mesh path table * mesh_path_add - allocate and add a new path to the mesh path table
* @addr: destination address of the path (ETH_ALEN length) * @dst: destination address of the path (ETH_ALEN length)
* @sdata: local subif * @sdata: local subif
* *
* Returns: 0 on success * Returns: 0 on success
* *
* State: the initial state of the new path is set to 0 * State: the initial state of the new path is set to 0
*/ */
int mesh_path_add(const u8 *dst, struct ieee80211_sub_if_data *sdata) int mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst)
{ {
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
@ -630,7 +631,8 @@ void mesh_mpp_table_grow(void)
write_unlock_bh(&pathtbl_resize_lock); write_unlock_bh(&pathtbl_resize_lock);
} }
int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) int mpp_path_add(struct ieee80211_sub_if_data *sdata,
const u8 *dst, const u8 *mpp)
{ {
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
@ -739,9 +741,10 @@ void mesh_plink_broken(struct sta_info *sta)
mpath->flags &= ~MESH_PATH_ACTIVE; mpath->flags &= ~MESH_PATH_ACTIVE;
++mpath->sn; ++mpath->sn;
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,
mpath->dst, cpu_to_le32(mpath->sn), sdata->u.mesh.mshcfg.element_ttl,
reason, bcast, sdata); mpath->dst, cpu_to_le32(mpath->sn),
reason, bcast);
} }
} }
rcu_read_unlock(); rcu_read_unlock();
@ -856,7 +859,7 @@ void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
* *
* Returns: 0 if successful * Returns: 0 if successful
*/ */
int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
{ {
struct mesh_table *tbl; struct mesh_table *tbl;
struct mesh_path *mpath; struct mesh_path *mpath;
@ -965,8 +968,8 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
* *
* Locking: the function must me called within a rcu_read_lock region * Locking: the function must me called within a rcu_read_lock region
*/ */
void mesh_path_discard_frame(struct sk_buff *skb, void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata) struct sk_buff *skb)
{ {
kfree_skb(skb); kfree_skb(skb);
sdata->u.mesh.mshstats.dropped_frames_no_route++; sdata->u.mesh.mshstats.dropped_frames_no_route++;
@ -984,7 +987,7 @@ void mesh_path_flush_pending(struct mesh_path *mpath)
struct sk_buff *skb; struct sk_buff *skb;
while ((skb = skb_dequeue(&mpath->frame_queue)) != NULL) while ((skb = skb_dequeue(&mpath->frame_queue)) != NULL)
mesh_path_discard_frame(skb, mpath->sdata); mesh_path_discard_frame(mpath->sdata, skb);
} }
/** /**
@ -1105,7 +1108,7 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
if ((!(mpath->flags & MESH_PATH_RESOLVING)) && if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
(!(mpath->flags & MESH_PATH_FIXED)) && (!(mpath->flags & MESH_PATH_FIXED)) &&
time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
mesh_path_del(mpath->dst, mpath->sdata); mesh_path_del(mpath->sdata, mpath->dst);
} }
rcu_read_unlock(); rcu_read_unlock();
} }

View File

@ -37,9 +37,31 @@ enum plink_event {
CLS_IGNR CLS_IGNR
}; };
static const char * const mplstates[] = {
[NL80211_PLINK_LISTEN] = "LISTEN",
[NL80211_PLINK_OPN_SNT] = "OPN-SNT",
[NL80211_PLINK_OPN_RCVD] = "OPN-RCVD",
[NL80211_PLINK_CNF_RCVD] = "CNF_RCVD",
[NL80211_PLINK_ESTAB] = "ESTAB",
[NL80211_PLINK_HOLDING] = "HOLDING",
[NL80211_PLINK_BLOCKED] = "BLOCKED"
};
static const char * const mplevents[] = {
[PLINK_UNDEFINED] = "NONE",
[OPN_ACPT] = "OPN_ACPT",
[OPN_RJCT] = "OPN_RJCT",
[OPN_IGNR] = "OPN_IGNR",
[CNF_ACPT] = "CNF_ACPT",
[CNF_RJCT] = "CNF_RJCT",
[CNF_IGNR] = "CNF_IGNR",
[CLS_ACPT] = "CLS_ACPT",
[CLS_IGNR] = "CLS_IGNR"
};
static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
enum ieee80211_self_protected_actioncode action, enum ieee80211_self_protected_actioncode action,
u8 *da, __le16 llid, __le16 plid, __le16 reason); u8 *da, __le16 llid, __le16 plid, __le16 reason);
/** /**
* mesh_plink_fsm_restart - restart a mesh peer link finite state machine * mesh_plink_fsm_restart - restart a mesh peer link finite state machine
@ -129,7 +151,6 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct sta_info *sta; struct sta_info *sta;
u32 changed = 0;
u16 ht_opmode; u16 ht_opmode;
bool non_ht_sta = false, ht20_sta = false; bool non_ht_sta = false, ht20_sta = false;
@ -142,23 +163,19 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
sta->plink_state != NL80211_PLINK_ESTAB) sta->plink_state != NL80211_PLINK_ESTAB)
continue; continue;
switch (sta->ch_width) { if (sta->sta.bandwidth > IEEE80211_STA_RX_BW_20)
case NL80211_CHAN_WIDTH_20_NOHT: continue;
mpl_dbg(sdata,
"mesh_plink %pM: nonHT sta (%pM) is present\n", if (!sta->sta.ht_cap.ht_supported) {
sdata->vif.addr, sta->sta.addr); mpl_dbg(sdata, "nonHT sta (%pM) is present\n",
sta->sta.addr);
non_ht_sta = true; non_ht_sta = true;
goto out;
case NL80211_CHAN_WIDTH_20:
mpl_dbg(sdata,
"mesh_plink %pM: HT20 sta (%pM) is present\n",
sdata->vif.addr, sta->sta.addr);
ht20_sta = true;
default:
break; break;
} }
mpl_dbg(sdata, "HT20 sta (%pM) is present\n", sta->sta.addr);
ht20_sta = true;
} }
out:
rcu_read_unlock(); rcu_read_unlock();
if (non_ht_sta) if (non_ht_sta)
@ -169,16 +186,13 @@ out:
else else
ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE; ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { if (sdata->vif.bss_conf.ht_operation_mode == ht_opmode)
sdata->vif.bss_conf.ht_operation_mode = ht_opmode; return 0;
sdata->u.mesh.mshcfg.ht_opmode = ht_opmode;
changed = BSS_CHANGED_HT;
mpl_dbg(sdata,
"mesh_plink %pM: protection mode changed to %d\n",
sdata->vif.addr, ht_opmode);
}
return changed; sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
sdata->u.mesh.mshcfg.ht_opmode = ht_opmode;
mpl_dbg(sdata, "selected new HT protection mode %d\n", ht_opmode);
return BSS_CHANGED_HT;
} }
/** /**
@ -231,8 +245,9 @@ u32 mesh_plink_deactivate(struct sta_info *sta)
} }
static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
enum ieee80211_self_protected_actioncode action, enum ieee80211_self_protected_actioncode action,
u8 *da, __le16 llid, __le16 plid, __le16 reason) { u8 *da, __le16 llid, __le16 plid, __le16 reason)
{
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct sk_buff *skb; struct sk_buff *skb;
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
@ -283,13 +298,13 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
} }
if (ieee80211_add_srates_ie(sdata, skb, true, band) || if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
ieee80211_add_ext_srates_ie(sdata, skb, true, band) || ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
mesh_add_rsn_ie(skb, sdata) || mesh_add_rsn_ie(sdata, skb) ||
mesh_add_meshid_ie(skb, sdata) || mesh_add_meshid_ie(sdata, skb) ||
mesh_add_meshconf_ie(skb, sdata)) mesh_add_meshconf_ie(sdata, skb))
goto free; goto free;
} else { /* WLAN_SP_MESH_PEERING_CLOSE */ } else { /* WLAN_SP_MESH_PEERING_CLOSE */
info->flags |= IEEE80211_TX_CTL_NO_ACK; info->flags |= IEEE80211_TX_CTL_NO_ACK;
if (mesh_add_meshid_ie(skb, sdata)) if (mesh_add_meshid_ie(sdata, skb))
goto free; goto free;
} }
@ -333,12 +348,12 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
} }
if (action != WLAN_SP_MESH_PEERING_CLOSE) { if (action != WLAN_SP_MESH_PEERING_CLOSE) {
if (mesh_add_ht_cap_ie(skb, sdata) || if (mesh_add_ht_cap_ie(sdata, skb) ||
mesh_add_ht_oper_ie(skb, sdata)) mesh_add_ht_oper_ie(sdata, skb))
goto free; goto free;
} }
if (mesh_add_vendor_ies(skb, sdata)) if (mesh_add_vendor_ies(sdata, skb))
goto free; goto free;
ieee80211_tx_skb(sdata, skb); ieee80211_tx_skb(sdata, skb);
@ -370,24 +385,18 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
if (sta->sta.supp_rates[band] != rates) if (sta->sta.supp_rates[band] != rates)
changed |= IEEE80211_RC_SUPP_RATES_CHANGED; changed |= IEEE80211_RC_SUPP_RATES_CHANGED;
sta->sta.supp_rates[band] = rates; sta->sta.supp_rates[band] = rates;
if (elems->ht_cap_elem &&
sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
elems->ht_cap_elem, sta);
else
memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap));
if (elems->ht_operation) { if (ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
struct cfg80211_chan_def chandef; elems->ht_cap_elem, sta))
changed |= IEEE80211_RC_BW_CHANGED;
if (!(elems->ht_operation->ht_param & /* HT peer is operating 20MHz-only */
IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) if (elems->ht_operation &&
sta->sta.bandwidth = IEEE80211_STA_RX_BW_20; !(elems->ht_operation->ht_param &
ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
elems->ht_operation, &chandef); if (sta->sta.bandwidth != IEEE80211_STA_RX_BW_20)
if (sta->ch_width != chandef.width)
changed |= IEEE80211_RC_BW_CHANGED; changed |= IEEE80211_RC_BW_CHANGED;
sta->ch_width = chandef.width; sta->sta.bandwidth = IEEE80211_STA_RX_BW_20;
} }
if (insert) if (insert)
@ -666,8 +675,9 @@ u32 mesh_plink_block(struct sta_info *sta)
} }
void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
size_t len, struct ieee80211_rx_status *rx_status) struct ieee80211_mgmt *mgmt, size_t len,
struct ieee80211_rx_status *rx_status)
{ {
struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
struct ieee802_11_elems elems; struct ieee802_11_elems elems;
@ -680,15 +690,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
u8 *baseaddr; u8 *baseaddr;
u32 changed = 0; u32 changed = 0;
__le16 plid, llid, reason; __le16 plid, llid, reason;
static const char *mplstates[] = {
[NL80211_PLINK_LISTEN] = "LISTEN",
[NL80211_PLINK_OPN_SNT] = "OPN-SNT",
[NL80211_PLINK_OPN_RCVD] = "OPN-RCVD",
[NL80211_PLINK_CNF_RCVD] = "CNF_RCVD",
[NL80211_PLINK_ESTAB] = "ESTAB",
[NL80211_PLINK_HOLDING] = "HOLDING",
[NL80211_PLINK_BLOCKED] = "BLOCKED"
};
/* need action_code, aux */ /* need action_code, aux */
if (len < IEEE80211_MIN_ACTION_SIZE + 3) if (len < IEEE80211_MIN_ACTION_SIZE + 3)
@ -708,13 +709,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
baselen += 4; baselen += 4;
} }
ieee802_11_parse_elems(baseaddr, len - baselen, &elems); ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
if (!elems.peering) { if (!elems.peering) {
mpl_dbg(sdata, mpl_dbg(sdata,
"Mesh plink: missing necessary peer link ie\n"); "Mesh plink: missing necessary peer link ie\n");
return; return;
} }
if (elems.rsn_len && if (elems.rsn_len &&
sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
mpl_dbg(sdata, mpl_dbg(sdata,
"Mesh plink: can't establish link with secure peer\n"); "Mesh plink: can't establish link with secure peer\n");
return; return;
@ -733,7 +736,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
} }
if (ftype != WLAN_SP_MESH_PEERING_CLOSE && if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
(!elems.mesh_id || !elems.mesh_config)) { (!elems.mesh_id || !elems.mesh_config)) {
mpl_dbg(sdata, "Mesh plink: missing necessary ie\n"); mpl_dbg(sdata, "Mesh plink: missing necessary ie\n");
return; return;
} }
@ -859,11 +862,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
} }
} }
mpl_dbg(sdata, mpl_dbg(sdata, "peer %pM in state %s got event %s\n", mgmt->sa,
"Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n", mplstates[sta->plink_state], mplevents[event]);
mgmt->sa, mplstates[sta->plink_state],
le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
event);
reason = 0; reason = 0;
spin_lock_bh(&sta->lock); spin_lock_bh(&sta->lock);
switch (sta->plink_state) { switch (sta->plink_state) {

View File

@ -43,7 +43,7 @@ struct sync_method {
static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie) static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie)
{ {
return (ie->mesh_config->meshconf_cap & return (ie->mesh_config->meshconf_cap &
IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING) != 0; IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING) != 0;
} }
void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata) void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
@ -112,7 +112,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) { if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) {
clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
msync_dbg(sdata, "STA %pM : is adjusting TBTT\n", sta->sta.addr); msync_dbg(sdata, "STA %pM : is adjusting TBTT\n",
sta->sta.addr);
goto no_sync; goto no_sync;
} }
@ -129,18 +130,15 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
sta->t_offset = t_t - t_r; sta->t_offset = t_t - t_r;
if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
s64 t_clockdrift = sta->t_offset_setpoint s64 t_clockdrift = sta->t_offset_setpoint - sta->t_offset;
- sta->t_offset;
msync_dbg(sdata, msync_dbg(sdata,
"STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld\n", "STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld\n",
sta->sta.addr, sta->sta.addr, (long long) sta->t_offset,
(long long) sta->t_offset, (long long) sta->t_offset_setpoint,
(long long)
sta->t_offset_setpoint,
(long long) t_clockdrift); (long long) t_clockdrift);
if (t_clockdrift > TOFFSET_MAXIMUM_ADJUSTMENT || if (t_clockdrift > TOFFSET_MAXIMUM_ADJUSTMENT ||
t_clockdrift < -TOFFSET_MAXIMUM_ADJUSTMENT) { t_clockdrift < -TOFFSET_MAXIMUM_ADJUSTMENT) {
msync_dbg(sdata, msync_dbg(sdata,
"STA %pM : t_clockdrift=%lld too large, setpoint reset\n", "STA %pM : t_clockdrift=%lld too large, setpoint reset\n",
sta->sta.addr, sta->sta.addr,
@ -149,15 +147,10 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
goto no_sync; goto no_sync;
} }
rcu_read_unlock();
spin_lock_bh(&ifmsh->sync_offset_lock); spin_lock_bh(&ifmsh->sync_offset_lock);
if (t_clockdrift > if (t_clockdrift > ifmsh->sync_offset_clockdrift_max)
ifmsh->sync_offset_clockdrift_max) ifmsh->sync_offset_clockdrift_max = t_clockdrift;
ifmsh->sync_offset_clockdrift_max
= t_clockdrift;
spin_unlock_bh(&ifmsh->sync_offset_lock); spin_unlock_bh(&ifmsh->sync_offset_lock);
} else { } else {
sta->t_offset_setpoint = sta->t_offset - TOFFSET_SET_MARGIN; sta->t_offset_setpoint = sta->t_offset - TOFFSET_SET_MARGIN;
set_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); set_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
@ -165,9 +158,7 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
"STA %pM : offset was invalid, sta->t_offset=%lld\n", "STA %pM : offset was invalid, sta->t_offset=%lld\n",
sta->sta.addr, sta->sta.addr,
(long long) sta->t_offset); (long long) sta->t_offset);
rcu_read_unlock();
} }
return;
no_sync: no_sync:
rcu_read_unlock(); rcu_read_unlock();
@ -177,14 +168,12 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
{ {
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
WARN_ON(ifmsh->mesh_sp_id WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET);
!= IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET);
BUG_ON(!rcu_read_lock_held()); BUG_ON(!rcu_read_lock_held());
spin_lock_bh(&ifmsh->sync_offset_lock); spin_lock_bh(&ifmsh->sync_offset_lock);
if (ifmsh->sync_offset_clockdrift_max > if (ifmsh->sync_offset_clockdrift_max > TOFFSET_MINIMUM_ADJUSTMENT) {
TOFFSET_MINIMUM_ADJUSTMENT) {
/* Since ajusting the tsf here would /* Since ajusting the tsf here would
* require a possibly blocking call * require a possibly blocking call
* to the driver tsf setter, we punt * to the driver tsf setter, we punt
@ -193,8 +182,7 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
msync_dbg(sdata, msync_dbg(sdata,
"TBTT : kicking off TBTT adjustment with clockdrift_max=%lld\n", "TBTT : kicking off TBTT adjustment with clockdrift_max=%lld\n",
ifmsh->sync_offset_clockdrift_max); ifmsh->sync_offset_clockdrift_max);
set_bit(MESH_WORK_DRIFT_ADJUST, set_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags);
&ifmsh->wrkq_flags);
ifmsh->adjusting_tbtt = true; ifmsh->adjusting_tbtt = true;
} else { } else {
@ -220,14 +208,11 @@ static const struct sync_method sync_methods[] = {
const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method) const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method)
{ {
const struct ieee80211_mesh_sync_ops *ops = NULL; int i;
u8 i;
for (i = 0 ; i < ARRAY_SIZE(sync_methods); ++i) { for (i = 0 ; i < ARRAY_SIZE(sync_methods); ++i) {
if (sync_methods[i].method == method) { if (sync_methods[i].method == method)
ops = &sync_methods[i].ops; return &sync_methods[i].ops;
break;
}
} }
return ops; return NULL;
} }

View File

@ -2027,7 +2027,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
/* frame is in RMC, don't forward */ /* frame is in RMC, don't forward */
if (ieee80211_is_data(hdr->frame_control) && if (ieee80211_is_data(hdr->frame_control) &&
is_multicast_ether_addr(hdr->addr1) && is_multicast_ether_addr(hdr->addr1) &&
mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata)) mesh_rmc_check(rx->sdata, hdr->addr3, mesh_hdr))
return RX_DROP_MONITOR; return RX_DROP_MONITOR;
if (!ieee80211_is_data(hdr->frame_control) || if (!ieee80211_is_data(hdr->frame_control) ||
@ -2054,9 +2054,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
} }
rcu_read_lock(); rcu_read_lock();
mppath = mpp_path_lookup(proxied_addr, sdata); mppath = mpp_path_lookup(sdata, proxied_addr);
if (!mppath) { if (!mppath) {
mpp_path_add(proxied_addr, mpp_addr, sdata); mpp_path_add(sdata, proxied_addr, mpp_addr);
} else { } else {
spin_lock_bh(&mppath->state_lock); spin_lock_bh(&mppath->state_lock);
if (!ether_addr_equal(mppath->mpp, mpp_addr)) if (!ether_addr_equal(mppath->mpp, mpp_addr))
@ -2104,13 +2104,13 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN); memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
/* update power mode indication when forwarding */ /* update power mode indication when forwarding */
ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr); ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
} else if (!mesh_nexthop_lookup(fwd_skb, sdata)) { } else if (!mesh_nexthop_lookup(sdata, fwd_skb)) {
/* mesh power mode flags updated in mesh_nexthop_lookup */ /* mesh power mode flags updated in mesh_nexthop_lookup */
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast); IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
} else { } else {
/* unable to resolve next hop */ /* unable to resolve next hop */
mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3, mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
0, reason, fwd_hdr->addr2, sdata); fwd_hdr->addr3, 0, reason, fwd_hdr->addr2);
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route); IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
kfree_skb(fwd_skb); kfree_skb(fwd_skb);
return RX_DROP_MONITOR; return RX_DROP_MONITOR;

View File

@ -285,7 +285,6 @@ struct sta_ampdu_mlme {
* @t_offset: timing offset relative to this host * @t_offset: timing offset relative to this host
* @t_offset_setpoint: reference timing offset of this sta to be used when * @t_offset_setpoint: reference timing offset of this sta to be used when
* calculating clockdrift * calculating clockdrift
* @ch_width: peer's channel width
* @local_pm: local link-specific power save mode * @local_pm: local link-specific power save mode
* @peer_pm: peer-specific power save mode towards local STA * @peer_pm: peer-specific power save mode towards local STA
* @nonpeer_pm: STA power save mode towards non-peer neighbors * @nonpeer_pm: STA power save mode towards non-peer neighbors
@ -386,7 +385,6 @@ struct sta_info {
struct timer_list plink_timer; struct timer_list plink_timer;
s64 t_offset; s64 t_offset;
s64 t_offset_setpoint; s64 t_offset_setpoint;
enum nl80211_chan_width ch_width;
/* mesh power save */ /* mesh power save */
enum nl80211_mesh_power_mode local_pm; enum nl80211_mesh_power_mode local_pm;
enum nl80211_mesh_power_mode peer_pm; enum nl80211_mesh_power_mode peer_pm;

View File

@ -479,7 +479,7 @@ TRACE_EVENT(drv_set_tim,
TP_printk( TP_printk(
LOCAL_PR_FMT STA_PR_FMT " set:%d", LOCAL_PR_FMT STA_PR_FMT " set:%d",
LOCAL_PR_ARG, STA_PR_FMT, __entry->set LOCAL_PR_ARG, STA_PR_ARG, __entry->set
) )
); );
@ -1684,7 +1684,7 @@ TRACE_EVENT(api_sta_block_awake,
TP_printk( TP_printk(
LOCAL_PR_FMT STA_PR_FMT " block:%d", LOCAL_PR_FMT STA_PR_FMT " block:%d",
LOCAL_PR_ARG, STA_PR_FMT, __entry->block LOCAL_PR_ARG, STA_PR_ARG, __entry->block
) )
); );
@ -1782,7 +1782,7 @@ TRACE_EVENT(api_eosp,
TP_printk( TP_printk(
LOCAL_PR_FMT STA_PR_FMT, LOCAL_PR_FMT STA_PR_FMT,
LOCAL_PR_ARG, STA_PR_FMT LOCAL_PR_ARG, STA_PR_ARG
) )
); );

View File

@ -1495,7 +1495,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
if (ieee80211_vif_is_mesh(&sdata->vif)) { if (ieee80211_vif_is_mesh(&sdata->vif)) {
if (ieee80211_is_data(hdr->frame_control) && if (ieee80211_is_data(hdr->frame_control) &&
is_unicast_ether_addr(hdr->addr1)) { is_unicast_ether_addr(hdr->addr1)) {
if (mesh_nexthop_resolve(skb, sdata)) if (mesh_nexthop_resolve(sdata, skb))
return; /* skb queued: don't free */ return; /* skb queued: don't free */
} else { } else {
ieee80211_mps_set_frame_flags(sdata, NULL, hdr); ieee80211_mps_set_frame_flags(sdata, NULL, hdr);
@ -1844,9 +1844,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
} }
if (!is_multicast_ether_addr(skb->data)) { if (!is_multicast_ether_addr(skb->data)) {
mpath = mesh_path_lookup(skb->data, sdata); mpath = mesh_path_lookup(sdata, skb->data);
if (!mpath) if (!mpath)
mppath = mpp_path_lookup(skb->data, sdata); mppath = mpp_path_lookup(sdata, skb->data);
} }
/* /*
@ -1859,8 +1859,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
!(mppath && !ether_addr_equal(mppath->mpp, skb->data))) { !(mppath && !ether_addr_equal(mppath->mpp, skb->data))) {
hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
skb->data, skb->data + ETH_ALEN); skb->data, skb->data + ETH_ALEN);
meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, meshhdrlen = ieee80211_new_mesh_header(sdata, &mesh_hdr,
sdata, NULL, NULL); NULL, NULL);
} else { } else {
/* DS -> MBSS (802.11-2012 13.11.3.3). /* DS -> MBSS (802.11-2012 13.11.3.3).
* For unicast with unknown forwarding information, * For unicast with unknown forwarding information,
@ -1879,18 +1879,14 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
mesh_da, sdata->vif.addr); mesh_da, sdata->vif.addr);
if (is_multicast_ether_addr(mesh_da)) if (is_multicast_ether_addr(mesh_da))
/* DA TA mSA AE:SA */ /* DA TA mSA AE:SA */
meshhdrlen = meshhdrlen = ieee80211_new_mesh_header(
ieee80211_new_mesh_header(&mesh_hdr, sdata, &mesh_hdr,
sdata, skb->data + ETH_ALEN, NULL);
skb->data + ETH_ALEN,
NULL);
else else
/* RA TA mDA mSA AE:DA SA */ /* RA TA mDA mSA AE:DA SA */
meshhdrlen = meshhdrlen = ieee80211_new_mesh_header(
ieee80211_new_mesh_header(&mesh_hdr, sdata, &mesh_hdr, skb->data,
sdata, skb->data + ETH_ALEN);
skb->data,
skb->data + ETH_ALEN);
} }
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);

View File

@ -3418,19 +3418,10 @@ nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = {
static int nl80211_set_station_tdls(struct genl_info *info, static int nl80211_set_station_tdls(struct genl_info *info,
struct station_parameters *params) struct station_parameters *params)
{ {
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct nlattr *tb[NL80211_STA_WME_MAX + 1]; struct nlattr *tb[NL80211_STA_WME_MAX + 1];
struct nlattr *nla; struct nlattr *nla;
int err; int err;
/* Can only set if TDLS ... */
if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS))
return -EOPNOTSUPP;
/* ... with external setup is supported */
if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
return -EOPNOTSUPP;
/* Dummy STA entry gets updated once the peer capabilities are known */ /* Dummy STA entry gets updated once the peer capabilities are known */
if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
params->ht_capa = params->ht_capa =