Work continues in various areas:
* port authorized event for 4-way-HS offload (Avi) * enable MFP optional for such devices (Emmanuel) * Kees's timer setup patch for mac80211 mesh (the part that isn't trivially scripted) * improve VLAN vs. TXQ handling (myself) * load regulatory database as firmware file (myself) * with various other small improvements and cleanups I merged net-next once in the meantime to allow Kees's timer setup patch to go in. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEExu3sM/nZ1eRSfR9Ha3t4Rpy0AB0FAlneDzEACgkQa3t4Rpy0 AB3EHBAAhQana6YiMx0Ag4ANGlll3xnxFCZlkmlBoJ/EwKgQhPonylHntuvtkXf6 kZRsOr4uA+wpN/opHLGfMJzat9uxztHVo2sT4rxVnvZq4DYcB/JdlhTMLZDsdDgm kHRpUEKh/+2FAgq2A4VEUpVb+Mtg0dq8iJJXFw89xb3Sw5UhNA6ljWQZ4zpXuI0P xOB8Z52LqAcMNnspP+L2TRpanu2ETLcl4Laj+cMl1Yiut2GHkclXUoGvbZ1al5SO CYqpjVKk67ENLJMrmhQ7DVzj0rpwlV+Eh756RU9DhamPAWbxqWLWJgfuGBskRXnI GneCUQkLZ5j1kUJjvQdXBv1UmpkCG4/3yITZX8kL3UR+AbhSCqzVQDo7it5hsWEf XTNAlhdTDhSn7OQQ6XOxvWeydAiaaz671bhPuIvKEo9D/+7Uv0PxHmvu8QqUm0xH Wvyh0LYRrblDz7fgEkaFctjJKYKnwviQ9O2LGx98C8NVam+Qyti2MlLA4AO5E+it ky97W3Dh5ftjQhFD0Ip9P4+BO/9hvNELlCRWUXI197n6B0/KH7FWX1eqw/vpnKc4 w7VB/V59mB8zMmZ1QUdwT1/Ru+MD++6ds93STttZvH/0P3H0dDRGuxUK4m32YHiX s97uSBAbBMy2UH6b8HyxjVMGWvmW3KRakBID1zv2NRSIXtyfWj4= =gW8q -----END PGP SIGNATURE----- Merge tag 'mac80211-next-for-davem-2017-10-11' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next Johannes Berg says: ==================== Work continues in various areas: * port authorized event for 4-way-HS offload (Avi) * enable MFP optional for such devices (Emmanuel) * Kees's timer setup patch for mac80211 mesh (the part that isn't trivially scripted) * improve VLAN vs. TXQ handling (myself) * load regulatory database as firmware file (myself) * with various other small improvements and cleanups I merged net-next once in the meantime to allow Kees's timer setup patch to go in. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
df2fd38a08
@ -299,9 +299,6 @@ Data path helpers
|
||||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:functions: ieee80211_data_to_8023
|
||||
|
||||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:functions: ieee80211_data_from_8023
|
||||
|
||||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:functions: ieee80211_amsdu_to_8023s
|
||||
|
||||
|
@ -19,6 +19,14 @@ core regulatory domain all wireless devices should adhere to.
|
||||
How to get regulatory domains to the kernel
|
||||
-------------------------------------------
|
||||
|
||||
When the regulatory domain is first set up, the kernel will request a
|
||||
database file (regulatory.db) containing all the regulatory rules. It
|
||||
will then use that database when it needs to look up the rules for a
|
||||
given country.
|
||||
|
||||
How to get regulatory domains to the kernel (old CRDA solution)
|
||||
---------------------------------------------------------------
|
||||
|
||||
Userspace gets a regulatory domain in the kernel by having
|
||||
a userspace agent build it and send it via nl80211. Only
|
||||
expected regulatory domains will be respected by the kernel.
|
||||
@ -192,23 +200,5 @@ Then in some part of your code after your wiphy has been registered:
|
||||
Statically compiled regulatory database
|
||||
---------------------------------------
|
||||
|
||||
In most situations the userland solution using CRDA as described
|
||||
above is the preferred solution. However in some cases a set of
|
||||
rules built into the kernel itself may be desirable. To account
|
||||
for this situation, a configuration option has been provided
|
||||
(i.e. CONFIG_CFG80211_INTERNAL_REGDB). With this option enabled,
|
||||
the wireless database information contained in net/wireless/db.txt is
|
||||
used to generate a data structure encoded in net/wireless/regdb.c.
|
||||
That option also enables code in net/wireless/reg.c which queries
|
||||
the data in regdb.c as an alternative to using CRDA.
|
||||
|
||||
The file net/wireless/db.txt should be kept up-to-date with the db.txt
|
||||
file available in the git repository here:
|
||||
|
||||
git://git.kernel.org/pub/scm/linux/kernel/git/sforshee/wireless-regdb.git
|
||||
|
||||
Again, most users in most situations should be using the CRDA package
|
||||
provided with their distribution, and in most other situations users
|
||||
should be building and using CRDA on their own rather than using
|
||||
this option. If you are not absolutely sure that you should be using
|
||||
CONFIG_CFG80211_INTERNAL_REGDB then _DO_NOT_USE_IT_.
|
||||
When a database should be fixed into the kernel, it can be provided as a
|
||||
firmware file at build time that is then linked into the kernel.
|
||||
|
13
MAINTAINERS
13
MAINTAINERS
@ -3329,17 +3329,22 @@ S: Maintained
|
||||
F: drivers/auxdisplay/cfag12864bfb.c
|
||||
F: include/linux/cfag12864b.h
|
||||
|
||||
CFG80211 and NL80211
|
||||
802.11 (including CFG80211/NL80211)
|
||||
M: Johannes Berg <johannes@sipsolutions.net>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
W: http://wireless.kernel.org/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
|
||||
S: Maintained
|
||||
F: net/wireless/
|
||||
F: include/uapi/linux/nl80211.h
|
||||
F: include/linux/ieee80211.h
|
||||
F: include/net/wext.h
|
||||
F: include/net/cfg80211.h
|
||||
F: net/wireless/*
|
||||
X: net/wireless/wext*
|
||||
F: include/net/iw_handler.h
|
||||
F: include/net/ieee80211_radiotap.h
|
||||
F: Documentation/driver-api/80211/cfg80211.rst
|
||||
F: Documentation/networking/regulatory.txt
|
||||
|
||||
CHAR and MISC DRIVERS
|
||||
M: Arnd Bergmann <arnd@arndb.de>
|
||||
@ -8208,6 +8213,7 @@ F: Documentation/networking/mac80211-injection.txt
|
||||
F: include/net/mac80211.h
|
||||
F: net/mac80211/
|
||||
F: drivers/net/wireless/mac80211_hwsim.[ch]
|
||||
F: Documentation/networking/mac80211_hwsim/README
|
||||
|
||||
MAILBOX API
|
||||
M: Jassi Brar <jassisinghbrar@gmail.com>
|
||||
@ -11492,6 +11498,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
|
||||
S: Maintained
|
||||
F: Documentation/rfkill.txt
|
||||
F: Documentation/ABI/stable/sysfs-class-rfkill
|
||||
F: net/rfkill/
|
||||
|
||||
RHASHTABLE
|
||||
|
@ -396,7 +396,7 @@ static int mac80211_hwsim_vendor_cmd_test(struct wiphy *wiphy,
|
||||
if (!tb[QCA_WLAN_VENDOR_ATTR_TEST])
|
||||
return -EINVAL;
|
||||
val = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_TEST]);
|
||||
wiphy_debug(wiphy, "%s: test=%u\n", __func__, val);
|
||||
wiphy_dbg(wiphy, "%s: test=%u\n", __func__, val);
|
||||
|
||||
/* Send a vendor event as a test. Note that this would not normally be
|
||||
* done within a command handler, but rather, based on some other
|
||||
@ -643,9 +643,9 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
|
||||
if (!vp->assoc)
|
||||
return;
|
||||
|
||||
wiphy_debug(data->hw->wiphy,
|
||||
"%s: send PS-Poll to %pM for aid %d\n",
|
||||
__func__, vp->bssid, vp->aid);
|
||||
wiphy_dbg(data->hw->wiphy,
|
||||
"%s: send PS-Poll to %pM for aid %d\n",
|
||||
__func__, vp->bssid, vp->aid);
|
||||
|
||||
skb = dev_alloc_skb(sizeof(*pspoll));
|
||||
if (!skb)
|
||||
@ -674,9 +674,9 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
|
||||
if (!vp->assoc)
|
||||
return;
|
||||
|
||||
wiphy_debug(data->hw->wiphy,
|
||||
"%s: send data::nullfunc to %pM ps=%d\n",
|
||||
__func__, vp->bssid, ps);
|
||||
wiphy_dbg(data->hw->wiphy,
|
||||
"%s: send data::nullfunc to %pM ps=%d\n",
|
||||
__func__, vp->bssid, ps);
|
||||
|
||||
skb = dev_alloc_skb(sizeof(*hdr));
|
||||
if (!skb)
|
||||
@ -1034,7 +1034,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
|
||||
msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0,
|
||||
HWSIM_CMD_FRAME);
|
||||
if (msg_head == NULL) {
|
||||
printk(KERN_DEBUG "mac80211_hwsim: problem with msg_head\n");
|
||||
pr_debug("mac80211_hwsim: problem with msg_head\n");
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
@ -1093,7 +1093,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
|
||||
nla_put_failure:
|
||||
nlmsg_free(skb);
|
||||
err_free_txskb:
|
||||
printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
|
||||
pr_debug("mac80211_hwsim: error occurred in %s\n", __func__);
|
||||
ieee80211_free_txskb(hw, my_skb);
|
||||
data->tx_failed++;
|
||||
}
|
||||
@ -1347,7 +1347,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
|
||||
}
|
||||
|
||||
if (data->idle && !data->tmp_chan) {
|
||||
wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n");
|
||||
wiphy_dbg(hw->wiphy, "Trying to TX when idle - reject\n");
|
||||
ieee80211_free_txskb(hw, skb);
|
||||
return;
|
||||
}
|
||||
@ -1408,7 +1408,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
|
||||
static int mac80211_hwsim_start(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct mac80211_hwsim_data *data = hw->priv;
|
||||
wiphy_debug(hw->wiphy, "%s\n", __func__);
|
||||
wiphy_dbg(hw->wiphy, "%s\n", __func__);
|
||||
data->started = true;
|
||||
return 0;
|
||||
}
|
||||
@ -1419,16 +1419,16 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
|
||||
struct mac80211_hwsim_data *data = hw->priv;
|
||||
data->started = false;
|
||||
tasklet_hrtimer_cancel(&data->beacon_timer);
|
||||
wiphy_debug(hw->wiphy, "%s\n", __func__);
|
||||
wiphy_dbg(hw->wiphy, "%s\n", __func__);
|
||||
}
|
||||
|
||||
|
||||
static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
wiphy_debug(hw->wiphy, "%s (type=%d mac_addr=%pM)\n",
|
||||
__func__, ieee80211_vif_type_p2p(vif),
|
||||
vif->addr);
|
||||
wiphy_dbg(hw->wiphy, "%s (type=%d mac_addr=%pM)\n",
|
||||
__func__, ieee80211_vif_type_p2p(vif),
|
||||
vif->addr);
|
||||
hwsim_set_magic(vif);
|
||||
|
||||
vif->cab_queue = 0;
|
||||
@ -1447,9 +1447,9 @@ static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw,
|
||||
bool newp2p)
|
||||
{
|
||||
newtype = ieee80211_iftype_p2p(newtype, newp2p);
|
||||
wiphy_debug(hw->wiphy,
|
||||
"%s (old type=%d, new type=%d, mac_addr=%pM)\n",
|
||||
__func__, ieee80211_vif_type_p2p(vif),
|
||||
wiphy_dbg(hw->wiphy,
|
||||
"%s (old type=%d, new type=%d, mac_addr=%pM)\n",
|
||||
__func__, ieee80211_vif_type_p2p(vif),
|
||||
newtype, vif->addr);
|
||||
hwsim_check_magic(vif);
|
||||
|
||||
@ -1465,9 +1465,9 @@ static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw,
|
||||
static void mac80211_hwsim_remove_interface(
|
||||
struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
{
|
||||
wiphy_debug(hw->wiphy, "%s (type=%d mac_addr=%pM)\n",
|
||||
__func__, ieee80211_vif_type_p2p(vif),
|
||||
vif->addr);
|
||||
wiphy_dbg(hw->wiphy, "%s (type=%d mac_addr=%pM)\n",
|
||||
__func__, ieee80211_vif_type_p2p(vif),
|
||||
vif->addr);
|
||||
hwsim_check_magic(vif);
|
||||
hwsim_clear_magic(vif);
|
||||
}
|
||||
@ -1589,23 +1589,23 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
|
||||
int idx;
|
||||
|
||||
if (conf->chandef.chan)
|
||||
wiphy_debug(hw->wiphy,
|
||||
"%s (freq=%d(%d - %d)/%s idle=%d ps=%d smps=%s)\n",
|
||||
__func__,
|
||||
conf->chandef.chan->center_freq,
|
||||
conf->chandef.center_freq1,
|
||||
conf->chandef.center_freq2,
|
||||
hwsim_chanwidths[conf->chandef.width],
|
||||
!!(conf->flags & IEEE80211_CONF_IDLE),
|
||||
!!(conf->flags & IEEE80211_CONF_PS),
|
||||
smps_modes[conf->smps_mode]);
|
||||
wiphy_dbg(hw->wiphy,
|
||||
"%s (freq=%d(%d - %d)/%s idle=%d ps=%d smps=%s)\n",
|
||||
__func__,
|
||||
conf->chandef.chan->center_freq,
|
||||
conf->chandef.center_freq1,
|
||||
conf->chandef.center_freq2,
|
||||
hwsim_chanwidths[conf->chandef.width],
|
||||
!!(conf->flags & IEEE80211_CONF_IDLE),
|
||||
!!(conf->flags & IEEE80211_CONF_PS),
|
||||
smps_modes[conf->smps_mode]);
|
||||
else
|
||||
wiphy_debug(hw->wiphy,
|
||||
"%s (freq=0 idle=%d ps=%d smps=%s)\n",
|
||||
__func__,
|
||||
!!(conf->flags & IEEE80211_CONF_IDLE),
|
||||
!!(conf->flags & IEEE80211_CONF_PS),
|
||||
smps_modes[conf->smps_mode]);
|
||||
wiphy_dbg(hw->wiphy,
|
||||
"%s (freq=0 idle=%d ps=%d smps=%s)\n",
|
||||
__func__,
|
||||
!!(conf->flags & IEEE80211_CONF_IDLE),
|
||||
!!(conf->flags & IEEE80211_CONF_PS),
|
||||
smps_modes[conf->smps_mode]);
|
||||
|
||||
data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);
|
||||
|
||||
@ -1659,7 +1659,7 @@ static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
|
||||
{
|
||||
struct mac80211_hwsim_data *data = hw->priv;
|
||||
|
||||
wiphy_debug(hw->wiphy, "%s\n", __func__);
|
||||
wiphy_dbg(hw->wiphy, "%s\n", __func__);
|
||||
|
||||
data->rx_filter = 0;
|
||||
if (*total_flags & FIF_ALLMULTI)
|
||||
@ -1688,25 +1688,25 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
|
||||
|
||||
hwsim_check_magic(vif);
|
||||
|
||||
wiphy_debug(hw->wiphy, "%s(changed=0x%x vif->addr=%pM)\n",
|
||||
__func__, changed, vif->addr);
|
||||
wiphy_dbg(hw->wiphy, "%s(changed=0x%x vif->addr=%pM)\n",
|
||||
__func__, changed, vif->addr);
|
||||
|
||||
if (changed & BSS_CHANGED_BSSID) {
|
||||
wiphy_debug(hw->wiphy, "%s: BSSID changed: %pM\n",
|
||||
__func__, info->bssid);
|
||||
wiphy_dbg(hw->wiphy, "%s: BSSID changed: %pM\n",
|
||||
__func__, info->bssid);
|
||||
memcpy(vp->bssid, info->bssid, ETH_ALEN);
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_ASSOC) {
|
||||
wiphy_debug(hw->wiphy, " ASSOC: assoc=%d aid=%d\n",
|
||||
info->assoc, info->aid);
|
||||
wiphy_dbg(hw->wiphy, " ASSOC: assoc=%d aid=%d\n",
|
||||
info->assoc, info->aid);
|
||||
vp->assoc = info->assoc;
|
||||
vp->aid = info->aid;
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_BEACON_ENABLED) {
|
||||
wiphy_debug(hw->wiphy, " BCN EN: %d (BI=%u)\n",
|
||||
info->enable_beacon, info->beacon_int);
|
||||
wiphy_dbg(hw->wiphy, " BCN EN: %d (BI=%u)\n",
|
||||
info->enable_beacon, info->beacon_int);
|
||||
vp->bcn_en = info->enable_beacon;
|
||||
if (data->started &&
|
||||
!hrtimer_is_queued(&data->beacon_timer.timer) &&
|
||||
@ -1725,8 +1725,8 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
data->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
mac80211_hwsim_bcn_en_iter, &count);
|
||||
wiphy_debug(hw->wiphy, " beaconing vifs remaining: %u",
|
||||
count);
|
||||
wiphy_dbg(hw->wiphy, " beaconing vifs remaining: %u",
|
||||
count);
|
||||
if (count == 0) {
|
||||
tasklet_hrtimer_cancel(&data->beacon_timer);
|
||||
data->beacon_int = 0;
|
||||
@ -1735,31 +1735,31 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
|
||||
wiphy_debug(hw->wiphy, " ERP_CTS_PROT: %d\n",
|
||||
info->use_cts_prot);
|
||||
wiphy_dbg(hw->wiphy, " ERP_CTS_PROT: %d\n",
|
||||
info->use_cts_prot);
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
|
||||
wiphy_debug(hw->wiphy, " ERP_PREAMBLE: %d\n",
|
||||
info->use_short_preamble);
|
||||
wiphy_dbg(hw->wiphy, " ERP_PREAMBLE: %d\n",
|
||||
info->use_short_preamble);
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_ERP_SLOT) {
|
||||
wiphy_debug(hw->wiphy, " ERP_SLOT: %d\n", info->use_short_slot);
|
||||
wiphy_dbg(hw->wiphy, " ERP_SLOT: %d\n", info->use_short_slot);
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_HT) {
|
||||
wiphy_debug(hw->wiphy, " HT: op_mode=0x%x\n",
|
||||
info->ht_operation_mode);
|
||||
wiphy_dbg(hw->wiphy, " HT: op_mode=0x%x\n",
|
||||
info->ht_operation_mode);
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_BASIC_RATES) {
|
||||
wiphy_debug(hw->wiphy, " BASIC_RATES: 0x%llx\n",
|
||||
(unsigned long long) info->basic_rates);
|
||||
wiphy_dbg(hw->wiphy, " BASIC_RATES: 0x%llx\n",
|
||||
(unsigned long long) info->basic_rates);
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_TXPOWER)
|
||||
wiphy_debug(hw->wiphy, " TX Power: %d dBm\n", info->txpower);
|
||||
wiphy_dbg(hw->wiphy, " TX Power: %d dBm\n", info->txpower);
|
||||
}
|
||||
|
||||
static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw,
|
||||
@ -1813,11 +1813,11 @@ static int mac80211_hwsim_conf_tx(
|
||||
struct ieee80211_vif *vif, u16 queue,
|
||||
const struct ieee80211_tx_queue_params *params)
|
||||
{
|
||||
wiphy_debug(hw->wiphy,
|
||||
"%s (queue=%d txop=%d cw_min=%d cw_max=%d aifs=%d)\n",
|
||||
__func__, queue,
|
||||
params->txop, params->cw_min,
|
||||
params->cw_max, params->aifs);
|
||||
wiphy_dbg(hw->wiphy,
|
||||
"%s (queue=%d txop=%d cw_min=%d cw_max=%d aifs=%d)\n",
|
||||
__func__, queue,
|
||||
params->txop, params->cw_min,
|
||||
params->cw_max, params->aifs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1981,7 +1981,7 @@ static void hw_scan_work(struct work_struct *work)
|
||||
.aborted = false,
|
||||
};
|
||||
|
||||
wiphy_debug(hwsim->hw->wiphy, "hw scan complete\n");
|
||||
wiphy_dbg(hwsim->hw->wiphy, "hw scan complete\n");
|
||||
ieee80211_scan_completed(hwsim->hw, &info);
|
||||
hwsim->hw_scan_request = NULL;
|
||||
hwsim->hw_scan_vif = NULL;
|
||||
@ -1990,8 +1990,8 @@ static void hw_scan_work(struct work_struct *work)
|
||||
return;
|
||||
}
|
||||
|
||||
wiphy_debug(hwsim->hw->wiphy, "hw scan %d MHz\n",
|
||||
req->channels[hwsim->scan_chan_idx]->center_freq);
|
||||
wiphy_dbg(hwsim->hw->wiphy, "hw scan %d MHz\n",
|
||||
req->channels[hwsim->scan_chan_idx]->center_freq);
|
||||
|
||||
hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx];
|
||||
if (hwsim->tmp_chan->flags & (IEEE80211_CHAN_NO_IR |
|
||||
@ -2060,7 +2060,7 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
|
||||
memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data));
|
||||
mutex_unlock(&hwsim->mutex);
|
||||
|
||||
wiphy_debug(hw->wiphy, "hwsim hw_scan request\n");
|
||||
wiphy_dbg(hw->wiphy, "hwsim hw_scan request\n");
|
||||
|
||||
ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0);
|
||||
|
||||
@ -2075,7 +2075,7 @@ static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw,
|
||||
.aborted = true,
|
||||
};
|
||||
|
||||
wiphy_debug(hw->wiphy, "hwsim cancel_hw_scan\n");
|
||||
wiphy_dbg(hw->wiphy, "hwsim cancel_hw_scan\n");
|
||||
|
||||
cancel_delayed_work_sync(&hwsim->hw_scan);
|
||||
|
||||
@ -2096,11 +2096,11 @@ static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw,
|
||||
mutex_lock(&hwsim->mutex);
|
||||
|
||||
if (hwsim->scanning) {
|
||||
printk(KERN_DEBUG "two hwsim sw_scans detected!\n");
|
||||
pr_debug("two hwsim sw_scans detected!\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "hwsim sw_scan request, prepping stuff\n");
|
||||
pr_debug("hwsim sw_scan request, prepping stuff\n");
|
||||
|
||||
memcpy(hwsim->scan_addr, mac_addr, ETH_ALEN);
|
||||
hwsim->scanning = true;
|
||||
@ -2117,7 +2117,7 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw,
|
||||
|
||||
mutex_lock(&hwsim->mutex);
|
||||
|
||||
printk(KERN_DEBUG "hwsim sw_scan_complete\n");
|
||||
pr_debug("hwsim sw_scan_complete\n");
|
||||
hwsim->scanning = false;
|
||||
eth_zero_addr(hwsim->scan_addr);
|
||||
|
||||
@ -2131,7 +2131,7 @@ static void hw_roc_start(struct work_struct *work)
|
||||
|
||||
mutex_lock(&hwsim->mutex);
|
||||
|
||||
wiphy_debug(hwsim->hw->wiphy, "hwsim ROC begins\n");
|
||||
wiphy_dbg(hwsim->hw->wiphy, "hwsim ROC begins\n");
|
||||
hwsim->tmp_chan = hwsim->roc_chan;
|
||||
ieee80211_ready_on_channel(hwsim->hw);
|
||||
|
||||
@ -2151,7 +2151,7 @@ static void hw_roc_done(struct work_struct *work)
|
||||
hwsim->tmp_chan = NULL;
|
||||
mutex_unlock(&hwsim->mutex);
|
||||
|
||||
wiphy_debug(hwsim->hw->wiphy, "hwsim ROC expired\n");
|
||||
wiphy_dbg(hwsim->hw->wiphy, "hwsim ROC expired\n");
|
||||
}
|
||||
|
||||
static int mac80211_hwsim_roc(struct ieee80211_hw *hw,
|
||||
@ -2172,8 +2172,8 @@ static int mac80211_hwsim_roc(struct ieee80211_hw *hw,
|
||||
hwsim->roc_duration = duration;
|
||||
mutex_unlock(&hwsim->mutex);
|
||||
|
||||
wiphy_debug(hw->wiphy, "hwsim ROC (%d MHz, %d ms)\n",
|
||||
chan->center_freq, duration);
|
||||
wiphy_dbg(hw->wiphy, "hwsim ROC (%d MHz, %d ms)\n",
|
||||
chan->center_freq, duration);
|
||||
ieee80211_queue_delayed_work(hw, &hwsim->roc_start, HZ/50);
|
||||
|
||||
return 0;
|
||||
@ -2190,7 +2190,7 @@ static int mac80211_hwsim_croc(struct ieee80211_hw *hw)
|
||||
hwsim->tmp_chan = NULL;
|
||||
mutex_unlock(&hwsim->mutex);
|
||||
|
||||
wiphy_debug(hw->wiphy, "hwsim ROC canceled\n");
|
||||
wiphy_dbg(hw->wiphy, "hwsim ROC canceled\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2199,20 +2199,20 @@ static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_chanctx_conf *ctx)
|
||||
{
|
||||
hwsim_set_chanctx_magic(ctx);
|
||||
wiphy_debug(hw->wiphy,
|
||||
"add channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n",
|
||||
ctx->def.chan->center_freq, ctx->def.width,
|
||||
ctx->def.center_freq1, ctx->def.center_freq2);
|
||||
wiphy_dbg(hw->wiphy,
|
||||
"add channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n",
|
||||
ctx->def.chan->center_freq, ctx->def.width,
|
||||
ctx->def.center_freq1, ctx->def.center_freq2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_chanctx_conf *ctx)
|
||||
{
|
||||
wiphy_debug(hw->wiphy,
|
||||
"remove channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n",
|
||||
ctx->def.chan->center_freq, ctx->def.width,
|
||||
ctx->def.center_freq1, ctx->def.center_freq2);
|
||||
wiphy_dbg(hw->wiphy,
|
||||
"remove channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n",
|
||||
ctx->def.chan->center_freq, ctx->def.width,
|
||||
ctx->def.center_freq1, ctx->def.center_freq2);
|
||||
hwsim_check_chanctx_magic(ctx);
|
||||
hwsim_clear_chanctx_magic(ctx);
|
||||
}
|
||||
@ -2222,10 +2222,10 @@ static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw,
|
||||
u32 changed)
|
||||
{
|
||||
hwsim_check_chanctx_magic(ctx);
|
||||
wiphy_debug(hw->wiphy,
|
||||
"change channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n",
|
||||
ctx->def.chan->center_freq, ctx->def.width,
|
||||
ctx->def.center_freq1, ctx->def.center_freq2);
|
||||
wiphy_dbg(hw->wiphy,
|
||||
"change channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n",
|
||||
ctx->def.chan->center_freq, ctx->def.width,
|
||||
ctx->def.center_freq1, ctx->def.center_freq2);
|
||||
}
|
||||
|
||||
static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw,
|
||||
@ -2479,7 +2479,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||
ops = &mac80211_hwsim_mchan_ops;
|
||||
hw = ieee80211_alloc_hw_nm(sizeof(*data), ops, param->hwname);
|
||||
if (!hw) {
|
||||
printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw failed\n");
|
||||
pr_debug("mac80211_hwsim: ieee80211_alloc_hw failed\n");
|
||||
err = -ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
@ -2507,7 +2507,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||
data->dev->driver = &mac80211_hwsim_driver.driver;
|
||||
err = device_bind_driver(data->dev);
|
||||
if (err != 0) {
|
||||
printk(KERN_DEBUG "mac80211_hwsim: device_bind_driver failed (%d)\n",
|
||||
pr_debug("mac80211_hwsim: device_bind_driver failed (%d)\n",
|
||||
err);
|
||||
goto failed_bind;
|
||||
}
|
||||
@ -2698,12 +2698,12 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||
|
||||
err = ieee80211_register_hw(hw);
|
||||
if (err < 0) {
|
||||
printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n",
|
||||
pr_debug("mac80211_hwsim: ieee80211_register_hw failed (%d)\n",
|
||||
err);
|
||||
goto failed_hw;
|
||||
}
|
||||
|
||||
wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr);
|
||||
wiphy_dbg(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr);
|
||||
|
||||
if (param->reg_alpha2) {
|
||||
data->alpha2[0] = param->reg_alpha2[0];
|
||||
@ -3067,7 +3067,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
|
||||
|
||||
return 0;
|
||||
err:
|
||||
printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
|
||||
pr_debug("mac80211_hwsim: error occurred in %s\n", __func__);
|
||||
out:
|
||||
dev_kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
@ -3098,7 +3098,7 @@ static int hwsim_register_received_nl(struct sk_buff *skb_2,
|
||||
|
||||
hwsim_register_wmediumd(net, info->snd_portid);
|
||||
|
||||
printk(KERN_DEBUG "mac80211_hwsim: received a REGISTER, "
|
||||
pr_debug("mac80211_hwsim: received a REGISTER, "
|
||||
"switching to wmediumd mode with pid %d\n", info->snd_portid);
|
||||
|
||||
return 0;
|
||||
@ -3387,7 +3387,7 @@ static int __init hwsim_init_netlink(void)
|
||||
return 0;
|
||||
|
||||
failure:
|
||||
printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
|
||||
pr_debug("mac80211_hwsim: error occurred in %s\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -3578,7 +3578,7 @@ module_init(init_mac80211_hwsim);
|
||||
|
||||
static void __exit exit_mac80211_hwsim(void)
|
||||
{
|
||||
printk(KERN_DEBUG "mac80211_hwsim: unregister radios\n");
|
||||
pr_debug("mac80211_hwsim: unregister radios\n");
|
||||
|
||||
hwsim_exit_netlink();
|
||||
|
||||
|
@ -2445,6 +2445,7 @@ enum ieee80211_sa_query_action {
|
||||
#define WLAN_OUI_TYPE_MICROSOFT_WPA 1
|
||||
#define WLAN_OUI_TYPE_MICROSOFT_WMM 2
|
||||
#define WLAN_OUI_TYPE_MICROSOFT_WPS 4
|
||||
#define WLAN_OUI_TYPE_MICROSOFT_TPC 8
|
||||
|
||||
/*
|
||||
* WMM/802.11e Tspec Element
|
||||
|
@ -4346,19 +4346,6 @@ static inline int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||||
return ieee80211_data_to_8023_exthdr(skb, NULL, addr, iftype);
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_data_from_8023 - convert an 802.3 frame to 802.11
|
||||
* @skb: the 802.3 frame
|
||||
* @addr: the device MAC address
|
||||
* @iftype: the virtual interface type
|
||||
* @bssid: the network bssid (used only for iftype STATION and ADHOC)
|
||||
* @qos: build 802.11 QoS data frame
|
||||
* Return: 0 on success, or a negative error code.
|
||||
*/
|
||||
int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
|
||||
enum nl80211_iftype iftype, const u8 *bssid,
|
||||
bool qos);
|
||||
|
||||
/**
|
||||
* ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame
|
||||
*
|
||||
@ -5441,9 +5428,6 @@ cfg80211_connect_timeout(struct net_device *dev, const u8 *bssid,
|
||||
* @req_ie_len: association request IEs length
|
||||
* @resp_ie: association response IEs (may be %NULL)
|
||||
* @resp_ie_len: assoc response IEs length
|
||||
* @authorized: true if the 802.1X authentication was done by the driver or is
|
||||
* not needed (e.g., when Fast Transition protocol was used), false
|
||||
* otherwise. Ignored for networks that don't use 802.1X authentication.
|
||||
*/
|
||||
struct cfg80211_roam_info {
|
||||
struct ieee80211_channel *channel;
|
||||
@ -5453,7 +5437,6 @@ struct cfg80211_roam_info {
|
||||
size_t req_ie_len;
|
||||
const u8 *resp_ie;
|
||||
size_t resp_ie_len;
|
||||
bool authorized;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -5477,6 +5460,23 @@ struct cfg80211_roam_info {
|
||||
void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info,
|
||||
gfp_t gfp);
|
||||
|
||||
/**
|
||||
* cfg80211_port_authorized - notify cfg80211 of successful security association
|
||||
*
|
||||
* @dev: network device
|
||||
* @bssid: the BSSID of the AP
|
||||
* @gfp: allocation flags
|
||||
*
|
||||
* This function should be called by a driver that supports 4 way handshake
|
||||
* offload after a security association was successfully established (i.e.,
|
||||
* the 4 way handshake was completed successfully). The call to this function
|
||||
* should be preceded with a call to cfg80211_connect_result(),
|
||||
* cfg80211_connect_done(), cfg80211_connect_bss() or cfg80211_roamed() to
|
||||
* indicate the 802.11 association.
|
||||
*/
|
||||
void cfg80211_port_authorized(struct net_device *dev, const u8 *bssid,
|
||||
gfp_t gfp);
|
||||
|
||||
/**
|
||||
* cfg80211_disconnected - notify cfg80211 that connection was dropped
|
||||
*
|
||||
@ -5934,7 +5934,8 @@ int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len,
|
||||
* @ies: the IE buffer
|
||||
* @ielen: the length of the IE buffer
|
||||
* @ids: an array with element IDs that are allowed before
|
||||
* the split
|
||||
* the split. A WLAN_EID_EXTENSION value means that the next
|
||||
* EID in the list is a sub-element of the EXTENSION IE.
|
||||
* @n_ids: the size of the element ID array
|
||||
* @after_ric: array IE types that come after the RIC element
|
||||
* @n_after_ric: size of the @after_ric array
|
||||
@ -5965,7 +5966,8 @@ size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen,
|
||||
* @ies: the IE buffer
|
||||
* @ielen: the length of the IE buffer
|
||||
* @ids: an array with element IDs that are allowed before
|
||||
* the split
|
||||
* the split. A WLAN_EID_EXTENSION value means that the next
|
||||
* EID in the list is a sub-element of the EXTENSION IE.
|
||||
* @n_ids: the size of the element ID array
|
||||
* @offset: offset where to start splitting in the buffer
|
||||
*
|
||||
|
@ -90,6 +90,13 @@ typedef void fq_skb_free_t(struct fq *,
|
||||
struct fq_flow *,
|
||||
struct sk_buff *);
|
||||
|
||||
/* Return %true to filter (drop) the frame. */
|
||||
typedef bool fq_skb_filter_t(struct fq *,
|
||||
struct fq_tin *,
|
||||
struct fq_flow *,
|
||||
struct sk_buff *,
|
||||
void *);
|
||||
|
||||
typedef struct fq_flow *fq_flow_get_default_t(struct fq *,
|
||||
struct fq_tin *,
|
||||
int idx,
|
||||
|
@ -12,24 +12,22 @@
|
||||
|
||||
/* functions that are embedded into includer */
|
||||
|
||||
static struct sk_buff *fq_flow_dequeue(struct fq *fq,
|
||||
struct fq_flow *flow)
|
||||
static void fq_adjust_removal(struct fq *fq,
|
||||
struct fq_flow *flow,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct fq_tin *tin = flow->tin;
|
||||
struct fq_flow *i;
|
||||
struct sk_buff *skb;
|
||||
|
||||
lockdep_assert_held(&fq->lock);
|
||||
|
||||
skb = __skb_dequeue(&flow->queue);
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
||||
tin->backlog_bytes -= skb->len;
|
||||
tin->backlog_packets--;
|
||||
flow->backlog -= skb->len;
|
||||
fq->backlog--;
|
||||
fq->memory_usage -= skb->truesize;
|
||||
}
|
||||
|
||||
static void fq_rejigger_backlog(struct fq *fq, struct fq_flow *flow)
|
||||
{
|
||||
struct fq_flow *i;
|
||||
|
||||
if (flow->backlog == 0) {
|
||||
list_del_init(&flow->backlogchain);
|
||||
@ -43,6 +41,21 @@ static struct sk_buff *fq_flow_dequeue(struct fq *fq,
|
||||
list_move_tail(&flow->backlogchain,
|
||||
&i->backlogchain);
|
||||
}
|
||||
}
|
||||
|
||||
static struct sk_buff *fq_flow_dequeue(struct fq *fq,
|
||||
struct fq_flow *flow)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
lockdep_assert_held(&fq->lock);
|
||||
|
||||
skb = __skb_dequeue(&flow->queue);
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
||||
fq_adjust_removal(fq, flow, skb);
|
||||
fq_rejigger_backlog(fq, flow);
|
||||
|
||||
return skb;
|
||||
}
|
||||
@ -188,6 +201,45 @@ static void fq_tin_enqueue(struct fq *fq,
|
||||
}
|
||||
}
|
||||
|
||||
static void fq_flow_filter(struct fq *fq,
|
||||
struct fq_flow *flow,
|
||||
fq_skb_filter_t filter_func,
|
||||
void *filter_data,
|
||||
fq_skb_free_t free_func)
|
||||
{
|
||||
struct fq_tin *tin = flow->tin;
|
||||
struct sk_buff *skb, *tmp;
|
||||
|
||||
lockdep_assert_held(&fq->lock);
|
||||
|
||||
skb_queue_walk_safe(&flow->queue, skb, tmp) {
|
||||
if (!filter_func(fq, tin, flow, skb, filter_data))
|
||||
continue;
|
||||
|
||||
__skb_unlink(skb, &flow->queue);
|
||||
fq_adjust_removal(fq, flow, skb);
|
||||
free_func(fq, tin, flow, skb);
|
||||
}
|
||||
|
||||
fq_rejigger_backlog(fq, flow);
|
||||
}
|
||||
|
||||
static void fq_tin_filter(struct fq *fq,
|
||||
struct fq_tin *tin,
|
||||
fq_skb_filter_t filter_func,
|
||||
void *filter_data,
|
||||
fq_skb_free_t free_func)
|
||||
{
|
||||
struct fq_flow *flow;
|
||||
|
||||
lockdep_assert_held(&fq->lock);
|
||||
|
||||
list_for_each_entry(flow, &tin->new_flows, flowchain)
|
||||
fq_flow_filter(fq, flow, filter_func, filter_data, free_func);
|
||||
list_for_each_entry(flow, &tin->old_flows, flowchain)
|
||||
fq_flow_filter(fq, flow, filter_func, filter_data, free_func);
|
||||
}
|
||||
|
||||
static void fq_flow_reset(struct fq *fq,
|
||||
struct fq_flow *flow,
|
||||
fq_skb_free_t free_func)
|
||||
|
@ -5441,8 +5441,14 @@ void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
|
||||
*/
|
||||
void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn);
|
||||
|
||||
/**
|
||||
* ieee80211_manage_rx_ba_offl - helper to queue an RX BA work
|
||||
* @vif: &struct ieee80211_vif pointer from the add_interface callback
|
||||
* @addr: station mac address
|
||||
* @tid: the rx tid
|
||||
*/
|
||||
void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif, const u8 *addr,
|
||||
unsigned int bit);
|
||||
unsigned int tid);
|
||||
|
||||
/**
|
||||
* ieee80211_start_rx_ba_session_offl - start a Rx BA session
|
||||
|
@ -569,13 +569,14 @@
|
||||
* authentication/association or not receiving a response from the AP.
|
||||
* Non-zero %NL80211_ATTR_STATUS_CODE value is indicated in that case as
|
||||
* well to remain backwards compatible.
|
||||
* @NL80211_CMD_ROAM: notifcation indicating the card/driver roamed by itself.
|
||||
* When the driver roamed in a network that requires 802.1X authentication,
|
||||
* %NL80211_ATTR_PORT_AUTHORIZED should be set if the 802.1X authentication
|
||||
* was done by the driver or if roaming was done using Fast Transition
|
||||
* protocol (in which case 802.1X authentication is not needed). If
|
||||
* %NL80211_ATTR_PORT_AUTHORIZED is not set, user space is responsible for
|
||||
* the 802.1X authentication.
|
||||
* When establishing a security association, drivers that support 4 way
|
||||
* handshake offload should send %NL80211_CMD_PORT_AUTHORIZED event when
|
||||
* the 4 way handshake is completed successfully.
|
||||
* @NL80211_CMD_ROAM: Notification indicating the card/driver roamed by itself.
|
||||
* When a security association was established with the new AP (e.g. if
|
||||
* the FT protocol was used for roaming or the driver completed the 4 way
|
||||
* handshake), this event should be followed by an
|
||||
* %NL80211_CMD_PORT_AUTHORIZED event.
|
||||
* @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
|
||||
* userspace that a connection was dropped by the AP or due to other
|
||||
* reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
|
||||
@ -982,6 +983,14 @@
|
||||
* @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously
|
||||
* configured PMK for the authenticator address identified by
|
||||
* &NL80211_ATTR_MAC.
|
||||
* @NL80211_CMD_PORT_AUTHORIZED: An event that indicates that the 4 way
|
||||
* handshake was completed successfully by the driver. The BSSID is
|
||||
* specified with &NL80211_ATTR_MAC. Drivers that support 4 way handshake
|
||||
* offload should send this event after indicating 802.11 association with
|
||||
* &NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed
|
||||
* &NL80211_CMD_DISCONNECT should be indicated instead.
|
||||
*
|
||||
* @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
|
||||
*
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
@ -1185,6 +1194,10 @@ enum nl80211_commands {
|
||||
NL80211_CMD_SET_PMK,
|
||||
NL80211_CMD_DEL_PMK,
|
||||
|
||||
NL80211_CMD_PORT_AUTHORIZED,
|
||||
|
||||
NL80211_CMD_RELOAD_REGDB,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
@ -1407,8 +1420,12 @@ enum nl80211_commands {
|
||||
*
|
||||
* @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
|
||||
* used for the association (&enum nl80211_mfp, represented as a u32);
|
||||
* this attribute can be used
|
||||
* with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests
|
||||
* this attribute can be used with %NL80211_CMD_ASSOCIATE and
|
||||
* %NL80211_CMD_CONNECT requests. %NL80211_MFP_OPTIONAL is not allowed for
|
||||
* %NL80211_CMD_ASSOCIATE since user space SME is expected and hence, it
|
||||
* must have decided whether to use management frame protection or not.
|
||||
* Setting %NL80211_MFP_OPTIONAL with a %NL80211_CMD_CONNECT request will
|
||||
* let the driver (or the firmware) decide whether to use MFP or not.
|
||||
*
|
||||
* @NL80211_ATTR_STA_FLAGS2: Attribute containing a
|
||||
* &struct nl80211_sta_flag_update.
|
||||
@ -2134,10 +2151,7 @@ enum nl80211_commands {
|
||||
* in %NL80211_CMD_CONNECT to indicate that for 802.1X authentication it
|
||||
* wants to use the supported offload of the 4-way handshake.
|
||||
* @NL80211_ATTR_PMKR0_NAME: PMK-R0 Name for offloaded FT.
|
||||
* @NL80211_ATTR_PORT_AUTHORIZED: flag attribute used in %NL80211_CMD_ROAMED
|
||||
* notification indicating that that 802.1X authentication was done by
|
||||
* the driver or is not needed (because roaming used the Fast Transition
|
||||
* protocol).
|
||||
* @NL80211_ATTR_PORT_AUTHORIZED: (reserved)
|
||||
*
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
@ -3947,10 +3961,12 @@ enum nl80211_key_type {
|
||||
* enum nl80211_mfp - Management frame protection state
|
||||
* @NL80211_MFP_NO: Management frame protection not used
|
||||
* @NL80211_MFP_REQUIRED: Management frame protection required
|
||||
* @NL80211_MFP_OPTIONAL: Management frame protection is optional
|
||||
*/
|
||||
enum nl80211_mfp {
|
||||
NL80211_MFP_NO,
|
||||
NL80211_MFP_REQUIRED,
|
||||
NL80211_MFP_OPTIONAL,
|
||||
};
|
||||
|
||||
enum nl80211_wpa_versions {
|
||||
@ -4914,6 +4930,17 @@ enum nl80211_feature_flags {
|
||||
* handshake with 802.1X in station mode (will pass EAP frames to the host
|
||||
* and accept the set_pmk/del_pmk commands), doing it in the host might not
|
||||
* be supported.
|
||||
* @NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME: Driver is capable of overriding
|
||||
* the max channel attribute in the FILS request params IE with the
|
||||
* actual dwell time.
|
||||
* @NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP: Driver accepts broadcast probe
|
||||
* response
|
||||
* @NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE: Driver supports sending
|
||||
* the first probe request in each channel at rate of at least 5.5Mbps.
|
||||
* @NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION: Driver supports
|
||||
* probe request tx deferral and suppression
|
||||
* @NL80211_EXT_FEATURE_MFP_OPTIONAL: Driver supports the %NL80211_MFP_OPTIONAL
|
||||
* value in %NL80211_ATTR_USE_MFP.
|
||||
*
|
||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||
@ -4936,6 +4963,11 @@ enum nl80211_ext_feature_index {
|
||||
NL80211_EXT_FEATURE_FILS_SK_OFFLOAD,
|
||||
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK,
|
||||
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X,
|
||||
NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME,
|
||||
NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP,
|
||||
NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE,
|
||||
NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION,
|
||||
NL80211_EXT_FEATURE_MFP_OPTIONAL,
|
||||
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
@ -5012,12 +5044,28 @@ enum nl80211_timeout_reason {
|
||||
* locally administered 1, multicast 0) is assumed.
|
||||
* This flag must not be requested when the feature isn't supported, check
|
||||
* the nl80211 feature flags for the device.
|
||||
* @NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME: fill the dwell time in the FILS
|
||||
* request parameters IE in the probe request
|
||||
* @NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP: accept broadcast probe responses
|
||||
* @NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE: send probe request frames at
|
||||
* rate of at least 5.5M. In case non OCE AP is dicovered in the channel,
|
||||
* only the first probe req in the channel will be sent in high rate.
|
||||
* @NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION: allow probe request
|
||||
* tx deferral (dot11FILSProbeDelay shall be set to 15ms)
|
||||
* and suppression (if it has received a broadcast Probe Response frame,
|
||||
* Beacon frame or FILS Discovery frame from an AP that the STA considers
|
||||
* a suitable candidate for (re-)association - suitable in terms of
|
||||
* SSID and/or RSSI
|
||||
*/
|
||||
enum nl80211_scan_flags {
|
||||
NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
|
||||
NL80211_SCAN_FLAG_FLUSH = 1<<1,
|
||||
NL80211_SCAN_FLAG_AP = 1<<2,
|
||||
NL80211_SCAN_FLAG_RANDOM_ADDR = 1<<3,
|
||||
NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
|
||||
NL80211_SCAN_FLAG_FLUSH = 1<<1,
|
||||
NL80211_SCAN_FLAG_AP = 1<<2,
|
||||
NL80211_SCAN_FLAG_RANDOM_ADDR = 1<<3,
|
||||
NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME = 1<<4,
|
||||
NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP = 1<<5,
|
||||
NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE = 1<<6,
|
||||
NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION = 1<<7,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -6,6 +6,7 @@ mac80211-y := \
|
||||
driver-ops.o \
|
||||
sta_info.o \
|
||||
wep.o \
|
||||
aead_api.o \
|
||||
wpa.o \
|
||||
scan.o offchannel.o \
|
||||
ht.o agg-tx.o agg-rx.o \
|
||||
@ -15,8 +16,6 @@ mac80211-y := \
|
||||
rate.o \
|
||||
michael.o \
|
||||
tkip.o \
|
||||
aes_ccm.o \
|
||||
aes_gcm.o \
|
||||
aes_cmac.o \
|
||||
aes_gmac.o \
|
||||
fils_aead.o \
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright 2003-2004, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright 2014-2015, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Rewrite: Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
|
||||
*
|
||||
@ -12,30 +13,29 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <crypto/aead.h>
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include "key.h"
|
||||
#include "aes_ccm.h"
|
||||
#include "aead_api.h"
|
||||
|
||||
int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic,
|
||||
size_t mic_len)
|
||||
int aead_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len,
|
||||
u8 *data, size_t data_len, u8 *mic)
|
||||
{
|
||||
size_t mic_len = tfm->authsize;
|
||||
struct scatterlist sg[3];
|
||||
struct aead_request *aead_req;
|
||||
int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
|
||||
u8 *__aad;
|
||||
|
||||
aead_req = kzalloc(reqsize + CCM_AAD_LEN, GFP_ATOMIC);
|
||||
aead_req = kzalloc(reqsize + aad_len, GFP_ATOMIC);
|
||||
if (!aead_req)
|
||||
return -ENOMEM;
|
||||
|
||||
__aad = (u8 *)aead_req + reqsize;
|
||||
memcpy(__aad, aad, CCM_AAD_LEN);
|
||||
memcpy(__aad, aad, aad_len);
|
||||
|
||||
sg_init_table(sg, 3);
|
||||
sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
|
||||
sg_set_buf(&sg[0], __aad, aad_len);
|
||||
sg_set_buf(&sg[1], data, data_len);
|
||||
sg_set_buf(&sg[2], mic, mic_len);
|
||||
|
||||
@ -49,10 +49,10 @@ int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic,
|
||||
size_t mic_len)
|
||||
int aead_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len,
|
||||
u8 *data, size_t data_len, u8 *mic)
|
||||
{
|
||||
size_t mic_len = tfm->authsize;
|
||||
struct scatterlist sg[3];
|
||||
struct aead_request *aead_req;
|
||||
int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
|
||||
@ -62,15 +62,15 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
if (data_len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
aead_req = kzalloc(reqsize + CCM_AAD_LEN, GFP_ATOMIC);
|
||||
aead_req = kzalloc(reqsize + aad_len, GFP_ATOMIC);
|
||||
if (!aead_req)
|
||||
return -ENOMEM;
|
||||
|
||||
__aad = (u8 *)aead_req + reqsize;
|
||||
memcpy(__aad, aad, CCM_AAD_LEN);
|
||||
memcpy(__aad, aad, aad_len);
|
||||
|
||||
sg_init_table(sg, 3);
|
||||
sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
|
||||
sg_set_buf(&sg[0], __aad, aad_len);
|
||||
sg_set_buf(&sg[1], data, data_len);
|
||||
sg_set_buf(&sg[2], mic, mic_len);
|
||||
|
||||
@ -84,14 +84,14 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
return err;
|
||||
}
|
||||
|
||||
struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
|
||||
size_t key_len,
|
||||
size_t mic_len)
|
||||
struct crypto_aead *
|
||||
aead_key_setup_encrypt(const char *alg, const u8 key[],
|
||||
size_t key_len, size_t mic_len)
|
||||
{
|
||||
struct crypto_aead *tfm;
|
||||
int err;
|
||||
|
||||
tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC);
|
||||
tfm = crypto_alloc_aead(alg, 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm))
|
||||
return tfm;
|
||||
|
||||
@ -109,7 +109,7 @@ free_aead:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
void ieee80211_aes_key_free(struct crypto_aead *tfm)
|
||||
void aead_key_free(struct crypto_aead *tfm)
|
||||
{
|
||||
crypto_free_aead(tfm);
|
||||
}
|
27
net/mac80211/aead_api.h
Normal file
27
net/mac80211/aead_api.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _AEAD_API_H
|
||||
#define _AEAD_API_H
|
||||
|
||||
#include <crypto/aead.h>
|
||||
#include <linux/crypto.h>
|
||||
|
||||
struct crypto_aead *
|
||||
aead_key_setup_encrypt(const char *alg, const u8 key[],
|
||||
size_t key_len, size_t mic_len);
|
||||
|
||||
int aead_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
size_t aad_len, u8 *data,
|
||||
size_t data_len, u8 *mic);
|
||||
|
||||
int aead_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
size_t aad_len, u8 *data,
|
||||
size_t data_len, u8 *mic);
|
||||
|
||||
void aead_key_free(struct crypto_aead *tfm);
|
||||
|
||||
#endif /* _AEAD_API_H */
|
@ -10,19 +10,39 @@
|
||||
#ifndef AES_CCM_H
|
||||
#define AES_CCM_H
|
||||
|
||||
#include <linux/crypto.h>
|
||||
#include "aead_api.h"
|
||||
|
||||
#define CCM_AAD_LEN 32
|
||||
|
||||
struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
|
||||
size_t key_len,
|
||||
size_t mic_len);
|
||||
int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic,
|
||||
size_t mic_len);
|
||||
int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic,
|
||||
size_t mic_len);
|
||||
void ieee80211_aes_key_free(struct crypto_aead *tfm);
|
||||
static inline struct crypto_aead *
|
||||
ieee80211_aes_key_setup_encrypt(const u8 key[], size_t key_len, size_t mic_len)
|
||||
{
|
||||
return aead_key_setup_encrypt("ccm(aes)", key, key_len, mic_len);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm,
|
||||
u8 *b_0, u8 *aad, u8 *data,
|
||||
size_t data_len, u8 *mic)
|
||||
{
|
||||
return aead_encrypt(tfm, b_0, aad + 2,
|
||||
be16_to_cpup((__be16 *)aad),
|
||||
data, data_len, mic);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm,
|
||||
u8 *b_0, u8 *aad, u8 *data,
|
||||
size_t data_len, u8 *mic)
|
||||
{
|
||||
return aead_decrypt(tfm, b_0, aad + 2,
|
||||
be16_to_cpup((__be16 *)aad),
|
||||
data, data_len, mic);
|
||||
}
|
||||
|
||||
static inline void ieee80211_aes_key_free(struct crypto_aead *tfm)
|
||||
{
|
||||
return aead_key_free(tfm);
|
||||
}
|
||||
|
||||
#endif /* AES_CCM_H */
|
||||
|
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2015, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/err.h>
|
||||
#include <crypto/aead.h>
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include "key.h"
|
||||
#include "aes_gcm.h"
|
||||
|
||||
int ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic)
|
||||
{
|
||||
struct scatterlist sg[3];
|
||||
struct aead_request *aead_req;
|
||||
int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
|
||||
u8 *__aad;
|
||||
|
||||
aead_req = kzalloc(reqsize + GCM_AAD_LEN, GFP_ATOMIC);
|
||||
if (!aead_req)
|
||||
return -ENOMEM;
|
||||
|
||||
__aad = (u8 *)aead_req + reqsize;
|
||||
memcpy(__aad, aad, GCM_AAD_LEN);
|
||||
|
||||
sg_init_table(sg, 3);
|
||||
sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
|
||||
sg_set_buf(&sg[1], data, data_len);
|
||||
sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_LEN);
|
||||
|
||||
aead_request_set_tfm(aead_req, tfm);
|
||||
aead_request_set_crypt(aead_req, sg, sg, data_len, j_0);
|
||||
aead_request_set_ad(aead_req, sg[0].length);
|
||||
|
||||
crypto_aead_encrypt(aead_req);
|
||||
kzfree(aead_req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic)
|
||||
{
|
||||
struct scatterlist sg[3];
|
||||
struct aead_request *aead_req;
|
||||
int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
|
||||
u8 *__aad;
|
||||
int err;
|
||||
|
||||
if (data_len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
aead_req = kzalloc(reqsize + GCM_AAD_LEN, GFP_ATOMIC);
|
||||
if (!aead_req)
|
||||
return -ENOMEM;
|
||||
|
||||
__aad = (u8 *)aead_req + reqsize;
|
||||
memcpy(__aad, aad, GCM_AAD_LEN);
|
||||
|
||||
sg_init_table(sg, 3);
|
||||
sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
|
||||
sg_set_buf(&sg[1], data, data_len);
|
||||
sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_LEN);
|
||||
|
||||
aead_request_set_tfm(aead_req, tfm);
|
||||
aead_request_set_crypt(aead_req, sg, sg,
|
||||
data_len + IEEE80211_GCMP_MIC_LEN, j_0);
|
||||
aead_request_set_ad(aead_req, sg[0].length);
|
||||
|
||||
err = crypto_aead_decrypt(aead_req);
|
||||
kzfree(aead_req);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[],
|
||||
size_t key_len)
|
||||
{
|
||||
struct crypto_aead *tfm;
|
||||
int err;
|
||||
|
||||
tfm = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm))
|
||||
return tfm;
|
||||
|
||||
err = crypto_aead_setkey(tfm, key, key_len);
|
||||
if (err)
|
||||
goto free_aead;
|
||||
err = crypto_aead_setauthsize(tfm, IEEE80211_GCMP_MIC_LEN);
|
||||
if (err)
|
||||
goto free_aead;
|
||||
|
||||
return tfm;
|
||||
|
||||
free_aead:
|
||||
crypto_free_aead(tfm);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
void ieee80211_aes_gcm_key_free(struct crypto_aead *tfm)
|
||||
{
|
||||
crypto_free_aead(tfm);
|
||||
}
|
@ -9,16 +9,38 @@
|
||||
#ifndef AES_GCM_H
|
||||
#define AES_GCM_H
|
||||
|
||||
#include <linux/crypto.h>
|
||||
#include "aead_api.h"
|
||||
|
||||
#define GCM_AAD_LEN 32
|
||||
|
||||
int ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic);
|
||||
int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
|
||||
u8 *data, size_t data_len, u8 *mic);
|
||||
struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[],
|
||||
size_t key_len);
|
||||
void ieee80211_aes_gcm_key_free(struct crypto_aead *tfm);
|
||||
static inline int ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm,
|
||||
u8 *j_0, u8 *aad, u8 *data,
|
||||
size_t data_len, u8 *mic)
|
||||
{
|
||||
return aead_encrypt(tfm, j_0, aad + 2,
|
||||
be16_to_cpup((__be16 *)aad),
|
||||
data, data_len, mic);
|
||||
}
|
||||
|
||||
static inline int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm,
|
||||
u8 *j_0, u8 *aad, u8 *data,
|
||||
size_t data_len, u8 *mic)
|
||||
{
|
||||
return aead_decrypt(tfm, j_0, aad + 2,
|
||||
be16_to_cpup((__be16 *)aad),
|
||||
data, data_len, mic);
|
||||
}
|
||||
|
||||
static inline struct crypto_aead *
|
||||
ieee80211_aes_gcm_key_setup_encrypt(const u8 key[], size_t key_len)
|
||||
{
|
||||
return aead_key_setup_encrypt("gcm(aes)", key,
|
||||
key_len, IEEE80211_GCMP_MIC_LEN);
|
||||
}
|
||||
|
||||
static inline void ieee80211_aes_gcm_key_free(struct crypto_aead *tfm)
|
||||
{
|
||||
return aead_key_free(tfm);
|
||||
}
|
||||
|
||||
#endif /* AES_GCM_H */
|
||||
|
@ -459,7 +459,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
||||
}
|
||||
|
||||
void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif,
|
||||
const u8 *addr, unsigned int bit)
|
||||
const u8 *addr, unsigned int tid)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
@ -470,7 +470,7 @@ void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif,
|
||||
if (!sta)
|
||||
goto unlock;
|
||||
|
||||
set_bit(bit, sta->ampdu_mlme.tid_rx_manage_offl);
|
||||
set_bit(tid, sta->ampdu_mlme.tid_rx_manage_offl);
|
||||
ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
|
@ -290,13 +290,15 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&sta->ampdu_mlme.mtx);
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
|
||||
__ieee80211_stop_tx_ba_session(sta, i, reason);
|
||||
__ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
|
||||
WLAN_REASON_QSTA_LEAVE_QBSS,
|
||||
reason != AGG_STOP_DESTROY_STA &&
|
||||
reason != AGG_STOP_PEER_REQUEST);
|
||||
___ieee80211_stop_tx_ba_session(sta, i, reason);
|
||||
___ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
|
||||
WLAN_REASON_QSTA_LEAVE_QBSS,
|
||||
reason != AGG_STOP_DESTROY_STA &&
|
||||
reason != AGG_STOP_PEER_REQUEST);
|
||||
}
|
||||
mutex_unlock(&sta->ampdu_mlme.mtx);
|
||||
|
||||
/* stopping might queue the work again - so cancel only afterwards */
|
||||
cancel_work_sync(&sta->ampdu_mlme.work);
|
||||
|
@ -2009,6 +2009,8 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
|
||||
struct txq_info *txq, int tid);
|
||||
void ieee80211_txq_purge(struct ieee80211_local *local,
|
||||
struct txq_info *txqi);
|
||||
void ieee80211_txq_remove_vlan(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
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,
|
||||
|
@ -793,9 +793,7 @@ static int ieee80211_open(struct net_device *dev)
|
||||
static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
bool going_down)
|
||||
{
|
||||
struct ieee80211_sub_if_data *txq_sdata = sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct fq *fq = &local->fq;
|
||||
unsigned long flags;
|
||||
struct sk_buff *skb, *tmp;
|
||||
u32 hw_reconf_flags = 0;
|
||||
@ -939,9 +937,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
txq_sdata = container_of(sdata->bss,
|
||||
struct ieee80211_sub_if_data, u.ap);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
list_del(&sdata->u.vlan.list);
|
||||
mutex_unlock(&local->mtx);
|
||||
@ -998,8 +993,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
skb_queue_purge(&sdata->skb_queue);
|
||||
}
|
||||
|
||||
sdata->bss = NULL;
|
||||
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
|
||||
skb_queue_walk_safe(&local->pending[i], skb, tmp) {
|
||||
@ -1012,22 +1005,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
if (txq_sdata->vif.txq) {
|
||||
struct txq_info *txqi = to_txq_info(txq_sdata->vif.txq);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
ieee80211_txq_remove_vlan(local, sdata);
|
||||
|
||||
/*
|
||||
* FIXME FIXME
|
||||
*
|
||||
* We really shouldn't purge the *entire* txqi since that
|
||||
* contains frames for the other AP_VLANs (and possibly
|
||||
* the AP itself) as well, but there's no API in FQ now
|
||||
* to be able to filter.
|
||||
*/
|
||||
|
||||
spin_lock_bh(&fq->lock);
|
||||
ieee80211_txq_purge(local, txqi);
|
||||
spin_unlock_bh(&fq->lock);
|
||||
}
|
||||
sdata->bss = NULL;
|
||||
|
||||
if (local->open_count == 0)
|
||||
ieee80211_clear_tx_pending(local);
|
||||
@ -1772,7 +1753,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||
sizeof(void *));
|
||||
int txq_size = 0;
|
||||
|
||||
if (local->ops->wake_tx_queue)
|
||||
if (local->ops->wake_tx_queue &&
|
||||
type != NL80211_IFTYPE_AP_VLAN &&
|
||||
type != NL80211_IFTYPE_MONITOR)
|
||||
txq_size += sizeof(struct txq_info) +
|
||||
local->hw.txq_data_size;
|
||||
|
||||
|
@ -675,8 +675,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
|
||||
enum nl80211_band band;
|
||||
u8 *pos;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) +
|
||||
sizeof(mgmt->u.beacon);
|
||||
int hdr_len = offsetofend(struct ieee80211_mgmt, u.beacon);
|
||||
|
||||
sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh);
|
||||
rcu_read_lock();
|
||||
|
@ -275,6 +275,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
|
||||
u8 *hw_addr, 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);
|
||||
void mesh_plink_timer(struct timer_list *t);
|
||||
void mesh_plink_broken(struct sta_info *sta);
|
||||
u32 mesh_plink_deactivate(struct sta_info *sta);
|
||||
u32 mesh_plink_open(struct sta_info *sta);
|
||||
|
@ -111,8 +111,8 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u8 *pos, ie_len;
|
||||
int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.mesh_action) +
|
||||
sizeof(mgmt->u.action.u.mesh_action);
|
||||
int hdr_len = offsetofend(struct ieee80211_mgmt,
|
||||
u.action.u.mesh_action);
|
||||
|
||||
skb = dev_alloc_skb(local->tx_headroom +
|
||||
hdr_len +
|
||||
@ -242,8 +242,8 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u8 *pos, ie_len;
|
||||
int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.mesh_action) +
|
||||
sizeof(mgmt->u.action.u.mesh_action);
|
||||
int hdr_len = offsetofend(struct ieee80211_mgmt,
|
||||
u.action.u.mesh_action);
|
||||
|
||||
if (time_before(jiffies, ifmsh->next_perr))
|
||||
return -EAGAIN;
|
||||
|
@ -220,8 +220,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
|
||||
bool include_plid = false;
|
||||
u16 peering_proto = 0;
|
||||
u8 *pos, ie_len = 4;
|
||||
int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.self_prot) +
|
||||
sizeof(mgmt->u.action.u.self_prot);
|
||||
int hdr_len = offsetofend(struct ieee80211_mgmt, u.action.u.self_prot);
|
||||
int err = -ENOMEM;
|
||||
|
||||
skb = dev_alloc_skb(local->tx_headroom +
|
||||
@ -604,8 +603,9 @@ out:
|
||||
ieee80211_mbss_info_change_notify(sdata, changed);
|
||||
}
|
||||
|
||||
static void mesh_plink_timer(unsigned long data)
|
||||
void mesh_plink_timer(struct timer_list *t)
|
||||
{
|
||||
struct mesh_sta *mesh = from_timer(mesh, t, plink_timer);
|
||||
struct sta_info *sta;
|
||||
u16 reason = 0;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
@ -617,7 +617,7 @@ static void mesh_plink_timer(unsigned long data)
|
||||
* del_timer_sync() this timer after having made sure
|
||||
* it cannot be readded (by deleting the plink.)
|
||||
*/
|
||||
sta = (struct sta_info *) data;
|
||||
sta = mesh->plink_sta;
|
||||
|
||||
if (sta->sdata->local->quiescing)
|
||||
return;
|
||||
@ -697,11 +697,8 @@ static void mesh_plink_timer(unsigned long data)
|
||||
|
||||
static inline void mesh_plink_timer_set(struct sta_info *sta, u32 timeout)
|
||||
{
|
||||
sta->mesh->plink_timer.expires = jiffies + msecs_to_jiffies(timeout);
|
||||
sta->mesh->plink_timer.data = (unsigned long) sta;
|
||||
sta->mesh->plink_timer.function = mesh_plink_timer;
|
||||
sta->mesh->plink_timeout = timeout;
|
||||
add_timer(&sta->mesh->plink_timer);
|
||||
mod_timer(&sta->mesh->plink_timer, jiffies + msecs_to_jiffies(timeout));
|
||||
}
|
||||
|
||||
static bool llid_in_use(struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -780,11 +780,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
|
||||
WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
|
||||
WLAN_EID_HT_CAPABILITY,
|
||||
WLAN_EID_BSS_COEX_2040,
|
||||
/* luckily this is almost always there */
|
||||
WLAN_EID_EXT_CAPABILITY,
|
||||
WLAN_EID_QOS_TRAFFIC_CAPA,
|
||||
WLAN_EID_TIM_BCAST_REQ,
|
||||
WLAN_EID_INTERWORKING,
|
||||
/* 60GHz doesn't happen right now */
|
||||
/* 60 GHz (Multi-band, DMG, MMS) can't happen */
|
||||
WLAN_EID_VHT_CAPABILITY,
|
||||
WLAN_EID_OPMODE_NOTIF,
|
||||
};
|
||||
@ -811,22 +812,16 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
|
||||
/* if present, add any custom IEs that go before VHT */
|
||||
if (assoc_data->ie_len) {
|
||||
static const u8 before_vht[] = {
|
||||
WLAN_EID_SSID,
|
||||
WLAN_EID_SUPP_RATES,
|
||||
WLAN_EID_EXT_SUPP_RATES,
|
||||
WLAN_EID_PWR_CAPABILITY,
|
||||
WLAN_EID_SUPPORTED_CHANNELS,
|
||||
WLAN_EID_RSN,
|
||||
WLAN_EID_QOS_CAPA,
|
||||
WLAN_EID_RRM_ENABLED_CAPABILITIES,
|
||||
WLAN_EID_MOBILITY_DOMAIN,
|
||||
WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
|
||||
WLAN_EID_HT_CAPABILITY,
|
||||
/*
|
||||
* no need to list the ones split off before HT
|
||||
* or generated here
|
||||
*/
|
||||
WLAN_EID_BSS_COEX_2040,
|
||||
WLAN_EID_EXT_CAPABILITY,
|
||||
WLAN_EID_QOS_TRAFFIC_CAPA,
|
||||
WLAN_EID_TIM_BCAST_REQ,
|
||||
WLAN_EID_INTERWORKING,
|
||||
/* 60 GHz (Multi-band, DMG, MMS) can't happen */
|
||||
};
|
||||
|
||||
/* RIC already taken above, so no need to handle here anymore */
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright 2016 Intel Deutschland GmbH
|
||||
* Copyright 2016-2017 Intel Deutschland GmbH
|
||||
*
|
||||
* 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
|
||||
@ -183,6 +183,20 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
return bss;
|
||||
}
|
||||
|
||||
static bool ieee80211_scan_accept_presp(struct ieee80211_sub_if_data *sdata,
|
||||
u32 scan_flags, const u8 *da)
|
||||
{
|
||||
if (!sdata)
|
||||
return false;
|
||||
/* accept broadcast for OCE */
|
||||
if (scan_flags & NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP &&
|
||||
is_broadcast_ether_addr(da))
|
||||
return true;
|
||||
if (scan_flags & NL80211_SCAN_FLAG_RANDOM_ADDR)
|
||||
return true;
|
||||
return ether_addr_equal(da, sdata->vif.addr);
|
||||
}
|
||||
|
||||
void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
|
||||
@ -208,19 +222,24 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
|
||||
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
struct cfg80211_sched_scan_request *sched_scan_req;
|
||||
u32 scan_req_flags = 0, sched_scan_req_flags = 0;
|
||||
|
||||
scan_req = rcu_dereference(local->scan_req);
|
||||
sched_scan_req = rcu_dereference(local->sched_scan_req);
|
||||
|
||||
/* ignore ProbeResp to foreign address unless scanning
|
||||
* with randomised address
|
||||
if (scan_req)
|
||||
scan_req_flags = scan_req->flags;
|
||||
|
||||
if (sched_scan_req)
|
||||
sched_scan_req_flags = sched_scan_req->flags;
|
||||
|
||||
/* ignore ProbeResp to foreign address or non-bcast (OCE)
|
||||
* unless scanning with randomised address
|
||||
*/
|
||||
if (!(sdata1 &&
|
||||
(ether_addr_equal(mgmt->da, sdata1->vif.addr) ||
|
||||
scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) &&
|
||||
!(sdata2 &&
|
||||
(ether_addr_equal(mgmt->da, sdata2->vif.addr) ||
|
||||
sched_scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)))
|
||||
if (!ieee80211_scan_accept_presp(sdata1, scan_req_flags,
|
||||
mgmt->da) &&
|
||||
!ieee80211_scan_accept_presp(sdata2, sched_scan_req_flags,
|
||||
mgmt->da))
|
||||
return;
|
||||
|
||||
elements = mgmt->u.probe_resp.variable;
|
||||
|
@ -329,10 +329,12 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
||||
sta->mesh = kzalloc(sizeof(*sta->mesh), gfp);
|
||||
if (!sta->mesh)
|
||||
goto free;
|
||||
sta->mesh->plink_sta = sta;
|
||||
spin_lock_init(&sta->mesh->plink_lock);
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif) &&
|
||||
!sdata->u.mesh.user_mpm)
|
||||
init_timer(&sta->mesh->plink_timer);
|
||||
timer_setup(&sta->mesh->plink_timer, mesh_plink_timer,
|
||||
0);
|
||||
sta->mesh->nonpeer_pm = NL80211_MESH_POWER_ACTIVE;
|
||||
}
|
||||
#endif
|
||||
@ -515,6 +517,31 @@ static int sta_info_insert_drv_state(struct ieee80211_local *local,
|
||||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_recalc_p2p_go_ps_allowed(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
bool allow_p2p_go_ps = sdata->vif.p2p;
|
||||
struct sta_info *sta;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
||||
if (sdata != sta->sdata ||
|
||||
!test_sta_flag(sta, WLAN_STA_ASSOC))
|
||||
continue;
|
||||
if (!sta->sta.support_p2p_ps) {
|
||||
allow_p2p_go_ps = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (allow_p2p_go_ps != sdata->vif.bss_conf.allow_p2p_go_ps) {
|
||||
sdata->vif.bss_conf.allow_p2p_go_ps = allow_p2p_go_ps;
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_P2P_PS);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* should be called with sta_mtx locked
|
||||
* this function replaces the mutex lock
|
||||
@ -561,6 +588,13 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
|
||||
goto out_remove;
|
||||
|
||||
set_sta_flag(sta, WLAN_STA_INSERTED);
|
||||
|
||||
if (sta->sta_state >= IEEE80211_STA_ASSOC) {
|
||||
ieee80211_recalc_min_chandef(sta->sdata);
|
||||
if (!sta->sta.support_p2p_ps)
|
||||
ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
|
||||
}
|
||||
|
||||
/* accept BA sessions now */
|
||||
clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
|
||||
|
||||
@ -1788,31 +1822,6 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_sta_set_buffered);
|
||||
|
||||
static void
|
||||
ieee80211_recalc_p2p_go_ps_allowed(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
bool allow_p2p_go_ps = sdata->vif.p2p;
|
||||
struct sta_info *sta;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
||||
if (sdata != sta->sdata ||
|
||||
!test_sta_flag(sta, WLAN_STA_ASSOC))
|
||||
continue;
|
||||
if (!sta->sta.support_p2p_ps) {
|
||||
allow_p2p_go_ps = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (allow_p2p_go_ps != sdata->vif.bss_conf.allow_p2p_go_ps) {
|
||||
sdata->vif.bss_conf.allow_p2p_go_ps = allow_p2p_go_ps;
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_P2P_PS);
|
||||
}
|
||||
}
|
||||
|
||||
int sta_info_move_state(struct sta_info *sta,
|
||||
enum ieee80211_sta_state new_state)
|
||||
{
|
||||
|
@ -344,6 +344,7 @@ DECLARE_EWMA(mesh_fail_avg, 20, 8)
|
||||
* @plink_state: peer link state
|
||||
* @plink_timeout: timeout of peer link
|
||||
* @plink_timer: peer link watch timer
|
||||
* @plink_sta: peer link watch timer's sta_info
|
||||
* @t_offset: timing offset relative to this host
|
||||
* @t_offset_setpoint: reference timing offset of this sta to be used when
|
||||
* calculating clockdrift
|
||||
@ -356,6 +357,7 @@ DECLARE_EWMA(mesh_fail_avg, 20, 8)
|
||||
*/
|
||||
struct mesh_sta {
|
||||
struct timer_list plink_timer;
|
||||
struct sta_info *plink_sta;
|
||||
|
||||
s64 t_offset;
|
||||
s64 t_offset_setpoint;
|
||||
@ -398,7 +400,7 @@ struct ieee80211_sta_rx_stats {
|
||||
u64 msdu[IEEE80211_NUM_TIDS + 1];
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* The bandwidth threshold below which the per-station CoDel parameters will be
|
||||
* scaled to be more lenient (to prevent starvation of slow stations). This
|
||||
* value will be scaled by the number of active stations when it is being
|
||||
|
@ -1396,6 +1396,40 @@ static void ieee80211_txq_enqueue(struct ieee80211_local *local,
|
||||
fq_flow_get_default_func);
|
||||
}
|
||||
|
||||
static bool fq_vlan_filter_func(struct fq *fq, struct fq_tin *tin,
|
||||
struct fq_flow *flow, struct sk_buff *skb,
|
||||
void *data)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
return info->control.vif == data;
|
||||
}
|
||||
|
||||
void ieee80211_txq_remove_vlan(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct fq *fq = &local->fq;
|
||||
struct txq_info *txqi;
|
||||
struct fq_tin *tin;
|
||||
struct ieee80211_sub_if_data *ap;
|
||||
|
||||
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
|
||||
return;
|
||||
|
||||
ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
|
||||
|
||||
if (!ap->vif.txq)
|
||||
return;
|
||||
|
||||
txqi = to_txq_info(ap->vif.txq);
|
||||
tin = &txqi->tin;
|
||||
|
||||
spin_lock_bh(&fq->lock);
|
||||
fq_tin_filter(fq, tin, fq_vlan_filter_func, &sdata->vif,
|
||||
fq_skb_free_func);
|
||||
spin_unlock_bh(&fq->lock);
|
||||
}
|
||||
|
||||
void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta,
|
||||
struct txq_info *txqi, int tid)
|
||||
|
@ -1392,10 +1392,10 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
|
||||
/* insert custom IEs that go before HT */
|
||||
if (ie && ie_len) {
|
||||
static const u8 before_ht[] = {
|
||||
WLAN_EID_SSID,
|
||||
WLAN_EID_SUPP_RATES,
|
||||
WLAN_EID_REQUEST,
|
||||
WLAN_EID_EXT_SUPP_RATES,
|
||||
/*
|
||||
* no need to list the ones split off already
|
||||
* (or generated here)
|
||||
*/
|
||||
WLAN_EID_DS_PARAMS,
|
||||
WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
|
||||
};
|
||||
@ -1424,20 +1424,17 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
|
||||
/* insert custom IEs that go before VHT */
|
||||
if (ie && ie_len) {
|
||||
static const u8 before_vht[] = {
|
||||
WLAN_EID_SSID,
|
||||
WLAN_EID_SUPP_RATES,
|
||||
WLAN_EID_REQUEST,
|
||||
WLAN_EID_EXT_SUPP_RATES,
|
||||
WLAN_EID_DS_PARAMS,
|
||||
WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
|
||||
WLAN_EID_HT_CAPABILITY,
|
||||
/*
|
||||
* no need to list the ones split off already
|
||||
* (or generated here)
|
||||
*/
|
||||
WLAN_EID_BSS_COEX_2040,
|
||||
WLAN_EID_EXT_CAPABILITY,
|
||||
WLAN_EID_SSID_LIST,
|
||||
WLAN_EID_CHANNEL_USAGE,
|
||||
WLAN_EID_INTERWORKING,
|
||||
WLAN_EID_MESH_ID,
|
||||
/* 60 GHz can't happen here right now */
|
||||
/* 60 GHz (Multi-band, DMG, MMS) can't happen */
|
||||
};
|
||||
noffset = ieee80211_ie_split(ie, ie_len,
|
||||
before_vht, ARRAY_SIZE(before_vht),
|
||||
@ -2980,8 +2977,8 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int freq;
|
||||
int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.chan_switch) +
|
||||
sizeof(mgmt->u.action.u.chan_switch);
|
||||
int hdr_len = offsetofend(struct ieee80211_mgmt,
|
||||
u.action.u.chan_switch);
|
||||
u8 *pos;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
|
||||
|
@ -386,6 +386,16 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta)
|
||||
|
||||
bw = ieee80211_sta_cap_rx_bw(sta);
|
||||
bw = min(bw, sta->cur_max_bandwidth);
|
||||
|
||||
/* Don't consider AP's bandwidth for TDLS peers, section 11.23.1 of
|
||||
* IEEE80211-2016 specification makes higher bandwidth operation
|
||||
* possible on the TDLS link if the peers have wider bandwidth
|
||||
* capability.
|
||||
*/
|
||||
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
|
||||
test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW))
|
||||
return bw;
|
||||
|
||||
bw = min(bw, ieee80211_chan_width_to_rx_bw(bss_width));
|
||||
|
||||
return bw;
|
||||
|
@ -464,7 +464,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb,
|
||||
pos += IEEE80211_CCMP_HDR_LEN;
|
||||
ccmp_special_blocks(skb, pn, b_0, aad);
|
||||
return ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
|
||||
skb_put(skb, mic_len), mic_len);
|
||||
skb_put(skb, mic_len));
|
||||
}
|
||||
|
||||
|
||||
@ -543,7 +543,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx,
|
||||
key->u.ccmp.tfm, b_0, aad,
|
||||
skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN,
|
||||
data_len,
|
||||
skb->data + skb->len - mic_len, mic_len))
|
||||
skb->data + skb->len - mic_len))
|
||||
return RX_DROP_UNUSABLE;
|
||||
}
|
||||
|
||||
|
3
net/wireless/.gitignore
vendored
3
net/wireless/.gitignore
vendored
@ -1 +1,2 @@
|
||||
regdb.c
|
||||
shipped-certs.c
|
||||
extra-certs.c
|
||||
|
@ -19,6 +19,7 @@ config WEXT_PRIV
|
||||
config CFG80211
|
||||
tristate "cfg80211 - wireless configuration API"
|
||||
depends on RFKILL || !RFKILL
|
||||
select FW_LOADER
|
||||
---help---
|
||||
cfg80211 is the Linux wireless LAN (802.11) configuration API.
|
||||
Enable this if you have a wireless device.
|
||||
@ -82,6 +83,36 @@ config CFG80211_CERTIFICATION_ONUS
|
||||
you are a wireless researcher and are working in a controlled
|
||||
and approved environment by your local regulatory agency.
|
||||
|
||||
config CFG80211_REQUIRE_SIGNED_REGDB
|
||||
bool "require regdb signature" if CFG80211_CERTIFICATION_ONUS
|
||||
default y
|
||||
select SYSTEM_DATA_VERIFICATION
|
||||
help
|
||||
Require that in addition to the "regulatory.db" file a
|
||||
"regulatory.db.p7s" can be loaded with a valid PKCS#7
|
||||
signature for the regulatory.db file made by one of the
|
||||
keys in the certs/ directory.
|
||||
|
||||
config CFG80211_USE_KERNEL_REGDB_KEYS
|
||||
bool "allow regdb keys shipped with the kernel" if CFG80211_CERTIFICATION_ONUS
|
||||
default y
|
||||
depends on CFG80211_REQUIRE_SIGNED_REGDB
|
||||
help
|
||||
Allow the regulatory database to be signed by one of the keys for
|
||||
which certificates are part of the kernel sources
|
||||
(in net/wireless/certs/).
|
||||
|
||||
This is currently only Seth Forshee's key, who is the regulatory
|
||||
database maintainer.
|
||||
|
||||
config CFG80211_EXTRA_REGDB_KEYDIR
|
||||
string "additional regdb key directory" if CFG80211_CERTIFICATION_ONUS
|
||||
depends on CFG80211_REQUIRE_SIGNED_REGDB
|
||||
help
|
||||
If selected, point to a directory with DER-encoded X.509
|
||||
certificates like in the kernel sources (net/wireless/certs/)
|
||||
that shall be accepted for a signed regulatory database.
|
||||
|
||||
config CFG80211_REG_CELLULAR_HINTS
|
||||
bool "cfg80211 regulatory support for cellular base station hints"
|
||||
depends on CFG80211_CERTIFICATION_ONUS
|
||||
@ -139,35 +170,14 @@ config CFG80211_DEBUGFS
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config CFG80211_INTERNAL_REGDB
|
||||
bool "use statically compiled regulatory rules database" if EXPERT
|
||||
default n
|
||||
depends on CFG80211
|
||||
---help---
|
||||
This option generates an internal data structure representing
|
||||
the wireless regulatory rules described in net/wireless/db.txt
|
||||
and includes code to query that database. This is an alternative
|
||||
to using CRDA for defining regulatory rules for the kernel.
|
||||
|
||||
Using this option requires some parsing of the db.txt at build time,
|
||||
the parser will be upkept with the latest wireless-regdb updates but
|
||||
older wireless-regdb formats will be ignored. The parser may later
|
||||
be replaced to avoid issues with conflicts on versions of
|
||||
wireless-regdb.
|
||||
|
||||
For details see:
|
||||
|
||||
http://wireless.kernel.org/en/developers/Regulatory
|
||||
|
||||
Most distributions have a CRDA package. So if unsure, say N.
|
||||
|
||||
config CFG80211_CRDA_SUPPORT
|
||||
bool "support CRDA" if CFG80211_INTERNAL_REGDB
|
||||
bool "support CRDA" if EXPERT
|
||||
default y
|
||||
depends on CFG80211
|
||||
help
|
||||
You should enable this option unless you know for sure you have no
|
||||
need for it, for example when using internal regdb (above.)
|
||||
need for it, for example when using internal regdb (above) or the
|
||||
database loaded as a firmware file.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
|
@ -14,11 +14,27 @@ cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o
|
||||
cfg80211-$(CONFIG_OF) += of.o
|
||||
cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
|
||||
cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
|
||||
cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
|
||||
|
||||
CFLAGS_trace.o := -I$(src)
|
||||
|
||||
$(obj)/regdb.c: $(src)/db.txt $(src)/genregdb.awk
|
||||
@$(AWK) -f $(srctree)/$(src)/genregdb.awk < $< > $@
|
||||
cfg80211-$(CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS) += shipped-certs.o
|
||||
ifneq ($(CONFIG_CFG80211_EXTRA_REGDB_KEYDIR),)
|
||||
cfg80211-y += extra-certs.o
|
||||
endif
|
||||
|
||||
clean-files := regdb.c
|
||||
$(obj)/shipped-certs.c: $(wildcard $(srctree)/$(src)/certs/*.x509)
|
||||
@echo " GEN $@"
|
||||
@echo '#include "reg.h"' > $@
|
||||
@echo 'const u8 shipped_regdb_certs[] = {' >> $@
|
||||
@for f in $^ ; do hexdump -v -e '1/1 "0x%.2x," "\n"' < $$f >> $@ ; done
|
||||
@echo '};' >> $@
|
||||
@echo 'unsigned int shipped_regdb_certs_len = sizeof(shipped_regdb_certs);' >> $@
|
||||
|
||||
$(obj)/extra-certs.c: $(CONFIG_CFG80211_EXTRA_REGDB_KEYDIR:"%"=%) \
|
||||
$(wildcard $(CONFIG_CFG80211_EXTRA_REGDB_KEYDIR:"%"=%)/*.x509)
|
||||
@echo " GEN $@"
|
||||
@echo '#include "reg.h"' > $@
|
||||
@echo 'const u8 extra_regdb_certs[] = {' >> $@
|
||||
@for f in $^ ; do test -f $$f && hexdump -v -e '1/1 "0x%.2x," "\n"' < $$f >> $@ || true ; done
|
||||
@echo '};' >> $@
|
||||
@echo 'unsigned int extra_regdb_certs_len = sizeof(extra_regdb_certs);' >> $@
|
||||
|
BIN
net/wireless/certs/sforshee.x509
Normal file
BIN
net/wireless/certs/sforshee.x509
Normal file
Binary file not shown.
@ -1384,7 +1384,7 @@ out_fail_sysfs:
|
||||
out_fail_pernet:
|
||||
return err;
|
||||
}
|
||||
subsys_initcall(cfg80211_init);
|
||||
fs_initcall(cfg80211_init);
|
||||
|
||||
static void __exit cfg80211_exit(void)
|
||||
{
|
||||
|
@ -216,6 +216,7 @@ enum cfg80211_event_type {
|
||||
EVENT_DISCONNECTED,
|
||||
EVENT_IBSS_JOINED,
|
||||
EVENT_STOPPED,
|
||||
EVENT_PORT_AUTHORIZED,
|
||||
};
|
||||
|
||||
struct cfg80211_event {
|
||||
@ -235,6 +236,9 @@ struct cfg80211_event {
|
||||
u8 bssid[ETH_ALEN];
|
||||
struct ieee80211_channel *channel;
|
||||
} ij;
|
||||
struct {
|
||||
u8 bssid[ETH_ALEN];
|
||||
} pa;
|
||||
};
|
||||
};
|
||||
|
||||
@ -385,6 +389,7 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
|
||||
bool wextev);
|
||||
void __cfg80211_roamed(struct wireless_dev *wdev,
|
||||
struct cfg80211_roam_info *info);
|
||||
void __cfg80211_port_authorized(struct wireless_dev *wdev, const u8 *bssid);
|
||||
int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev);
|
||||
void cfg80211_autodisconnect_wk(struct work_struct *work);
|
||||
|
@ -1,17 +0,0 @@
|
||||
#
|
||||
# This file is a placeholder to prevent accidental build breakage if someone
|
||||
# enables CONFIG_CFG80211_INTERNAL_REGDB. Almost no one actually needs to
|
||||
# enable that build option.
|
||||
#
|
||||
# You should be using CRDA instead. It is even better if you use the CRDA
|
||||
# package provided by your distribution, since they will probably keep it
|
||||
# up-to-date on your behalf.
|
||||
#
|
||||
# If you _really_ intend to use CONFIG_CFG80211_INTERNAL_REGDB then you will
|
||||
# need to replace this file with one containing appropriately formatted
|
||||
# regulatory rules that cover the regulatory domains you will be using. Your
|
||||
# best option is to extract the db.txt file from the wireless-regdb git
|
||||
# repository:
|
||||
#
|
||||
# git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git
|
||||
#
|
@ -1,158 +0,0 @@
|
||||
#!/usr/bin/awk -f
|
||||
#
|
||||
# genregdb.awk -- generate regdb.c from db.txt
|
||||
#
|
||||
# Actually, it reads from stdin (presumed to be db.txt) and writes
|
||||
# to stdout (presumed to be regdb.c), but close enough...
|
||||
#
|
||||
# Copyright 2009 John W. Linville <linville@tuxdriver.com>
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
BEGIN {
|
||||
active = 0
|
||||
rules = 0;
|
||||
print "/*"
|
||||
print " * DO NOT EDIT -- file generated from data in db.txt"
|
||||
print " */"
|
||||
print ""
|
||||
print "#include <linux/nl80211.h>"
|
||||
print "#include <net/cfg80211.h>"
|
||||
print "#include \"regdb.h\""
|
||||
print ""
|
||||
regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n"
|
||||
}
|
||||
|
||||
function parse_country_head() {
|
||||
country=$2
|
||||
sub(/:/, "", country)
|
||||
printf "static const struct ieee80211_regdomain regdom_%s = {\n", country
|
||||
printf "\t.alpha2 = \"%s\",\n", country
|
||||
if ($NF ~ /DFS-ETSI/)
|
||||
printf "\t.dfs_region = NL80211_DFS_ETSI,\n"
|
||||
else if ($NF ~ /DFS-FCC/)
|
||||
printf "\t.dfs_region = NL80211_DFS_FCC,\n"
|
||||
else if ($NF ~ /DFS-JP/)
|
||||
printf "\t.dfs_region = NL80211_DFS_JP,\n"
|
||||
printf "\t.reg_rules = {\n"
|
||||
active = 1
|
||||
regdb = regdb "\t®dom_" country ",\n"
|
||||
}
|
||||
|
||||
function parse_reg_rule()
|
||||
{
|
||||
flag_starts_at = 7
|
||||
|
||||
start = $1
|
||||
sub(/\(/, "", start)
|
||||
end = $3
|
||||
bw = $5
|
||||
sub(/\),/, "", bw)
|
||||
gain = 0
|
||||
power = $6
|
||||
# power might be in mW...
|
||||
units = $7
|
||||
dfs_cac = 0
|
||||
|
||||
sub(/\(/, "", power)
|
||||
sub(/\),/, "", power)
|
||||
sub(/\),/, "", units)
|
||||
sub(/\)/, "", units)
|
||||
|
||||
if (units == "mW") {
|
||||
flag_starts_at = 8
|
||||
power = 10 * log(power)/log(10)
|
||||
if ($8 ~ /[[:digit:]]/) {
|
||||
flag_starts_at = 9
|
||||
dfs_cac = $8
|
||||
}
|
||||
} else {
|
||||
if ($7 ~ /[[:digit:]]/) {
|
||||
flag_starts_at = 8
|
||||
dfs_cac = $7
|
||||
}
|
||||
}
|
||||
sub(/\(/, "", dfs_cac)
|
||||
sub(/\),/, "", dfs_cac)
|
||||
flagstr = ""
|
||||
for (i=flag_starts_at; i<=NF; i++)
|
||||
flagstr = flagstr $i
|
||||
split(flagstr, flagarray, ",")
|
||||
flags = ""
|
||||
for (arg in flagarray) {
|
||||
if (flagarray[arg] == "NO-OFDM") {
|
||||
flags = flags "\n\t\t\tNL80211_RRF_NO_OFDM | "
|
||||
} else if (flagarray[arg] == "NO-CCK") {
|
||||
flags = flags "\n\t\t\tNL80211_RRF_NO_CCK | "
|
||||
} else if (flagarray[arg] == "NO-INDOOR") {
|
||||
flags = flags "\n\t\t\tNL80211_RRF_NO_INDOOR | "
|
||||
} else if (flagarray[arg] == "NO-OUTDOOR") {
|
||||
flags = flags "\n\t\t\tNL80211_RRF_NO_OUTDOOR | "
|
||||
} else if (flagarray[arg] == "DFS") {
|
||||
flags = flags "\n\t\t\tNL80211_RRF_DFS | "
|
||||
} else if (flagarray[arg] == "PTP-ONLY") {
|
||||
flags = flags "\n\t\t\tNL80211_RRF_PTP_ONLY | "
|
||||
} else if (flagarray[arg] == "PTMP-ONLY") {
|
||||
flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | "
|
||||
} else if (flagarray[arg] == "PASSIVE-SCAN") {
|
||||
flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
|
||||
} else if (flagarray[arg] == "NO-IBSS") {
|
||||
flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
|
||||
} else if (flagarray[arg] == "NO-IR") {
|
||||
flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
|
||||
} else if (flagarray[arg] == "AUTO-BW") {
|
||||
flags = flags "\n\t\t\tNL80211_RRF_AUTO_BW | "
|
||||
}
|
||||
|
||||
}
|
||||
flags = flags "0"
|
||||
printf "\t\tREG_RULE_EXT(%d, %d, %d, %d, %.0f, %d, %s),\n", start, end, bw, gain, power, dfs_cac, flags
|
||||
rules++
|
||||
}
|
||||
|
||||
function print_tail_country()
|
||||
{
|
||||
active = 0
|
||||
printf "\t},\n"
|
||||
printf "\t.n_reg_rules = %d\n", rules
|
||||
printf "};\n\n"
|
||||
rules = 0;
|
||||
}
|
||||
|
||||
/^[ \t]*#/ {
|
||||
# Ignore
|
||||
}
|
||||
|
||||
!active && /^[ \t]*$/ {
|
||||
# Ignore
|
||||
}
|
||||
|
||||
!active && /country/ {
|
||||
parse_country_head()
|
||||
}
|
||||
|
||||
active && /^[ \t]*\(/ {
|
||||
parse_reg_rule()
|
||||
}
|
||||
|
||||
active && /^[ \t]*$/ {
|
||||
print_tail_country()
|
||||
}
|
||||
|
||||
END {
|
||||
if (active)
|
||||
print_tail_country()
|
||||
print regdb "};"
|
||||
print ""
|
||||
print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);"
|
||||
}
|
@ -2130,6 +2130,15 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
|
||||
case NL80211_CHAN_HT40MINUS:
|
||||
cfg80211_chandef_create(chandef, chandef->chan,
|
||||
chantype);
|
||||
/* user input for center_freq is incorrect */
|
||||
if (info->attrs[NL80211_ATTR_CENTER_FREQ1] &&
|
||||
chandef->center_freq1 != nla_get_u32(
|
||||
info->attrs[NL80211_ATTR_CENTER_FREQ1]))
|
||||
return -EINVAL;
|
||||
/* center_freq2 must be zero */
|
||||
if (info->attrs[NL80211_ATTR_CENTER_FREQ2] &&
|
||||
nla_get_u32(info->attrs[NL80211_ATTR_CENTER_FREQ2]))
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -5677,6 +5686,11 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
|
||||
}
|
||||
}
|
||||
|
||||
static int nl80211_reload_regdb(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
return reg_reload_regdb();
|
||||
}
|
||||
|
||||
static int nl80211_get_mesh_config(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
@ -6618,6 +6632,77 @@ static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev)
|
||||
return regulatory_pre_cac_allowed(wdev->wiphy);
|
||||
}
|
||||
|
||||
static int
|
||||
nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
void *request, struct nlattr **attrs,
|
||||
bool is_sched_scan)
|
||||
{
|
||||
u8 *mac_addr, *mac_addr_mask;
|
||||
u32 *flags;
|
||||
enum nl80211_feature_flags randomness_flag;
|
||||
|
||||
if (!attrs[NL80211_ATTR_SCAN_FLAGS])
|
||||
return 0;
|
||||
|
||||
if (is_sched_scan) {
|
||||
struct cfg80211_sched_scan_request *req = request;
|
||||
|
||||
randomness_flag = wdev ?
|
||||
NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR :
|
||||
NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
|
||||
flags = &req->flags;
|
||||
mac_addr = req->mac_addr;
|
||||
mac_addr_mask = req->mac_addr_mask;
|
||||
} else {
|
||||
struct cfg80211_scan_request *req = request;
|
||||
|
||||
randomness_flag = NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
|
||||
flags = &req->flags;
|
||||
mac_addr = req->mac_addr;
|
||||
mac_addr_mask = req->mac_addr_mask;
|
||||
}
|
||||
|
||||
*flags = nla_get_u32(attrs[NL80211_ATTR_SCAN_FLAGS]);
|
||||
|
||||
if ((*flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
|
||||
!(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (*flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
|
||||
int err;
|
||||
|
||||
if (!(wiphy->features & randomness_flag) ||
|
||||
(wdev && wdev->current_bss))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
err = nl80211_parse_random_mac(attrs, mac_addr, mac_addr_mask);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((*flags & NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME) &&
|
||||
!wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if ((*flags & NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP) &&
|
||||
!wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if ((*flags & NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION) &&
|
||||
!wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if ((*flags & NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE) &&
|
||||
!wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
@ -6823,34 +6908,10 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
|
||||
nla_get_flag(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY]);
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
|
||||
request->flags = nla_get_u32(
|
||||
info->attrs[NL80211_ATTR_SCAN_FLAGS]);
|
||||
if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
|
||||
!(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
|
||||
if (!(wiphy->features &
|
||||
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR)) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (wdev->current_bss) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
err = nl80211_parse_random_mac(info->attrs,
|
||||
request->mac_addr,
|
||||
request->mac_addr_mask);
|
||||
if (err)
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
err = nl80211_check_scan_flags(wiphy, wdev, request, info->attrs,
|
||||
false);
|
||||
if (err)
|
||||
goto out_free;
|
||||
|
||||
request->no_cck =
|
||||
nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
|
||||
@ -7298,37 +7359,9 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
request->ie_len);
|
||||
}
|
||||
|
||||
if (attrs[NL80211_ATTR_SCAN_FLAGS]) {
|
||||
request->flags = nla_get_u32(
|
||||
attrs[NL80211_ATTR_SCAN_FLAGS]);
|
||||
if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
|
||||
!(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
|
||||
u32 flg = NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
|
||||
|
||||
if (!wdev) /* must be net-detect */
|
||||
flg = NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
|
||||
|
||||
if (!(wiphy->features & flg)) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (wdev && wdev->current_bss) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
err = nl80211_parse_random_mac(attrs, request->mac_addr,
|
||||
request->mac_addr_mask);
|
||||
if (err)
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
err = nl80211_check_scan_flags(wiphy, wdev, request, attrs, true);
|
||||
if (err)
|
||||
goto out_free;
|
||||
|
||||
if (attrs[NL80211_ATTR_SCHED_SCAN_DELAY])
|
||||
request->delay =
|
||||
@ -8932,8 +8965,14 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
if (info->attrs[NL80211_ATTR_USE_MFP]) {
|
||||
connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
|
||||
if (connect.mfp == NL80211_MFP_OPTIONAL &&
|
||||
!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_MFP_OPTIONAL))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (connect.mfp != NL80211_MFP_REQUIRED &&
|
||||
connect.mfp != NL80211_MFP_NO)
|
||||
connect.mfp != NL80211_MFP_NO &&
|
||||
connect.mfp != NL80211_MFP_OPTIONAL)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
connect.mfp = NL80211_MFP_NO;
|
||||
@ -12684,6 +12723,12 @@ static const struct genl_ops nl80211_ops[] = {
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_RELOAD_REGDB,
|
||||
.doit = nl80211_reload_regdb,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_GET_MESH_CONFIG,
|
||||
.doit = nl80211_get_mesh_config,
|
||||
@ -13812,9 +13857,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
|
||||
info->req_ie)) ||
|
||||
(info->resp_ie &&
|
||||
nla_put(msg, NL80211_ATTR_RESP_IE, info->resp_ie_len,
|
||||
info->resp_ie)) ||
|
||||
(info->authorized &&
|
||||
nla_put_flag(msg, NL80211_ATTR_PORT_AUTHORIZED)))
|
||||
info->resp_ie)))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
@ -13828,6 +13871,36 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
|
||||
nlmsg_free(msg);
|
||||
}
|
||||
|
||||
void nl80211_send_port_authorized(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *bssid)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PORT_AUTHORIZED);
|
||||
if (!hdr) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
|
||||
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
|
||||
NL80211_MCGRP_MLME, GFP_KERNEL);
|
||||
return;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
nlmsg_free(msg);
|
||||
}
|
||||
|
||||
void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, u16 reason,
|
||||
const u8 *ie, size_t ie_len, bool from_ap)
|
||||
|
@ -58,6 +58,8 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
|
||||
void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev,
|
||||
struct cfg80211_roam_info *info, gfp_t gfp);
|
||||
void nl80211_send_port_authorized(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *bssid);
|
||||
void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, u16 reason,
|
||||
const u8 *ie, size_t ie_len, bool from_ap);
|
||||
|
@ -53,12 +53,13 @@
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/nl80211.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/verification.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "core.h"
|
||||
#include "reg.h"
|
||||
#include "rdev-ops.h"
|
||||
#include "regdb.h"
|
||||
#include "nl80211.h"
|
||||
|
||||
/*
|
||||
@ -100,7 +101,7 @@ static struct regulatory_request core_request_world = {
|
||||
static struct regulatory_request __rcu *last_request =
|
||||
(void __force __rcu *)&core_request_world;
|
||||
|
||||
/* To trigger userspace events */
|
||||
/* To trigger userspace events and load firmware */
|
||||
static struct platform_device *reg_pdev;
|
||||
|
||||
/*
|
||||
@ -443,7 +444,6 @@ reg_copy_regd(const struct ieee80211_regdomain *src_regd)
|
||||
return regd;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CFG80211_INTERNAL_REGDB
|
||||
struct reg_regdb_apply_request {
|
||||
struct list_head list;
|
||||
const struct ieee80211_regdomain *regdom;
|
||||
@ -475,55 +475,26 @@ static void reg_regdb_apply(struct work_struct *work)
|
||||
|
||||
static DECLARE_WORK(reg_regdb_work, reg_regdb_apply);
|
||||
|
||||
static int reg_query_builtin(const char *alpha2)
|
||||
static int reg_schedule_apply(const struct ieee80211_regdomain *regdom)
|
||||
{
|
||||
const struct ieee80211_regdomain *regdom = NULL;
|
||||
struct reg_regdb_apply_request *request;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < reg_regdb_size; i++) {
|
||||
if (alpha2_equal(alpha2, reg_regdb[i]->alpha2)) {
|
||||
regdom = reg_regdb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!regdom)
|
||||
return -ENODATA;
|
||||
|
||||
request = kzalloc(sizeof(struct reg_regdb_apply_request), GFP_KERNEL);
|
||||
if (!request)
|
||||
return -ENOMEM;
|
||||
|
||||
request->regdom = reg_copy_regd(regdom);
|
||||
if (IS_ERR_OR_NULL(request->regdom)) {
|
||||
kfree(request);
|
||||
if (!request) {
|
||||
kfree(regdom);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
request->regdom = regdom;
|
||||
|
||||
mutex_lock(®_regdb_apply_mutex);
|
||||
list_add_tail(&request->list, ®_regdb_apply_list);
|
||||
mutex_unlock(®_regdb_apply_mutex);
|
||||
|
||||
schedule_work(®_regdb_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Feel free to add any other sanity checks here */
|
||||
static void reg_regdb_size_check(void)
|
||||
{
|
||||
/* We should ideally BUILD_BUG_ON() but then random builds would fail */
|
||||
WARN_ONCE(!reg_regdb_size, "db.txt is empty, you should update it...");
|
||||
}
|
||||
#else
|
||||
static inline void reg_regdb_size_check(void) {}
|
||||
static inline int reg_query_builtin(const char *alpha2)
|
||||
{
|
||||
return -ENODATA;
|
||||
}
|
||||
#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
|
||||
|
||||
#ifdef CONFIG_CFG80211_CRDA_SUPPORT
|
||||
/* Max number of consecutive attempts to communicate with CRDA */
|
||||
#define REG_MAX_CRDA_TIMEOUTS 10
|
||||
@ -599,10 +570,402 @@ static inline int call_crda(const char *alpha2)
|
||||
}
|
||||
#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
|
||||
|
||||
/* code to directly load a firmware database through request_firmware */
|
||||
static const struct fwdb_header *regdb;
|
||||
|
||||
struct fwdb_country {
|
||||
u8 alpha2[2];
|
||||
__be16 coll_ptr;
|
||||
/* this struct cannot be extended */
|
||||
} __packed __aligned(4);
|
||||
|
||||
struct fwdb_collection {
|
||||
u8 len;
|
||||
u8 n_rules;
|
||||
u8 dfs_region;
|
||||
/* no optional data yet */
|
||||
/* aligned to 2, then followed by __be16 array of rule pointers */
|
||||
} __packed __aligned(4);
|
||||
|
||||
enum fwdb_flags {
|
||||
FWDB_FLAG_NO_OFDM = BIT(0),
|
||||
FWDB_FLAG_NO_OUTDOOR = BIT(1),
|
||||
FWDB_FLAG_DFS = BIT(2),
|
||||
FWDB_FLAG_NO_IR = BIT(3),
|
||||
FWDB_FLAG_AUTO_BW = BIT(4),
|
||||
};
|
||||
|
||||
struct fwdb_rule {
|
||||
u8 len;
|
||||
u8 flags;
|
||||
__be16 max_eirp;
|
||||
__be32 start, end, max_bw;
|
||||
/* start of optional data */
|
||||
__be16 cac_timeout;
|
||||
} __packed __aligned(4);
|
||||
|
||||
#define FWDB_MAGIC 0x52474442
|
||||
#define FWDB_VERSION 20
|
||||
|
||||
struct fwdb_header {
|
||||
__be32 magic;
|
||||
__be32 version;
|
||||
struct fwdb_country country[];
|
||||
} __packed __aligned(4);
|
||||
|
||||
static bool valid_rule(const u8 *data, unsigned int size, u16 rule_ptr)
|
||||
{
|
||||
struct fwdb_rule *rule = (void *)(data + (rule_ptr << 2));
|
||||
|
||||
if ((u8 *)rule + sizeof(rule->len) > data + size)
|
||||
return false;
|
||||
|
||||
/* mandatory fields */
|
||||
if (rule->len < offsetofend(struct fwdb_rule, max_bw))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool valid_country(const u8 *data, unsigned int size,
|
||||
const struct fwdb_country *country)
|
||||
{
|
||||
unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
|
||||
struct fwdb_collection *coll = (void *)(data + ptr);
|
||||
__be16 *rules_ptr;
|
||||
unsigned int i;
|
||||
|
||||
/* make sure we can read len/n_rules */
|
||||
if ((u8 *)coll + offsetofend(typeof(*coll), n_rules) > data + size)
|
||||
return false;
|
||||
|
||||
/* make sure base struct and all rules fit */
|
||||
if ((u8 *)coll + ALIGN(coll->len, 2) +
|
||||
(coll->n_rules * 2) > data + size)
|
||||
return false;
|
||||
|
||||
/* mandatory fields must exist */
|
||||
if (coll->len < offsetofend(struct fwdb_collection, dfs_region))
|
||||
return false;
|
||||
|
||||
rules_ptr = (void *)((u8 *)coll + ALIGN(coll->len, 2));
|
||||
|
||||
for (i = 0; i < coll->n_rules; i++) {
|
||||
u16 rule_ptr = be16_to_cpu(rules_ptr[i]);
|
||||
|
||||
if (!valid_rule(data, size, rule_ptr))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CFG80211_REQUIRE_SIGNED_REGDB
|
||||
static struct key *builtin_regdb_keys;
|
||||
|
||||
static void __init load_keys_from_buffer(const u8 *p, unsigned int buflen)
|
||||
{
|
||||
const u8 *end = p + buflen;
|
||||
size_t plen;
|
||||
key_ref_t key;
|
||||
|
||||
while (p < end) {
|
||||
/* Each cert begins with an ASN.1 SEQUENCE tag and must be more
|
||||
* than 256 bytes in size.
|
||||
*/
|
||||
if (end - p < 4)
|
||||
goto dodgy_cert;
|
||||
if (p[0] != 0x30 &&
|
||||
p[1] != 0x82)
|
||||
goto dodgy_cert;
|
||||
plen = (p[2] << 8) | p[3];
|
||||
plen += 4;
|
||||
if (plen > end - p)
|
||||
goto dodgy_cert;
|
||||
|
||||
key = key_create_or_update(make_key_ref(builtin_regdb_keys, 1),
|
||||
"asymmetric", NULL, p, plen,
|
||||
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
||||
KEY_USR_VIEW | KEY_USR_READ),
|
||||
KEY_ALLOC_NOT_IN_QUOTA |
|
||||
KEY_ALLOC_BUILT_IN |
|
||||
KEY_ALLOC_BYPASS_RESTRICTION);
|
||||
if (IS_ERR(key)) {
|
||||
pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
|
||||
PTR_ERR(key));
|
||||
} else {
|
||||
pr_notice("Loaded X.509 cert '%s'\n",
|
||||
key_ref_to_ptr(key)->description);
|
||||
key_ref_put(key);
|
||||
}
|
||||
p += plen;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
dodgy_cert:
|
||||
pr_err("Problem parsing in-kernel X.509 certificate list\n");
|
||||
}
|
||||
|
||||
static int __init load_builtin_regdb_keys(void)
|
||||
{
|
||||
builtin_regdb_keys =
|
||||
keyring_alloc(".builtin_regdb_keys",
|
||||
KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
|
||||
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
||||
KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
|
||||
KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
|
||||
if (IS_ERR(builtin_regdb_keys))
|
||||
return PTR_ERR(builtin_regdb_keys);
|
||||
|
||||
pr_notice("Loading compiled-in X.509 certificates for regulatory database\n");
|
||||
|
||||
#ifdef CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS
|
||||
load_keys_from_buffer(shipped_regdb_certs, shipped_regdb_certs_len);
|
||||
#endif
|
||||
#ifdef CFG80211_EXTRA_REGDB_KEYDIR
|
||||
if (CONFIG_CFG80211_EXTRA_REGDB_KEYDIR[0] != '\0')
|
||||
load_keys_from_buffer(extra_regdb_certs, extra_regdb_certs_len);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool regdb_has_valid_signature(const u8 *data, unsigned int size)
|
||||
{
|
||||
const struct firmware *sig;
|
||||
bool result;
|
||||
|
||||
if (request_firmware(&sig, "regulatory.db.p7s", ®_pdev->dev))
|
||||
return false;
|
||||
|
||||
result = verify_pkcs7_signature(data, size, sig->data, sig->size,
|
||||
builtin_regdb_keys,
|
||||
VERIFYING_UNSPECIFIED_SIGNATURE,
|
||||
NULL, NULL) == 0;
|
||||
|
||||
release_firmware(sig);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void free_regdb_keyring(void)
|
||||
{
|
||||
key_put(builtin_regdb_keys);
|
||||
}
|
||||
#else
|
||||
static int load_builtin_regdb_keys(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool regdb_has_valid_signature(const u8 *data, unsigned int size)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void free_regdb_keyring(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_CFG80211_REQUIRE_SIGNED_REGDB */
|
||||
|
||||
static bool valid_regdb(const u8 *data, unsigned int size)
|
||||
{
|
||||
const struct fwdb_header *hdr = (void *)data;
|
||||
const struct fwdb_country *country;
|
||||
|
||||
if (size < sizeof(*hdr))
|
||||
return false;
|
||||
|
||||
if (hdr->magic != cpu_to_be32(FWDB_MAGIC))
|
||||
return false;
|
||||
|
||||
if (hdr->version != cpu_to_be32(FWDB_VERSION))
|
||||
return false;
|
||||
|
||||
if (!regdb_has_valid_signature(data, size))
|
||||
return false;
|
||||
|
||||
country = &hdr->country[0];
|
||||
while ((u8 *)(country + 1) <= data + size) {
|
||||
if (!country->coll_ptr)
|
||||
break;
|
||||
if (!valid_country(data, size, country))
|
||||
return false;
|
||||
country++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int regdb_query_country(const struct fwdb_header *db,
|
||||
const struct fwdb_country *country)
|
||||
{
|
||||
unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
|
||||
struct fwdb_collection *coll = (void *)((u8 *)db + ptr);
|
||||
struct ieee80211_regdomain *regdom;
|
||||
unsigned int size_of_regd;
|
||||
unsigned int i;
|
||||
|
||||
size_of_regd =
|
||||
sizeof(struct ieee80211_regdomain) +
|
||||
coll->n_rules * sizeof(struct ieee80211_reg_rule);
|
||||
|
||||
regdom = kzalloc(size_of_regd, GFP_KERNEL);
|
||||
if (!regdom)
|
||||
return -ENOMEM;
|
||||
|
||||
regdom->n_reg_rules = coll->n_rules;
|
||||
regdom->alpha2[0] = country->alpha2[0];
|
||||
regdom->alpha2[1] = country->alpha2[1];
|
||||
regdom->dfs_region = coll->dfs_region;
|
||||
|
||||
for (i = 0; i < regdom->n_reg_rules; i++) {
|
||||
__be16 *rules_ptr = (void *)((u8 *)coll + ALIGN(coll->len, 2));
|
||||
unsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
|
||||
struct fwdb_rule *rule = (void *)((u8 *)db + rule_ptr);
|
||||
struct ieee80211_reg_rule *rrule = ®dom->reg_rules[i];
|
||||
|
||||
rrule->freq_range.start_freq_khz = be32_to_cpu(rule->start);
|
||||
rrule->freq_range.end_freq_khz = be32_to_cpu(rule->end);
|
||||
rrule->freq_range.max_bandwidth_khz = be32_to_cpu(rule->max_bw);
|
||||
|
||||
rrule->power_rule.max_antenna_gain = 0;
|
||||
rrule->power_rule.max_eirp = be16_to_cpu(rule->max_eirp);
|
||||
|
||||
rrule->flags = 0;
|
||||
if (rule->flags & FWDB_FLAG_NO_OFDM)
|
||||
rrule->flags |= NL80211_RRF_NO_OFDM;
|
||||
if (rule->flags & FWDB_FLAG_NO_OUTDOOR)
|
||||
rrule->flags |= NL80211_RRF_NO_OUTDOOR;
|
||||
if (rule->flags & FWDB_FLAG_DFS)
|
||||
rrule->flags |= NL80211_RRF_DFS;
|
||||
if (rule->flags & FWDB_FLAG_NO_IR)
|
||||
rrule->flags |= NL80211_RRF_NO_IR;
|
||||
if (rule->flags & FWDB_FLAG_AUTO_BW)
|
||||
rrule->flags |= NL80211_RRF_AUTO_BW;
|
||||
|
||||
rrule->dfs_cac_ms = 0;
|
||||
|
||||
/* handle optional data */
|
||||
if (rule->len >= offsetofend(struct fwdb_rule, cac_timeout))
|
||||
rrule->dfs_cac_ms =
|
||||
1000 * be16_to_cpu(rule->cac_timeout);
|
||||
}
|
||||
|
||||
return reg_schedule_apply(regdom);
|
||||
}
|
||||
|
||||
static int query_regdb(const char *alpha2)
|
||||
{
|
||||
const struct fwdb_header *hdr = regdb;
|
||||
const struct fwdb_country *country;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (IS_ERR(regdb))
|
||||
return PTR_ERR(regdb);
|
||||
|
||||
country = &hdr->country[0];
|
||||
while (country->coll_ptr) {
|
||||
if (alpha2_equal(alpha2, country->alpha2))
|
||||
return regdb_query_country(regdb, country);
|
||||
country++;
|
||||
}
|
||||
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
static void regdb_fw_cb(const struct firmware *fw, void *context)
|
||||
{
|
||||
int set_error = 0;
|
||||
bool restore = true;
|
||||
void *db;
|
||||
|
||||
if (!fw) {
|
||||
pr_info("failed to load regulatory.db\n");
|
||||
set_error = -ENODATA;
|
||||
} else if (!valid_regdb(fw->data, fw->size)) {
|
||||
pr_info("loaded regulatory.db is malformed or signature is missing/invalid\n");
|
||||
set_error = -EINVAL;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
if (WARN_ON(regdb && !IS_ERR(regdb))) {
|
||||
/* just restore and free new db */
|
||||
} else if (set_error) {
|
||||
regdb = ERR_PTR(set_error);
|
||||
} else if (fw) {
|
||||
db = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
||||
if (db) {
|
||||
regdb = db;
|
||||
restore = context && query_regdb(context);
|
||||
} else {
|
||||
restore = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (restore)
|
||||
restore_regulatory_settings(true);
|
||||
|
||||
rtnl_unlock();
|
||||
|
||||
kfree(context);
|
||||
|
||||
release_firmware(fw);
|
||||
}
|
||||
|
||||
static int query_regdb_file(const char *alpha2)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (regdb)
|
||||
return query_regdb(alpha2);
|
||||
|
||||
alpha2 = kmemdup(alpha2, 2, GFP_KERNEL);
|
||||
if (!alpha2)
|
||||
return -ENOMEM;
|
||||
|
||||
return request_firmware_nowait(THIS_MODULE, true, "regulatory.db",
|
||||
®_pdev->dev, GFP_KERNEL,
|
||||
(void *)alpha2, regdb_fw_cb);
|
||||
}
|
||||
|
||||
int reg_reload_regdb(void)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
void *db;
|
||||
int err;
|
||||
|
||||
err = request_firmware(&fw, "regulatory.db", ®_pdev->dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!valid_regdb(fw->data, fw->size)) {
|
||||
err = -ENODATA;
|
||||
goto out;
|
||||
}
|
||||
|
||||
db = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
||||
if (!db) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
if (!IS_ERR_OR_NULL(regdb))
|
||||
kfree(regdb);
|
||||
regdb = db;
|
||||
rtnl_unlock();
|
||||
|
||||
out:
|
||||
release_firmware(fw);
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool reg_query_database(struct regulatory_request *request)
|
||||
{
|
||||
/* query internal regulatory database (if it exists) */
|
||||
if (reg_query_builtin(request->alpha2) == 0)
|
||||
if (query_regdb_file(request->alpha2) == 0)
|
||||
return true;
|
||||
|
||||
if (call_crda(request->alpha2) == 0)
|
||||
@ -3285,6 +3648,10 @@ int __init regulatory_init(void)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err = load_builtin_regdb_keys();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0);
|
||||
if (IS_ERR(reg_pdev))
|
||||
return PTR_ERR(reg_pdev);
|
||||
@ -3293,8 +3660,6 @@ int __init regulatory_init(void)
|
||||
spin_lock_init(®_pending_beacons_lock);
|
||||
spin_lock_init(®_indoor_lock);
|
||||
|
||||
reg_regdb_size_check();
|
||||
|
||||
rcu_assign_pointer(cfg80211_regdomain, cfg80211_world_regdom);
|
||||
|
||||
user_alpha2[0] = '9';
|
||||
@ -3360,4 +3725,9 @@ void regulatory_exit(void)
|
||||
list_del(®_request->list);
|
||||
kfree(reg_request);
|
||||
}
|
||||
|
||||
if (!IS_ERR_OR_NULL(regdb))
|
||||
kfree(regdb);
|
||||
|
||||
free_regdb_keyring();
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
#ifndef __NET_WIRELESS_REG_H
|
||||
#define __NET_WIRELESS_REG_H
|
||||
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
/*
|
||||
* Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
|
||||
*
|
||||
@ -179,4 +182,15 @@ void regulatory_propagate_dfs_state(struct wiphy *wiphy,
|
||||
* @wiphy2 - wiphy it's dfs_region to be checked against that of wiphy1
|
||||
*/
|
||||
bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2);
|
||||
|
||||
/**
|
||||
* reg_reload_regdb - reload the regulatory.db firmware file
|
||||
*/
|
||||
int reg_reload_regdb(void);
|
||||
|
||||
extern const u8 shipped_regdb_certs[];
|
||||
extern unsigned int shipped_regdb_certs_len;
|
||||
extern const u8 extra_regdb_certs[];
|
||||
extern unsigned int extra_regdb_certs_len;
|
||||
|
||||
#endif /* __NET_WIRELESS_REG_H */
|
||||
|
@ -1,23 +0,0 @@
|
||||
#ifndef __REGDB_H__
|
||||
#define __REGDB_H__
|
||||
|
||||
/*
|
||||
* Copyright 2009 John W. Linville <linville@tuxdriver.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
extern const struct ieee80211_regdomain *reg_regdb[];
|
||||
extern int reg_regdb_size;
|
||||
|
||||
#endif /* __REGDB_H__ */
|
@ -960,7 +960,6 @@ void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info,
|
||||
ev->rm.resp_ie_len = info->resp_ie_len;
|
||||
memcpy((void *)ev->rm.resp_ie, info->resp_ie, info->resp_ie_len);
|
||||
ev->rm.bss = info->bss;
|
||||
ev->rm.authorized = info->authorized;
|
||||
|
||||
spin_lock_irqsave(&wdev->event_lock, flags);
|
||||
list_add_tail(&ev->list, &wdev->event_list);
|
||||
@ -969,6 +968,50 @@ void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info,
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_roamed);
|
||||
|
||||
void __cfg80211_port_authorized(struct wireless_dev *wdev, const u8 *bssid)
|
||||
{
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
|
||||
return;
|
||||
|
||||
if (WARN_ON(!wdev->current_bss) ||
|
||||
WARN_ON(!ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
|
||||
return;
|
||||
|
||||
nl80211_send_port_authorized(wiphy_to_rdev(wdev->wiphy), wdev->netdev,
|
||||
bssid);
|
||||
}
|
||||
|
||||
void cfg80211_port_authorized(struct net_device *dev, const u8 *bssid,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
struct cfg80211_event *ev;
|
||||
unsigned long flags;
|
||||
|
||||
if (WARN_ON(!bssid))
|
||||
return;
|
||||
|
||||
ev = kzalloc(sizeof(*ev), gfp);
|
||||
if (!ev)
|
||||
return;
|
||||
|
||||
ev->type = EVENT_PORT_AUTHORIZED;
|
||||
memcpy(ev->pa.bssid, bssid, ETH_ALEN);
|
||||
|
||||
/*
|
||||
* Use the wdev event list so that if there are pending
|
||||
* connected/roamed events, they will be reported first.
|
||||
*/
|
||||
spin_lock_irqsave(&wdev->event_lock, flags);
|
||||
list_add_tail(&ev->list, &wdev->event_list);
|
||||
spin_unlock_irqrestore(&wdev->event_lock, flags);
|
||||
queue_work(cfg80211_wq, &rdev->event_work);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_port_authorized);
|
||||
|
||||
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
|
||||
size_t ie_len, u16 reason, bool from_ap)
|
||||
{
|
||||
|
@ -157,32 +157,30 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband)
|
||||
case NL80211_BAND_2GHZ:
|
||||
want = 7;
|
||||
for (i = 0; i < sband->n_bitrates; i++) {
|
||||
if (sband->bitrates[i].bitrate == 10) {
|
||||
switch (sband->bitrates[i].bitrate) {
|
||||
case 10:
|
||||
case 20:
|
||||
case 55:
|
||||
case 110:
|
||||
sband->bitrates[i].flags |=
|
||||
IEEE80211_RATE_MANDATORY_B |
|
||||
IEEE80211_RATE_MANDATORY_G;
|
||||
want--;
|
||||
}
|
||||
|
||||
if (sband->bitrates[i].bitrate == 20 ||
|
||||
sband->bitrates[i].bitrate == 55 ||
|
||||
sband->bitrates[i].bitrate == 110 ||
|
||||
sband->bitrates[i].bitrate == 60 ||
|
||||
sband->bitrates[i].bitrate == 120 ||
|
||||
sband->bitrates[i].bitrate == 240) {
|
||||
break;
|
||||
case 60:
|
||||
case 120:
|
||||
case 240:
|
||||
sband->bitrates[i].flags |=
|
||||
IEEE80211_RATE_MANDATORY_G;
|
||||
want--;
|
||||
}
|
||||
|
||||
if (sband->bitrates[i].bitrate != 10 &&
|
||||
sband->bitrates[i].bitrate != 20 &&
|
||||
sband->bitrates[i].bitrate != 55 &&
|
||||
sband->bitrates[i].bitrate != 110)
|
||||
/* fall through */
|
||||
default:
|
||||
sband->bitrates[i].flags |=
|
||||
IEEE80211_RATE_ERP_G;
|
||||
break;
|
||||
}
|
||||
}
|
||||
WARN_ON(want != 0 && want != 3 && want != 6);
|
||||
WARN_ON(want != 0 && want != 3);
|
||||
break;
|
||||
case NL80211_BAND_60GHZ:
|
||||
/* check for mandatory HT MCS 1..4 */
|
||||
@ -529,121 +527,6 @@ int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_data_to_8023_exthdr);
|
||||
|
||||
int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
|
||||
enum nl80211_iftype iftype,
|
||||
const u8 *bssid, bool qos)
|
||||
{
|
||||
struct ieee80211_hdr hdr;
|
||||
u16 hdrlen, ethertype;
|
||||
__le16 fc;
|
||||
const u8 *encaps_data;
|
||||
int encaps_len, skip_header_bytes;
|
||||
int nh_pos, h_pos;
|
||||
int head_need;
|
||||
|
||||
if (unlikely(skb->len < ETH_HLEN))
|
||||
return -EINVAL;
|
||||
|
||||
nh_pos = skb_network_header(skb) - skb->data;
|
||||
h_pos = skb_transport_header(skb) - skb->data;
|
||||
|
||||
/* convert Ethernet header to proper 802.11 header (based on
|
||||
* operation mode) */
|
||||
ethertype = (skb->data[12] << 8) | skb->data[13];
|
||||
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
|
||||
|
||||
switch (iftype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
|
||||
/* DA BSSID SA */
|
||||
memcpy(hdr.addr1, skb->data, ETH_ALEN);
|
||||
memcpy(hdr.addr2, addr, ETH_ALEN);
|
||||
memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
|
||||
hdrlen = 24;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
|
||||
/* BSSID SA DA */
|
||||
memcpy(hdr.addr1, bssid, ETH_ALEN);
|
||||
memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
|
||||
memcpy(hdr.addr3, skb->data, ETH_ALEN);
|
||||
hdrlen = 24;
|
||||
break;
|
||||
case NL80211_IFTYPE_OCB:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
/* DA SA BSSID */
|
||||
memcpy(hdr.addr1, skb->data, ETH_ALEN);
|
||||
memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
|
||||
memcpy(hdr.addr3, bssid, ETH_ALEN);
|
||||
hdrlen = 24;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (qos) {
|
||||
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
|
||||
hdrlen += 2;
|
||||
}
|
||||
|
||||
hdr.frame_control = fc;
|
||||
hdr.duration_id = 0;
|
||||
hdr.seq_ctrl = 0;
|
||||
|
||||
skip_header_bytes = ETH_HLEN;
|
||||
if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
|
||||
encaps_data = bridge_tunnel_header;
|
||||
encaps_len = sizeof(bridge_tunnel_header);
|
||||
skip_header_bytes -= 2;
|
||||
} else if (ethertype >= ETH_P_802_3_MIN) {
|
||||
encaps_data = rfc1042_header;
|
||||
encaps_len = sizeof(rfc1042_header);
|
||||
skip_header_bytes -= 2;
|
||||
} else {
|
||||
encaps_data = NULL;
|
||||
encaps_len = 0;
|
||||
}
|
||||
|
||||
skb_pull(skb, skip_header_bytes);
|
||||
nh_pos -= skip_header_bytes;
|
||||
h_pos -= skip_header_bytes;
|
||||
|
||||
head_need = hdrlen + encaps_len - skb_headroom(skb);
|
||||
|
||||
if (head_need > 0 || skb_cloned(skb)) {
|
||||
head_need = max(head_need, 0);
|
||||
if (head_need)
|
||||
skb_orphan(skb);
|
||||
|
||||
if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (encaps_data) {
|
||||
memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
|
||||
nh_pos += encaps_len;
|
||||
h_pos += encaps_len;
|
||||
}
|
||||
|
||||
memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
|
||||
|
||||
nh_pos += hdrlen;
|
||||
h_pos += hdrlen;
|
||||
|
||||
/* Update skb pointers to various headers since this modified frame
|
||||
* is going to go through Linux networking code that may potentially
|
||||
* need things like pointer to IP header. */
|
||||
skb_reset_mac_header(skb);
|
||||
skb_set_network_header(skb, nh_pos);
|
||||
skb_set_transport_header(skb, h_pos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_data_from_8023);
|
||||
|
||||
static void
|
||||
__frame_add_frag(struct sk_buff *skb, struct page *page,
|
||||
void *ptr, int len, int size)
|
||||
@ -963,6 +846,9 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
|
||||
case EVENT_STOPPED:
|
||||
__cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev);
|
||||
break;
|
||||
case EVENT_PORT_AUTHORIZED:
|
||||
__cfg80211_port_authorized(wdev, ev->pa.bssid);
|
||||
break;
|
||||
}
|
||||
wdev_unlock(wdev);
|
||||
|
||||
@ -1367,13 +1253,29 @@ int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len,
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_get_p2p_attr);
|
||||
|
||||
static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
|
||||
static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id, bool id_ext)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_ids; i++)
|
||||
if (ids[i] == id)
|
||||
/* Make sure array values are legal */
|
||||
if (WARN_ON(ids[n_ids - 1] == WLAN_EID_EXTENSION))
|
||||
return false;
|
||||
|
||||
i = 0;
|
||||
while (i < n_ids) {
|
||||
if (ids[i] == WLAN_EID_EXTENSION) {
|
||||
if (id_ext && (ids[i + 1] == id))
|
||||
return true;
|
||||
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ids[i] == id && !id_ext)
|
||||
return true;
|
||||
|
||||
i++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1403,14 +1305,36 @@ size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen,
|
||||
{
|
||||
size_t pos = offset;
|
||||
|
||||
while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) {
|
||||
while (pos < ielen) {
|
||||
u8 ext = 0;
|
||||
|
||||
if (ies[pos] == WLAN_EID_EXTENSION)
|
||||
ext = 2;
|
||||
if ((pos + ext) >= ielen)
|
||||
break;
|
||||
|
||||
if (!ieee80211_id_in_list(ids, n_ids, ies[pos + ext],
|
||||
ies[pos] == WLAN_EID_EXTENSION))
|
||||
break;
|
||||
|
||||
if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) {
|
||||
pos = skip_ie(ies, ielen, pos);
|
||||
|
||||
while (pos < ielen &&
|
||||
!ieee80211_id_in_list(after_ric, n_after_ric,
|
||||
ies[pos]))
|
||||
pos = skip_ie(ies, ielen, pos);
|
||||
while (pos < ielen) {
|
||||
if (ies[pos] == WLAN_EID_EXTENSION)
|
||||
ext = 2;
|
||||
else
|
||||
ext = 0;
|
||||
|
||||
if ((pos + ext) >= ielen)
|
||||
break;
|
||||
|
||||
if (!ieee80211_id_in_list(after_ric,
|
||||
n_after_ric,
|
||||
ies[pos + ext],
|
||||
ext == 2))
|
||||
pos = skip_ie(ies, ielen, pos);
|
||||
}
|
||||
} else {
|
||||
pos = skip_ie(ies, ielen, pos);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user