Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
This commit is contained in:
Коммит
a9908ebf5c
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
Загрузка…
Ссылка в новой задаче