Only a few changes at this point:

* new channels in 60 GHz
  * clarify (average) ACK signal reporting API
  * expose ieee80211_send_layer2_update() for all drivers
  * start/stop mac80211's TXQs properly when required
  * avoid regulatory restore with IE ignoring
  * spelling: contidion -> condition
  * fully implement WFA Multi-AP backhaul
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAluGiMwACgkQB8qZga/f
 l8SHMRAAhlYZNjZIHMqbyqRMFeGkgyfgQRYKb4xhrYr7v0542g5U99MWMNBtUJmq
 8aP4dzUFuPkR0qOi220PCs8PBBjuVcdTK1vq7AYiwiK4Um10/MtAlay6BUJFKVqU
 sJMaMbPy4mB3ocWl/q2K4nKaCZARsr854xwiIJZVwbc8n8t60Mr5ELbzELb5prGS
 jPpeRzYd7m4y4xnSYaiXWchdNOplFRN04NcuKJx10Pr3oWilGlj/ujGvwp78U6Uy
 v1H3T9S4XWMFkvl3deeOS6SVkejx76cvH8Ryoq+/qqQsAgs3c9tPQX+mwj6mNicq
 KsQcMIX6WmHNG5IcyaWat4LzdPgb5Xv31brA5tciZ3jebmIbc0P4dSYDLs7Jq1fg
 gkYuyNV3Jlwzv93RzqcrxfAIquZAvI7fy4CGiiRwtMk3wuHJlGy21PjGqZtWwqbn
 v0MbQf9riv1e653ygKSUpm1UoT5HMFbs6ZzbqpSy7Vr0e9+6B78Xkcp5u1DAvIan
 09YSqzKlypoGC+/802BL34HTpoUnf/hiBzVjYFmqvL/X2qv7oEUMOIv2x9Lg7NHh
 NZOPWcwjtPN57UP97Y6gCRAI2kJTigNdVnKISbIzZgNJ/HhB0M7ZmJ2UpB7EuJ1M
 q5aTIolqdoruwdGJ8d3gRr9xjDcuhhjr+FS8h6KfByJ0Qixroqk=
 =BW1J
 -----END PGP SIGNATURE-----

Merge tag 'mac80211-next-for-davem-2018-08-29' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

Johannes Berg says:

====================
Only a few changes at this point:
 * new channels in 60 GHz
 * clarify (average) ACK signal reporting API
 * expose ieee80211_send_layer2_update() for all drivers
 * start/stop mac80211's TXQs properly when required
 * avoid regulatory restore with IE ignoring
 * spelling: contidion -> condition
 * fully implement WFA Multi-AP backhaul
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2018-08-29 22:13:47 -07:00
commit f0259b6ac4
16 changed files with 258 additions and 77 deletions

View File

@ -1436,7 +1436,7 @@ static int wil_freq_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
u32 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
seq_printf(s, "Freq = %d\n", freq);

View File

@ -149,7 +149,7 @@ enum ieee80211_channel_flags {
*/
struct ieee80211_channel {
enum nl80211_band band;
u16 center_freq;
u32 center_freq;
u16 hw_value;
u32 flags;
int max_antenna_gain;
@ -4732,6 +4732,17 @@ static inline const u8 *cfg80211_find_ext_ie(u8 ext_eid, const u8 *ies, int len)
const u8 *cfg80211_find_vendor_ie(unsigned int oui, int oui_type,
const u8 *ies, int len);
/**
* cfg80211_send_layer2_update - send layer 2 update frame
*
* @dev: network device
* @addr: STA MAC address
*
* Wireless drivers can use this function to update forwarding tables in bridge
* devices upon STA association.
*/
void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr);
/**
* DOC: Regulatory enforcement infrastructure
*

View File

@ -1504,6 +1504,8 @@ enum ieee80211_vif_flags {
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void \*).
* @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
* @txqs_stopped: per AC flag to indicate that intermediate TXQs are stopped,
* protected by fq->lock.
*/
struct ieee80211_vif {
enum nl80211_iftype type;
@ -1528,6 +1530,8 @@ struct ieee80211_vif {
unsigned int probe_req_reg;
bool txqs_stopped[IEEE80211_NUM_ACS];
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
};

View File

@ -3050,8 +3050,7 @@ enum nl80211_sta_bss_param {
* received from the station (u64, usec)
* @NL80211_STA_INFO_PAD: attribute used for padding for 64-bit alignment
* @NL80211_STA_INFO_ACK_SIGNAL: signal strength of the last ACK frame(u8, dBm)
* @NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG: avg signal strength of (data)
* ACK frame (s8, dBm)
* @NL80211_STA_INFO_ACK_SIGNAL_AVG: avg signal strength of ACK frames (s8, dBm)
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@ -3091,13 +3090,17 @@ enum nl80211_sta_info {
NL80211_STA_INFO_RX_DURATION,
NL80211_STA_INFO_PAD,
NL80211_STA_INFO_ACK_SIGNAL,
NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG,
NL80211_STA_INFO_ACK_SIGNAL_AVG,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
};
/* we renamed this - stay compatible */
#define NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG NL80211_STA_INFO_ACK_SIGNAL_AVG
/**
* enum nl80211_tid_stats - per TID statistics attributes
* @__NL80211_TID_STATS_INVALID: attribute number 0 is reserved
@ -4338,7 +4341,7 @@ enum nl80211_txrate_gi {
* enum nl80211_band - Frequency band
* @NL80211_BAND_2GHZ: 2.4 GHz ISM band
* @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
* @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz)
* @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 69.12 GHz)
* @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
* since newer kernel versions may support more bands
*/
@ -5213,9 +5216,8 @@ enum nl80211_feature_flags {
* "radar detected" event.
* @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and
* receiving control port frames over nl80211 instead of the netdevice.
* @NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT: This Driver support data ack
* rssi if firmware support, this flag is to intimate about ack rssi
* support to nl80211.
* @NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT: This driver/device supports
* (average) ACK signal strength reporting.
* @NL80211_EXT_FEATURE_TXQS: Driver supports FQ-CoDel-enabled intermediate
* TXQs.
* @NL80211_EXT_FEATURE_SCAN_RANDOM_SN: Driver/device supports randomizing the
@ -5255,7 +5257,9 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN,
NL80211_EXT_FEATURE_DFS_OFFLOAD,
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211,
NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT,
NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT,
/* we renamed this - stay compatible */
NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT = NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT,
NL80211_EXT_FEATURE_TXQS,
NL80211_EXT_FEATURE_SCAN_RANDOM_SN,
NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,

View File

@ -1092,50 +1092,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
return 0;
}
/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
struct iapp_layer2_update {
u8 da[ETH_ALEN]; /* broadcast */
u8 sa[ETH_ALEN]; /* STA addr */
__be16 len; /* 6 */
u8 dsap; /* 0 */
u8 ssap; /* 0 */
u8 control;
u8 xid_info[3];
} __packed;
static void ieee80211_send_layer2_update(struct sta_info *sta)
{
struct iapp_layer2_update *msg;
struct sk_buff *skb;
/* Send Level 2 Update Frame to update forwarding tables in layer 2
* bridge devices */
skb = dev_alloc_skb(sizeof(*msg));
if (!skb)
return;
msg = skb_put(skb, sizeof(*msg));
/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
* Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
eth_broadcast_addr(msg->da);
memcpy(msg->sa, sta->sta.addr, ETH_ALEN);
msg->len = htons(6);
msg->dsap = 0;
msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */
msg->control = 0xaf; /* XID response lsb.1111F101.
* F=0 (no poll command; unsolicited frame) */
msg->xid_info[0] = 0x81; /* XID format identifier */
msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */
skb->dev = sta->sdata->dev;
skb->protocol = eth_type_trans(skb, sta->sdata->dev);
memset(skb->cb, 0, sizeof(skb->cb));
netif_rx_ni(skb);
}
static int sta_apply_auth_flags(struct ieee80211_local *local,
struct sta_info *sta,
u32 mask, u32 set)
@ -1499,7 +1455,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
}
if (layer2_update)
ieee80211_send_layer2_update(sta);
cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr);
rcu_read_unlock();
@ -1601,7 +1557,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
ieee80211_vif_inc_num_mcast(sta->sdata);
ieee80211_send_layer2_update(sta);
cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr);
}
err = sta_apply_parameters(local, sta, params);

View File

@ -818,6 +818,7 @@ enum txq_info_flags {
IEEE80211_TXQ_STOP,
IEEE80211_TXQ_AMPDU,
IEEE80211_TXQ_NO_AMSDU,
IEEE80211_TXQ_STOP_NETIF_TX,
};
/**
@ -1226,6 +1227,7 @@ struct ieee80211_local {
struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
struct tasklet_struct tx_pending_tasklet;
struct tasklet_struct wake_txqs_tasklet;
atomic_t agg_queue_stop[IEEE80211_MAX_QUEUES];
@ -2038,6 +2040,7 @@ void ieee80211_txq_remove_vlan(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
void ieee80211_fill_txq_stats(struct cfg80211_txq_stats *txqstats,
struct txq_info *txqi);
void ieee80211_wake_txqs(unsigned long data);
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg, u16 status,
const u8 *extra, size_t extra_len, const u8 *bssid,

View File

@ -668,6 +668,10 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
(unsigned long)local);
if (ops->wake_tx_queue)
tasklet_init(&local->wake_txqs_tasklet, ieee80211_wake_txqs,
(unsigned long)local);
tasklet_init(&local->tasklet,
ieee80211_tasklet_handler,
(unsigned long) local);

View File

@ -2313,7 +2313,7 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control)
if (!sdata->u.mgd.use_4addr)
return -1;
else
else if (!ether_addr_equal(hdr->addr1, sdata->vif.addr))
check_port_control = true;
}

View File

@ -2323,13 +2323,13 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL);
}
if (ieee80211_hw_check(&sta->local->hw, REPORTS_TX_ACK_STATUS) &&
!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG))) {
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG)) &&
sta->status_stats.ack_signal_filled) {
sinfo->avg_ack_signal =
-(s8)ewma_avg_signal_read(
&sta->status_stats.avg_ack_signal);
sinfo->filled |=
BIT_ULL(NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG);
BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG);
}
}

View File

@ -3466,13 +3466,19 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info;
struct ieee80211_tx_data tx;
ieee80211_tx_result r;
struct ieee80211_vif *vif;
struct ieee80211_vif *vif = txq->vif;
spin_lock_bh(&fq->lock);
if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags))
if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ||
test_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags))
goto out;
if (vif->txqs_stopped[ieee80211_ac_from_tid(txq->tid)]) {
set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags);
goto out;
}
/* Make sure fragments stay together. */
skb = __skb_dequeue(&txqi->frags);
if (skb)
@ -3567,6 +3573,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
}
IEEE80211_SKB_CB(skb)->control.vif = vif;
out:
spin_unlock_bh(&fq->lock);

View File

@ -240,6 +240,99 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_ctstoself_duration);
static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_vif *vif = &sdata->vif;
struct fq *fq = &local->fq;
struct ps_data *ps = NULL;
struct txq_info *txqi;
struct sta_info *sta;
int i;
spin_lock_bh(&fq->lock);
if (sdata->vif.type == NL80211_IFTYPE_AP)
ps = &sdata->bss->ps;
sdata->vif.txqs_stopped[ac] = false;
list_for_each_entry_rcu(sta, &local->sta_list, list) {
if (sdata != sta->sdata)
continue;
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
struct ieee80211_txq *txq = sta->sta.txq[i];
txqi = to_txq_info(txq);
if (ac != txq->ac)
continue;
if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX,
&txqi->flags))
continue;
spin_unlock_bh(&fq->lock);
drv_wake_tx_queue(local, txqi);
spin_lock_bh(&fq->lock);
}
}
if (!vif->txq)
goto out;
txqi = to_txq_info(vif->txq);
if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags) ||
(ps && atomic_read(&ps->num_sta_ps)) || ac != vif->txq->ac)
goto out;
spin_unlock_bh(&fq->lock);
drv_wake_tx_queue(local, txqi);
return;
out:
spin_unlock_bh(&fq->lock);
}
void ieee80211_wake_txqs(unsigned long data)
{
struct ieee80211_local *local = (struct ieee80211_local *)data;
struct ieee80211_sub_if_data *sdata;
int n_acs = IEEE80211_NUM_ACS;
unsigned long flags;
int i;
rcu_read_lock();
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
if (local->hw.queues < IEEE80211_NUM_ACS)
n_acs = 1;
for (i = 0; i < local->hw.queues; i++) {
if (local->queue_stop_reasons[i])
continue;
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
int ac;
for (ac = 0; ac < n_acs; ac++) {
int ac_queue = sdata->vif.hw_queue[ac];
if (ac_queue == i ||
sdata->vif.cab_queue == i)
__ieee80211_wake_txqs(sdata, ac);
}
}
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
rcu_read_unlock();
}
void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
{
struct ieee80211_sub_if_data *sdata;
@ -308,6 +401,9 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
rcu_read_unlock();
} else
tasklet_schedule(&local->tx_pending_tasklet);
if (local->ops->wake_tx_queue)
tasklet_schedule(&local->wake_txqs_tasklet);
}
void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
@ -351,9 +447,6 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue]))
return;
if (local->ops->wake_tx_queue)
return;
if (local->hw.queues < IEEE80211_NUM_ACS)
n_acs = 1;
@ -366,8 +459,15 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
for (ac = 0; ac < n_acs; ac++) {
if (sdata->vif.hw_queue[ac] == queue ||
sdata->vif.cab_queue == queue)
netif_stop_subqueue(sdata->dev, ac);
sdata->vif.cab_queue == queue) {
if (!local->ops->wake_tx_queue) {
netif_stop_subqueue(sdata->dev, ac);
continue;
}
spin_lock(&local->fq.lock);
sdata->vif.txqs_stopped[ac] = true;
spin_unlock(&local->fq.lock);
}
}
}
rcu_read_unlock();

View File

@ -510,8 +510,8 @@ void rfkill_remove_epo_lock(void)
/**
* rfkill_is_epo_lock_active - returns true EPO is active
*
* Returns 0 (false) if there is NOT an active EPO contidion,
* and 1 (true) if there is an active EPO contition, which
* Returns 0 (false) if there is NOT an active EPO condition,
* and 1 (true) if there is an active EPO condition, which
* locks all radios in one of the BLOCKED states.
*
* Can be called in atomic context.

View File

@ -4724,10 +4724,11 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
PUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc);
PUT_SINFO_U64(BEACON_RX, rx_beacon);
PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);
PUT_SINFO(ACK_SIGNAL, ack_signal, u8);
if (wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT))
PUT_SINFO(DATA_ACK_SIGNAL_AVG, avg_ack_signal, s8);
NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT)) {
PUT_SINFO(ACK_SIGNAL, ack_signal, u8);
PUT_SINFO(ACK_SIGNAL_AVG, avg_ack_signal, s8);
}
#undef PUT_SINFO
#undef PUT_SINFO_U64

View File

@ -3249,13 +3249,59 @@ static void restore_regulatory_settings(bool reset_user)
schedule_work(&reg_work);
}
static bool is_wiphy_all_set_reg_flag(enum ieee80211_regulatory_flags flag)
{
struct cfg80211_registered_device *rdev;
struct wireless_dev *wdev;
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
wdev_lock(wdev);
if (!(wdev->wiphy->regulatory_flags & flag)) {
wdev_unlock(wdev);
return false;
}
wdev_unlock(wdev);
}
}
return true;
}
void regulatory_hint_disconnect(void)
{
/* Restore of regulatory settings is not required when wiphy(s)
* ignore IE from connected access point but clearance of beacon hints
* is required when wiphy(s) supports beacon hints.
*/
if (is_wiphy_all_set_reg_flag(REGULATORY_COUNTRY_IE_IGNORE)) {
struct reg_beacon *reg_beacon, *btmp;
if (is_wiphy_all_set_reg_flag(REGULATORY_DISABLE_BEACON_HINTS))
return;
spin_lock_bh(&reg_pending_beacons_lock);
list_for_each_entry_safe(reg_beacon, btmp,
&reg_pending_beacons, list) {
list_del(&reg_beacon->list);
kfree(reg_beacon);
}
spin_unlock_bh(&reg_pending_beacons_lock);
list_for_each_entry_safe(reg_beacon, btmp,
&reg_beacon_list, list) {
list_del(&reg_beacon->list);
kfree(reg_beacon);
}
return;
}
pr_debug("All devices are disconnected, going to restore regulatory settings\n");
restore_regulatory_settings(false);
}
static bool freq_is_chan_12_13_14(u16 freq)
static bool freq_is_chan_12_13_14(u32 freq)
{
if (freq == ieee80211_channel_to_frequency(12, NL80211_BAND_2GHZ) ||
freq == ieee80211_channel_to_frequency(13, NL80211_BAND_2GHZ) ||

View File

@ -112,7 +112,7 @@
} while (0)
#define CHAN_ENTRY __field(enum nl80211_band, band) \
__field(u16, center_freq)
__field(u32, center_freq)
#define CHAN_ASSIGN(chan) \
do { \
if (chan) { \

View File

@ -88,7 +88,7 @@ int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
return 5000 + chan * 5;
break;
case NL80211_BAND_60GHZ:
if (chan < 5)
if (chan < 7)
return 56160 + chan * 2160;
break;
default:
@ -109,7 +109,7 @@ int ieee80211_frequency_to_channel(int freq)
return (freq - 4000) / 5;
else if (freq <= 45000) /* DMG band lower limit */
return (freq - 5000) / 5;
else if (freq >= 58320 && freq <= 64800)
else if (freq >= 58320 && freq <= 70200)
return (freq - 56160) / 2160;
else
return 0;
@ -1568,7 +1568,7 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
}
/* 56.16 GHz, channel 1..4 */
if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) {
if (chandef->width >= NL80211_CHAN_WIDTH_40)
return false;
@ -1893,3 +1893,48 @@ EXPORT_SYMBOL(rfc1042_header);
const unsigned char bridge_tunnel_header[] __aligned(2) =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
EXPORT_SYMBOL(bridge_tunnel_header);
/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
struct iapp_layer2_update {
u8 da[ETH_ALEN]; /* broadcast */
u8 sa[ETH_ALEN]; /* STA addr */
__be16 len; /* 6 */
u8 dsap; /* 0 */
u8 ssap; /* 0 */
u8 control;
u8 xid_info[3];
} __packed;
void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr)
{
struct iapp_layer2_update *msg;
struct sk_buff *skb;
/* Send Level 2 Update Frame to update forwarding tables in layer 2
* bridge devices */
skb = dev_alloc_skb(sizeof(*msg));
if (!skb)
return;
msg = skb_put(skb, sizeof(*msg));
/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
* Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
eth_broadcast_addr(msg->da);
ether_addr_copy(msg->sa, addr);
msg->len = htons(6);
msg->dsap = 0;
msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */
msg->control = 0xaf; /* XID response lsb.1111F101.
* F=0 (no poll command; unsolicited frame) */
msg->xid_info[0] = 0x81; /* XID format identifier */
msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
memset(skb->cb, 0, sizeof(skb->cb));
netif_rx_ni(skb);
}
EXPORT_SYMBOL(cfg80211_send_layer2_update);