diff options
-rw-r--r-- | drivers/bluetooth/btmrvl_drv.h | 1 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_main.c | 13 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_sdio.c | 6 | ||||
-rw-r--r-- | drivers/bluetooth/hci_bcm.c | 7 | ||||
-rw-r--r-- | drivers/net/ieee802154/cc2520.c | 145 | ||||
-rw-r--r-- | include/net/bluetooth/hci_core.h | 31 | ||||
-rw-r--r-- | include/net/bluetooth/mgmt.h | 2 | ||||
-rw-r--r-- | include/net/ieee802154_netdev.h | 2 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 6 | ||||
-rw-r--r-- | net/bluetooth/hci_request.c | 11 | ||||
-rw-r--r-- | net/bluetooth/hci_sock.c | 27 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 56 | ||||
-rw-r--r-- | net/mac802154/mac_cmd.c | 2 | ||||
-rw-r--r-- | net/rfkill/rfkill-gpio.c | 4 |
14 files changed, 244 insertions, 69 deletions
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 27a9aac25583..05904732e6f1 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -89,6 +89,7 @@ struct btmrvl_adapter { wait_queue_head_t event_hs_wait_q; u8 cmd_complete; bool is_suspended; + bool is_suspending; }; struct btmrvl_private { diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index f2b38c880b11..f25a825a693f 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -436,6 +436,11 @@ static int btmrvl_send_frame(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("type=%d, len=%d", hci_skb_pkt_type(skb), skb->len); + if (priv->adapter->is_suspending || priv->adapter->is_suspended) { + BT_ERR("%s: Device is suspending or suspended", __func__); + return -EBUSY; + } + switch (hci_skb_pkt_type(skb)) { case HCI_COMMAND_PKT: hdev->stat.cmd_tx++; @@ -452,7 +457,8 @@ static int btmrvl_send_frame(struct hci_dev *hdev, struct sk_buff *skb) skb_queue_tail(&priv->adapter->tx_queue, skb); - wake_up_interruptible(&priv->main_thread.wait_q); + if (!priv->adapter->is_suspended) + wake_up_interruptible(&priv->main_thread.wait_q); return 0; } @@ -543,7 +549,7 @@ static int btmrvl_setup(struct hci_dev *hdev) if (ret) return ret; - priv->btmrvl_dev.gpio_gap = 0xffff; + priv->btmrvl_dev.gpio_gap = 0xfffe; btmrvl_check_device_tree(priv); @@ -643,7 +649,8 @@ static int btmrvl_service_main_thread(void *data) if (adapter->ps_state == PS_SLEEP) continue; - if (!priv->btmrvl_dev.tx_dnld_rdy) + if (!priv->btmrvl_dev.tx_dnld_rdy || + priv->adapter->is_suspended) continue; skb = skb_dequeue(&adapter->tx_queue); diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index d3a4acdf98c9..6ed8acfcfa9c 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1112,7 +1112,8 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) */ if (btmrvl_sdio_verify_fw_download(card, pollnum)) { BT_ERR("FW failed to be active in time!"); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto done; } sdio_release_host(card->func); @@ -1544,10 +1545,10 @@ static int btmrvl_sdio_suspend(struct device *dev) } priv = card->priv; + priv->adapter->is_suspending = true; hcidev = priv->btmrvl_dev.hcidev; BT_DBG("%s: SDIO suspend", hcidev->name); hci_suspend_dev(hcidev); - skb_queue_purge(&priv->adapter->tx_queue); if (priv->adapter->hs_state != HS_ACTIVATED) { if (btmrvl_enable_hs(priv)) { @@ -1556,6 +1557,7 @@ static int btmrvl_sdio_suspend(struct device *dev) } } + priv->adapter->is_suspending = false; priv->adapter->is_suspended = true; /* We will keep the power when hs enabled successfully */ diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 5c7c696c5838..5f3de181e744 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -814,9 +814,16 @@ static const struct hci_uart_proto bcm_proto = { #ifdef CONFIG_ACPI static const struct acpi_device_id bcm_acpi_match[] = { + { "BCM2E1A", 0 }, { "BCM2E39", 0 }, + { "BCM2E3A", 0 }, + { "BCM2E3D", 0 }, + { "BCM2E3F", 0 }, + { "BCM2E40", 0 }, + { "BCM2E64", 0 }, { "BCM2E65", 0 }, { "BCM2E67", 0 }, + { "BCM2E7B", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, bcm_acpi_match); diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index e65b60591317..d50add705a79 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -21,6 +21,8 @@ #include <linux/skbuff.h> #include <linux/of_gpio.h> #include <linux/ieee802154.h> +#include <linux/crc-ccitt.h> +#include <asm/unaligned.h> #include <net/mac802154.h> #include <net/cfg802154.h> @@ -189,6 +191,18 @@ #define CC2520_RXFIFOCNT 0x3E #define CC2520_TXFIFOCNT 0x3F +/* CC2520_FRMFILT0 */ +#define FRMFILT0_FRAME_FILTER_EN BIT(0) +#define FRMFILT0_PAN_COORDINATOR BIT(1) + +/* CC2520_FRMCTRL0 */ +#define FRMCTRL0_AUTOACK BIT(5) +#define FRMCTRL0_AUTOCRC BIT(6) + +/* CC2520_FRMCTRL1 */ +#define FRMCTRL1_SET_RXENMASK_ON_TX BIT(0) +#define FRMCTRL1_IGNORE_TX_UNDERF BIT(1) + /* Driver private information */ struct cc2520_private { struct spi_device *spi; /* SPI device structure */ @@ -201,6 +215,7 @@ struct cc2520_private { struct work_struct fifop_irqwork;/* Workqueue for FIFOP */ spinlock_t lock; /* Lock for is_tx*/ struct completion tx_complete; /* Work completion for Tx */ + bool promiscuous; /* Flag for promiscuous mode */ }; /* Generic Functions */ @@ -367,14 +382,14 @@ cc2520_read_register(struct cc2520_private *priv, u8 reg, u8 *data) } static int -cc2520_write_txfifo(struct cc2520_private *priv, u8 *data, u8 len) +cc2520_write_txfifo(struct cc2520_private *priv, u8 pkt_len, u8 *data, u8 len) { int status; /* length byte must include FCS even * if it is calculated in the hardware */ - int len_byte = len + 2; + int len_byte = pkt_len; struct spi_message msg; @@ -414,7 +429,7 @@ cc2520_write_txfifo(struct cc2520_private *priv, u8 *data, u8 len) } static int -cc2520_read_rxfifo(struct cc2520_private *priv, u8 *data, u8 len, u8 *lqi) +cc2520_read_rxfifo(struct cc2520_private *priv, u8 *data, u8 len) { int status; struct spi_message msg; @@ -470,12 +485,25 @@ cc2520_tx(struct ieee802154_hw *hw, struct sk_buff *skb) unsigned long flags; int rc; u8 status = 0; + u8 pkt_len; + + /* In promiscuous mode we disable AUTOCRC so we can get the raw CRC + * values on RX. This means we need to manually add the CRC on TX. + */ + if (priv->promiscuous) { + u16 crc = crc_ccitt(0, skb->data, skb->len); + + put_unaligned_le16(crc, skb_put(skb, 2)); + pkt_len = skb->len; + } else { + pkt_len = skb->len + 2; + } rc = cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHTX); if (rc) goto err_tx; - rc = cc2520_write_txfifo(priv, skb->data, skb->len); + rc = cc2520_write_txfifo(priv, pkt_len, skb->data, skb->len); if (rc) goto err_tx; @@ -518,22 +546,62 @@ static int cc2520_rx(struct cc2520_private *priv) u8 len = 0, lqi = 0, bytes = 1; struct sk_buff *skb; - cc2520_read_rxfifo(priv, &len, bytes, &lqi); + /* Read single length byte from the radio. */ + cc2520_read_rxfifo(priv, &len, bytes); - if (len < 2 || len > IEEE802154_MTU) - return -EINVAL; + if (!ieee802154_is_valid_psdu_len(len)) { + /* Corrupted frame received, clear frame buffer by + * reading entire buffer. + */ + dev_dbg(&priv->spi->dev, "corrupted frame received\n"); + len = IEEE802154_MTU; + } skb = dev_alloc_skb(len); if (!skb) return -ENOMEM; - if (cc2520_read_rxfifo(priv, skb_put(skb, len), len, &lqi)) { + if (cc2520_read_rxfifo(priv, skb_put(skb, len), len)) { dev_dbg(&priv->spi->dev, "frame reception failed\n"); kfree_skb(skb); return -EINVAL; } - skb_trim(skb, skb->len - 2); + /* In promiscuous mode, we configure the radio to include the + * CRC (AUTOCRC==0) and we pass on the packet unconditionally. If not + * in promiscuous mode, we check the CRC here, but leave the + * RSSI/LQI/CRC_OK bytes as they will get removed in the mac layer. + */ + if (!priv->promiscuous) { + bool crc_ok; + + /* Check if the CRC is valid. With AUTOCRC set, the most + * significant bit of the last byte returned from the CC2520 + * is CRC_OK flag. See section 20.3.4 of the datasheet. + */ + crc_ok = skb->data[len - 1] & BIT(7); + + /* If we failed CRC drop the packet in the driver layer. */ + if (!crc_ok) { + dev_dbg(&priv->spi->dev, "CRC check failed\n"); + kfree_skb(skb); + return -EINVAL; + } + + /* To calculate LQI, the lower 7 bits of the last byte (the + * correlation value provided by the radio) must be scaled to + * the range 0-255. According to section 20.6, the correlation + * value ranges from 50-110. Ideally this would be calibrated + * per hardware design, but we use roughly the datasheet values + * to get close enough while avoiding floating point. + */ + lqi = skb->data[len - 1] & 0x7f; + if (lqi < 50) + lqi = 50; + else if (lqi > 113) + lqi = 113; + lqi = (lqi - 50) * 4; + } ieee802154_rx_irqsafe(priv->hw, skb, lqi); @@ -619,14 +687,19 @@ cc2520_filter(struct ieee802154_hw *hw, } if (changed & IEEE802154_AFILT_PANC_CHANGED) { + u8 frmfilt0; + dev_vdbg(&priv->spi->dev, "cc2520_filter called for panc change\n"); + + cc2520_read_register(priv, CC2520_FRMFILT0, &frmfilt0); + if (filt->pan_coord) - ret = cc2520_write_register(priv, CC2520_FRMFILT0, - 0x02); + frmfilt0 |= FRMFILT0_PAN_COORDINATOR; else - ret = cc2520_write_register(priv, CC2520_FRMFILT0, - 0x00); + frmfilt0 &= ~FRMFILT0_PAN_COORDINATOR; + + ret = cc2520_write_register(priv, CC2520_FRMFILT0, frmfilt0); } return ret; @@ -723,6 +796,30 @@ cc2520_set_txpower(struct ieee802154_hw *hw, s32 mbm) return cc2520_cc2591_set_tx_power(priv, mbm); } +static int +cc2520_set_promiscuous_mode(struct ieee802154_hw *hw, bool on) +{ + struct cc2520_private *priv = hw->priv; + u8 frmfilt0; + + dev_dbg(&priv->spi->dev, "%s : mode %d\n", __func__, on); + + priv->promiscuous = on; + + cc2520_read_register(priv, CC2520_FRMFILT0, &frmfilt0); + + if (on) { + /* Disable automatic ACK, automatic CRC, and frame filtering. */ + cc2520_write_register(priv, CC2520_FRMCTRL0, 0); + frmfilt0 &= ~FRMFILT0_FRAME_FILTER_EN; + } else { + cc2520_write_register(priv, CC2520_FRMCTRL0, FRMCTRL0_AUTOACK | + FRMCTRL0_AUTOCRC); + frmfilt0 |= FRMFILT0_FRAME_FILTER_EN; + } + return cc2520_write_register(priv, CC2520_FRMFILT0, frmfilt0); +} + static const struct ieee802154_ops cc2520_ops = { .owner = THIS_MODULE, .start = cc2520_start, @@ -732,6 +829,7 @@ static const struct ieee802154_ops cc2520_ops = { .set_channel = cc2520_set_channel, .set_hw_addr_filt = cc2520_filter, .set_txpower = cc2520_set_txpower, + .set_promiscuous_mode = cc2520_set_promiscuous_mode, }; static int cc2520_register(struct cc2520_private *priv) @@ -749,7 +847,8 @@ static int cc2520_register(struct cc2520_private *priv) /* We do support only 2.4 Ghz */ priv->hw->phy->supported.channels[0] = 0x7FFF800; - priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AFILT; + priv->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT | + IEEE802154_HW_PROMISCUOUS; priv->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER; @@ -919,6 +1018,11 @@ static int cc2520_hw_init(struct cc2520_private *priv) } /* Registers default value: section 28.1 in Datasheet */ + + /* Set the CCA threshold to -50 dBm. This seems to have been copied + * from the TinyOS CC2520 driver and is much higher than the -84 dBm + * threshold suggested in the datasheet. + */ ret = cc2520_write_register(priv, CC2520_CCACTRL0, 0x1A); if (ret) goto err_ret; @@ -955,15 +1059,10 @@ static int cc2520_hw_init(struct cc2520_private *priv) if (ret) goto err_ret; - ret = cc2520_write_register(priv, CC2520_FRMCTRL0, 0x60); - if (ret) - goto err_ret; - - ret = cc2520_write_register(priv, CC2520_FRMCTRL1, 0x03); - if (ret) - goto err_ret; - - ret = cc2520_write_register(priv, CC2520_FRMFILT0, 0x00); + /* Configure registers correctly for this driver. */ + ret = cc2520_write_register(priv, CC2520_FRMCTRL1, + FRMCTRL1_SET_RXENMASK_ON_TX | + FRMCTRL1_IGNORE_TX_UNDERF); if (ret) goto err_ret; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c95e0326c41a..d4f82edb5cff 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -77,6 +77,7 @@ struct discovery_state { u8 last_adv_data_len; bool report_invalid_rssi; bool result_filtering; + bool limited; s8 rssi; u16 uuid_count; u8 (*uuids)[16]; @@ -1283,31 +1284,41 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, mutex_unlock(&hci_cb_list_lock); } -static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) +static inline void *eir_get_data(u8 *eir, size_t eir_len, u8 type, + size_t *data_len) { size_t parsed = 0; - if (data_len < 2) - return false; + if (eir_len < 2) + return NULL; - while (parsed < data_len - 1) { - u8 field_len = data[0]; + while (parsed < eir_len - 1) { + u8 field_len = eir[0]; if (field_len == 0) break; parsed += field_len + 1; - if (parsed > data_len) + if (parsed > eir_len) break; - if (data[1] == type) - return true; + if (eir[1] != type) { + eir += field_len + 1; + continue; + } + + /* Zero length data */ + if (field_len == 1) + return NULL; - data += field_len + 1; + if (data_len) + *data_len = field_len - 1; + + return &eir[2]; } - return false; + return NULL; } static inline bool hci_bdaddr_is_rpa(bdaddr_t *bdaddr, u8 addr_type) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index af17774c9416..ea73e0826aa7 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -584,6 +584,8 @@ struct mgmt_rp_get_adv_size_info { __u8 max_scan_rsp_len; } __packed; +#define MGMT_OP_START_LIMITED_DISCOVERY 0x0041 + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index a62a051a3a2f..c4b31601cd53 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -337,7 +337,7 @@ struct ieee802154_mlme_ops { void (*get_mac_params)(struct net_device *dev, struct ieee802154_mac_params *params); - struct ieee802154_llsec_ops *llsec; + const struct ieee802154_llsec_ops *llsec; }; static inline struct ieee802154_mlme_ops * diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 7554da5b7a8f..c162af5d16bf 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3833,9 +3833,9 @@ static void hci_extended_inquiry_result_evt(struct hci_dev *hdev, data.ssp_mode = 0x01; if (hci_dev_test_flag(hdev, HCI_MGMT)) - name_known = eir_has_data_type(info->data, - sizeof(info->data), - EIR_NAME_COMPLETE); + name_known = eir_get_data(info->data, + sizeof(info->data), + EIR_NAME_COMPLETE, NULL); else name_known = true; diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 9997c31ef987..41b5f3813f02 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -1737,8 +1737,8 @@ static int le_scan_disable(struct hci_request *req, unsigned long opt) static int bredr_inquiry(struct hci_request *req, unsigned long opt) { u8 length = opt; - /* General inquiry access code (GIAC) */ - u8 lap[3] = { 0x33, 0x8b, 0x9e }; + const u8 giac[3] = { 0x33, 0x8b, 0x9e }; + const u8 liac[3] = { 0x00, 0x8b, 0x9e }; struct hci_cp_inquiry cp; BT_DBG("%s", req->hdev->name); @@ -1748,7 +1748,12 @@ static int bredr_inquiry(struct hci_request *req, unsigned long opt) hci_dev_unlock(req->hdev); memset(&cp, 0, sizeof(cp)); - memcpy(&cp.lap, lap, sizeof(cp.lap)); + + if (req->hdev->discovery.limited) + memcpy(&cp.lap, liac, sizeof(cp.lap)); + else + memcpy(&cp.lap, giac, sizeof(cp.lap)); + cp.length = length; hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp); diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 41f579ba447b..1298d723c0e0 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -25,9 +25,8 @@ /* Bluetooth HCI sockets. */ #include <linux/export.h> +#include <linux/utsname.h> #include <asm/unaligned.h> -#include <generated/compile.h> -#include <generated/utsrelease.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> @@ -385,17 +384,26 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event) return skb; } -static void send_monitor_note(struct sock *sk, const char *text) +static void __printf(2, 3) +send_monitor_note(struct sock *sk, const char *fmt, ...) { - size_t len = strlen(text); + size_t len; struct hci_mon_hdr *hdr; struct sk_buff *skb; + va_list args; + + va_start(args, fmt); + len = vsnprintf(NULL, 0, fmt, args); + va_end(args); skb = bt_skb_alloc(len + 1, GFP_ATOMIC); if (!skb) return; - strcpy(skb_put(skb, len + 1), text); + va_start(args, fmt); + vsprintf(skb_put(skb, len), fmt, args); + *skb_put(skb, 1) = 0; + va_end(args); __net_timestamp(skb); @@ -897,10 +905,11 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, */ hci_sock_set_flag(sk, HCI_SOCK_TRUSTED); - send_monitor_note(sk, "Linux version " UTS_RELEASE - " (" UTS_MACHINE ")"); - send_monitor_note(sk, "Bluetooth subsystem version " - BT_SUBSYS_VERSION); + send_monitor_note(sk, "Linux version %s (%s)", + init_utsname()->release, + init_utsname()->machine); + send_monitor_note(sk, "Bluetooth subsystem version %s", + BT_SUBSYS_VERSION); send_monitor_replay(sk); atomic_inc(&monitor_promisc); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 621f6fdd0dd1..5a5089cb6570 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -103,6 +103,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_ADD_ADVERTISING, MGMT_OP_REMOVE_ADVERTISING, MGMT_OP_GET_ADV_SIZE_INFO, + MGMT_OP_START_LIMITED_DISCOVERY, }; static const u16 mgmt_events[] = { @@ -3283,6 +3284,9 @@ void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status) if (!cmd) cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev); + if (!cmd) + cmd = pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev); + if (cmd) { cmd->cmd_complete(cmd, mgmt_status(status)); mgmt_pending_remove(cmd); @@ -3318,8 +3322,8 @@ static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type, return true; } -static int start_discovery(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) +static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev, + u16 op, void *data, u16 len) { struct mgmt_cp_start_discovery *cp = data; struct mgmt_pending_cmd *cmd; @@ -3331,7 +3335,7 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, hci_dev_lock(hdev); if (!hdev_is_powered(hdev)) { - err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY, + err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_NOT_POWERED, &cp->type, sizeof(cp->type)); goto failed; @@ -3339,15 +3343,14 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, if (hdev->discovery.state != DISCOVERY_STOPPED || hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) { - err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY, - MGMT_STATUS_BUSY, &cp->type, - sizeof(cp->type)); + err = mgmt_cmd_complete(sk, hdev->id, op, MGMT_STATUS_BUSY, + &cp->type, sizeof(cp->type)); goto failed; } if (!discovery_type_is_valid(hdev, cp->type, &status)) { - err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY, - status, &cp->type, sizeof(cp->type)); + err = mgmt_cmd_complete(sk, hdev->id, op, status, + &cp->type, sizeof(cp->type)); goto failed; } @@ -3358,8 +3361,12 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, hdev->discovery.type = cp->type; hdev->discovery.report_invalid_rssi = false; + if (op == MGMT_OP_START_LIMITED_DISCOVERY) + hdev->discovery.limited = true; + else + hdev->discovery.limited = false; - cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len); + cmd = mgmt_pending_add(sk, op, hdev, data, len); if (!cmd) { err = -ENOMEM; goto failed; @@ -3376,6 +3383,21 @@ failed: return err; } +static int start_discovery(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + return start_discovery_internal(sk, hdev, MGMT_OP_START_DISCOVERY, + data, len); +} + +static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + return start_discovery_internal(sk, hdev, + MGMT_OP_START_LIMITED_DISCOVERY, + data, len); +} + static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) { @@ -6313,6 +6335,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = { HCI_MGMT_VAR_LEN }, { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE }, { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE }, + { start_limited_discovery, MGMT_START_DISCOVERY_SIZE }, }; void mgmt_index_added(struct hci_dev *hdev) @@ -7237,6 +7260,18 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, return; } + if (hdev->discovery.limited) { + /* Check for limited discoverable bit */ + if (dev_class) { + if (!(dev_class[1] & 0x20)) + return; + } else { + u8 *flags = eir_get_data(eir, eir_len, EIR_FLAGS, NULL); + if (!flags || !(flags[0] & LE_AD_LIMITED)) + return; + } + } + /* Make sure that the buffer is big enough. The 5 extra bytes * are for the potential CoD field. */ @@ -7266,7 +7301,8 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, /* Copy EIR or advertising data into event */ memcpy(ev->eir, eir, eir_len); - if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV)) + if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, + NULL)) eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, dev_class, 3); diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c index 8606da459ff3..3db16346cab3 100644 --- a/net/mac802154/mac_cmd.c +++ b/net/mac802154/mac_cmd.c @@ -126,7 +126,7 @@ static void mac802154_get_mac_params(struct net_device *dev, params->lbt = wpan_dev->lbt; } -static struct ieee802154_llsec_ops mac802154_llsec_ops = { +static const struct ieee802154_llsec_ops mac802154_llsec_ops = { .get_params = mac802154_get_params, .set_params = mac802154_set_params, .add_key = mac802154_add_key, diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c index 93127220cb54..4b1e3f35f06c 100644 --- a/net/rfkill/rfkill-gpio.c +++ b/net/rfkill/rfkill-gpio.c @@ -163,10 +163,6 @@ static int rfkill_gpio_remove(struct platform_device *pdev) #ifdef CONFIG_ACPI static const struct acpi_device_id rfkill_acpi_match[] = { - { "BCM2E1A", RFKILL_TYPE_BLUETOOTH }, - { "BCM2E3D", RFKILL_TYPE_BLUETOOTH }, - { "BCM2E40", RFKILL_TYPE_BLUETOOTH }, - { "BCM2E64", RFKILL_TYPE_BLUETOOTH }, { "BCM4752", RFKILL_TYPE_GPS }, { "LNV4752", RFKILL_TYPE_GPS }, { }, |