Commit 090adb89 authored by David S. Miller's avatar David S. Miller

Merge branch 'wireless'

John W. Linville says:

====================
For now I have dropped the mac80211 tree from this request.
We are developing a little backlog of fixes and I would like to
avoid introducing any more uncertainty to this pull request for the
3.10 stream.  All the other bits are the same as what was in the
2013-06-06 request, including the ath9k fixes intended to address
the problems observed by Linus w/ his Pixel, and a CVE fix for a
potential security issue in the b43 driver.

Regarding the wl12xx bits, Luca says:

"Here are three patches that I'd like to get into 3.10.  Two of them, by
me, are related to the firmware version checks in our driver.  Without
them, the firmwares fail to load.  The other one, by Eliad, fixes a typo
bug in our 5GHz scanning code."

And as for the Bluetooth bits, Gustavo says:

"The following patches are important bug fixes for 3.10, plus the
support for a new device. We do have three fixes from Johan. The first
one is a fix to avoid LE-only devices to rely on the (inexistent)
extended features data. The second patch fixes length checks on
incoming L2CAP signalling PDUs so we can discard PDU whose size
doesn't match the one reported in the header.  The last one fixes
the handling of power on failures, we now report proper errors to
mgmt when hci_dev_open()."

Along with that...

Larry Finger corrects an rtlwifi problem that caused some devices to
refuse to connect to non-WPA2 networks if the device had previously
assocated with a WPA2 network.  He also adds a one-line fix to prevent
false reports from kmemleak.

Mark A. Greer fixes an out of bounds array access in mwifiex.

Felix Fietkau reverts an earlier ath9k initval patch that reduced rx
sensitivity in a number of ath9k devices with no corresponding benefit.

Kees Cook fixes a potential uid-0 to ring-0 escalation in b43
(CVE-2013-2852).

Sujith Manoharan turns-off powersave mode by default for ath9k, and
also defaults ath9k to use the minstrel_ht rate control algorithm.
Both of these are believed to contribute to greater stability/usability
of ath9k in real-world situations.

Yijing Wang fixes an iwlegacy build error for il_pm_ops if CONFIG_PM
is set but CONFIG_PM_SLEEP is not set.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b79462a8 42d887a6
...@@ -201,7 +201,7 @@ config BT_MRVL ...@@ -201,7 +201,7 @@ config BT_MRVL
The core driver to support Marvell Bluetooth devices. The core driver to support Marvell Bluetooth devices.
This driver is required if you want to support This driver is required if you want to support
Marvell Bluetooth devices, such as 8688/8787/8797. Marvell Bluetooth devices, such as 8688/8787/8797/8897.
Say Y here to compile Marvell Bluetooth driver Say Y here to compile Marvell Bluetooth driver
into the kernel or say M to compile it as module. into the kernel or say M to compile it as module.
...@@ -214,7 +214,7 @@ config BT_MRVL_SDIO ...@@ -214,7 +214,7 @@ config BT_MRVL_SDIO
The driver for Marvell Bluetooth chipsets with SDIO interface. The driver for Marvell Bluetooth chipsets with SDIO interface.
This driver is required if you want to use Marvell Bluetooth This driver is required if you want to use Marvell Bluetooth
devices with SDIO interface. Currently SD8688/SD8787/SD8797 devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8897
chipsets are supported. chipsets are supported.
Say Y here to compile support for Marvell BT-over-SDIO driver Say Y here to compile support for Marvell BT-over-SDIO driver
......
...@@ -82,6 +82,23 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { ...@@ -82,6 +82,23 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
.io_port_2 = 0x7a, .io_port_2 = 0x7a,
}; };
static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
.cfg = 0x00,
.host_int_mask = 0x02,
.host_intstatus = 0x03,
.card_status = 0x50,
.sq_read_base_addr_a0 = 0x60,
.sq_read_base_addr_a1 = 0x61,
.card_revision = 0xbc,
.card_fw_status0 = 0xc0,
.card_fw_status1 = 0xc1,
.card_rx_len = 0xc2,
.card_rx_unit = 0xc3,
.io_port_0 = 0xd8,
.io_port_1 = 0xd9,
.io_port_2 = 0xda,
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
.helper = "mrvl/sd8688_helper.bin", .helper = "mrvl/sd8688_helper.bin",
.firmware = "mrvl/sd8688.bin", .firmware = "mrvl/sd8688.bin",
...@@ -103,6 +120,13 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { ...@@ -103,6 +120,13 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
.sd_blksz_fw_dl = 256, .sd_blksz_fw_dl = 256,
}; };
static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
.helper = NULL,
.firmware = "mrvl/sd8897_uapsta.bin",
.reg = &btmrvl_reg_88xx,
.sd_blksz_fw_dl = 256,
};
static const struct sdio_device_id btmrvl_sdio_ids[] = { static const struct sdio_device_id btmrvl_sdio_ids[] = {
/* Marvell SD8688 Bluetooth device */ /* Marvell SD8688 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105), { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
...@@ -116,6 +140,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = { ...@@ -116,6 +140,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = {
/* Marvell SD8797 Bluetooth device */ /* Marvell SD8797 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A), { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
.driver_data = (unsigned long) &btmrvl_sdio_sd8797 }, .driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
/* Marvell SD8897 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E),
.driver_data = (unsigned long) &btmrvl_sdio_sd8897 },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
...@@ -1194,3 +1221,4 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin"); ...@@ -1194,3 +1221,4 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
MODULE_FIRMWARE("mrvl/sd8688.bin"); MODULE_FIRMWARE("mrvl/sd8688.bin");
MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
...@@ -92,13 +92,17 @@ config ATH9K_MAC_DEBUG ...@@ -92,13 +92,17 @@ config ATH9K_MAC_DEBUG
This option enables collection of statistics for Rx/Tx status This option enables collection of statistics for Rx/Tx status
data and some other MAC related statistics data and some other MAC related statistics
config ATH9K_RATE_CONTROL config ATH9K_LEGACY_RATE_CONTROL
bool "Atheros ath9k rate control" bool "Atheros ath9k rate control"
depends on ATH9K depends on ATH9K
default y default n
---help--- ---help---
Say Y, if you want to use the ath9k specific rate control Say Y, if you want to use the ath9k specific rate control
module instead of minstrel_ht. module instead of minstrel_ht. Be warned that there are various
issues with the ath9k RC and minstrel is a more robust algorithm.
Note that even if this option is selected, "ath9k_rate_control"
has to be passed to mac80211 using the module parameter,
ieee80211_default_rc_algo.
config ATH9K_HTC config ATH9K_HTC
tristate "Atheros HTC based wireless cards support" tristate "Atheros HTC based wireless cards support"
......
...@@ -8,7 +8,7 @@ ath9k-y += beacon.o \ ...@@ -8,7 +8,7 @@ ath9k-y += beacon.o \
antenna.o antenna.o
ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o ath9k-$(CONFIG_ATH9K_LEGACY_RATE_CONTROL) += rc.o
ath9k-$(CONFIG_ATH9K_PCI) += pci.o ath9k-$(CONFIG_ATH9K_PCI) += pci.o
ath9k-$(CONFIG_ATH9K_AHB) += ahb.o ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
......
...@@ -958,11 +958,11 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = { ...@@ -958,11 +958,11 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
{0x0000a074, 0x00000000}, {0x0000a074, 0x00000000},
{0x0000a078, 0x00000000}, {0x0000a078, 0x00000000},
{0x0000a07c, 0x00000000}, {0x0000a07c, 0x00000000},
{0x0000a080, 0x1a1a1a1a}, {0x0000a080, 0x22222229},
{0x0000a084, 0x1a1a1a1a}, {0x0000a084, 0x1d1d1d1d},
{0x0000a088, 0x1a1a1a1a}, {0x0000a088, 0x1d1d1d1d},
{0x0000a08c, 0x1a1a1a1a}, {0x0000a08c, 0x1d1d1d1d},
{0x0000a090, 0x171a1a1a}, {0x0000a090, 0x171d1d1d},
{0x0000a094, 0x11111717}, {0x0000a094, 0x11111717},
{0x0000a098, 0x00030311}, {0x0000a098, 0x00030311},
{0x0000a09c, 0x00000000}, {0x0000a09c, 0x00000000},
......
...@@ -787,8 +787,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) ...@@ -787,8 +787,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->wiphy->iface_combinations = if_comb; hw->wiphy->iface_combinations = if_comb;
hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
if (AR_SREV_5416(sc->sc_ah)) hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
...@@ -830,10 +829,6 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) ...@@ -830,10 +829,6 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
sc->ant_rx = hw->wiphy->available_antennas_rx; sc->ant_rx = hw->wiphy->available_antennas_rx;
sc->ant_tx = hw->wiphy->available_antennas_tx; sc->ant_tx = hw->wiphy->available_antennas_tx;
#ifdef CONFIG_ATH9K_RATE_CONTROL
hw->rate_control_algorithm = "ath9k_rate_control";
#endif
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
hw->wiphy->bands[IEEE80211_BAND_2GHZ] = hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&sc->sbands[IEEE80211_BAND_2GHZ]; &sc->sbands[IEEE80211_BAND_2GHZ];
......
...@@ -231,7 +231,7 @@ static inline void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, ...@@ -231,7 +231,7 @@ static inline void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
} }
#endif #endif
#ifdef CONFIG_ATH9K_RATE_CONTROL #ifdef CONFIG_ATH9K_LEGACY_RATE_CONTROL
int ath_rate_control_register(void); int ath_rate_control_register(void);
void ath_rate_control_unregister(void); void ath_rate_control_unregister(void);
#else #else
......
...@@ -2458,7 +2458,7 @@ static void b43_request_firmware(struct work_struct *work) ...@@ -2458,7 +2458,7 @@ static void b43_request_firmware(struct work_struct *work)
for (i = 0; i < B43_NR_FWTYPES; i++) { for (i = 0; i < B43_NR_FWTYPES; i++) {
errmsg = ctx->errors[i]; errmsg = ctx->errors[i];
if (strlen(errmsg)) if (strlen(errmsg))
b43err(dev->wl, errmsg); b43err(dev->wl, "%s", errmsg);
} }
b43_print_fw_helptext(dev->wl, 1); b43_print_fw_helptext(dev->wl, 1);
goto out; goto out;
......
...@@ -1832,16 +1832,16 @@ u32 il_usecs_to_beacons(struct il_priv *il, u32 usec, u32 beacon_interval); ...@@ -1832,16 +1832,16 @@ u32 il_usecs_to_beacons(struct il_priv *il, u32 usec, u32 beacon_interval);
__le32 il_add_beacon_time(struct il_priv *il, u32 base, u32 addon, __le32 il_add_beacon_time(struct il_priv *il, u32 base, u32 addon,
u32 beacon_interval); u32 beacon_interval);
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
extern const struct dev_pm_ops il_pm_ops; extern const struct dev_pm_ops il_pm_ops;
#define IL_LEGACY_PM_OPS (&il_pm_ops) #define IL_LEGACY_PM_OPS (&il_pm_ops)
#else /* !CONFIG_PM */ #else /* !CONFIG_PM_SLEEP */
#define IL_LEGACY_PM_OPS NULL #define IL_LEGACY_PM_OPS NULL
#endif /* !CONFIG_PM */ #endif /* !CONFIG_PM_SLEEP */
/***************************************************** /*****************************************************
* Error Handling Debugging * Error Handling Debugging
......
...@@ -26,10 +26,17 @@ ...@@ -26,10 +26,17 @@
static struct dentry *mwifiex_dfs_dir; static struct dentry *mwifiex_dfs_dir;
static char *bss_modes[] = { static char *bss_modes[] = {
"Unknown", "UNSPECIFIED",
"Ad-hoc", "ADHOC",
"Managed", "STATION",
"Auto" "AP",
"AP_VLAN",
"WDS",
"MONITOR",
"MESH_POINT",
"P2P_CLIENT",
"P2P_GO",
"P2P_DEVICE",
}; };
/* size/addr for mwifiex_debug_info */ /* size/addr for mwifiex_debug_info */
...@@ -200,7 +207,12 @@ mwifiex_info_read(struct file *file, char __user *ubuf, ...@@ -200,7 +207,12 @@ mwifiex_info_read(struct file *file, char __user *ubuf,
p += sprintf(p, "driver_version = %s", fmt); p += sprintf(p, "driver_version = %s", fmt);
p += sprintf(p, "\nverext = %s", priv->version_str); p += sprintf(p, "\nverext = %s", priv->version_str);
p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name); p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
if (info.bss_mode >= ARRAY_SIZE(bss_modes))
p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode);
else
p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
p += sprintf(p, "media_state=\"%s\"\n", p += sprintf(p, "media_state=\"%s\"\n",
(!priv->media_connected ? "Disconnected" : "Connected")); (!priv->media_connected ? "Disconnected" : "Connected"));
p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr); p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr);
......
...@@ -764,6 +764,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) ...@@ -764,6 +764,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
"can't alloc skb for rx\n"); "can't alloc skb for rx\n");
goto done; goto done;
} }
kmemleak_not_leak(new_skb);
pci_unmap_single(rtlpci->pdev, pci_unmap_single(rtlpci->pdev,
*((dma_addr_t *) skb->cb), *((dma_addr_t *) skb->cb),
......
...@@ -1973,26 +1973,35 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) ...@@ -1973,26 +1973,35 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
} }
} }
void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, static void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, struct ieee80211_sta *sta)
u8 rssi_level)
{ {
struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_phy *rtlphy = &(rtlpriv->phy);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
u32 ratr_value = (u32) mac->basic_rates; struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u8 *mcsrate = mac->mcs; u32 ratr_value;
u8 ratr_index = 0; u8 ratr_index = 0;
u8 nmode = mac->ht_enable; u8 nmode = mac->ht_enable;
u8 mimo_ps = 1; u8 mimo_ps = IEEE80211_SMPS_OFF;
u16 shortgi_rate = 0; u16 shortgi_rate;
u32 tmp_ratr_value = 0; u32 tmp_ratr_value;
u8 curtxbw_40mhz = mac->bw_40; u8 curtxbw_40mhz = mac->bw_40;
u8 curshortgi_40mhz = mac->sgi_40; u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
u8 curshortgi_20mhz = mac->sgi_20; 1 : 0;
u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
1 : 0;
enum wireless_mode wirelessmode = mac->mode; enum wireless_mode wirelessmode = mac->mode;
ratr_value |= ((*(u16 *) (mcsrate))) << 12; if (rtlhal->current_bandtype == BAND_ON_5G)
ratr_value = sta->supp_rates[1] << 4;
else
ratr_value = sta->supp_rates[0];
if (mac->opmode == NL80211_IFTYPE_ADHOC)
ratr_value = 0xfff;
ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
sta->ht_cap.mcs.rx_mask[0] << 12);
switch (wirelessmode) { switch (wirelessmode) {
case WIRELESS_MODE_B: case WIRELESS_MODE_B:
if (ratr_value & 0x0000000c) if (ratr_value & 0x0000000c)
...@@ -2006,7 +2015,7 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, ...@@ -2006,7 +2015,7 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
case WIRELESS_MODE_N_24G: case WIRELESS_MODE_N_24G:
case WIRELESS_MODE_N_5G: case WIRELESS_MODE_N_5G:
nmode = 1; nmode = 1;
if (mimo_ps == 0) { if (mimo_ps == IEEE80211_SMPS_STATIC) {
ratr_value &= 0x0007F005; ratr_value &= 0x0007F005;
} else { } else {
u32 ratr_mask; u32 ratr_mask;
...@@ -2016,8 +2025,7 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, ...@@ -2016,8 +2025,7 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
ratr_mask = 0x000ff005; ratr_mask = 0x000ff005;
else else
ratr_mask = 0x0f0ff005; ratr_mask = 0x0f0ff005;
if (curtxbw_40mhz)
ratr_mask |= 0x00000010;
ratr_value &= ratr_mask; ratr_value &= ratr_mask;
} }
break; break;
...@@ -2026,41 +2034,74 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, ...@@ -2026,41 +2034,74 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
ratr_value &= 0x000ff0ff; ratr_value &= 0x000ff0ff;
else else
ratr_value &= 0x0f0ff0ff; ratr_value &= 0x0f0ff0ff;
break; break;
} }
ratr_value &= 0x0FFFFFFF; ratr_value &= 0x0FFFFFFF;
if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) ||
(!curtxbw_40mhz && curshortgi_20mhz))) { if (nmode && ((curtxbw_40mhz &&
curshortgi_40mhz) || (!curtxbw_40mhz &&
curshortgi_20mhz))) {
ratr_value |= 0x10000000; ratr_value |= 0x10000000;
tmp_ratr_value = (ratr_value >> 12); tmp_ratr_value = (ratr_value >> 12);
for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
if ((1 << shortgi_rate) & tmp_ratr_value) if ((1 << shortgi_rate) & tmp_ratr_value)
break; break;
} }
shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
(shortgi_rate << 4) | (shortgi_rate); (shortgi_rate << 4) | (shortgi_rate);
} }
rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value); rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value);
RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "%x\n",
rtl_read_dword(rtlpriv, REG_ARFR0));
} }
void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) static void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u8 rssi_level)
{ {
struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_phy *rtlphy = &(rtlpriv->phy);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
u32 ratr_bitmap = (u32) mac->basic_rates; struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u8 *p_mcsrate = mac->mcs; struct rtl_sta_info *sta_entry = NULL;
u8 ratr_index = 0; u32 ratr_bitmap;
u8 curtxbw_40mhz = mac->bw_40; u8 ratr_index;
u8 curshortgi_40mhz = mac->sgi_40; u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0;
u8 curshortgi_20mhz = mac->sgi_20; u8 curshortgi_40mhz = curtxbw_40mhz &&
enum wireless_mode wirelessmode = mac->mode; (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
1 : 0;
u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
1 : 0;
enum wireless_mode wirelessmode = 0;
bool shortgi = false; bool shortgi = false;
u8 rate_mask[5]; u8 rate_mask[5];
u8 macid = 0; u8 macid = 0;
u8 mimops = 1; u8 mimo_ps = IEEE80211_SMPS_OFF;
ratr_bitmap |= (p_mcsrate[1] << 20) | (p_mcsrate[0] << 12); sta_entry = (struct rtl_sta_info *) sta->drv_priv;
wirelessmode = sta_entry->wireless_mode;
if (mac->opmode == NL80211_IFTYPE_STATION ||
mac->opmode == NL80211_IFTYPE_MESH_POINT)
curtxbw_40mhz = mac->bw_40;
else if (mac->opmode == NL80211_IFTYPE_AP ||
mac->opmode == NL80211_IFTYPE_ADHOC)
macid = sta->aid + 1;
if (rtlhal->current_bandtype == BAND_ON_5G)
ratr_bitmap = sta->supp_rates[1] << 4;
else
ratr_bitmap = sta->supp_rates[0];
if (mac->opmode == NL80211_IFTYPE_ADHOC)
ratr_bitmap = 0xfff;
ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
sta->ht_cap.mcs.rx_mask[0] << 12);
switch (wirelessmode) { switch (wirelessmode) {
case WIRELESS_MODE_B: case WIRELESS_MODE_B:
ratr_index = RATR_INX_WIRELESS_B; ratr_index = RATR_INX_WIRELESS_B;
...@@ -2071,6 +2112,7 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) ...@@ -2071,6 +2112,7 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
break; break;
case WIRELESS_MODE_G: case WIRELESS_MODE_G:
ratr_index = RATR_INX_WIRELESS_GB; ratr_index = RATR_INX_WIRELESS_GB;
if (rssi_level == 1) if (rssi_level == 1)
ratr_bitmap &= 0x00000f00; ratr_bitmap &= 0x00000f00;
else if (rssi_level == 2) else if (rssi_level == 2)
...@@ -2085,7 +2127,8 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) ...@@ -2085,7 +2127,8 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
case WIRELESS_MODE_N_24G: case WIRELESS_MODE_N_24G:
case WIRELESS_MODE_N_5G: case WIRELESS_MODE_N_5G:
ratr_index = RATR_INX_WIRELESS_NGB; ratr_index = RATR_INX_WIRELESS_NGB;
if (mimops == 0) {
if (mimo_ps == IEEE80211_SMPS_STATIC) {
if (rssi_level == 1) if (rssi_level == 1)
ratr_bitmap &= 0x00070000; ratr_bitmap &= 0x00070000;
else if (rssi_level == 2) else if (rssi_level == 2)
...@@ -2128,8 +2171,10 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) ...@@ -2128,8 +2171,10 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
} }
} }
} }
if ((curtxbw_40mhz && curshortgi_40mhz) || if ((curtxbw_40mhz && curshortgi_40mhz) ||
(!curtxbw_40mhz && curshortgi_20mhz)) { (!curtxbw_40mhz && curshortgi_20mhz)) {
if (macid == 0) if (macid == 0)
shortgi = true; shortgi = true;
else if (macid == 1) else if (macid == 1)
...@@ -2138,21 +2183,42 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) ...@@ -2138,21 +2183,42 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
break; break;
default: default:
ratr_index = RATR_INX_WIRELESS_NGB; ratr_index = RATR_INX_WIRELESS_NGB;
if (rtlphy->rf_type == RF_1T2R) if (rtlphy->rf_type == RF_1T2R)
ratr_bitmap &= 0x000ff0ff; ratr_bitmap &= 0x000ff0ff;
else else
ratr_bitmap &= 0x0f0ff0ff; ratr_bitmap &= 0x0f0ff0ff;
break; break;
} }
RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "ratr_bitmap :%x\n", sta_entry->ratr_index = ratr_index;
ratr_bitmap);
*(u32 *)&rate_mask = ((ratr_bitmap & 0x0fffffff) | RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
ratr_index << 28); "ratr_bitmap :%x\n", ratr_bitmap);
*(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
(ratr_index << 28);
rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80; rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80;
RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
"Rate_index:%x, ratr_val:%x, %5phC\n", "Rate_index:%x, ratr_val:%x, %5phC\n",
ratr_index, ratr_bitmap, rate_mask); ratr_index, ratr_bitmap, rate_mask);
rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask); memcpy(rtlpriv->rate_mask, rate_mask, 5);
/* rtl92c_fill_h2c_cmd() does USB I/O and will result in a
* "scheduled while atomic" if called directly */
schedule_work(&rtlpriv->works.fill_h2c_cmd);
if (macid != 0)
sta_entry->ratr_index = ratr_index;
}
void rtl92cu_update_hal_rate_tbl(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u8 rssi_level)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
if (rtlpriv->dm.useramask)
rtl92cu_update_hal_rate_mask(hw, sta, rssi_level);
else
rtl92cu_update_hal_rate_table(hw, sta);
} }
void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw) void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw)
......
...@@ -98,10 +98,6 @@ void rtl92cu_update_interrupt_mask(struct ieee80211_hw *hw, ...@@ -98,10 +98,6 @@ void rtl92cu_update_interrupt_mask(struct ieee80211_hw *hw,
u32 add_msr, u32 rm_msr); u32 add_msr, u32 rm_msr);
void rtl92cu_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); void rtl92cu_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u8 rssi_level);
void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level);
void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw); void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw);
bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid); bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid);
......
...@@ -289,14 +289,30 @@ void rtl92c_set_key(struct ieee80211_hw *hw, u32 key_index, ...@@ -289,14 +289,30 @@ void rtl92c_set_key(struct ieee80211_hw *hw, u32 key_index,
macaddr = cam_const_broad; macaddr = cam_const_broad;
entry_id = key_index; entry_id = key_index;
} else { } else {
if (mac->opmode == NL80211_IFTYPE_AP ||
mac->opmode == NL80211_IFTYPE_MESH_POINT) {
entry_id = rtl_cam_get_free_entry(hw,
p_macaddr);
if (entry_id >= TOTAL_CAM_ENTRY) {
RT_TRACE(rtlpriv, COMP_SEC,
DBG_EMERG,
"Can not find free hw security cam entry\n");
return;
}
} else {
entry_id = CAM_PAIRWISE_KEY_POSITION;
}
key_index = PAIRWISE_KEYIDX; key_index = PAIRWISE_KEYIDX;
entry_id = CAM_PAIRWISE_KEY_POSITION;
is_pairwise = true; is_pairwise = true;
} }
} }
if (rtlpriv->sec.key_len[key_index] == 0) { if (rtlpriv->sec.key_len[key_index] == 0) {
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
"delete one entry\n"); "delete one entry\n");
if (mac->opmode == NL80211_IFTYPE_AP ||
mac->opmode == NL80211_IFTYPE_MESH_POINT)
rtl_cam_del_entry(hw, p_macaddr);
rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
} else { } else {
RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
......
...@@ -106,8 +106,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = { ...@@ -106,8 +106,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = {
.update_interrupt_mask = rtl92cu_update_interrupt_mask, .update_interrupt_mask = rtl92cu_update_interrupt_mask,
.get_hw_reg = rtl92cu_get_hw_reg, .get_hw_reg = rtl92cu_get_hw_reg,
.set_hw_reg = rtl92cu_set_hw_reg, .set_hw_reg = rtl92cu_set_hw_reg,
.update_rate_tbl = rtl92cu_update_hal_rate_table, .update_rate_tbl = rtl92cu_update_hal_rate_tbl,
.update_rate_mask = rtl92cu_update_hal_rate_mask,
.fill_tx_desc = rtl92cu_tx_fill_desc, .fill_tx_desc = rtl92cu_tx_fill_desc,
.fill_fake_txdesc = rtl92cu_fill_fake_txdesc, .fill_fake_txdesc = rtl92cu_fill_fake_txdesc,
.fill_tx_cmddesc = rtl92cu_tx_fill_cmddesc, .fill_tx_cmddesc = rtl92cu_tx_fill_cmddesc,
...@@ -137,6 +136,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = { ...@@ -137,6 +136,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = {
.phy_lc_calibrate = _rtl92cu_phy_lc_calibrate, .phy_lc_calibrate = _rtl92cu_phy_lc_calibrate,
.phy_set_bw_mode_callback = rtl92cu_phy_set_bw_mode_callback, .phy_set_bw_mode_callback = rtl92cu_phy_set_bw_mode_callback,
.dm_dynamic_txpower = rtl92cu_dm_dynamic_txpower, .dm_dynamic_txpower = rtl92cu_dm_dynamic_txpower,
.fill_h2c_cmd = rtl92c_fill_h2c_cmd,
}; };
static struct rtl_mod_params rtl92cu_mod_params = { static struct rtl_mod_params rtl92cu_mod_params = {
......
...@@ -49,5 +49,8 @@ bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, ...@@ -49,5 +49,8 @@ bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 regaddr, u32 bitmask); enum radio_path rfpath, u32 regaddr, u32 bitmask);
void rtl92cu_phy_set_bw_mode_callback(struct ieee80211_hw *hw); void rtl92cu_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
void rtl92cu_update_hal_rate_tbl(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u8 rssi_level);
#endif #endif
...@@ -824,6 +824,7 @@ static void rtl_usb_stop(struct ieee80211_hw *hw) ...@@ -824,6 +824,7 @@ static void rtl_usb_stop(struct ieee80211_hw *hw)
/* should after adapter start and interrupt enable. */ /* should after adapter start and interrupt enable. */
set_hal_stop(rtlhal); set_hal_stop(rtlhal);
cancel_work_sync(&rtlpriv->works.fill_h2c_cmd);
/* Enable software */ /* Enable software */
SET_USB_STOP(rtlusb); SET_USB_STOP(rtlusb);
rtl_usb_deinit(hw); rtl_usb_deinit(hw);
...@@ -1026,6 +1027,16 @@ static bool rtl_usb_tx_chk_waitq_insert(struct ieee80211_hw *hw, ...@@ -1026,6 +1027,16 @@ static bool rtl_usb_tx_chk_waitq_insert(struct ieee80211_hw *hw,
return false; return false;
} }
static void rtl_fill_h2c_cmd_work_callback(struct work_struct *work)
{
struct rtl_works *rtlworks =
container_of(work, struct rtl_works, fill_h2c_cmd);
struct ieee80211_hw *hw = rtlworks->hw;
struct rtl_priv *rtlpriv = rtl_priv(hw);
rtlpriv->cfg->ops->fill_h2c_cmd(hw, H2C_RA_MASK, 5, rtlpriv->rate_mask);
}
static struct rtl_intf_ops rtl_usb_ops = { static struct rtl_intf_ops rtl_usb_ops = {
.adapter_start = rtl_usb_start, .adapter_start = rtl_usb_start,
.adapter_stop = rtl_usb_stop, .adapter_stop = rtl_usb_stop,
...@@ -1057,6 +1068,8 @@ int rtl_usb_probe(struct usb_interface *intf, ...@@ -1057,6 +1068,8 @@ int rtl_usb_probe(struct usb_interface *intf,
/* this spin lock must be initialized early */ /* this spin lock must be initialized early */
spin_lock_init(&rtlpriv->locks.usb_lock); spin_lock_init(&rtlpriv->locks.usb_lock);
INIT_WORK(&rtlpriv->works.fill_h2c_cmd,
rtl_fill_h2c_cmd_work_callback);
rtlpriv->usb_data_index = 0; rtlpriv->usb_data_index = 0;
init_completion(&rtlpriv->firmware_loading_complete); init_completion(&rtlpriv->firmware_loading_complete);
......
...@@ -1736,6 +1736,8 @@ struct rtl_hal_ops { ...@@ -1736,6 +1736,8 @@ struct rtl_hal_ops {
void (*bt_wifi_media_status_notify) (struct ieee80211_hw *hw, void (*bt_wifi_media_status_notify) (struct ieee80211_hw *hw,
bool mstate); bool mstate);
void (*bt_coex_off_before_lps) (struct ieee80211_hw *hw); void (*bt_coex_off_before_lps) (struct ieee80211_hw *hw);
void (*fill_h2c_cmd) (struct ieee80211_hw *hw, u8 element_id,
u32 cmd_len, u8 *p_cmdbuffer);
}; };
struct rtl_intf_ops { struct rtl_intf_ops {
...@@ -1869,6 +1871,7 @@ struct rtl_works { ...@@ -1869,6 +1871,7 @@ struct rtl_works {
struct delayed_work fwevt_wq; struct delayed_work fwevt_wq;
struct work_struct lps_change_work; struct work_struct lps_change_work;
struct work_struct fill_h2c_cmd;
}; };
struct rtl_debug { struct rtl_debug {
...@@ -2048,6 +2051,7 @@ struct rtl_priv { ...@@ -2048,6 +2051,7 @@ struct rtl_priv {
}; };
}; };
bool enter_ps; /* true when entering PS */ bool enter_ps; /* true when entering PS */
u8 rate_mask[5];
/*This must be the last item so /*This must be the last item so
that it points to the data allocated that it points to the data allocated
......
...@@ -310,7 +310,7 @@ static void wl12xx_adjust_channels(struct wl1271_cmd_sched_scan_config *cmd, ...@@ -310,7 +310,7 @@ static void wl12xx_adjust_channels(struct wl1271_cmd_sched_scan_config *cmd,
memcpy(cmd->channels_2, cmd_channels->channels_2, memcpy(cmd->channels_2, cmd_channels->channels_2,
sizeof(cmd->channels_2)); sizeof(cmd->channels_2));
memcpy(cmd->channels_5, cmd_channels->channels_5, memcpy(cmd->channels_5, cmd_channels->channels_5,
sizeof(cmd->channels_2)); sizeof(cmd->channels_5));
/* channels_4 are not supported, so no need to copy them */ /* channels_4 are not supported, so no need to copy them */
} }
......
...@@ -36,12 +36,12 @@ ...@@ -36,12 +36,12 @@
#define WL127X_IFTYPE_SR_VER 3 #define WL127X_IFTYPE_SR_VER 3
#define WL127X_MAJOR_SR_VER 10 #define WL127X_MAJOR_SR_VER 10
#define WL127X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE #define WL127X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE
#define WL127X_MINOR_SR_VER 115 #define WL127X_MINOR_SR_VER 133
/* minimum multi-role FW version for wl127x */ /* minimum multi-role FW version for wl127x */
#define WL127X_IFTYPE_MR_VER 5 #define WL127X_IFTYPE_MR_VER 5
#define WL127X_MAJOR_MR_VER 7 #define WL127X_MAJOR_MR_VER 7
#define WL127X_SUBTYPE_MR_VER WLCORE_FW_VER_IGNORE #define WL127X_SUBTYPE_MR_VER WLCORE_FW_VER_IGNORE
#define WL127X_MINOR_MR_VER 115 #define WL127X_MINOR_MR_VER 42
/* FW chip version for wl128x */ /* FW chip version for wl128x */
#define WL128X_CHIP_VER 7 #define WL128X_CHIP_VER 7
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
#define WL128X_IFTYPE_SR_VER 3 #define WL128X_IFTYPE_SR_VER 3
#define WL128X_MAJOR_SR_VER 10 #define WL128X_MAJOR_SR_VER 10
#define WL128X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE #define WL128X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE
#define WL128X_MINOR_SR_VER 115 #define WL128X_MINOR_SR_VER 133
/* minimum multi-role FW version for wl128x */ /* minimum multi-role FW version for wl128x */
#define WL128X_IFTYPE_MR_VER 5 #define WL128X_IFTYPE_MR_VER 5
#define WL128X_MAJOR_MR_VER 7 #define WL128X_MAJOR_MR_VER 7
......
...@@ -34,7 +34,7 @@ static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd, ...@@ -34,7 +34,7 @@ static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd,
memcpy(cmd->channels_2, cmd_channels->channels_2, memcpy(cmd->channels_2, cmd_channels->channels_2,
sizeof(cmd->channels_2)); sizeof(cmd->channels_2));
memcpy(cmd->channels_5, cmd_channels->channels_5, memcpy(cmd->channels_5, cmd_channels->channels_5,
sizeof(cmd->channels_2)); sizeof(cmd->channels_5));
/* channels_4 are not supported, so no need to copy them */ /* channels_4 are not supported, so no need to copy them */
} }
......
...@@ -1117,6 +1117,7 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event); ...@@ -1117,6 +1117,7 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event);
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len); int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
int mgmt_index_added(struct hci_dev *hdev); int mgmt_index_added(struct hci_dev *hdev);
int mgmt_index_removed(struct hci_dev *hdev); int mgmt_index_removed(struct hci_dev *hdev);
int mgmt_set_powered_failed(struct hci_dev *hdev, int err);
int mgmt_powered(struct hci_dev *hdev, u8 powered); int mgmt_powered(struct hci_dev *hdev, u8 powered);
int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable); int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable);
int mgmt_connectable(struct hci_dev *hdev, u8 connectable); int mgmt_connectable(struct hci_dev *hdev, u8 connectable);
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#define MGMT_STATUS_NOT_POWERED 0x0f #define MGMT_STATUS_NOT_POWERED 0x0f
#define MGMT_STATUS_CANCELLED 0x10 #define MGMT_STATUS_CANCELLED 0x10
#define MGMT_STATUS_INVALID_INDEX 0x11 #define MGMT_STATUS_INVALID_INDEX 0x11
#define MGMT_STATUS_RFKILLED 0x12
struct mgmt_hdr { struct mgmt_hdr {
__le16 opcode; __le16 opcode;
......
...@@ -1555,11 +1555,15 @@ static const struct rfkill_ops hci_rfkill_ops = { ...@@ -1555,11 +1555,15 @@ static const struct rfkill_ops hci_rfkill_ops = {
static void hci_power_on(struct work_struct *work) static void hci_power_on(struct work_struct *work)
{ {
struct hci_dev *hdev = container_of(work, struct hci_dev, power_on); struct hci_dev *hdev = container_of(work, struct hci_dev, power_on);
int err;
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
if (hci_dev_open(hdev->id) < 0) err = hci_dev_open(hdev->id);
if (err < 0) {
mgmt_set_powered_failed(hdev, err);
return; return;
}
if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
queue_delayed_work(hdev->req_workqueue, &hdev->power_off, queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
......
...@@ -3677,10 +3677,14 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) ...@@ -3677,10 +3677,14 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
} }
static inline int l2cap_command_rej(struct l2cap_conn *conn, static inline int l2cap_command_rej(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u8 *data) struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
{ {
struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data; struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
if (cmd_len < sizeof(*rej))
return -EPROTO;
if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD) if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
return 0; return 0;
...@@ -3829,11 +3833,14 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, ...@@ -3829,11 +3833,14 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
} }
static int l2cap_connect_req(struct l2cap_conn *conn, static int l2cap_connect_req(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u8 *data) struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
{ {
struct hci_dev *hdev = conn->hcon->hdev; struct hci_dev *hdev = conn->hcon->hdev;
struct hci_conn *hcon = conn->hcon; struct hci_conn *hcon = conn->hcon;
if (cmd_len < sizeof(struct l2cap_conn_req))
return -EPROTO;
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->dev_flags) && if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &hcon->flags)) !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &hcon->flags))
...@@ -3847,7 +3854,8 @@ static int l2cap_connect_req(struct l2cap_conn *conn, ...@@ -3847,7 +3854,8 @@ static int l2cap_connect_req(struct l2cap_conn *conn,
} }
static int l2cap_connect_create_rsp(struct l2cap_conn *conn, static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u8 *data) struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
{ {
struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data; struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
u16 scid, dcid, result, status; u16 scid, dcid, result, status;
...@@ -3855,6 +3863,9 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn, ...@@ -3855,6 +3863,9 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
u8 req[128]; u8 req[128];
int err; int err;
if (cmd_len < sizeof(*rsp))
return -EPROTO;
scid = __le16_to_cpu(rsp->scid); scid = __le16_to_cpu(rsp->scid);
dcid = __le16_to_cpu(rsp->dcid); dcid = __le16_to_cpu(rsp->dcid);
result = __le16_to_cpu(rsp->result); result = __le16_to_cpu(rsp->result);
...@@ -3952,6 +3963,9 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, ...@@ -3952,6 +3963,9 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
struct l2cap_chan *chan; struct l2cap_chan *chan;
int len, err = 0; int len, err = 0;
if (cmd_len < sizeof(*req))
return -EPROTO;
dcid = __le16_to_cpu(req->dcid); dcid = __le16_to_cpu(req->dcid);
flags = __le16_to_cpu(req->flags); flags = __le16_to_cpu(req->flags);
...@@ -3975,7 +3989,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, ...@@ -3975,7 +3989,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
/* Reject if config buffer is too small. */ /* Reject if config buffer is too small. */
len = cmd_len - sizeof(*req); len = cmd_len - sizeof(*req);
if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) { if (chan->conf_len + len > sizeof(chan->conf_req)) {
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
l2cap_build_conf_rsp(chan, rsp, l2cap_build_conf_rsp(chan, rsp,
L2CAP_CONF_REJECT, flags), rsp); L2CAP_CONF_REJECT, flags), rsp);
...@@ -4053,14 +4067,18 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, ...@@ -4053,14 +4067,18 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
} }
static inline int l2cap_config_rsp(struct l2cap_conn *conn, static inline int l2cap_config_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u8 *data) struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
{ {
struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data; struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
u16 scid, flags, result; u16 scid, flags, result;
struct l2cap_chan *chan; struct l2cap_chan *chan;
int len = le16_to_cpu(cmd->len) - sizeof(*rsp); int len = cmd_len - sizeof(*rsp);
int err = 0; int err = 0;
if (cmd_len < sizeof(*rsp))
return -EPROTO;
scid = __le16_to_cpu(rsp->scid); scid = __le16_to_cpu(rsp->scid);
flags = __le16_to_cpu(rsp->flags); flags = __le16_to_cpu(rsp->flags);
result = __le16_to_cpu(rsp->result); result = __le16_to_cpu(rsp->result);
...@@ -4161,7 +4179,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, ...@@ -4161,7 +4179,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
} }
static inline int l2cap_disconnect_req(struct l2cap_conn *conn, static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u8 *data) struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
{ {
struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data; struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
struct l2cap_disconn_rsp rsp; struct l2cap_disconn_rsp rsp;
...@@ -4169,6 +4188,9 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, ...@@ -4169,6 +4188,9 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
struct l2cap_chan *chan; struct l2cap_chan *chan;
struct sock *sk; struct sock *sk;
if (cmd_len != sizeof(*req))
return -EPROTO;
scid = __le16_to_cpu(req->scid); scid = __le16_to_cpu(req->scid);
dcid = __le16_to_cpu(req->dcid); dcid = __le16_to_cpu(req->dcid);
...@@ -4208,12 +4230,16 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, ...@@ -4208,12 +4230,16 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
} }
static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u8 *data) struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
{ {
struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data; struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
u16 dcid, scid; u16 dcid, scid;
struct l2cap_chan *chan; struct l2cap_chan *chan;
if (cmd_len != sizeof(*rsp))
return -EPROTO;
scid = __le16_to_cpu(rsp->scid); scid = __le16_to_cpu(rsp->scid);
dcid = __le16_to_cpu(rsp->dcid); dcid = __le16_to_cpu(rsp->dcid);
...@@ -4243,11 +4269,15 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, ...@@ -4243,11 +4269,15 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
} }
static inline int l2cap_information_req(struct l2cap_conn *conn, static inline int l2cap_information_req(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u8 *data) struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
{ {
struct l2cap_info_req *req = (struct l2cap_info_req *) data; struct l2cap_info_req *req = (struct l2cap_info_req *) data;
u16 type; u16 type;
if (cmd_len != sizeof(*req))
return -EPROTO;
type = __le16_to_cpu(req->type); type = __le16_to_cpu(req->type);
BT_DBG("type 0x%4.4x", type); BT_DBG("type 0x%4.4x", type);
...@@ -4294,11 +4324,15 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, ...@@ -4294,11 +4324,15 @@ static inline int l2cap_information_req(struct l2cap_conn *conn,
} }
static inline int l2cap_information_rsp(struct l2cap_conn *conn, static inline int l2cap_information_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u8 *data) struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
{ {
struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data; struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
u16 type, result; u16 type, result;
if (cmd_len != sizeof(*rsp))
return -EPROTO;
type = __le16_to_cpu(rsp->type); type = __le16_to_cpu(rsp->type);
result = __le16_to_cpu(rsp->result); result = __le16_to_cpu(rsp->result);
...@@ -5164,16 +5198,16 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, ...@@ -5164,16 +5198,16 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
switch (cmd->code) { switch (cmd->code) {
case L2CAP_COMMAND_REJ: case L2CAP_COMMAND_REJ:
l2cap_command_rej(conn, cmd, data); l2cap_command_rej(conn, cmd, cmd_len, data);
break; break;
case L2CAP_CONN_REQ: case L2CAP_CONN_REQ:
err = l2cap_connect_req(conn, cmd, data); err = l2cap_connect_req(conn, cmd, cmd_len, data);
break; break;
case L2CAP_CONN_RSP: case L2CAP_CONN_RSP:
case L2CAP_CREATE_CHAN_RSP: case L2CAP_CREATE_CHAN_RSP:
err = l2cap_connect_create_rsp(conn, cmd, data); err = l2cap_connect_create_rsp(conn, cmd, cmd_len, data);
break; break;
case L2CAP_CONF_REQ: case L2CAP_CONF_REQ:
...@@ -5181,15 +5215,15 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, ...@@ -5181,15 +5215,15 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
break; break;
case L2CAP_CONF_RSP: case L2CAP_CONF_RSP:
err = l2cap_config_rsp(conn, cmd, data); err = l2cap_config_rsp(conn, cmd, cmd_len, data);
break; break;
case L2CAP_DISCONN_REQ: case L2CAP_DISCONN_REQ:
err = l2cap_disconnect_req(conn, cmd, data); err = l2cap_disconnect_req(conn, cmd, cmd_len, data);
break; break;
case L2CAP_DISCONN_RSP: case L2CAP_DISCONN_RSP:
err = l2cap_disconnect_rsp(conn, cmd, data); err = l2cap_disconnect_rsp(conn, cmd, cmd_len, data);
break; break;
case L2CAP_ECHO_REQ: case L2CAP_ECHO_REQ:
...@@ -5200,11 +5234,11 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, ...@@ -5200,11 +5234,11 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
break; break;
case L2CAP_INFO_REQ: case L2CAP_INFO_REQ:
err = l2cap_information_req(conn, cmd, data); err = l2cap_information_req(conn, cmd, cmd_len, data);
break; break;
case L2CAP_INFO_RSP: case L2CAP_INFO_RSP:
err = l2cap_information_rsp(conn, cmd, data); err = l2cap_information_rsp(conn, cmd, cmd_len, data);
break; break;
case L2CAP_CREATE_CHAN_REQ: case L2CAP_CREATE_CHAN_REQ:
......
...@@ -2700,7 +2700,7 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, ...@@ -2700,7 +2700,7 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
break; break;
case DISCOV_TYPE_LE: case DISCOV_TYPE_LE:
if (!lmp_host_le_capable(hdev)) { if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_NOT_SUPPORTED); MGMT_STATUS_NOT_SUPPORTED);
mgmt_pending_remove(cmd); mgmt_pending_remove(cmd);
...@@ -3418,6 +3418,27 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) ...@@ -3418,6 +3418,27 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered)
return err; return err;
} }
int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
{
struct pending_cmd *cmd;
u8 status;
cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
if (!cmd)
return -ENOENT;
if (err == -ERFKILL)
status = MGMT_STATUS_RFKILLED;
else
status = MGMT_STATUS_FAILED;
err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
mgmt_pending_remove(cmd);
return err;
}
int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
{ {
struct cmd_lookup match = { NULL, hdev }; struct cmd_lookup match = { NULL, hdev };
......
...@@ -770,7 +770,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) ...@@ -770,7 +770,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level); BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
if (!lmp_host_le_capable(hcon->hdev)) if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags))
return 1; return 1;
if (sec_level == BT_SECURITY_LOW) if (sec_level == BT_SECURITY_LOW)
...@@ -851,7 +851,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -851,7 +851,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
__u8 reason; __u8 reason;
int err = 0; int err = 0;
if (!lmp_host_le_capable(conn->hcon->hdev)) { if (!test_bit(HCI_LE_ENABLED, &conn->hcon->hdev->dev_flags)) {
err = -ENOTSUPP; err = -ENOTSUPP;
reason = SMP_PAIRING_NOTSUPP; reason = SMP_PAIRING_NOTSUPP;
goto done; goto done;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment