Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Johan Hedberg says: ==================== pull request: bluetooth-next 2016-01-08 Here's one more bluetooth-next pull request for the 4.5 kernel: - Support for CRC check and promiscuous mode for CC2520 - Fixes to btmrvl driver - New ACPI IDs for hci_bcm driver - Limited Discovery support for the Bluetooth mgmt interface - Minor other cleanups here and there Please let me know if there are any issues pulling. Thanks. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
250fbf129e
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
data += field_len + 1;
|
||||
/* Zero length data */
|
||||
if (field_len == 1)
|
||||
return NULL;
|
||||
|
||||
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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 },
|
||||
{ },
|
||||
|
|
Загрузка…
Ссылка в новой задаче