Release 4.11 net/mac80211/mesh.c
/*
* Copyright (c) 2008, 2009 open80211s Ltd.
* Authors: Luis Carlos Cobo <luisca@cozybit.com>
* Javier Cardona <javier@cozybit.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/slab.h>
#include <asm/unaligned.h>
#include "ieee80211_i.h"
#include "mesh.h"
#include "driver-ops.h"
static int mesh_allocated;
static struct kmem_cache *rm_cache;
bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
{
return (mgmt->u.action.u.mesh_action.action_code ==
WLAN_MESH_ACTION_HWMP_PATH_SELECTION);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Pedersen | 27 | 100.00% | 1 | 100.00% |
Total | 27 | 100.00% | 1 | 100.00% |
void ieee80211s_init(void)
{
mesh_allocated = 1;
rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry),
0, 0, NULL);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Luis Carlos Cobo Rus | 30 | 100.00% | 1 | 100.00% |
Total | 30 | 100.00% | 1 | 100.00% |
void ieee80211s_stop(void)
{
if (!mesh_allocated)
return;
kmem_cache_destroy(rm_cache);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Luis Carlos Cobo Rus | 12 | 66.67% | 1 | 50.00% |
Johannes Berg | 6 | 33.33% | 1 | 50.00% |
Total | 18 | 100.00% | 2 | 100.00% |
static void ieee80211_mesh_housekeeping_timer(unsigned long data)
{
struct ieee80211_sub_if_data *sdata = (void *) data;
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
ieee80211_queue_work(&local->hw, &sdata->work);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 56 | 86.15% | 2 | 33.33% |
Rui Paulo | 6 | 9.23% | 1 | 16.67% |
Luis R. Rodriguez | 2 | 3.08% | 2 | 33.33% |
Javier Cardona | 1 | 1.54% | 1 | 16.67% |
Total | 65 | 100.00% | 6 | 100.00% |
/**
* mesh_matches_local - check if the config of a mesh point matches ours
*
* @sdata: local mesh subif
* @ie: information elements of a management frame from the mesh peer
*
* This function checks if the mesh configuration of a mesh point matches the
* local mesh configuration, i.e. if both nodes belong to the same mesh network.
*/
bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *ie)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u32 basic_rates = 0;
struct cfg80211_chan_def sta_chan_def;
/*
* As support for each feature is added, check for matching
* - On mesh config capabilities
* - Power Save Support En
* - Sync support enabled
* - Sync support active
* - Sync support required from peer
* - MDA enabled
* - Power management control on fc
*/
if (!(ifmsh->mesh_id_len == ie->mesh_id_len &&
memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
(ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&
(ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) &&
(ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) &&
(ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) &&
(ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)))
return false;
ieee80211_sta_get_rates(sdata, ie, ieee80211_get_sdata_band(sdata),
&basic_rates);
if (sdata->vif.bss_conf.basic_rates != basic_rates)
return false;
cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chandef.chan,
NL80211_CHAN_NO_HT);
ieee80211_chandef_ht_oper(ie->ht_operation, &sta_chan_def);
ieee80211_chandef_vht_oper(ie->vht_operation, &sta_chan_def);
if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
&sta_chan_def))
return false;
return true;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 66 | 29.73% | 6 | 31.58% |
Luis Carlos Cobo Rus | 65 | 29.28% | 2 | 10.53% |
Rui Paulo | 25 | 11.26% | 2 | 10.53% |
Thomas Pedersen | 24 | 10.81% | 2 | 10.53% |
Ashok Nagarajan | 16 | 7.21% | 3 | 15.79% |
Javier Cardona | 14 | 6.31% | 1 | 5.26% |
Bob Copeland | 9 | 4.05% | 1 | 5.26% |
Jasper Bryant-Greene | 2 | 0.90% | 1 | 5.26% |
Simon Wunderlich | 1 | 0.45% | 1 | 5.26% |
Total | 222 | 100.00% | 19 | 100.00% |
/**
* mesh_peer_accepts_plinks - check if an mp is willing to establish peer links
*
* @ie: information elements of a management frame from the mesh peer
*/
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
{
return (ie->mesh_config->meshconf_cap &
IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS) != 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Luis Carlos Cobo Rus | 20 | 86.96% | 1 | 33.33% |
Rui Paulo | 2 | 8.70% | 1 | 33.33% |
Marco Porsch | 1 | 4.35% | 1 | 33.33% |
Total | 23 | 100.00% | 3 | 100.00% |
/**
* mesh_accept_plinks_update - update accepting_plink in local mesh beacons
*
* @sdata: mesh interface in which mesh beacons are going to be updated
*
* Returns: beacon changed flag if the beacon content changed.
*/
u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
{
bool free_plinks;
u32 changed = 0;
/* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0,
* the mesh interface might be able to establish plinks with peers that
* are already on the table but are not on PLINK_ESTAB state. However,
* in general the mesh interface is not accepting peer link requests
* from new peers, and that must be reflected in the beacon
*/
free_plinks = mesh_plink_availables(sdata);
if (free_plinks != sdata->u.mesh.accepting_plinks) {
sdata->u.mesh.accepting_plinks = free_plinks;
changed = BSS_CHANGED_BEACON;
}
return changed;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Luis Carlos Cobo Rus | 31 | 54.39% | 2 | 40.00% |
Marco Porsch | 23 | 40.35% | 1 | 20.00% |
Johannes Berg | 3 | 5.26% | 2 | 40.00% |
Total | 57 | 100.00% | 5 | 100.00% |
/*
* mesh_sta_cleanup - clean up any mesh sta state
*
* @sta: mesh sta to clean up.
*/
void mesh_sta_cleanup(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
u32 changed = mesh_plink_deactivate(sta);
if (changed)
ieee80211_mbss_info_change_notify(sdata, changed);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Pedersen | 36 | 94.74% | 2 | 50.00% |
Jouni Malinen | 1 | 2.63% | 1 | 25.00% |
Bob Copeland | 1 | 2.63% | 1 | 25.00% |
Total | 38 | 100.00% | 4 | 100.00% |
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
{
int i;
sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
if (!sdata->u.mesh.rmc)
return -ENOMEM;
sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1;
for (i = 0; i < RMC_BUCKETS; i++)
INIT_HLIST_HEAD(&sdata->u.mesh.rmc->bucket[i]);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Luis Carlos Cobo Rus | 87 | 92.55% | 1 | 25.00% |
Johannes Berg | 4 | 4.26% | 1 | 25.00% |
Jasper Bryant-Greene | 2 | 2.13% | 1 | 25.00% |
Bob Copeland | 1 | 1.06% | 1 | 25.00% |
Total | 94 | 100.00% | 4 | 100.00% |
void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
{
struct mesh_rmc *rmc = sdata->u.mesh.rmc;
struct rmc_entry *p;
struct hlist_node *n;
int i;
if (!sdata->u.mesh.rmc)
return;
for (i = 0; i < RMC_BUCKETS; i++) {
hlist_for_each_entry_safe(p, n, &rmc->bucket[i], list) {
hlist_del(&p->list);
kmem_cache_free(rm_cache, p);
}
}
kfree(rmc);
sdata->u.mesh.rmc = NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Luis Carlos Cobo Rus | 92 | 87.62% | 1 | 16.67% |
Bob Copeland | 5 | 4.76% | 1 | 16.67% |
Johannes Berg | 5 | 4.76% | 2 | 33.33% |
Jasper Bryant-Greene | 2 | 1.90% | 1 | 16.67% |
Thomas Pedersen | 1 | 0.95% | 1 | 16.67% |
Total | 105 | 100.00% | 6 | 100.00% |
/**
* mesh_rmc_check - Check frame in recent multicast cache and add if absent.
*
* @sdata: interface
* @sa: source address
* @mesh_hdr: mesh_header
*
* Returns: 0 if the frame is not in the cache, nonzero otherwise.
*
* Checks using the source address and the mesh sequence number if we have
* received this frame lately. If the frame is not in the cache, it is added to
* it.
*/
int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
const u8 *sa, struct ieee80211s_hdr *mesh_hdr)
{
struct mesh_rmc *rmc = sdata->u.mesh.rmc;
u32 seqnum = 0;
int entries = 0;
u8 idx;
struct rmc_entry *p;
struct hlist_node *n;
if (!rmc)
return -1;
/* Don't care about endianness since only match matters */
memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum));
idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask;
hlist_for_each_entry_safe(p, n, &rmc->bucket[idx], list) {
++entries;
if (time_after(jiffies, p->exp_time) ||
entries == RMC_QUEUE_MAX_LEN) {
hlist_del(&p->list);
kmem_cache_free(rm_cache, p);
--entries;
} else if ((seqnum == p->seqnum) && ether_addr_equal(sa, p->sa))
return -1;
}
p = kmem_cache_alloc(rm_cache, GFP_ATOMIC);
if (!p)
return 0;
p->seqnum = seqnum;
p->exp_time = jiffies + RMC_TIMEOUT;
memcpy(p->sa, sa, ETH_ALEN);
hlist_add_head(&p->list, &rmc->bucket[idx]);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Luis Carlos Cobo Rus | 206 | 88.79% | 2 | 22.22% |
Bob Copeland | 15 | 6.47% | 2 | 22.22% |
Johannes Berg | 7 | 3.02% | 2 | 22.22% |
Jasper Bryant-Greene | 2 | 0.86% | 1 | 11.11% |
Joe Perches | 1 | 0.43% | 1 | 11.11% |
Thomas Pedersen | 1 | 0.43% | 1 | 11.11% |
Total | 232 | 100.00% | 9 | 100.00% |
int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u8 *pos, neighbors;
u8 meshconf_len = sizeof(struct ieee80211_meshconf_ie);
if (skb_tailroom(skb) < 2 + meshconf_len)
return -ENOMEM;
pos = skb_put(skb, 2 + meshconf_len);
*pos++ = WLAN_EID_MESH_CONFIG;
*pos++ = meshconf_len;
/* save a pointer for quick updates in pre-tbtt */
ifmsh->meshconf_offset = pos - skb->data;
/* Active path selection protocol ID */
*pos++ = ifmsh->mesh_pp_id;
/* Active path selection metric ID */
*pos++ = ifmsh->mesh_pm_id;
/* Congestion control mode identifier */
*pos++ = ifmsh->mesh_cc_id;
/* Synchronization protocol identifier */
*pos++ = ifmsh->mesh_sp_id;
/* Authentication Protocol identifier */
*pos++ = ifmsh->mesh_auth_id;
/* Mesh Formation Info - number of neighbors */
neighbors = atomic_read(&ifmsh->estab_plinks);
neighbors = min_t(int, neighbors, IEEE80211_MAX_MESH_PEERINGS);
*pos++ = neighbors << 1;
/* Mesh capability */
*pos = 0x00;
*pos |= ifmsh->mshcfg.dot11MeshForwarding ?
IEEE80211_MESHCONF_CAPAB_FORWARDING : 0x00;
*pos |= ifmsh->accepting_plinks ?
IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
/* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */
*pos |= ifmsh->ps_peers_deep_sleep ?
IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Pedersen | 89 | 42.18% | 2 | 18.18% |
Luis Carlos Cobo Rus | 72 | 34.12% | 1 | 9.09% |
Marco Porsch | 14 | 6.64% | 2 | 18.18% |
Chun-Yeow Yeoh | 13 | 6.16% | 1 | 9.09% |
Rui Paulo | 10 | 4.74% | 2 | 18.18% |
Jacob Minshall | 7 | 3.32% | 1 | 9.09% |
Johannes Berg | 5 | 2.37% | 1 | 9.09% |
Jasper Bryant-Greene | 1 | 0.47% | 1 | 9.09% |
Total | 211 | 100.00% | 11 | 100.00% |
int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u8 *pos;
if (skb_tailroom(skb) < 2 + ifmsh->mesh_id_len)
return -ENOMEM;
pos = skb_put(skb, 2 + ifmsh->mesh_id_len);
*pos++ = WLAN_EID_MESH_ID;
*pos++ = ifmsh->mesh_id_len;
if (ifmsh->mesh_id_len)
memcpy(pos, ifmsh->mesh_id, ifmsh->mesh_id_len);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Pedersen | 51 | 52.58% | 1 | 33.33% |
Luis Carlos Cobo Rus | 41 | 42.27% | 1 | 33.33% |
Johannes Berg | 5 | 5.15% | 1 | 33.33% |
Total | 97 | 100.00% | 3 | 100.00% |
static int mesh_add_awake_window_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u8 *pos;
/* see IEEE802.11-2012 13.14.6 */
if (ifmsh->ps_peers_light_sleep == 0 &&
ifmsh->ps_peers_deep_sleep == 0 &&
ifmsh->nonpeer_pm == NL80211_MESH_POWER_ACTIVE)
return 0;
if (skb_tailroom(skb) < 4)
return -ENOMEM;
pos = skb_put(skb, 2 + 2);
*pos++ = WLAN_EID_MESH_AWAKE_WINDOW;
*pos++ = 2;
put_unaligned_le16(ifmsh->mshcfg.dot11MeshAwakeWindowDuration, pos);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Marco Porsch | 101 | 95.28% | 1 | 50.00% |
Johannes Berg | 5 | 4.72% | 1 | 50.00% |
Total | 106 | 100.00% | 2 | 100.00% |
int mesh_add_vendor_ies(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u8 offset, len;
const u8 *data;
if (!ifmsh->ie || !ifmsh->ie_len)
return 0;
/* fast-forward to vendor IEs */
offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0);
if (offset < ifmsh->ie_len) {
len = ifmsh->ie_len - offset;
data = ifmsh->ie + offset;
if (skb_tailroom(skb) < len)
return -ENOMEM;
memcpy(skb_put(skb, len), data, len);
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Pedersen | 99 | 79.84% | 1 | 14.29% |
Luis Carlos Cobo Rus | 7 | 5.65% | 1 | 14.29% |
Johannes Berg | 6 | 4.84% | 2 | 28.57% |
Javier Cardona | 5 | 4.03% | 1 | 14.29% |
Thorsten Horstmann | 4 | 3.23% | 1 | 14.29% |
Rui Paulo | 3 | 2.42% | 1 | 14.29% |
Total | 124 | 100.00% | 7 | 100.00% |
int mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u8 len = 0;
const u8 *data;
if (!ifmsh->ie || !ifmsh->ie_len)
return 0;
/* find RSN IE */
data = cfg80211_find_ie(WLAN_EID_RSN, ifmsh->ie, ifmsh->ie_len);
if (!data)
return 0;
len = data[1] + 2;
if (skb_tailroom(skb) < len)
return -ENOMEM;
memcpy(skb_put(skb, len), data, len);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Pedersen | 98 | 85.22% | 1 | 25.00% |
Bob Copeland | 11 | 9.57% | 1 | 25.00% |
Johannes Berg | 5 | 4.35% | 1 | 25.00% |
Rui Paulo | 1 | 0.87% | 1 | 25.00% |
Total | 115 | 100.00% | 4 | 100.00% |
static int mesh_add_ds_params_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan;
u8 *pos;
if (skb_tailroom(skb) < 3)
return -ENOMEM;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock();
return -EINVAL;
}
chan = chanctx_conf->def.chan;
rcu_read_unlock();
pos = skb_put(skb, 2 + 1);
*pos++ = WLAN_EID_DS_PARAMS;
*pos++ = 1;
*pos++ = ieee80211_frequency_to_channel(chan->center_freq);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 57 | 46.72% | 4 | 57.14% |
Thomas Pedersen | 46 | 37.70% | 1 | 14.29% |
Javier Cardona | 18 | 14.75% | 1 | 14.29% |
Luis Carlos Cobo Rus | 1 | 0.82% | 1 | 14.29% |
Total | 122 | 100.00% | 7 | 100.00% |
int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
enum nl80211_band band = ieee80211_get_sdata_band(sdata);
struct ieee80211_supported_band *sband;
u8 *pos;
sband = local->hw.wiphy->bands[band];
if (!sband->ht_cap.ht_supported ||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
return 0;
if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap))
return -ENOMEM;
pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap));
ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Pedersen | 107 | 68.59% | 1 | 12.50% |
Simon Wunderlich | 24 | 15.38% | 1 | 12.50% |
Johannes Berg | 22 | 14.10% | 5 | 62.50% |
Ben Greear | 3 | 1.92% | 1 | 12.50% |
Total | 156 | 100.00% | 8 | 100.00% |
int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *channel;
struct ieee80211_supported_band *sband;
struct ieee80211_sta_ht_cap *ht_cap;
u8 *pos;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock();
return -EINVAL;
}
channel = chanctx_conf->def.chan;
rcu_read_unlock();
sband = local->hw.wiphy->bands[channel->band];
ht_cap = &sband->ht_cap;
if (!ht_cap->ht_supported ||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
return 0;
if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation))
return -ENOMEM;
pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef,
sdata->vif.bss_conf.ht_operation_mode,
false);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Thomas Pedersen | 99 | 44.80% | 1 | 12.50% |
Johannes Berg | 78 | 35.29% | 4 | 50.00% |
Bob Copeland | 34 | 15.38% | 1 | 12.50% |
Ashok Nagarajan | 8 | 3.62% | 1 | 12.50% |
Arik Nemtsov | 2 | 0.90% | 1 | 12.50% |
Total | 221 | 100.00% | 8 | 100.00% |
int mesh_add_vht_cap_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
enum nl80211_band band = ieee80211_get_sdata_band(sdata);
struct ieee80211_supported_band *sband;
u8 *pos;
sband = local->hw.wiphy->bands[band];
if (!sband->vht_cap.vht_supported ||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
return 0;
if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_cap))
return -ENOMEM;
pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_cap));
ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, sband->vht_cap.cap);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Bob Copeland | 155 | 99.36% | 1 | 50.00% |
Johannes Berg | 1 | 0.64% | 1 | 50.00% |
Total | 156 | 100.00% | 2 | 100.00% |
int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *channel;
struct ieee80211_supported_band *sband;
struct ieee80211_sta_vht_cap *vht_cap;
u8 *pos;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock();
return -EINVAL;
}
channel = chanctx_conf->def.chan;
rcu_read_unlock();
sband = local->hw.wiphy->bands[channel->band];
vht_cap = &sband->vht_cap;
if (!vht_cap->vht_supported ||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
return 0;
if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_operation))
return -ENOMEM;
pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_operation));
ieee80211_ie_build_vht_oper(pos, vht_cap,
&sdata->vif.bss_conf.chandef);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Bob Copeland | 211 | 100.00% | 1 | 100.00% |
Total | 211 | 100.00% | 1 | 100.00% |
static void ieee80211_mesh_path_timer(unsigned long data)
{
struct ieee80211_sub_if_data *sdata =
(struct ieee80211_sub_if_data *) data;
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Luis Carlos Cobo Rus | 32 | 86.49% | 1 | 20.00% |
Luis R. Rodriguez | 2 | 5.41% | 2 | 40.00% |
Stanislaw Gruszka | 2 | 5.41% | 1 | 20.00% |
Johannes Berg | 1 | 2.70% | 1 | 20.00% |
Total | 37 | 100.00% | 5 | 100.00% |
static void ieee80211_mesh_path_root_timer(unsigned long data)
{
struct ieee80211_sub_if_data *sdata =
(struct ieee80211_sub_if_data *) data;
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Rui Paulo | 56 | 94.92% | 1 | 33.33% |
Stanislaw Gruszka | 2 | 3.39% | 1 | 33.33% |
Johannes Berg | 1 | 1.69% | 1 | 33.33% |
Total | 59 | 100.00% | 3 | 100.00% |
void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
{
if (ifmsh->mshcfg.dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)
set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
else {
clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
/* stop running timer */
del_timer_sync(&ifmsh->mesh_path_root_timer);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Rui Paulo | 50 | 96.15% | 1 | 50.00% |
Chun-Yeow Yeoh | 2 | 3.85% | 1 | 50.00% |
Total | 52 | 100.00% | 2 | 100.00% |
/**
* ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
* @hdr: 802.11 frame header
* @fc: frame control field
* @meshda: destination address in the mesh
* @meshsa: source address address in the mesh. Same as TA, as frame is
* locally originated.
*
* Return the length of the 802.11 (does not include a mesh control header)
*/
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
const u8 *meshda, const u8 *meshsa)
{
if (is_multicast_ether_addr(meshda)) {
*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
/* DA TA SA */
memcpy(hdr->addr1, meshda, ETH_ALEN);
memcpy(hdr->addr2, meshsa, ETH_ALEN);
memcpy(hdr->addr3, meshsa, ETH_ALEN);
return 24;
} else {
*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
/* RA TA DA SA */
eth_zero_addr(hdr->addr1); /* RA is resolved later */
memcpy(hdr->addr2, meshsa, ETH_ALEN);
memcpy(hdr->addr3, meshda, ETH_ALEN);
memcpy(hdr->addr4, meshsa, ETH_ALEN);
return 30;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Javier Cardona | 131 | 96.32% | 1 | 33.33% |
Johannes Berg | 4 | 2.94% | 1 | 33.33% |
Joe Perches | 1 | 0.74% | 1 | 33.33% |
Total | 136 | 100.00% | 3 | 100.00% |
/**
* ieee80211_new_mesh_header - create a new mesh header
* @sdata: mesh interface to be used
* @meshhdr: uninitialized mesh header
* @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
* be NULL.
* @addr6: 2nd address in the ae header, which corresponds to addr6 of the
* mesh frame
*
* Return the header length.
*/
unsigned int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
struct ieee80211s_hdr *meshhdr,
const char *addr4or5, const char *addr6)
{
if (WARN_ON(!addr4or5 && addr6))
return 0;
memset(meshhdr, 0, sizeof(*meshhdr));
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);
sdata->u.mesh.mesh_seqnum++;
if (addr4or5 && !addr6) {
meshhdr->flags |= MESH_FLAGS_AE_A4;
memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
return 2 * ETH_ALEN;
} else if (addr4or5 && addr6) {
meshhdr->flags |= MESH_FLAGS_AE_A5_A6;
memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
memcpy(meshhdr->eaddr2, addr6, ETH_ALEN);
return 3 * ETH_ALEN;
}
return ETH_ALEN;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Javier Cardona | 86 | 50.29% | 2 | 25.00% |
Johannes Berg | 75 | 43.86% | 3 | 37.50% |
Luis Carlos Cobo Rus | 8 | 4.68% | 1 | 12.50% |
Andrzej Hajda | 1 | 0.58% | 1 | 12.50% |
Julia Lawall | 1 | 0.58% | 1 | 12.50% |
Total | 171 | 100.00% | 8 | 100.00% |
static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u32 changed;
if (ifmsh->mshcfg.plink_timeout > 0)
ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ);
mesh_path_expire(sdata);
changed = mesh_accept_plinks_update(sdata);
ieee80211_mbss_info_change_notify(sdata, changed);
mod_timer(&ifmsh->housekeeping_timer,
round_jiffies(jiffies +
IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 60 | 72.29% | 3 | 42.86% |
Masashi Honma | 10 | 12.05% | 1 | 14.29% |
Colleen Twitty | 7 | 8.43% | 1 | 14.29% |
Marco Porsch | 5 | 6.02% | 1 | 14.29% |
Thomas Pedersen | 1 | 1.20% | 1 | 14.29% |
Total | 83 | 100.00% | 7 | 100.00% |
static void ieee80211_mesh_rootpath(struct