Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless into for-davem
John W. Linville says: ==================== Please pull these fixes intended for 3.6. There are more commits here than I would like -- I got a bit behind while I was stalking Steven Rostedt in San Diego last week... I'll slow it down after this! There are a couple of pulls here. One is from Johannes: "Please pull (according to the below information) to get a few fixes. * a fix to properly disconnect in the driver when authentication or association fails * a fix to prevent invalid information about mesh paths being reported to userspace * a memory leak fix in an nl80211 error path" The other comes via Gustavo: "A few updates for the 3.6 kernel. There are two btusb patches to add more supported devices through the new USB_VENDOR_AND_INTEFACE_INFO() macro and another one that add a new device id for a Sony Vaio laptop, one fix for a user-after-free and, finally, two patches from Vinicius to fix a issue in SMP pairing." Along with those... Arend van Spriel provides a fix for a use-after-free bug in brcmfmac. Daniel Drake avoids a hang by not trying to touch the libertas hardware duing suspend if it is already powered-down. Felix Fietkau provides a batch of ath9k fixes that adress some potential problems with power settings, as well as a fix to avoid a potential interrupt storm. Gertjan van Wingerde provides a register-width fix for rt2x00, and a rt2x00 fix to prevent incorrectly detecting the rfkill status. He also provides a device ID patch. Hante Meuleman gives us three brcmfmac fixes, one that properly initializes a command structure, one that fixes a race condition that could lose usb requests, and one that removes some log spam. Marc Kleine-Budde offers an rt2x00 fix for a voltage setting on some specific devices. Mohammed Shafi Shajakhan sent an ath9k fix to avoid a crash related to using timers that aren't allocated when 2 wire bluetooth coexistence hardware is in use. Sergei Poselenov changes rt2800usb to do some validity checking for received packets, avoiding crashes on an ARM Soc. Stone Piao gives us an mwifiex fix for an incorrectly set skb length value for a command buffer. All of these are localized to their specific drivers, and relatively small. The power-related patches from Felix are bigger than I would like, but I merged them in consideration of their isolation to ath9k and the sensitive nature of power settings in wireless devices. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
777bf135b7
|
@ -86,6 +86,7 @@ static struct usb_device_id ath3k_table[] = {
|
|||
|
||||
/* Atheros AR5BBU22 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xE03C) },
|
||||
{ USB_DEVICE(0x0489, 0xE036) },
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
@ -109,6 +110,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
|
|||
|
||||
/* Atheros AR5BBU22 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 },
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
|
|
@ -52,6 +52,9 @@ static struct usb_device_id btusb_table[] = {
|
|||
/* Generic Bluetooth USB device */
|
||||
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
|
||||
|
||||
/* Apple-specific (Broadcom) devices */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01) },
|
||||
|
||||
/* Broadcom SoftSailing reporting vendor specific */
|
||||
{ USB_DEVICE(0x0a5c, 0x21e1) },
|
||||
|
||||
|
@ -94,16 +97,14 @@ static struct usb_device_id btusb_table[] = {
|
|||
|
||||
/* Broadcom BCM20702A0 */
|
||||
{ USB_DEVICE(0x0489, 0xe042) },
|
||||
{ USB_DEVICE(0x0a5c, 0x21e3) },
|
||||
{ USB_DEVICE(0x0a5c, 0x21e6) },
|
||||
{ USB_DEVICE(0x0a5c, 0x21e8) },
|
||||
{ USB_DEVICE(0x0a5c, 0x21f3) },
|
||||
{ USB_DEVICE(0x0a5c, 0x21f4) },
|
||||
{ USB_DEVICE(0x413c, 0x8197) },
|
||||
|
||||
/* Foxconn - Hon Hai */
|
||||
{ USB_DEVICE(0x0489, 0xe033) },
|
||||
|
||||
/*Broadcom devices with vendor specific id */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
|
@ -141,6 +142,7 @@ static struct usb_device_id blacklist_table[] = {
|
|||
|
||||
/* Atheros AR5BBU12 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 },
|
||||
|
||||
/* Broadcom BCM2035 */
|
||||
{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
|
||||
|
|
|
@ -142,6 +142,7 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
|
|||
};
|
||||
int training_power;
|
||||
int i, val;
|
||||
u32 am2pm_mask = ah->paprd_ratemask;
|
||||
|
||||
if (IS_CHAN_2GHZ(ah->curchan))
|
||||
training_power = ar9003_get_training_power_2g(ah);
|
||||
|
@ -158,10 +159,13 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
|
|||
}
|
||||
ah->paprd_training_power = training_power;
|
||||
|
||||
if (AR_SREV_9330(ah))
|
||||
am2pm_mask = 0;
|
||||
|
||||
REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK,
|
||||
ah->paprd_ratemask);
|
||||
REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK,
|
||||
ah->paprd_ratemask);
|
||||
am2pm_mask);
|
||||
REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK,
|
||||
ah->paprd_ratemask_ht40);
|
||||
|
||||
|
@ -782,6 +786,102 @@ int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
|
|||
}
|
||||
EXPORT_SYMBOL(ar9003_paprd_setup_gain_table);
|
||||
|
||||
static bool ar9003_paprd_retrain_pa_in(struct ath_hw *ah,
|
||||
struct ath9k_hw_cal_data *caldata,
|
||||
int chain)
|
||||
{
|
||||
u32 *pa_in = caldata->pa_table[chain];
|
||||
int capdiv_offset, quick_drop_offset;
|
||||
int capdiv2g, quick_drop;
|
||||
int count = 0;
|
||||
int i;
|
||||
|
||||
if (!AR_SREV_9485(ah) && !AR_SREV_9330(ah))
|
||||
return false;
|
||||
|
||||
capdiv2g = REG_READ_FIELD(ah, AR_PHY_65NM_CH0_TXRF3,
|
||||
AR_PHY_65NM_CH0_TXRF3_CAPDIV2G);
|
||||
|
||||
quick_drop = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
|
||||
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP);
|
||||
|
||||
if (quick_drop)
|
||||
quick_drop -= 0x40;
|
||||
|
||||
for (i = 0; i < NUM_BIN + 1; i++) {
|
||||
if (pa_in[i] == 1400)
|
||||
count++;
|
||||
}
|
||||
|
||||
if (AR_SREV_9485(ah)) {
|
||||
if (pa_in[23] < 800) {
|
||||
capdiv_offset = (int)((1000 - pa_in[23] + 75) / 150);
|
||||
capdiv2g += capdiv_offset;
|
||||
if (capdiv2g > 7) {
|
||||
capdiv2g = 7;
|
||||
if (pa_in[23] < 600) {
|
||||
quick_drop++;
|
||||
if (quick_drop > 0)
|
||||
quick_drop = 0;
|
||||
}
|
||||
}
|
||||
} else if (pa_in[23] == 1400) {
|
||||
quick_drop_offset = min_t(int, count / 3, 2);
|
||||
quick_drop += quick_drop_offset;
|
||||
capdiv2g += quick_drop_offset / 2;
|
||||
|
||||
if (capdiv2g > 7)
|
||||
capdiv2g = 7;
|
||||
|
||||
if (quick_drop > 0) {
|
||||
quick_drop = 0;
|
||||
capdiv2g -= quick_drop_offset;
|
||||
if (capdiv2g < 0)
|
||||
capdiv2g = 0;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (AR_SREV_9330(ah)) {
|
||||
if (pa_in[23] < 1000) {
|
||||
capdiv_offset = (1000 - pa_in[23]) / 100;
|
||||
capdiv2g += capdiv_offset;
|
||||
if (capdiv_offset > 3) {
|
||||
capdiv_offset = 1;
|
||||
quick_drop--;
|
||||
}
|
||||
|
||||
capdiv2g += capdiv_offset;
|
||||
if (capdiv2g > 6)
|
||||
capdiv2g = 6;
|
||||
if (quick_drop < -4)
|
||||
quick_drop = -4;
|
||||
} else if (pa_in[23] == 1400) {
|
||||
if (count > 3) {
|
||||
quick_drop++;
|
||||
capdiv2g -= count / 4;
|
||||
if (quick_drop > -2)
|
||||
quick_drop = -2;
|
||||
} else {
|
||||
capdiv2g--;
|
||||
}
|
||||
|
||||
if (capdiv2g < 0)
|
||||
capdiv2g = 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_TXRF3,
|
||||
AR_PHY_65NM_CH0_TXRF3_CAPDIV2G, capdiv2g);
|
||||
REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
|
||||
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
|
||||
quick_drop);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int ar9003_paprd_create_curve(struct ath_hw *ah,
|
||||
struct ath9k_hw_cal_data *caldata, int chain)
|
||||
{
|
||||
|
@ -817,6 +917,9 @@ int ar9003_paprd_create_curve(struct ath_hw *ah,
|
|||
if (!create_pa_curve(data_L, data_U, pa_table, small_signal_gain))
|
||||
status = -2;
|
||||
|
||||
if (ar9003_paprd_retrain_pa_in(ah, caldata, chain))
|
||||
status = -EINPROGRESS;
|
||||
|
||||
REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
|
||||
AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
|
||||
|
||||
|
|
|
@ -625,6 +625,10 @@
|
|||
#define AR_PHY_AIC_CTRL_4_B0 (AR_SM_BASE + 0x4c0)
|
||||
#define AR_PHY_AIC_STAT_2_B0 (AR_SM_BASE + 0x4cc)
|
||||
|
||||
#define AR_PHY_65NM_CH0_TXRF3 0x16048
|
||||
#define AR_PHY_65NM_CH0_TXRF3_CAPDIV2G 0x0000001e
|
||||
#define AR_PHY_65NM_CH0_TXRF3_CAPDIV2G_S 1
|
||||
|
||||
#define AR_PHY_65NM_CH0_SYNTH4 0x1608c
|
||||
#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT (AR_SREV_9462(ah) ? 0x00000001 : 0x00000002)
|
||||
#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S (AR_SREV_9462(ah) ? 0 : 1)
|
||||
|
|
|
@ -341,7 +341,8 @@ void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc)
|
|||
{
|
||||
struct ath_btcoex *btcoex = &sc->btcoex;
|
||||
|
||||
ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
|
||||
if (btcoex->hw_timer_enabled)
|
||||
ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
|
||||
}
|
||||
|
||||
u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)
|
||||
|
|
|
@ -463,9 +463,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
|
|||
ah->config.spurchans[i][1] = AR_NO_SPUR;
|
||||
}
|
||||
|
||||
/* PAPRD needs some more work to be enabled */
|
||||
ah->config.paprd_disable = 1;
|
||||
|
||||
ah->config.rx_intr_mitigation = true;
|
||||
ah->config.pcieSerDesWrite = true;
|
||||
|
||||
|
@ -978,9 +975,6 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
|
|||
else
|
||||
imr_reg |= AR_IMR_TXOK;
|
||||
|
||||
if (opmode == NL80211_IFTYPE_AP)
|
||||
imr_reg |= AR_IMR_MIB;
|
||||
|
||||
ENABLE_REGWRITE_BUFFER(ah);
|
||||
|
||||
REG_WRITE(ah, AR_IMR, imr_reg);
|
||||
|
@ -1778,6 +1772,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
|||
/* Operating channel changed, reset channel calibration data */
|
||||
memset(caldata, 0, sizeof(*caldata));
|
||||
ath9k_init_nfcal_hist_buffer(ah, chan);
|
||||
} else if (caldata) {
|
||||
caldata->paprd_packet_sent = false;
|
||||
}
|
||||
ah->noise = ath9k_hw_getchan_noise(ah, chan);
|
||||
|
||||
|
@ -2502,7 +2498,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
|
|||
pCap->tx_desc_len = sizeof(struct ar9003_txc);
|
||||
pCap->txs_len = sizeof(struct ar9003_txs);
|
||||
if (!ah->config.paprd_disable &&
|
||||
ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
|
||||
ah->eep_ops->get_eeprom(ah, EEP_PAPRD) &&
|
||||
!AR_SREV_9462(ah))
|
||||
pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
|
||||
} else {
|
||||
pCap->tx_desc_len = sizeof(struct ath_desc);
|
||||
|
|
|
@ -405,6 +405,7 @@ struct ath9k_hw_cal_data {
|
|||
int8_t iCoff;
|
||||
int8_t qCoff;
|
||||
bool rtt_done;
|
||||
bool paprd_packet_sent;
|
||||
bool paprd_done;
|
||||
bool nfcal_pending;
|
||||
bool nfcal_interference;
|
||||
|
|
|
@ -254,8 +254,9 @@ void ath_paprd_calibrate(struct work_struct *work)
|
|||
int chain_ok = 0;
|
||||
int chain;
|
||||
int len = 1800;
|
||||
int ret;
|
||||
|
||||
if (!caldata)
|
||||
if (!caldata || !caldata->paprd_packet_sent || caldata->paprd_done)
|
||||
return;
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
|
@ -282,13 +283,6 @@ void ath_paprd_calibrate(struct work_struct *work)
|
|||
continue;
|
||||
|
||||
chain_ok = 0;
|
||||
|
||||
ath_dbg(common, CALIBRATE,
|
||||
"Sending PAPRD frame for thermal measurement on chain %d\n",
|
||||
chain);
|
||||
if (!ath_paprd_send_frame(sc, skb, chain))
|
||||
goto fail_paprd;
|
||||
|
||||
ar9003_paprd_setup_gain_table(ah, chain);
|
||||
|
||||
ath_dbg(common, CALIBRATE,
|
||||
|
@ -302,7 +296,13 @@ void ath_paprd_calibrate(struct work_struct *work)
|
|||
break;
|
||||
}
|
||||
|
||||
if (ar9003_paprd_create_curve(ah, caldata, chain)) {
|
||||
ret = ar9003_paprd_create_curve(ah, caldata, chain);
|
||||
if (ret == -EINPROGRESS) {
|
||||
ath_dbg(common, CALIBRATE,
|
||||
"PAPRD curve on chain %d needs to be re-trained\n",
|
||||
chain);
|
||||
break;
|
||||
} else if (ret) {
|
||||
ath_dbg(common, CALIBRATE,
|
||||
"PAPRD create curve failed on chain %d\n",
|
||||
chain);
|
||||
|
|
|
@ -2018,6 +2018,9 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
|||
|
||||
ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
|
||||
|
||||
if (sc->sc_ah->caldata)
|
||||
sc->sc_ah->caldata->paprd_packet_sent = true;
|
||||
|
||||
if (!(tx_flags & ATH_TX_ERROR))
|
||||
/* Frame was ACKed */
|
||||
tx_info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
|
|
|
@ -519,7 +519,7 @@ static void brcmf_usb_tx_complete(struct urb *urb)
|
|||
else
|
||||
devinfo->bus_pub.bus->dstats.tx_errors++;
|
||||
|
||||
dev_kfree_skb(req->skb);
|
||||
brcmu_pkt_buf_free_skb(req->skb);
|
||||
req->skb = NULL;
|
||||
brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req);
|
||||
|
||||
|
@ -540,7 +540,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
|
|||
devinfo->bus_pub.bus->dstats.rx_packets++;
|
||||
} else {
|
||||
devinfo->bus_pub.bus->dstats.rx_errors++;
|
||||
dev_kfree_skb(skb);
|
||||
brcmu_pkt_buf_free_skb(skb);
|
||||
brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
|
||||
return;
|
||||
}
|
||||
|
@ -550,13 +550,15 @@ static void brcmf_usb_rx_complete(struct urb *urb)
|
|||
if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) {
|
||||
brcmf_dbg(ERROR, "rx protocol error\n");
|
||||
brcmu_pkt_buf_free_skb(skb);
|
||||
brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
|
||||
devinfo->bus_pub.bus->dstats.rx_errors++;
|
||||
} else {
|
||||
brcmf_rx_packet(devinfo->dev, ifidx, skb);
|
||||
brcmf_usb_rx_refill(devinfo, req);
|
||||
}
|
||||
} else {
|
||||
dev_kfree_skb(skb);
|
||||
brcmu_pkt_buf_free_skb(skb);
|
||||
brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
|
||||
}
|
||||
return;
|
||||
|
||||
|
@ -581,14 +583,13 @@ static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
|
|||
usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->rx_pipe,
|
||||
skb->data, skb_tailroom(skb), brcmf_usb_rx_complete,
|
||||
req);
|
||||
req->urb->transfer_flags |= URB_ZERO_PACKET;
|
||||
req->devinfo = devinfo;
|
||||
brcmf_usb_enq(devinfo, &devinfo->rx_postq, req);
|
||||
|
||||
ret = usb_submit_urb(req->urb, GFP_ATOMIC);
|
||||
if (ret == 0) {
|
||||
brcmf_usb_enq(devinfo, &devinfo->rx_postq, req);
|
||||
} else {
|
||||
dev_kfree_skb(req->skb);
|
||||
if (ret) {
|
||||
brcmf_usb_del_fromq(devinfo, req);
|
||||
brcmu_pkt_buf_free_skb(req->skb);
|
||||
req->skb = NULL;
|
||||
brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
|
||||
}
|
||||
|
@ -683,23 +684,22 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
|
|||
|
||||
req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq);
|
||||
if (!req) {
|
||||
brcmu_pkt_buf_free_skb(skb);
|
||||
brcmf_dbg(ERROR, "no req to send\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!req->urb) {
|
||||
brcmf_dbg(ERROR, "no urb for req %p\n", req);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
req->skb = skb;
|
||||
req->devinfo = devinfo;
|
||||
usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe,
|
||||
skb->data, skb->len, brcmf_usb_tx_complete, req);
|
||||
req->urb->transfer_flags |= URB_ZERO_PACKET;
|
||||
brcmf_usb_enq(devinfo, &devinfo->tx_postq, req);
|
||||
ret = usb_submit_urb(req->urb, GFP_ATOMIC);
|
||||
if (!ret) {
|
||||
brcmf_usb_enq(devinfo, &devinfo->tx_postq, req);
|
||||
} else {
|
||||
if (ret) {
|
||||
brcmf_dbg(ERROR, "brcmf_usb_tx usb_submit_urb FAILED\n");
|
||||
brcmf_usb_del_fromq(devinfo, req);
|
||||
brcmu_pkt_buf_free_skb(req->skb);
|
||||
req->skb = NULL;
|
||||
brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req);
|
||||
}
|
||||
|
|
|
@ -1876,16 +1876,17 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
|
|||
}
|
||||
|
||||
if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) {
|
||||
scb_val.val = cpu_to_le32(0);
|
||||
memset(&scb_val, 0, sizeof(scb_val));
|
||||
err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val,
|
||||
sizeof(struct brcmf_scb_val_le));
|
||||
if (err)
|
||||
if (err) {
|
||||
WL_ERR("Could not get rssi (%d)\n", err);
|
||||
|
||||
rssi = le32_to_cpu(scb_val.val);
|
||||
sinfo->filled |= STATION_INFO_SIGNAL;
|
||||
sinfo->signal = rssi;
|
||||
WL_CONN("RSSI %d dBm\n", rssi);
|
||||
} else {
|
||||
rssi = le32_to_cpu(scb_val.val);
|
||||
sinfo->filled |= STATION_INFO_SIGNAL;
|
||||
sinfo->signal = rssi;
|
||||
WL_CONN("RSSI %d dBm\n", rssi);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
|
|
@ -1326,6 +1326,11 @@ static int if_sdio_suspend(struct device *dev)
|
|||
|
||||
mmc_pm_flag_t flags = sdio_get_host_pm_caps(func);
|
||||
|
||||
/* If we're powered off anyway, just let the mmc layer remove the
|
||||
* card. */
|
||||
if (!lbs_iface_active(card->priv))
|
||||
return -ENOSYS;
|
||||
|
||||
dev_info(dev, "%s: suspend: PM flags = 0x%x\n",
|
||||
sdio_func_id(func), flags);
|
||||
|
||||
|
|
|
@ -170,7 +170,20 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
|
|||
cmd_code = le16_to_cpu(host_cmd->command);
|
||||
cmd_size = le16_to_cpu(host_cmd->size);
|
||||
|
||||
skb_trim(cmd_node->cmd_skb, cmd_size);
|
||||
/* Adjust skb length */
|
||||
if (cmd_node->cmd_skb->len > cmd_size)
|
||||
/*
|
||||
* cmd_size is less than sizeof(struct host_cmd_ds_command).
|
||||
* Trim off the unused portion.
|
||||
*/
|
||||
skb_trim(cmd_node->cmd_skb, cmd_size);
|
||||
else if (cmd_node->cmd_skb->len < cmd_size)
|
||||
/*
|
||||
* cmd_size is larger than sizeof(struct host_cmd_ds_command)
|
||||
* because we have appended custom IE TLV. Increase skb length
|
||||
* accordingly.
|
||||
*/
|
||||
skb_put(cmd_node->cmd_skb, cmd_size - cmd_node->cmd_skb->len);
|
||||
|
||||
do_gettimeofday(&tstamp);
|
||||
dev_dbg(adapter->dev, "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d,"
|
||||
|
|
|
@ -1611,6 +1611,7 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
|
|||
static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
int retval;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Allocate eeprom data.
|
||||
|
@ -1623,6 +1624,14 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* Enable rfkill polling by setting GPIO direction of the
|
||||
* rfkill switch GPIO pin correctly.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®);
|
||||
rt2x00_set_field32(®, GPIOCSR_BIT8, 1);
|
||||
rt2x00pci_register_write(rt2x00dev, GPIOCSR, reg);
|
||||
|
||||
/*
|
||||
* Initialize hw specifications.
|
||||
*/
|
||||
|
|
|
@ -670,6 +670,7 @@
|
|||
#define GPIOCSR_BIT5 FIELD32(0x00000020)
|
||||
#define GPIOCSR_BIT6 FIELD32(0x00000040)
|
||||
#define GPIOCSR_BIT7 FIELD32(0x00000080)
|
||||
#define GPIOCSR_BIT8 FIELD32(0x00000100)
|
||||
|
||||
/*
|
||||
* BBPPCSR: BBP Pin control register.
|
||||
|
|
|
@ -1929,6 +1929,7 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
|
|||
static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
int retval;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Allocate eeprom data.
|
||||
|
@ -1941,6 +1942,14 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* Enable rfkill polling by setting GPIO direction of the
|
||||
* rfkill switch GPIO pin correctly.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, GPIOCSR, ®);
|
||||
rt2x00_set_field32(®, GPIOCSR_DIR0, 1);
|
||||
rt2x00pci_register_write(rt2x00dev, GPIOCSR, reg);
|
||||
|
||||
/*
|
||||
* Initialize hw specifications.
|
||||
*/
|
||||
|
|
|
@ -283,7 +283,7 @@ static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
|
|||
u16 reg;
|
||||
|
||||
rt2500usb_register_read(rt2x00dev, MAC_CSR19, ®);
|
||||
return rt2x00_get_field32(reg, MAC_CSR19_BIT7);
|
||||
return rt2x00_get_field16(reg, MAC_CSR19_BIT7);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RT2X00_LIB_LEDS
|
||||
|
@ -1768,6 +1768,7 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
|
|||
static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
int retval;
|
||||
u16 reg;
|
||||
|
||||
/*
|
||||
* Allocate eeprom data.
|
||||
|
@ -1780,6 +1781,14 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* Enable rfkill polling by setting GPIO direction of the
|
||||
* rfkill switch GPIO pin correctly.
|
||||
*/
|
||||
rt2500usb_register_read(rt2x00dev, MAC_CSR19, ®);
|
||||
rt2x00_set_field16(®, MAC_CSR19_BIT8, 0);
|
||||
rt2500usb_register_write(rt2x00dev, MAC_CSR19, reg);
|
||||
|
||||
/*
|
||||
* Initialize hw specifications.
|
||||
*/
|
||||
|
|
|
@ -189,14 +189,15 @@
|
|||
* MAC_CSR19: GPIO control register.
|
||||
*/
|
||||
#define MAC_CSR19 0x0426
|
||||
#define MAC_CSR19_BIT0 FIELD32(0x0001)
|
||||
#define MAC_CSR19_BIT1 FIELD32(0x0002)
|
||||
#define MAC_CSR19_BIT2 FIELD32(0x0004)
|
||||
#define MAC_CSR19_BIT3 FIELD32(0x0008)
|
||||
#define MAC_CSR19_BIT4 FIELD32(0x0010)
|
||||
#define MAC_CSR19_BIT5 FIELD32(0x0020)
|
||||
#define MAC_CSR19_BIT6 FIELD32(0x0040)
|
||||
#define MAC_CSR19_BIT7 FIELD32(0x0080)
|
||||
#define MAC_CSR19_BIT0 FIELD16(0x0001)
|
||||
#define MAC_CSR19_BIT1 FIELD16(0x0002)
|
||||
#define MAC_CSR19_BIT2 FIELD16(0x0004)
|
||||
#define MAC_CSR19_BIT3 FIELD16(0x0008)
|
||||
#define MAC_CSR19_BIT4 FIELD16(0x0010)
|
||||
#define MAC_CSR19_BIT5 FIELD16(0x0020)
|
||||
#define MAC_CSR19_BIT6 FIELD16(0x0040)
|
||||
#define MAC_CSR19_BIT7 FIELD16(0x0080)
|
||||
#define MAC_CSR19_BIT8 FIELD16(0x0100)
|
||||
|
||||
/*
|
||||
* MAC_CSR20: LED control register.
|
||||
|
|
|
@ -4089,6 +4089,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
|
|||
rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
|
||||
msleep(1);
|
||||
rt2800_register_read(rt2x00dev, LDO_CFG0, ®);
|
||||
rt2x00_set_field32(®, LDO_CFG0_LDO_CORE_VLEVEL, 0);
|
||||
rt2x00_set_field32(®, LDO_CFG0_BGSEL, 1);
|
||||
rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
|
||||
}
|
||||
|
|
|
@ -983,6 +983,7 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
|
|||
static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
int retval;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Allocate eeprom data.
|
||||
|
@ -995,6 +996,14 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* Enable rfkill polling by setting GPIO direction of the
|
||||
* rfkill switch GPIO pin correctly.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, GPIO_CTRL_CFG, ®);
|
||||
rt2x00_set_field32(®, GPIO_CTRL_CFG_GPIOD_BIT2, 1);
|
||||
rt2x00pci_register_write(rt2x00dev, GPIO_CTRL_CFG, reg);
|
||||
|
||||
/*
|
||||
* Initialize hw specifications.
|
||||
*/
|
||||
|
|
|
@ -667,8 +667,16 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
|
|||
skb_pull(entry->skb, RXINFO_DESC_SIZE);
|
||||
|
||||
/*
|
||||
* FIXME: we need to check for rx_pkt_len validity
|
||||
* Check for rx_pkt_len validity. Return if invalid, leaving
|
||||
* rxdesc->size zeroed out by the upper level.
|
||||
*/
|
||||
if (unlikely(rx_pkt_len == 0 ||
|
||||
rx_pkt_len > entry->queue->data_size)) {
|
||||
ERROR(entry->queue->rt2x00dev,
|
||||
"Bad frame size %d, forcing to 0\n", rx_pkt_len);
|
||||
return;
|
||||
}
|
||||
|
||||
rxd = (__le32 *)(entry->skb->data + rx_pkt_len);
|
||||
|
||||
/*
|
||||
|
@ -736,6 +744,7 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
|
|||
static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
int retval;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Allocate eeprom data.
|
||||
|
@ -748,6 +757,14 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* Enable rfkill polling by setting GPIO direction of the
|
||||
* rfkill switch GPIO pin correctly.
|
||||
*/
|
||||
rt2x00usb_register_read(rt2x00dev, GPIO_CTRL_CFG, ®);
|
||||
rt2x00_set_field32(®, GPIO_CTRL_CFG_GPIOD_BIT2, 1);
|
||||
rt2x00usb_register_write(rt2x00dev, GPIO_CTRL_CFG, reg);
|
||||
|
||||
/*
|
||||
* Initialize hw specifications.
|
||||
*/
|
||||
|
@ -1157,6 +1174,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||
{ USB_DEVICE(0x1690, 0x0744) },
|
||||
{ USB_DEVICE(0x1690, 0x0761) },
|
||||
{ USB_DEVICE(0x1690, 0x0764) },
|
||||
/* ASUS */
|
||||
{ USB_DEVICE(0x0b05, 0x179d) },
|
||||
/* Cisco */
|
||||
{ USB_DEVICE(0x167b, 0x4001) },
|
||||
/* EnGenius */
|
||||
|
@ -1222,7 +1241,6 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||
{ USB_DEVICE(0x0b05, 0x1760) },
|
||||
{ USB_DEVICE(0x0b05, 0x1761) },
|
||||
{ USB_DEVICE(0x0b05, 0x1790) },
|
||||
{ USB_DEVICE(0x0b05, 0x179d) },
|
||||
/* AzureWave */
|
||||
{ USB_DEVICE(0x13d3, 0x3262) },
|
||||
{ USB_DEVICE(0x13d3, 0x3284) },
|
||||
|
|
|
@ -629,7 +629,7 @@ void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp)
|
|||
*/
|
||||
if (unlikely(rxdesc.size == 0 ||
|
||||
rxdesc.size > entry->queue->data_size)) {
|
||||
WARNING(rt2x00dev, "Wrong frame size %d max %d.\n",
|
||||
ERROR(rt2x00dev, "Wrong frame size %d max %d.\n",
|
||||
rxdesc.size, entry->queue->data_size);
|
||||
dev_kfree_skb(entry->skb);
|
||||
goto renew_skb;
|
||||
|
|
|
@ -2832,6 +2832,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
|
|||
static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
int retval;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Disable power saving.
|
||||
|
@ -2849,6 +2850,14 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* Enable rfkill polling by setting GPIO direction of the
|
||||
* rfkill switch GPIO pin correctly.
|
||||
*/
|
||||
rt2x00pci_register_read(rt2x00dev, MAC_CSR13, ®);
|
||||
rt2x00_set_field32(®, MAC_CSR13_BIT13, 1);
|
||||
rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg);
|
||||
|
||||
/*
|
||||
* Initialize hw specifications.
|
||||
*/
|
||||
|
|
|
@ -372,6 +372,7 @@ struct hw_pairwise_ta_entry {
|
|||
#define MAC_CSR13_BIT10 FIELD32(0x00000400)
|
||||
#define MAC_CSR13_BIT11 FIELD32(0x00000800)
|
||||
#define MAC_CSR13_BIT12 FIELD32(0x00001000)
|
||||
#define MAC_CSR13_BIT13 FIELD32(0x00002000)
|
||||
|
||||
/*
|
||||
* MAC_CSR14: LED control register.
|
||||
|
|
|
@ -2177,6 +2177,7 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
|
|||
static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
int retval;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Allocate eeprom data.
|
||||
|
@ -2189,6 +2190,14 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* Enable rfkill polling by setting GPIO direction of the
|
||||
* rfkill switch GPIO pin correctly.
|
||||
*/
|
||||
rt2x00usb_register_read(rt2x00dev, MAC_CSR13, ®);
|
||||
rt2x00_set_field32(®, MAC_CSR13_BIT15, 0);
|
||||
rt2x00usb_register_write(rt2x00dev, MAC_CSR13, reg);
|
||||
|
||||
/*
|
||||
* Initialize hw specifications.
|
||||
*/
|
||||
|
|
|
@ -282,6 +282,9 @@ struct hw_pairwise_ta_entry {
|
|||
#define MAC_CSR13_BIT10 FIELD32(0x00000400)
|
||||
#define MAC_CSR13_BIT11 FIELD32(0x00000800)
|
||||
#define MAC_CSR13_BIT12 FIELD32(0x00001000)
|
||||
#define MAC_CSR13_BIT13 FIELD32(0x00002000)
|
||||
#define MAC_CSR13_BIT14 FIELD32(0x00004000)
|
||||
#define MAC_CSR13_BIT15 FIELD32(0x00008000)
|
||||
|
||||
/*
|
||||
* MAC_CSR14: LED control register.
|
||||
|
|
|
@ -136,7 +136,7 @@ struct smp_chan {
|
|||
};
|
||||
|
||||
/* SMP Commands */
|
||||
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level);
|
||||
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level);
|
||||
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
|
||||
int smp_distribute_keys(struct l2cap_conn *conn, __u8 force);
|
||||
int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <net/bluetooth/a2mp.h>
|
||||
#include <net/bluetooth/smp.h>
|
||||
|
||||
static void hci_le_connect(struct hci_conn *conn)
|
||||
{
|
||||
|
@ -619,6 +620,9 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
|||
{
|
||||
BT_DBG("hcon %p", conn);
|
||||
|
||||
if (conn->type == LE_LINK)
|
||||
return smp_conn_security(conn, sec_level);
|
||||
|
||||
/* For sdp we don't need the link key. */
|
||||
if (sec_level == BT_SECURITY_SDP)
|
||||
return 1;
|
||||
|
|
|
@ -1199,14 +1199,15 @@ clean:
|
|||
static void l2cap_conn_ready(struct l2cap_conn *conn)
|
||||
{
|
||||
struct l2cap_chan *chan;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (!conn->hcon->out && conn->hcon->type == LE_LINK)
|
||||
if (!hcon->out && hcon->type == LE_LINK)
|
||||
l2cap_le_conn_ready(conn);
|
||||
|
||||
if (conn->hcon->out && conn->hcon->type == LE_LINK)
|
||||
smp_conn_security(conn, conn->hcon->pending_sec_level);
|
||||
if (hcon->out && hcon->type == LE_LINK)
|
||||
smp_conn_security(hcon, hcon->pending_sec_level);
|
||||
|
||||
mutex_lock(&conn->chan_lock);
|
||||
|
||||
|
@ -1219,8 +1220,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (conn->hcon->type == LE_LINK) {
|
||||
if (smp_conn_security(conn, chan->sec_level))
|
||||
if (hcon->type == LE_LINK) {
|
||||
if (smp_conn_security(hcon, chan->sec_level))
|
||||
l2cap_chan_ready(chan);
|
||||
|
||||
} else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
|
||||
|
|
|
@ -616,7 +616,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
|
|||
break;
|
||||
}
|
||||
|
||||
if (smp_conn_security(conn, sec.level))
|
||||
if (smp_conn_security(conn->hcon, sec.level))
|
||||
break;
|
||||
sk->sk_state = BT_CONFIG;
|
||||
chan->state = BT_CONFIG;
|
||||
|
|
|
@ -267,10 +267,10 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
|
|||
mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type,
|
||||
hcon->dst_type, reason);
|
||||
|
||||
if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) {
|
||||
cancel_delayed_work_sync(&conn->security_timer);
|
||||
cancel_delayed_work_sync(&conn->security_timer);
|
||||
|
||||
if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
|
||||
smp_chan_destroy(conn);
|
||||
}
|
||||
}
|
||||
|
||||
#define JUST_WORKS 0x00
|
||||
|
@ -760,9 +760,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
|
||||
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
||||
{
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct l2cap_conn *conn = hcon->l2cap_data;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
__u8 authreq;
|
||||
|
||||
|
|
|
@ -1378,6 +1378,8 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop,
|
|||
else
|
||||
memset(next_hop, 0, ETH_ALEN);
|
||||
|
||||
memset(pinfo, 0, sizeof(*pinfo));
|
||||
|
||||
pinfo->generation = mesh_paths_generation;
|
||||
|
||||
pinfo->filled = MPATH_INFO_FRAME_QLEN |
|
||||
|
@ -1396,7 +1398,6 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop,
|
|||
pinfo->discovery_timeout =
|
||||
jiffies_to_msecs(mpath->discovery_timeout);
|
||||
pinfo->discovery_retries = mpath->discovery_retries;
|
||||
pinfo->flags = 0;
|
||||
if (mpath->flags & MESH_PATH_ACTIVE)
|
||||
pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE;
|
||||
if (mpath->flags & MESH_PATH_RESOLVING)
|
||||
|
@ -1405,10 +1406,8 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop,
|
|||
pinfo->flags |= NL80211_MPATH_FLAG_SN_VALID;
|
||||
if (mpath->flags & MESH_PATH_FIXED)
|
||||
pinfo->flags |= NL80211_MPATH_FLAG_FIXED;
|
||||
if (mpath->flags & MESH_PATH_RESOLVING)
|
||||
pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING;
|
||||
|
||||
pinfo->flags = mpath->flags;
|
||||
if (mpath->flags & MESH_PATH_RESOLVED)
|
||||
pinfo->flags |= NL80211_MPATH_FLAG_RESOLVED;
|
||||
}
|
||||
|
||||
static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
|
|
@ -3248,6 +3248,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
|
|||
goto out_unlock;
|
||||
|
||||
err_clear:
|
||||
memset(ifmgd->bssid, 0, ETH_ALEN);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
|
||||
ifmgd->auth_data = NULL;
|
||||
err_free:
|
||||
kfree(auth_data);
|
||||
|
@ -3439,6 +3441,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
err = 0;
|
||||
goto out;
|
||||
err_clear:
|
||||
memset(ifmgd->bssid, 0, ETH_ALEN);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
|
||||
ifmgd->assoc_data = NULL;
|
||||
err_free:
|
||||
kfree(assoc_data);
|
||||
|
|
|
@ -5633,8 +5633,10 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
|
|||
sizeof(connect.ht_capa_mask));
|
||||
|
||||
if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
|
||||
if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
|
||||
if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) {
|
||||
kfree(connkeys);
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(&connect.ht_capa,
|
||||
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
|
||||
sizeof(connect.ht_capa));
|
||||
|
|
Loading…
Reference in New Issue