Commit 29a3060a authored by David S. Miller's avatar David S. Miller

Merge branch 'for-upstream' of...

Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

Johan Hedberg says:

====================
pull request: bluetooth-next 2015-07-30

Here's a set of Bluetooth & 802.15.4 patches intended for the 4.3 kernel.

 - Cleanups & fixes to mac802154
 - Refactoring of Intel Bluetooth HCI driver
 - Various coding style fixes to Bluetooth HCI drivers
 - Support for Intel Lightning Peak Bluetooth devices
 - Generic class code in interface descriptor in btusb to match more HW
 - Refactoring of Bluetooth HS code together with a new config option
 - Support for BCM4330B1 Broadcom UART controller

Let me know if there are any issues pulling. Thanks.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 8013d1d7 5857d1db
...@@ -132,6 +132,7 @@ config BT_HCIUART_3WIRE ...@@ -132,6 +132,7 @@ config BT_HCIUART_3WIRE
config BT_HCIUART_INTEL config BT_HCIUART_INTEL
bool "Intel protocol support" bool "Intel protocol support"
depends on BT_HCIUART depends on BT_HCIUART
select BT_HCIUART_H4
select BT_INTEL select BT_INTEL
help help
The Intel protocol support enables Bluetooth HCI over serial The Intel protocol support enables Bluetooth HCI over serial
......
...@@ -492,7 +492,7 @@ static int bfusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -492,7 +492,7 @@ static int bfusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
case HCI_SCODATA_PKT: case HCI_SCODATA_PKT:
hdev->stat.sco_tx++; hdev->stat.sco_tx++;
break; break;
}; }
/* Prepend skb with frame type */ /* Prepend skb with frame type */
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
......
...@@ -427,7 +427,7 @@ static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -427,7 +427,7 @@ static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
case HCI_SCODATA_PKT: case HCI_SCODATA_PKT:
hdev->stat.sco_tx++; hdev->stat.sco_tx++;
break; break;
}; }
/* Prepend skb with frame type */ /* Prepend skb with frame type */
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) #define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}})
#define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}}) #define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}})
#define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}})
int btbcm_check_bdaddr(struct hci_dev *hdev) int btbcm_check_bdaddr(struct hci_dev *hdev)
{ {
...@@ -66,9 +67,13 @@ int btbcm_check_bdaddr(struct hci_dev *hdev) ...@@ -66,9 +67,13 @@ int btbcm_check_bdaddr(struct hci_dev *hdev)
* *
* The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller
* with waiting for configuration state. * with waiting for configuration state.
*
* The address 43:30:B1:00:00:00 indicates a BCM4330B1 controller
* with waiting for configuration state.
*/ */
if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) || if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) ||
!bacmp(&bda->bdaddr, BDADDR_BCM4324B3)) { !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) ||
!bacmp(&bda->bdaddr, BDADDR_BCM4330B1)) {
BT_INFO("%s: BCM: Using default device address (%pMR)", BT_INFO("%s: BCM: Using default device address (%pMR)",
hdev->name, &bda->bdaddr); hdev->name, &bda->bdaddr);
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
...@@ -241,6 +246,7 @@ static const struct { ...@@ -241,6 +246,7 @@ static const struct {
u16 subver; u16 subver;
const char *name; const char *name;
} bcm_uart_subver_table[] = { } bcm_uart_subver_table[] = {
{ 0x4103, "BCM4330B1" }, /* 002.001.003 */
{ 0x410e, "BCM43341B0" }, /* 002.001.014 */ { 0x410e, "BCM43341B0" }, /* 002.001.014 */
{ 0x4406, "BCM4324B3" }, /* 002.004.006 */ { 0x4406, "BCM4324B3" }, /* 002.004.006 */
{ 0x610c, "BCM4354" }, /* 003.001.012 */ { 0x610c, "BCM4354" }, /* 003.001.012 */
......
...@@ -89,6 +89,86 @@ int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) ...@@ -89,6 +89,86 @@ int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
} }
EXPORT_SYMBOL_GPL(btintel_set_bdaddr); EXPORT_SYMBOL_GPL(btintel_set_bdaddr);
void btintel_hw_error(struct hci_dev *hdev, u8 code)
{
struct sk_buff *skb;
u8 type = 0x00;
BT_ERR("%s: Hardware error 0x%2.2x", hdev->name, code);
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
BT_ERR("%s: Reset after hardware error failed (%ld)",
hdev->name, PTR_ERR(skb));
return;
}
kfree_skb(skb);
skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
BT_ERR("%s: Retrieving Intel exception info failed (%ld)",
hdev->name, PTR_ERR(skb));
return;
}
if (skb->len != 13) {
BT_ERR("%s: Exception info size mismatch", hdev->name);
kfree_skb(skb);
return;
}
BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1));
kfree_skb(skb);
}
EXPORT_SYMBOL_GPL(btintel_hw_error);
void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
{
const char *variant;
switch (ver->fw_variant) {
case 0x06:
variant = "Bootloader";
break;
case 0x23:
variant = "Firmware";
break;
default:
return;
}
BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name,
variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f,
ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy);
}
EXPORT_SYMBOL_GPL(btintel_version_info);
int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
const void *param)
{
while (plen > 0) {
struct sk_buff *skb;
u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen;
cmd_param[0] = fragment_type;
memcpy(cmd_param + 1, param, fragment_len);
skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1,
cmd_param, HCI_INIT_TIMEOUT);
if (IS_ERR(skb))
return PTR_ERR(skb);
kfree_skb(skb);
plen -= fragment_len;
param += fragment_len;
}
return 0;
}
EXPORT_SYMBOL_GPL(btintel_secure_send);
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION); MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
......
...@@ -73,6 +73,11 @@ struct intel_secure_send_result { ...@@ -73,6 +73,11 @@ struct intel_secure_send_result {
int btintel_check_bdaddr(struct hci_dev *hdev); int btintel_check_bdaddr(struct hci_dev *hdev);
int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
void btintel_hw_error(struct hci_dev *hdev, u8 code);
void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver);
int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
const void *param);
#else #else
...@@ -86,4 +91,18 @@ static inline int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdadd ...@@ -86,4 +91,18 @@ static inline int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdadd
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static inline void btintel_hw_error(struct hci_dev *hdev, u8 code)
{
}
static void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
{
}
static inline int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type,
u32 plen, const void *param)
{
return -EOPNOTSUPP;
}
#endif #endif
...@@ -95,10 +95,10 @@ struct btmrvl_private { ...@@ -95,10 +95,10 @@ struct btmrvl_private {
struct btmrvl_device btmrvl_dev; struct btmrvl_device btmrvl_dev;
struct btmrvl_adapter *adapter; struct btmrvl_adapter *adapter;
struct btmrvl_thread main_thread; struct btmrvl_thread main_thread;
int (*hw_host_to_card) (struct btmrvl_private *priv, int (*hw_host_to_card)(struct btmrvl_private *priv,
u8 *payload, u16 nb); u8 *payload, u16 nb);
int (*hw_wakeup_firmware) (struct btmrvl_private *priv); int (*hw_wakeup_firmware)(struct btmrvl_private *priv);
int (*hw_process_int_status) (struct btmrvl_private *priv); int (*hw_process_int_status)(struct btmrvl_private *priv);
void (*firmware_dump)(struct btmrvl_private *priv); void (*firmware_dump)(struct btmrvl_private *priv);
spinlock_t driver_lock; /* spinlock used by driver */ spinlock_t driver_lock; /* spinlock used by driver */
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
......
...@@ -68,6 +68,9 @@ static const struct usb_device_id btusb_table[] = { ...@@ -68,6 +68,9 @@ static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth AMP device */ /* Generic Bluetooth AMP device */
{ USB_DEVICE_INFO(0xe0, 0x01, 0x04), .driver_info = BTUSB_AMP }, { USB_DEVICE_INFO(0xe0, 0x01, 0x04), .driver_info = BTUSB_AMP },
/* Generic Bluetooth USB interface */
{ USB_INTERFACE_INFO(0xe0, 0x01, 0x01) },
/* Apple-specific (Broadcom) devices */ /* Apple-specific (Broadcom) devices */
{ USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01), { USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01),
.driver_info = BTUSB_BCM_APPLE }, .driver_info = BTUSB_BCM_APPLE },
...@@ -1878,51 +1881,6 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -1878,51 +1881,6 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb)
return -EILSEQ; return -EILSEQ;
} }
static int btusb_intel_secure_send(struct hci_dev *hdev, u8 fragment_type,
u32 plen, const void *param)
{
while (plen > 0) {
struct sk_buff *skb;
u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen;
cmd_param[0] = fragment_type;
memcpy(cmd_param + 1, param, fragment_len);
skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1,
cmd_param, HCI_INIT_TIMEOUT);
if (IS_ERR(skb))
return PTR_ERR(skb);
kfree_skb(skb);
plen -= fragment_len;
param += fragment_len;
}
return 0;
}
static void btusb_intel_version_info(struct hci_dev *hdev,
struct intel_version *ver)
{
const char *variant;
switch (ver->fw_variant) {
case 0x06:
variant = "Bootloader";
break;
case 0x23:
variant = "Firmware";
break;
default:
return;
}
BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name,
variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f,
ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy);
}
static int btusb_setup_intel_new(struct hci_dev *hdev) static int btusb_setup_intel_new(struct hci_dev *hdev)
{ {
static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01, static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01,
...@@ -1984,7 +1942,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) ...@@ -1984,7 +1942,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
return -EINVAL; return -EINVAL;
} }
btusb_intel_version_info(hdev, ver); btintel_version_info(hdev, ver);
/* The firmware variant determines if the device is in bootloader /* The firmware variant determines if the device is in bootloader
* mode or is running operational firmware. The value 0x06 identifies * mode or is running operational firmware. The value 0x06 identifies
...@@ -2104,7 +2062,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) ...@@ -2104,7 +2062,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
/* Start the firmware download transaction with the Init fragment /* Start the firmware download transaction with the Init fragment
* represented by the 128 bytes of CSS header. * represented by the 128 bytes of CSS header.
*/ */
err = btusb_intel_secure_send(hdev, 0x00, 128, fw->data); err = btintel_secure_send(hdev, 0x00, 128, fw->data);
if (err < 0) { if (err < 0) {
BT_ERR("%s: Failed to send firmware header (%d)", BT_ERR("%s: Failed to send firmware header (%d)",
hdev->name, err); hdev->name, err);
...@@ -2114,7 +2072,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) ...@@ -2114,7 +2072,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
/* Send the 256 bytes of public key information from the firmware /* Send the 256 bytes of public key information from the firmware
* as the PKey fragment. * as the PKey fragment.
*/ */
err = btusb_intel_secure_send(hdev, 0x03, 256, fw->data + 128); err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128);
if (err < 0) { if (err < 0) {
BT_ERR("%s: Failed to send firmware public key (%d)", BT_ERR("%s: Failed to send firmware public key (%d)",
hdev->name, err); hdev->name, err);
...@@ -2124,7 +2082,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) ...@@ -2124,7 +2082,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
/* Send the 256 bytes of signature information from the firmware /* Send the 256 bytes of signature information from the firmware
* as the Sign fragment. * as the Sign fragment.
*/ */
err = btusb_intel_secure_send(hdev, 0x02, 256, fw->data + 388); err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388);
if (err < 0) { if (err < 0) {
BT_ERR("%s: Failed to send firmware signature (%d)", BT_ERR("%s: Failed to send firmware signature (%d)",
hdev->name, err); hdev->name, err);
...@@ -2148,8 +2106,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) ...@@ -2148,8 +2106,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
* firmware data buffer as a single Data fragement. * firmware data buffer as a single Data fragement.
*/ */
if (!(frag_len % 4)) { if (!(frag_len % 4)) {
err = btusb_intel_secure_send(hdev, 0x01, frag_len, err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr);
fw_ptr);
if (err < 0) { if (err < 0) {
BT_ERR("%s: Failed to send firmware data (%d)", BT_ERR("%s: Failed to send firmware data (%d)",
hdev->name, err); hdev->name, err);
...@@ -2291,39 +2248,6 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) ...@@ -2291,39 +2248,6 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
return 0; return 0;
} }
static void btusb_hw_error_intel(struct hci_dev *hdev, u8 code)
{
struct sk_buff *skb;
u8 type = 0x00;
BT_ERR("%s: Hardware error 0x%2.2x", hdev->name, code);
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
BT_ERR("%s: Reset after hardware error failed (%ld)",
hdev->name, PTR_ERR(skb));
return;
}
kfree_skb(skb);
skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
BT_ERR("%s: Retrieving Intel exception info failed (%ld)",
hdev->name, PTR_ERR(skb));
return;
}
if (skb->len != 13) {
BT_ERR("%s: Exception info size mismatch", hdev->name);
kfree_skb(skb);
return;
}
BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1));
kfree_skb(skb);
}
static int btusb_shutdown_intel(struct hci_dev *hdev) static int btusb_shutdown_intel(struct hci_dev *hdev)
{ {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -2783,7 +2707,7 @@ static int btusb_probe(struct usb_interface *intf, ...@@ -2783,7 +2707,7 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_INTEL_NEW) { if (id->driver_info & BTUSB_INTEL_NEW) {
hdev->send = btusb_send_frame_intel; hdev->send = btusb_send_frame_intel;
hdev->setup = btusb_setup_intel_new; hdev->setup = btusb_setup_intel_new;
hdev->hw_error = btusb_hw_error_intel; hdev->hw_error = btintel_hw_error;
hdev->set_bdaddr = btintel_set_bdaddr; hdev->set_bdaddr = btintel_set_bdaddr;
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
} }
......
...@@ -182,9 +182,9 @@ static void dtl1_control(struct dtl1_info *info, struct sk_buff *skb) ...@@ -182,9 +182,9 @@ static void dtl1_control(struct dtl1_info *info, struct sk_buff *skb)
int i; int i;
printk(KERN_INFO "Bluetooth: Nokia control data ="); printk(KERN_INFO "Bluetooth: Nokia control data =");
for (i = 0; i < skb->len; i++) { for (i = 0; i < skb->len; i++)
printk(" %02x", skb->data[i]); printk(" %02x", skb->data[i]);
}
printk("\n"); printk("\n");
/* transition to active state */ /* transition to active state */
...@@ -406,7 +406,7 @@ static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -406,7 +406,7 @@ static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
break; break;
default: default:
return -EILSEQ; return -EILSEQ;
}; }
nsh.zero = 0; nsh.zero = 0;
nsh.len = skb->len; nsh.len = skb->len;
......
...@@ -75,7 +75,7 @@ struct h5 { ...@@ -75,7 +75,7 @@ struct h5 {
size_t rx_pending; /* Expecting more bytes */ size_t rx_pending; /* Expecting more bytes */
u8 rx_ack; /* Last ack number received */ u8 rx_ack; /* Last ack number received */
int (*rx_func) (struct hci_uart *hu, u8 c); int (*rx_func)(struct hci_uart *hu, u8 c);
struct timer_list timer; /* Retransmission timer */ struct timer_list timer; /* Retransmission timer */
......
This diff is collapsed.
...@@ -770,7 +770,7 @@ static int __init hci_uart_init(void) ...@@ -770,7 +770,7 @@ static int __init hci_uart_init(void)
/* Register the tty discipline */ /* Register the tty discipline */
memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc)); memset(&hci_uart_ldisc, 0, sizeof(hci_uart_ldisc));
hci_uart_ldisc.magic = TTY_LDISC_MAGIC; hci_uart_ldisc.magic = TTY_LDISC_MAGIC;
hci_uart_ldisc.name = "n_hci"; hci_uart_ldisc.name = "n_hci";
hci_uart_ldisc.open = hci_uart_tty_open; hci_uart_ldisc.open = hci_uart_tty_open;
...@@ -804,6 +804,9 @@ static int __init hci_uart_init(void) ...@@ -804,6 +804,9 @@ static int __init hci_uart_init(void)
#ifdef CONFIG_BT_HCIUART_3WIRE #ifdef CONFIG_BT_HCIUART_3WIRE
h5_init(); h5_init();
#endif #endif
#ifdef CONFIG_BT_HCIUART_INTEL
intel_init();
#endif
#ifdef CONFIG_BT_HCIUART_BCM #ifdef CONFIG_BT_HCIUART_BCM
bcm_init(); bcm_init();
#endif #endif
...@@ -830,6 +833,9 @@ static void __exit hci_uart_exit(void) ...@@ -830,6 +833,9 @@ static void __exit hci_uart_exit(void)
#ifdef CONFIG_BT_HCIUART_3WIRE #ifdef CONFIG_BT_HCIUART_3WIRE
h5_deinit(); h5_deinit();
#endif #endif
#ifdef CONFIG_BT_HCIUART_INTEL
intel_deinit();
#endif
#ifdef CONFIG_BT_HCIUART_BCM #ifdef CONFIG_BT_HCIUART_BCM
bcm_deinit(); bcm_deinit();
#endif #endif
......
...@@ -167,6 +167,11 @@ int h5_init(void); ...@@ -167,6 +167,11 @@ int h5_init(void);
int h5_deinit(void); int h5_deinit(void);
#endif #endif
#ifdef CONFIG_BT_HCIUART_INTEL
int intel_init(void);
int intel_deinit(void);
#endif
#ifdef CONFIG_BT_HCIUART_BCM #ifdef CONFIG_BT_HCIUART_BCM
int bcm_init(void); int bcm_init(void);
int bcm_deinit(void); int bcm_deinit(void);
......
...@@ -545,7 +545,9 @@ at86rf230_async_state_delay(void *context) ...@@ -545,7 +545,9 @@ at86rf230_async_state_delay(void *context)
} }
/* Default delay is 1us in the most cases */ /* Default delay is 1us in the most cases */
tim = ktime_set(0, NSEC_PER_USEC); udelay(1);
at86rf230_async_state_timer(&ctx->timer);
return;
change: change:
hrtimer_start(&ctx->timer, tim, HRTIMER_MODE_REL); hrtimer_start(&ctx->timer, tim, HRTIMER_MODE_REL);
......
...@@ -1151,7 +1151,6 @@ MODULE_DEVICE_TABLE(of, cc2520_of_ids); ...@@ -1151,7 +1151,6 @@ MODULE_DEVICE_TABLE(of, cc2520_of_ids);
static struct spi_driver cc2520_driver = { static struct spi_driver cc2520_driver = {
.driver = { .driver = {
.name = "cc2520", .name = "cc2520",
.bus = &spi_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(cc2520_of_ids), .of_match_table = of_match_ptr(cc2520_of_ids),
}, },
......
...@@ -812,7 +812,6 @@ MODULE_DEVICE_TABLE(spi, mrf24j40_ids); ...@@ -812,7 +812,6 @@ MODULE_DEVICE_TABLE(spi, mrf24j40_ids);
static struct spi_driver mrf24j40_driver = { static struct spi_driver mrf24j40_driver = {
.driver = { .driver = {
.name = "mrf24j40", .name = "mrf24j40",
.bus = &spi_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
.id_table = mrf24j40_ids, .id_table = mrf24j40_ids,
......
...@@ -1297,7 +1297,7 @@ static inline int hci_check_conn_params(u16 min, u16 max, u16 latency, ...@@ -1297,7 +1297,7 @@ static inline int hci_check_conn_params(u16 min, u16 max, u16 latency,
if (max >= to_multiplier * 8) if (max >= to_multiplier * 8)
return -EINVAL; return -EINVAL;
max_latency = (to_multiplier * 8 / max) - 1; max_latency = (to_multiplier * 4 / max) - 1;
if (latency > 499 || latency > max_latency) if (latency > 499 || latency > max_latency)
return -EINVAL; return -EINVAL;
......
...@@ -55,6 +55,8 @@ ...@@ -55,6 +55,8 @@
#define L2CAP_INFO_TIMEOUT msecs_to_jiffies(4000) #define L2CAP_INFO_TIMEOUT msecs_to_jiffies(4000)
#define L2CAP_MOVE_TIMEOUT msecs_to_jiffies(4000) #define L2CAP_MOVE_TIMEOUT msecs_to_jiffies(4000)
#define L2CAP_MOVE_ERTX_TIMEOUT msecs_to_jiffies(60000) #define L2CAP_MOVE_ERTX_TIMEOUT msecs_to_jiffies(60000)
#define L2CAP_WAIT_ACK_POLL_PERIOD msecs_to_jiffies(200)
#define L2CAP_WAIT_ACK_TIMEOUT msecs_to_jiffies(10000)
#define L2CAP_A2MP_DEFAULT_MTU 670 #define L2CAP_A2MP_DEFAULT_MTU 670
......
...@@ -34,6 +34,8 @@ struct cfg802154_ops { ...@@ -34,6 +34,8 @@ struct cfg802154_ops {
int type); int type);
void (*del_virtual_intf_deprecated)(struct wpan_phy *wpan_phy, void (*del_virtual_intf_deprecated)(struct wpan_phy *wpan_phy,
struct net_device *dev); struct net_device *dev);
int (*suspend)(struct wpan_phy *wpan_phy);
int (*resume)(struct wpan_phy *wpan_phy);
int (*add_virtual_intf)(struct wpan_phy *wpan_phy, int (*add_virtual_intf)(struct wpan_phy *wpan_phy,
const char *name, const char *name,
unsigned char name_assign_type, unsigned char name_assign_type,
......
...@@ -320,23 +320,6 @@ int ieee802154_register_hw(struct ieee802154_hw *hw); ...@@ -320,23 +320,6 @@ int ieee802154_register_hw(struct ieee802154_hw *hw);
*/ */
void ieee802154_unregister_hw(struct ieee802154_hw *hw); void ieee802154_unregister_hw(struct ieee802154_hw *hw);
/**
* ieee802154_rx - receive frame
*
* Use this function to hand received frames to mac802154. The receive
* buffer in @skb must start with an IEEE 802.15.4 header. In case of a
* paged @skb is used, the driver is recommended to put the ieee802154
* header of the frame on the linear part of the @skb to avoid memory
* allocation and/or memcpy by the stack.
*
* This function may not be called in IRQ context. Calls to this function
* for a single hardware must be synchronized against each other.
*
* @hw: the hardware this frame came in on
* @skb: the buffer to receive, owned by mac802154 after this call
*/
void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb);
/** /**
* ieee802154_rx_irqsafe - receive frame * ieee802154_rx_irqsafe - receive frame
* *
......
...@@ -613,6 +613,8 @@ EXPORT_SYMBOL_GPL(lowpan_header_compress); ...@@ -613,6 +613,8 @@ EXPORT_SYMBOL_GPL(lowpan_header_compress);
static int __init lowpan_module_init(void) static int __init lowpan_module_init(void)
{ {
request_module_nowait("ipv6");
request_module_nowait("nhc_dest"); request_module_nowait("nhc_dest");
request_module_nowait("nhc_fragment"); request_module_nowait("nhc_fragment");
request_module_nowait("nhc_hop"); request_module_nowait("nhc_hop");
......
...@@ -859,9 +859,22 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev) ...@@ -859,9 +859,22 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev)
SET_NETDEV_DEV(netdev, &chan->conn->hcon->hdev->dev); SET_NETDEV_DEV(netdev, &chan->conn->hcon->hdev->dev);
SET_NETDEV_DEVTYPE(netdev, &bt_type); SET_NETDEV_DEVTYPE(netdev, &bt_type);
*dev = netdev_priv(netdev);
(*dev)->netdev = netdev;
(*dev)->hdev = chan->conn->hcon->hdev;
INIT_LIST_HEAD(&(*dev)->peers);
spin_lock(&devices_lock);
INIT_LIST_HEAD(&(*dev)->list);
list_add_rcu(&(*dev)->list, &bt_6lowpan_devices);
spin_unlock(&devices_lock);
err = register_netdev(netdev); err = register_netdev(netdev);
if (err < 0) { if (err < 0) {
BT_INFO("register_netdev failed %d", err); BT_INFO("register_netdev failed %d", err);
spin_lock(&devices_lock);
list_del_rcu(&(*dev)->list);
spin_unlock(&devices_lock);
free_netdev(netdev); free_netdev(netdev);
goto out; goto out;
} }
...@@ -871,16 +884,6 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev) ...@@ -871,16 +884,6 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev)
&chan->src, chan->src_type); &chan->src, chan->src_type);
set_bit(__LINK_STATE_PRESENT, &netdev->state); set_bit(__LINK_STATE_PRESENT, &netdev->state);
*dev = netdev_priv(netdev);
(*dev)->netdev = netdev;
(*dev)->hdev = chan->conn->hcon->hdev;
INIT_LIST_HEAD(&(*dev)->peers);
spin_lock(&devices_lock);
INIT_LIST_HEAD(&(*dev)->list);
list_add_rcu(&(*dev)->list, &bt_6lowpan_devices);
spin_unlock(&devices_lock);
return 0; return 0;
out: out:
......
...@@ -53,6 +53,11 @@ source "net/bluetooth/cmtp/Kconfig" ...@@ -53,6 +53,11 @@ source "net/bluetooth/cmtp/Kconfig"
source "net/bluetooth/hidp/Kconfig" source "net/bluetooth/hidp/Kconfig"
config BT_HS
bool "Bluetooth High Speed (HS) features"
depends on BT_BREDR
default y
config BT_LE config BT_LE
bool "Bluetooth Low Energy (LE) features" bool "Bluetooth Low Energy (LE) features"
depends on BT depends on BT
......
...@@ -13,9 +13,10 @@ bluetooth_6lowpan-y := 6lowpan.o ...@@ -13,9 +13,10 @@ bluetooth_6lowpan-y := 6lowpan.o
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \ hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
a2mp.o amp.o ecc.o hci_request.o mgmt_util.o ecc.o hci_request.o mgmt_util.o
bluetooth-$(CONFIG_BT_BREDR) += sco.o bluetooth-$(CONFIG_BT_BREDR) += sco.o
bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o
bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h> #include <net/bluetooth/l2cap.h>
#include "hci_request.h"
#include "a2mp.h" #include "a2mp.h"
#include "amp.h" #include "amp.h"
...@@ -286,11 +287,21 @@ static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb, ...@@ -286,11 +287,21 @@ static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
return 0; return 0;
} }
static void read_local_amp_info_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
BT_DBG("%s status 0x%2.2x", hdev->name, status);
a2mp_send_getinfo_rsp(hdev);
}
static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb, static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
struct a2mp_cmd *hdr) struct a2mp_cmd *hdr)
{ {
struct a2mp_info_req *req = (void *) skb->data; struct a2mp_info_req *req = (void *) skb->data;
struct hci_dev *hdev; struct hci_dev *hdev;
struct hci_request hreq;
int err = 0;
if (le16_to_cpu(hdr->len) < sizeof(*req)) if (le16_to_cpu(hdr->len) < sizeof(*req))
return -EINVAL; return -EINVAL;
...@@ -311,7 +322,11 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb, ...@@ -311,7 +322,11 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
} }
set_bit(READ_LOC_AMP_INFO, &mgr->state); set_bit(READ_LOC_AMP_INFO, &mgr->state);
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL); hci_req_init(&hreq, hdev);
hci_req_add(&hreq, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
err = hci_req_run(&hreq, read_local_amp_info_complete);
if (err < 0)
a2mp_send_getinfo_rsp(hdev);
done: done:
if (hdev) if (hdev)
......
...@@ -130,10 +130,29 @@ struct a2mp_physlink_rsp { ...@@ -130,10 +130,29 @@ struct a2mp_physlink_rsp {
#define A2MP_STATUS_SECURITY_VIOLATION 0x06 #define A2MP_STATUS_SECURITY_VIOLATION 0x06
struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr); struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr);
#if IS_ENABLED(CONFIG_BT_HS)
int amp_mgr_put(struct amp_mgr *mgr); int amp_mgr_put(struct amp_mgr *mgr);
struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
struct sk_buff *skb); struct sk_buff *skb);
void a2mp_discover_amp(struct l2cap_chan *chan); void a2mp_discover_amp(struct l2cap_chan *chan);
#else
static inline int amp_mgr_put(struct amp_mgr *mgr)
{
return 0;
}
static inline struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
struct sk_buff *skb)
{
return NULL;
}
static inline void a2mp_discover_amp(struct l2cap_chan *chan)
{
}
#endif
void a2mp_send_getinfo_rsp(struct hci_dev *hdev); void a2mp_send_getinfo_rsp(struct hci_dev *hdev);
void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status); void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status);
void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status); void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#include <crypto/hash.h> #include <crypto/hash.h>
#include "hci_request.h"
#include "a2mp.h" #include "a2mp.h"
#include "amp.h" #include "amp.h"
...@@ -220,10 +221,49 @@ int phylink_gen_key(struct hci_conn *conn, u8 *data, u8 *len, u8 *type) ...@@ -220,10 +221,49 @@ int phylink_gen_key(struct hci_conn *conn, u8 *data, u8 *len, u8 *type)
return hmac_sha256(gamp_key, HCI_AMP_LINK_KEY_SIZE, "802b", 4, data); return hmac_sha256(gamp_key, HCI_AMP_LINK_KEY_SIZE, "802b", 4, data);
} }
static void read_local_amp_assoc_complete(struct hci_dev *hdev, u8 status,
u16 opcode, struct sk_buff *skb)
{
struct hci_rp_read_local_amp_assoc *rp = (void *)skb->data;
struct amp_assoc *assoc = &hdev->loc_assoc;
size_t rem_len, frag_len;
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status)
goto send_rsp;
frag_len = skb->len - sizeof(*rp);
rem_len = __le16_to_cpu(rp->rem_len);
if (rem_len > frag_len) {
BT_DBG("frag_len %zu rem_len %zu", frag_len, rem_len);
memcpy(assoc->data + assoc->offset, rp->frag, frag_len);
assoc->offset += frag_len;
/* Read other fragments */
amp_read_loc_assoc_frag(hdev, rp->phy_handle);
return;
}
memcpy(assoc->data + assoc->offset, rp->frag, rem_len);
assoc->len = assoc->offset + rem_len;
assoc->offset = 0;
send_rsp:
/* Send A2MP Rsp when all fragments are received */
a2mp_send_getampassoc_rsp(hdev, rp->status);
a2mp_send_create_phy_link_req(hdev, rp->status);
}
void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle) void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle)
{ {
struct hci_cp_read_local_amp_assoc cp; struct hci_cp_read_local_amp_assoc cp;
struct amp_assoc *loc_assoc = &hdev->loc_assoc; struct amp_assoc *loc_assoc = &hdev->loc_assoc;
struct hci_request req;
int err = 0;
BT_DBG("%s handle %d", hdev->name, phy_handle); BT_DBG("%s handle %d", hdev->name, phy_handle);
...@@ -231,12 +271,18 @@ void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle) ...@@ -231,12 +271,18 @@ void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle)
cp.max_len = cpu_to_le16(hdev->amp_assoc_size); cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
cp.len_so_far = cpu_to_le16(loc_assoc->offset); cp.len_so_far = cpu_to_le16(loc_assoc->offset);
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); hci_req_init(&req, hdev);
hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
err = hci_req_run_skb(&req, read_local_amp_assoc_complete);
if (err < 0)
a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID);
} }
void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr) void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
{ {
struct hci_cp_read_local_amp_assoc cp; struct hci_cp_read_local_amp_assoc cp;
struct hci_request req;
int err = 0;
memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc)); memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc));
memset(&cp, 0, sizeof(cp)); memset(&cp, 0, sizeof(cp));
...@@ -244,7 +290,11 @@ void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr) ...@@ -244,7 +290,11 @@ void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
cp.max_len = cpu_to_le16(hdev->amp_assoc_size); cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
set_bit(READ_LOC_AMP_ASSOC, &mgr->state); set_bit(READ_LOC_AMP_ASSOC, &mgr->state);
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); hci_req_init(&req, hdev);
hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
hci_req_run_skb(&req, read_local_amp_assoc_complete);
if (err < 0)
a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID);
} }
void amp_read_loc_assoc_final_data(struct hci_dev *hdev, void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
...@@ -252,6 +302,8 @@ void amp_read_loc_assoc_final_data(struct hci_dev *hdev, ...@@ -252,6 +302,8 @@ void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
{ {
struct hci_cp_read_local_amp_assoc cp; struct hci_cp_read_local_amp_assoc cp;
struct amp_mgr *mgr = hcon->amp_mgr; struct amp_mgr *mgr = hcon->amp_mgr;
struct hci_request req;
int err = 0;
cp.phy_handle = hcon->handle; cp.phy_handle = hcon->handle;
cp.len_so_far = cpu_to_le16(0); cp.len_so_far = cpu_to_le16(0);
...@@ -260,7 +312,25 @@ void amp_read_loc_assoc_final_data(struct hci_dev *hdev, ...@@ -260,7 +312,25 @@ void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
set_bit(READ_LOC_AMP_ASSOC_FINAL, &mgr->state); set_bit(READ_LOC_AMP_ASSOC_FINAL, &mgr->state);
/* Read Local AMP Assoc final link information data */ /* Read Local AMP Assoc final link information data */
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); hci_req_init(&req, hdev);
hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
hci_req_run_skb(&req, read_local_amp_assoc_complete);
if (err < 0)
a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID);
}
static void write_remote_amp_assoc_complete(struct hci_dev *hdev, u8 status,
u16 opcode, struct sk_buff *skb)
{
struct hci_rp_write_remote_amp_assoc *rp = (void *)skb->data;
BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x",
hdev->name, rp->status, rp->phy_handle);
if (rp->status)
return;
amp_write_rem_assoc_continue(hdev, rp->phy_handle);
} }
/* Write AMP Assoc data fragments, returns true with last fragment written*/ /* Write AMP Assoc data fragments, returns true with last fragment written*/
...@@ -270,6 +340,7 @@ static bool amp_write_rem_assoc_frag(struct hci_dev *hdev, ...@@ -270,6 +340,7 @@ static bool amp_write_rem_assoc_frag(struct hci_dev *hdev,
struct hci_cp_write_remote_amp_assoc *cp; struct hci_cp_write_remote_amp_assoc *cp;
struct amp_mgr *mgr = hcon->amp_mgr; struct amp_mgr *mgr = hcon->amp_mgr;
struct amp_ctrl *ctrl; struct amp_ctrl *ctrl;
struct hci_request req;
u16 frag_len, len; u16 frag_len, len;
ctrl = amp_ctrl_lookup(mgr, hcon->remote_id); ctrl = amp_ctrl_lookup(mgr, hcon->remote_id);
...@@ -307,7 +378,9 @@ static bool amp_write_rem_assoc_frag(struct hci_dev *hdev, ...@@ -307,7 +378,9 @@ static bool amp_write_rem_assoc_frag(struct hci_dev *hdev,
amp_ctrl_put(ctrl); amp_ctrl_put(ctrl);
hci_send_cmd(hdev, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp); hci_req_init(&req, hdev);
hci_req_add(&req, HCI_OP_WRITE_REMOTE_AMP_ASSOC, sizeof(cp), &cp);
hci_req_run_skb(&req, write_remote_amp_assoc_complete);
kfree(cp); kfree(cp);
...@@ -344,10 +417,37 @@ void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle) ...@@ -344,10 +417,37 @@ void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle)
amp_write_rem_assoc_frag(hdev, hcon); amp_write_rem_assoc_frag(hdev, hcon);
} }
static void create_phylink_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct hci_cp_create_phy_link *cp;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);
if (!cp)
return;
hci_dev_lock(hdev);
if (status) {
struct hci_conn *hcon;
hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle);
if (hcon)
hci_conn_del(hcon);
} else {
amp_write_remote_assoc(hdev, cp->phy_handle);
}
hci_dev_unlock(hdev);
}
void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon) struct hci_conn *hcon)
{ {
struct hci_cp_create_phy_link cp; struct hci_cp_create_phy_link cp;
struct hci_request req;
cp.phy_handle = hcon->handle; cp.phy_handle = hcon->handle;
...@@ -360,13 +460,33 @@ void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, ...@@ -360,13 +460,33 @@ void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
return; return;
} }
hci_send_cmd(hdev, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp); hci_req_init(&req, hdev);
hci_req_add(&req, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp);
hci_req_run(&req, create_phylink_complete);
}
static void accept_phylink_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct hci_cp_accept_phy_link *cp;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (status)
return;
cp = hci_sent_cmd_data(hdev, HCI_OP_ACCEPT_PHY_LINK);
if (!cp)
return;
amp_write_remote_assoc(hdev, cp->phy_handle);
} }
void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon) struct hci_conn *hcon)
{ {
struct hci_cp_accept_phy_link cp; struct hci_cp_accept_phy_link cp;
struct hci_request req;
cp.phy_handle = hcon->handle; cp.phy_handle = hcon->handle;
...@@ -379,7 +499,9 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, ...@@ -379,7 +499,9 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
return; return;
} }
hci_send_cmd(hdev, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp); hci_req_init(&req, hdev);
hci_req_add(&req, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp);
hci_req_run(&req, accept_phylink_complete);
} }
void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon) void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon)
......
...@@ -44,6 +44,20 @@ void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, ...@@ -44,6 +44,20 @@ void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon); struct hci_conn *hcon);
void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon); struct hci_conn *hcon);
#if IS_ENABLED(CONFIG_BT_HS)
void amp_create_logical_link(struct l2cap_chan *chan);
void amp_disconnect_logical_link(struct hci_chan *hchan);
#else
static inline void amp_create_logical_link(struct l2cap_chan *chan)
{
}
static inline void amp_disconnect_logical_link(struct hci_chan *hchan)
{
}
#endif
void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle); void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);
void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle); void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle);
void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon); void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon);
......
...@@ -100,9 +100,9 @@ static void cmtp_application_del(struct cmtp_session *session, struct cmtp_appli ...@@ -100,9 +100,9 @@ static void cmtp_application_del(struct cmtp_session *session, struct cmtp_appli
static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value) static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
{ {
struct cmtp_application *app; struct cmtp_application *app;
struct list_head *p, *n; struct list_head *p;
list_for_each_safe(p, n, &session->applications) { list_for_each(p, &session->applications) {
app = list_entry(p, struct cmtp_application, list); app = list_entry(p, struct cmtp_application, list);
switch (pattern) { switch (pattern) {
case CMTP_MSGNUM: case CMTP_MSGNUM:
...@@ -511,13 +511,13 @@ static int cmtp_proc_show(struct seq_file *m, void *v) ...@@ -511,13 +511,13 @@ static int cmtp_proc_show(struct seq_file *m, void *v)
struct capi_ctr *ctrl = m->private; struct capi_ctr *ctrl = m->private;
struct cmtp_session *session = ctrl->driverdata; struct cmtp_session *session = ctrl->driverdata;
struct cmtp_application *app; struct cmtp_application *app;
struct list_head *p, *n; struct list_head *p;
seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl)); seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
seq_printf(m, "addr %s\n", session->name); seq_printf(m, "addr %s\n", session->name);
seq_printf(m, "ctrl %d\n", session->num); seq_printf(m, "ctrl %d\n", session->num);
list_for_each_safe(p, n, &session->applications) { list_for_each(p, &session->applications) {
app = list_entry(p, struct cmtp_application, list); app = list_entry(p, struct cmtp_application, list);
seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping); seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
} }
......
...@@ -2822,10 +2822,6 @@ struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, ...@@ -2822,10 +2822,6 @@ struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
{ {
struct hci_conn_params *params; struct hci_conn_params *params;
/* The conn params list only contains identity addresses */
if (!hci_is_identity_address(addr, addr_type))
return NULL;
list_for_each_entry(params, &hdev->le_conn_params, list) { list_for_each_entry(params, &hdev->le_conn_params, list) {
if (bacmp(&params->addr, addr) == 0 && if (bacmp(&params->addr, addr) == 0 &&
params->addr_type == addr_type) { params->addr_type == addr_type) {
...@@ -2842,10 +2838,6 @@ struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list, ...@@ -2842,10 +2838,6 @@ struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list,
{ {
struct hci_conn_params *param; struct hci_conn_params *param;
/* The list only contains identity addresses */
if (!hci_is_identity_address(addr, addr_type))
return NULL;
list_for_each_entry(param, list, action) { list_for_each_entry(param, list, action) {
if (bacmp(&param->addr, addr) == 0 && if (bacmp(&param->addr, addr) == 0 &&
param->addr_type == addr_type) param->addr_type == addr_type)
...@@ -2861,9 +2853,6 @@ struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev, ...@@ -2861,9 +2853,6 @@ struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev,
{ {
struct hci_conn_params *params; struct hci_conn_params *params;
if (!hci_is_identity_address(addr, addr_type))
return NULL;
params = hci_conn_params_lookup(hdev, addr, addr_type); params = hci_conn_params_lookup(hdev, addr, addr_type);
if (params) if (params)
return params; return params;
......
...@@ -823,7 +823,7 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev, ...@@ -823,7 +823,7 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status) if (rp->status)
goto a2mp_rsp; return;
hdev->amp_status = rp->amp_status; hdev->amp_status = rp->amp_status;
hdev->amp_total_bw = __le32_to_cpu(rp->total_bw); hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
...@@ -835,46 +835,6 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev, ...@@ -835,46 +835,6 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size); hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size);
hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to); hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to); hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
a2mp_rsp:
a2mp_send_getinfo_rsp(hdev);
}
static void hci_cc_read_local_amp_assoc(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_rp_read_local_amp_assoc *rp = (void *) skb->data;
struct amp_assoc *assoc = &hdev->loc_assoc;
size_t rem_len, frag_len;
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status)
goto a2mp_rsp;
frag_len = skb->len - sizeof(*rp);
rem_len = __le16_to_cpu(rp->rem_len);
if (rem_len > frag_len) {
BT_DBG("frag_len %zu rem_len %zu", frag_len, rem_len);
memcpy(assoc->data + assoc->offset, rp->frag, frag_len);
assoc->offset += frag_len;
/* Read other fragments */
amp_read_loc_assoc_frag(hdev, rp->phy_handle);
return;
}
memcpy(assoc->data + assoc->offset, rp->frag, rem_len);
assoc->len = assoc->offset + rem_len;
assoc->offset = 0;
a2mp_rsp:
/* Send A2MP Rsp when all fragments are received */
a2mp_send_getampassoc_rsp(hdev, rp->status);
a2mp_send_create_phy_link_req(hdev, rp->status);
} }
static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
...@@ -1409,20 +1369,6 @@ static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -1409,20 +1369,6 @@ static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_rp_write_remote_amp_assoc *rp = (void *) skb->data;
BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x",
hdev->name, rp->status, rp->phy_handle);
if (rp->status)
return;
amp_write_rem_assoc_continue(hdev, rp->phy_handle);
}
static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_rp_read_rssi *rp = (void *) skb->data; struct hci_rp_read_rssi *rp = (void *) skb->data;
...@@ -1944,47 +1890,6 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status) ...@@ -1944,47 +1890,6 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
{
struct hci_cp_create_phy_link *cp;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);
if (!cp)
return;
hci_dev_lock(hdev);
if (status) {
struct hci_conn *hcon;
hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle);
if (hcon)
hci_conn_del(hcon);
} else {
amp_write_remote_assoc(hdev, cp->phy_handle);
}
hci_dev_unlock(hdev);
}
static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
{
struct hci_cp_accept_phy_link *cp;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (status)
return;
cp = hci_sent_cmd_data(hdev, HCI_OP_ACCEPT_PHY_LINK);
if (!cp)
return;
amp_write_remote_assoc(hdev, cp->phy_handle);
}
static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status) static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status)
{ {
struct hci_cp_le_create_conn *cp; struct hci_cp_le_create_conn *cp;
...@@ -2998,10 +2903,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb, ...@@ -2998,10 +2903,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
hci_cc_read_clock(hdev, skb); hci_cc_read_clock(hdev, skb);
break; break;
case HCI_OP_READ_LOCAL_AMP_ASSOC:
hci_cc_read_local_amp_assoc(hdev, skb);
break;
case HCI_OP_READ_INQ_RSP_TX_POWER: case HCI_OP_READ_INQ_RSP_TX_POWER:
hci_cc_read_inq_rsp_tx_power(hdev, skb); hci_cc_read_inq_rsp_tx_power(hdev, skb);
break; break;
...@@ -3106,10 +3007,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb, ...@@ -3106,10 +3007,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
hci_cc_set_adv_param(hdev, skb); hci_cc_set_adv_param(hdev, skb);
break; break;
case HCI_OP_WRITE_REMOTE_AMP_ASSOC:
hci_cc_write_remote_amp_assoc(hdev, skb);
break;
case HCI_OP_READ_RSSI: case HCI_OP_READ_RSSI:
hci_cc_read_rssi(hdev, skb); hci_cc_read_rssi(hdev, skb);
break; break;
...@@ -3193,14 +3090,6 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb, ...@@ -3193,14 +3090,6 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb,
hci_cs_setup_sync_conn(hdev, ev->status); hci_cs_setup_sync_conn(hdev, ev->status);
break; break;
case HCI_OP_CREATE_PHY_LINK:
hci_cs_create_phylink(hdev, ev->status);
break;
case HCI_OP_ACCEPT_PHY_LINK:
hci_cs_accept_phylink(hdev, ev->status);
break;
case HCI_OP_SNIFF_MODE: case HCI_OP_SNIFF_MODE:
hci_cs_sniff_mode(hdev, ev->status); hci_cs_sniff_mode(hdev, ev->status);
break; break;
...@@ -4399,6 +4288,23 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev, ...@@ -4399,6 +4288,23 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
#if IS_ENABLED(CONFIG_BT_HS)
static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_channel_selected *ev = (void *)skb->data;
struct hci_conn *hcon;
BT_DBG("%s handle 0x%2.2x", hdev->name, ev->phy_handle);
skb_pull(skb, sizeof(*ev));
hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
if (!hcon)
return;
amp_read_loc_assoc_final_data(hdev, hcon);
}
static void hci_phy_link_complete_evt(struct hci_dev *hdev, static void hci_phy_link_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb) struct sk_buff *skb)
{ {
...@@ -4522,6 +4428,7 @@ static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev, ...@@ -4522,6 +4428,7 @@ static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev,
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
#endif
static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
...@@ -5206,22 +5113,6 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -5206,22 +5113,6 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
} }
} }
static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_channel_selected *ev = (void *) skb->data;
struct hci_conn *hcon;
BT_DBG("%s handle 0x%2.2x", hdev->name, ev->phy_handle);
skb_pull(skb, sizeof(*ev));
hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
if (!hcon)
return;
amp_read_loc_assoc_final_data(hdev, hcon);
}
static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode, static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
u8 event, struct sk_buff *skb) u8 event, struct sk_buff *skb)
{ {
...@@ -5442,14 +5333,15 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -5442,14 +5333,15 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_le_meta_evt(hdev, skb); hci_le_meta_evt(hdev, skb);
break; break;
case HCI_EV_CHANNEL_SELECTED:
hci_chan_selected_evt(hdev, skb);
break;
case HCI_EV_REMOTE_OOB_DATA_REQUEST: case HCI_EV_REMOTE_OOB_DATA_REQUEST:
hci_remote_oob_data_request_evt(hdev, skb); hci_remote_oob_data_request_evt(hdev, skb);
break; break;
#if IS_ENABLED(CONFIG_BT_HS)
case HCI_EV_CHANNEL_SELECTED:
hci_chan_selected_evt(hdev, skb);
break;
case HCI_EV_PHY_LINK_COMPLETE: case HCI_EV_PHY_LINK_COMPLETE:
hci_phy_link_complete_evt(hdev, skb); hci_phy_link_complete_evt(hdev, skb);
break; break;
...@@ -5465,6 +5357,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -5465,6 +5357,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
case HCI_EV_DISCONN_PHY_LINK_COMPLETE: case HCI_EV_DISCONN_PHY_LINK_COMPLETE:
hci_disconn_phylink_complete_evt(hdev, skb); hci_disconn_phylink_complete_evt(hdev, skb);
break; break;
#endif
case HCI_EV_NUM_COMP_BLOCKS: case HCI_EV_NUM_COMP_BLOCKS:
hci_num_comp_blocks_evt(hdev, skb); hci_num_comp_blocks_evt(hdev, skb);
......
...@@ -1054,18 +1054,23 @@ static void l2cap_sock_kill(struct sock *sk) ...@@ -1054,18 +1054,23 @@ static void l2cap_sock_kill(struct sock *sk)
sock_put(sk); sock_put(sk);
} }
static int __l2cap_wait_ack(struct sock *sk) static int __l2cap_wait_ack(struct sock *sk, struct l2cap_chan *chan)
{ {
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
int err = 0; int err = 0;
int timeo = HZ/5; int timeo = L2CAP_WAIT_ACK_POLL_PERIOD;
/* Timeout to prevent infinite loop */
unsigned long timeout = jiffies + L2CAP_WAIT_ACK_TIMEOUT;
add_wait_queue(sk_sleep(sk), &wait); add_wait_queue(sk_sleep(sk), &wait);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
while (chan->unacked_frames > 0 && chan->conn) { do {
BT_DBG("Waiting for %d ACKs, timeout %04d ms",
chan->unacked_frames, time_after(jiffies, timeout) ? 0 :
jiffies_to_msecs(timeout - jiffies));
if (!timeo) if (!timeo)
timeo = HZ/5; timeo = L2CAP_WAIT_ACK_POLL_PERIOD;
if (signal_pending(current)) { if (signal_pending(current)) {
err = sock_intr_errno(timeo); err = sock_intr_errno(timeo);
...@@ -1080,7 +1085,15 @@ static int __l2cap_wait_ack(struct sock *sk) ...@@ -1080,7 +1085,15 @@ static int __l2cap_wait_ack(struct sock *sk)
err = sock_error(sk); err = sock_error(sk);
if (err) if (err)
break; break;
}
if (time_after(jiffies, timeout)) {
err = -ENOLINK;
break;
}
} while (chan->unacked_frames > 0 &&
chan->state == BT_CONNECTED);
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait); remove_wait_queue(sk_sleep(sk), &wait);
return err; return err;
...@@ -1098,7 +1111,12 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) ...@@ -1098,7 +1111,12 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
if (!sk) if (!sk)
return 0; return 0;
/* prevent sk structure from being freed whilst unlocked */
sock_hold(sk);
chan = l2cap_pi(sk)->chan; chan = l2cap_pi(sk)->chan;
/* prevent chan structure from being freed whilst unlocked */
l2cap_chan_hold(chan);
conn = chan->conn; conn = chan->conn;
BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
...@@ -1110,8 +1128,10 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) ...@@ -1110,8 +1128,10 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
lock_sock(sk); lock_sock(sk);
if (!sk->sk_shutdown) { if (!sk->sk_shutdown) {
if (chan->mode == L2CAP_MODE_ERTM) if (chan->mode == L2CAP_MODE_ERTM &&
err = __l2cap_wait_ack(sk); chan->unacked_frames > 0 &&
chan->state == BT_CONNECTED)
err = __l2cap_wait_ack(sk, chan);
sk->sk_shutdown = SHUTDOWN_MASK; sk->sk_shutdown = SHUTDOWN_MASK;
...@@ -1134,6 +1154,11 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) ...@@ -1134,6 +1154,11 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
if (conn) if (conn)
mutex_unlock(&conn->chan_lock); mutex_unlock(&conn->chan_lock);
l2cap_chan_put(chan);
sock_put(sk);
BT_DBG("err: %d", err);
return err; return err;
} }
......
...@@ -6226,6 +6226,17 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, ...@@ -6226,6 +6226,17 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
else else
auto_conn = HCI_AUTO_CONN_REPORT; auto_conn = HCI_AUTO_CONN_REPORT;
/* Kernel internally uses conn_params with resolvable private
* address, but Add Device allows only identity addresses.
* Make sure it is enforced before calling
* hci_conn_params_lookup.
*/
if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
err = cmd->cmd_complete(cmd, MGMT_STATUS_INVALID_PARAMS);
mgmt_pending_remove(cmd);
goto unlock;
}
/* If the connection parameters don't exist for this device, /* If the connection parameters don't exist for this device,
* they will be created and configured with defaults. * they will be created and configured with defaults.
*/ */
...@@ -6340,6 +6351,18 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, ...@@ -6340,6 +6351,18 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
else else
addr_type = ADDR_LE_DEV_RANDOM; addr_type = ADDR_LE_DEV_RANDOM;
/* Kernel internally uses conn_params with resolvable private
* address, but Remove Device allows only identity addresses.
* Make sure it is enforced before calling
* hci_conn_params_lookup.
*/
if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) {
err = cmd->cmd_complete(cmd,
MGMT_STATUS_INVALID_PARAMS);
mgmt_pending_remove(cmd);
goto unlock;
}
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
addr_type); addr_type);
if (!params) { if (!params) {
......
...@@ -23,6 +23,26 @@ rdev_del_virtual_intf_deprecated(struct cfg802154_registered_device *rdev, ...@@ -23,6 +23,26 @@ rdev_del_virtual_intf_deprecated(struct cfg802154_registered_device *rdev,
rdev->ops->del_virtual_intf_deprecated(&rdev->wpan_phy, dev); rdev->ops->del_virtual_intf_deprecated(&rdev->wpan_phy, dev);
} }
static inline int
rdev_suspend(struct cfg802154_registered_device *rdev)
{
int ret;
trace_802154_rdev_suspend(&rdev->wpan_phy);
ret = rdev->ops->suspend(&rdev->wpan_phy);
trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
return ret;
}
static inline int
rdev_resume(struct cfg802154_registered_device *rdev)
{
int ret;
trace_802154_rdev_resume(&rdev->wpan_phy);
ret = rdev->ops->resume(&rdev->wpan_phy);
trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
return ret;
}
static inline int static inline int
rdev_add_virtual_intf(struct cfg802154_registered_device *rdev, char *name, rdev_add_virtual_intf(struct cfg802154_registered_device *rdev, char *name,
unsigned char name_assign_type, unsigned char name_assign_type,
......
...@@ -14,11 +14,13 @@ ...@@ -14,11 +14,13 @@
*/ */
#include <linux/device.h> #include <linux/device.h>
#include <linux/rtnetlink.h>
#include <net/cfg802154.h> #include <net/cfg802154.h>
#include "core.h" #include "core.h"
#include "sysfs.h" #include "sysfs.h"
#include "rdev-ops.h"
static inline struct cfg802154_registered_device * static inline struct cfg802154_registered_device *
dev_to_rdev(struct device *dev) dev_to_rdev(struct device *dev)
...@@ -62,10 +64,46 @@ static struct attribute *pmib_attrs[] = { ...@@ -62,10 +64,46 @@ static struct attribute *pmib_attrs[] = {
}; };
ATTRIBUTE_GROUPS(pmib); ATTRIBUTE_GROUPS(pmib);
#ifdef CONFIG_PM_SLEEP
static int wpan_phy_suspend(struct device *dev)
{
struct cfg802154_registered_device *rdev = dev_to_rdev(dev);
int ret = 0;
if (rdev->ops->suspend) {
rtnl_lock();
ret = rdev_suspend(rdev);
rtnl_unlock();
}
return ret;
}
static int wpan_phy_resume(struct device *dev)
{
struct cfg802154_registered_device *rdev = dev_to_rdev(dev);
int ret = 0;
if (rdev->ops->resume) {
rtnl_lock();
ret = rdev_resume(rdev);
rtnl_unlock();
}
return ret;
}
static SIMPLE_DEV_PM_OPS(wpan_phy_pm_ops, wpan_phy_suspend, wpan_phy_resume);
#define WPAN_PHY_PM_OPS (&wpan_phy_pm_ops)
#else
#define WPAN_PHY_PM_OPS NULL
#endif
struct class wpan_phy_class = { struct class wpan_phy_class = {
.name = "ieee802154", .name = "ieee802154",
.dev_release = wpan_phy_release, .dev_release = wpan_phy_release,
.dev_groups = pmib_groups, .dev_groups = pmib_groups,
.pm = WPAN_PHY_PM_OPS,
}; };
int wpan_phy_sysfs_init(void) int wpan_phy_sysfs_init(void)
......
...@@ -40,6 +40,28 @@ ...@@ -40,6 +40,28 @@
* rdev->ops traces * * rdev->ops traces *
*************************************************************/ *************************************************************/
DECLARE_EVENT_CLASS(wpan_phy_only_evt,
TP_PROTO(struct wpan_phy *wpan_phy),
TP_ARGS(wpan_phy),
TP_STRUCT__entry(
WPAN_PHY_ENTRY
),
TP_fast_assign(
WPAN_PHY_ASSIGN;
),
TP_printk(WPAN_PHY_PR_FMT, WPAN_PHY_PR_ARG)
);
DEFINE_EVENT(wpan_phy_only_evt, 802154_rdev_suspend,
TP_PROTO(struct wpan_phy *wpan_phy),
TP_ARGS(wpan_phy)
);
DEFINE_EVENT(wpan_phy_only_evt, 802154_rdev_resume,
TP_PROTO(struct wpan_phy *wpan_phy),
TP_ARGS(wpan_phy)
);
TRACE_EVENT(802154_rdev_add_virtual_intf, TRACE_EVENT(802154_rdev_add_virtual_intf,
TP_PROTO(struct wpan_phy *wpan_phy, char *name, TP_PROTO(struct wpan_phy *wpan_phy, char *name,
enum nl802154_iftype type, __le64 extended_addr), enum nl802154_iftype type, __le64 extended_addr),
......
...@@ -44,6 +44,49 @@ static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy, ...@@ -44,6 +44,49 @@ static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy,
ieee802154_if_remove(sdata); ieee802154_if_remove(sdata);
} }
#ifdef CONFIG_PM
static int ieee802154_suspend(struct wpan_phy *wpan_phy)
{
struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
if (!local->open_count)
goto suspend;
ieee802154_stop_queue(&local->hw);
synchronize_net();
/* stop hardware - this must stop RX */
ieee802154_stop_device(local);
suspend:
local->suspended = true;
return 0;
}
static int ieee802154_resume(struct wpan_phy *wpan_phy)
{
struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
int ret;
/* nothing to do if HW shouldn't run */
if (!local->open_count)
goto wake_up;
/* restart hardware */
ret = drv_start(local);
if (ret)
return ret;
wake_up:
ieee802154_wake_queue(&local->hw);
local->suspended = false;
return 0;
}
#else
#define ieee802154_suspend NULL
#define ieee802154_resume NULL
#endif
static int static int
ieee802154_add_iface(struct wpan_phy *phy, const char *name, ieee802154_add_iface(struct wpan_phy *phy, const char *name,
unsigned char name_assign_type, unsigned char name_assign_type,
...@@ -145,13 +188,18 @@ static int ...@@ -145,13 +188,18 @@ static int
ieee802154_set_pan_id(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, ieee802154_set_pan_id(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
__le16 pan_id) __le16 pan_id)
{ {
int ret;
ASSERT_RTNL(); ASSERT_RTNL();
if (wpan_dev->pan_id == pan_id) if (wpan_dev->pan_id == pan_id)
return 0; return 0;
wpan_dev->pan_id = pan_id; ret = mac802154_wpan_update_llsec(wpan_dev->netdev);
return 0; if (!ret)
wpan_dev->pan_id = pan_id;
return ret;
} }
static int static int
...@@ -227,6 +275,8 @@ ieee802154_set_lbt_mode(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, ...@@ -227,6 +275,8 @@ ieee802154_set_lbt_mode(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
const struct cfg802154_ops mac802154_config_ops = { const struct cfg802154_ops mac802154_config_ops = {
.add_virtual_intf_deprecated = ieee802154_add_iface_deprecated, .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated,
.del_virtual_intf_deprecated = ieee802154_del_iface_deprecated, .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated,
.suspend = ieee802154_suspend,
.resume = ieee802154_resume,
.add_virtual_intf = ieee802154_add_iface, .add_virtual_intf = ieee802154_add_iface,
.del_virtual_intf = ieee802154_del_iface, .del_virtual_intf = ieee802154_del_iface,
.set_channel = ieee802154_set_channel, .set_channel = ieee802154_set_channel,
......
...@@ -56,9 +56,13 @@ struct ieee802154_local { ...@@ -56,9 +56,13 @@ struct ieee802154_local {
struct hrtimer ifs_timer; struct hrtimer ifs_timer;
bool started; bool started;
bool suspended;
struct tasklet_struct tasklet; struct tasklet_struct tasklet;
struct sk_buff_head skb_queue; struct sk_buff_head skb_queue;
struct sk_buff *tx_skb;
struct work_struct tx_work;
}; };
enum { enum {
...@@ -94,8 +98,6 @@ struct ieee802154_sub_if_data { ...@@ -94,8 +98,6 @@ struct ieee802154_sub_if_data {
struct mac802154_llsec sec; struct mac802154_llsec sec;
}; };
#define MAC802154_CHAN_NONE 0xff /* No channel is assigned */
/* utility functions/constants */ /* utility functions/constants */
extern const void *const mac802154_wpan_phy_privid; /* for wpan_phy privid */ extern const void *const mac802154_wpan_phy_privid; /* for wpan_phy privid */
...@@ -125,6 +127,8 @@ ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata) ...@@ -125,6 +127,8 @@ ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata)
extern struct ieee802154_mlme_ops mac802154_mlme_wpan; extern struct ieee802154_mlme_ops mac802154_mlme_wpan;
void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb);
void ieee802154_xmit_worker(struct work_struct *work);
netdev_tx_t netdev_tx_t
ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
netdev_tx_t netdev_tx_t
...@@ -167,6 +171,8 @@ void mac802154_get_table(struct net_device *dev, ...@@ -167,6 +171,8 @@ void mac802154_get_table(struct net_device *dev,
struct ieee802154_llsec_table **t); struct ieee802154_llsec_table **t);
void mac802154_unlock_table(struct net_device *dev); void mac802154_unlock_table(struct net_device *dev);
int mac802154_wpan_update_llsec(struct net_device *dev);
/* interface handling */ /* interface handling */
int ieee802154_iface_init(void); int ieee802154_iface_init(void);
void ieee802154_iface_exit(void); void ieee802154_iface_exit(void);
...@@ -176,5 +182,6 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name, ...@@ -176,5 +182,6 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name,
unsigned char name_assign_type, enum nl802154_iftype type, unsigned char name_assign_type, enum nl802154_iftype type,
__le64 extended_addr); __le64 extended_addr);
void ieee802154_remove_interfaces(struct ieee802154_local *local); void ieee802154_remove_interfaces(struct ieee802154_local *local);
void ieee802154_stop_device(struct ieee802154_local *local);
#endif /* __IEEE802154_I_H */ #endif /* __IEEE802154_I_H */
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include "ieee802154_i.h" #include "ieee802154_i.h"
#include "driver-ops.h" #include "driver-ops.h"
static int mac802154_wpan_update_llsec(struct net_device *dev) int mac802154_wpan_update_llsec(struct net_device *dev)
{ {
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev); struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
...@@ -314,11 +314,8 @@ static int mac802154_slave_close(struct net_device *dev) ...@@ -314,11 +314,8 @@ static int mac802154_slave_close(struct net_device *dev)
clear_bit(SDATA_STATE_RUNNING, &sdata->state); clear_bit(SDATA_STATE_RUNNING, &sdata->state);
if (!local->open_count) { if (!local->open_count)
flush_workqueue(local->workqueue); ieee802154_stop_device(local);
hrtimer_cancel(&local->ifs_timer);
drv_stop(local);
}
return 0; return 0;
} }
...@@ -471,6 +468,7 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, ...@@ -471,6 +468,7 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
enum nl802154_iftype type) enum nl802154_iftype type)
{ {
struct wpan_dev *wpan_dev = &sdata->wpan_dev; struct wpan_dev *wpan_dev = &sdata->wpan_dev;
int ret;
u8 tmp; u8 tmp;
/* set some type-dependent values */ /* set some type-dependent values */
...@@ -505,6 +503,10 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, ...@@ -505,6 +503,10 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
mutex_init(&sdata->sec_mtx); mutex_init(&sdata->sec_mtx);
mac802154_llsec_init(&sdata->sec); mac802154_llsec_init(&sdata->sec);
ret = mac802154_wpan_update_llsec(sdata->dev);
if (ret < 0)
return ret;
break; break;
case NL802154_IFTYPE_MONITOR: case NL802154_IFTYPE_MONITOR:
sdata->dev->destructor = free_netdev; sdata->dev->destructor = free_netdev;
......
...@@ -40,7 +40,7 @@ static void ieee802154_tasklet_handler(unsigned long data) ...@@ -40,7 +40,7 @@ static void ieee802154_tasklet_handler(unsigned long data)
* netstack. * netstack.
*/ */
skb->pkt_type = 0; skb->pkt_type = 0;
ieee802154_rx(&local->hw, skb); ieee802154_rx(local, skb);
break; break;
default: default:
WARN(1, "mac802154: Packet is of unknown type %d\n", WARN(1, "mac802154: Packet is of unknown type %d\n",
...@@ -58,11 +58,9 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops) ...@@ -58,11 +58,9 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
struct ieee802154_local *local; struct ieee802154_local *local;
size_t priv_size; size_t priv_size;
if (!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed || if (WARN_ON(!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed ||
!ops->start || !ops->stop || !ops->set_channel) { !ops->start || !ops->stop || !ops->set_channel))
pr_err("undefined IEEE802.15.4 device operations\n");
return NULL; return NULL;
}
/* Ensure 32-byte alignment of our private data and hw private data. /* Ensure 32-byte alignment of our private data and hw private data.
* We use the wpan_phy priv data for both our ieee802154_local and for * We use the wpan_phy priv data for both our ieee802154_local and for
...@@ -107,6 +105,8 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops) ...@@ -107,6 +105,8 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
skb_queue_head_init(&local->skb_queue); skb_queue_head_init(&local->skb_queue);
INIT_WORK(&local->tx_work, ieee802154_xmit_worker);
/* init supported flags with 802.15.4 default ranges */ /* init supported flags with 802.15.4 default ranges */
phy->supported.max_minbe = 8; phy->supported.max_minbe = 8;
phy->supported.min_maxbe = 3; phy->supported.min_maxbe = 3;
......
...@@ -246,13 +246,15 @@ ieee802154_monitors_rx(struct ieee802154_local *local, struct sk_buff *skb) ...@@ -246,13 +246,15 @@ ieee802154_monitors_rx(struct ieee802154_local *local, struct sk_buff *skb)
} }
} }
void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb) void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb)
{ {
struct ieee802154_local *local = hw_to_local(hw);
u16 crc; u16 crc;
WARN_ON_ONCE(softirq_count() == 0); WARN_ON_ONCE(softirq_count() == 0);
if (local->suspended)
goto drop;
/* TODO: When a transceiver omits the checksum here, we /* TODO: When a transceiver omits the checksum here, we
* add an own calculated one. This is currently an ugly * add an own calculated one. This is currently an ugly
* solution because the monitor needs a crc here. * solution because the monitor needs a crc here.
...@@ -273,8 +275,7 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb) ...@@ -273,8 +275,7 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb)
crc = crc_ccitt(0, skb->data, skb->len); crc = crc_ccitt(0, skb->data, skb->len);
if (crc) { if (crc) {
rcu_read_unlock(); rcu_read_unlock();
kfree_skb(skb); goto drop;
return;
} }
} }
/* remove crc */ /* remove crc */
...@@ -283,8 +284,11 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb) ...@@ -283,8 +284,11 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb)
__ieee802154_rx_handle_packet(local, skb); __ieee802154_rx_handle_packet(local, skb);
rcu_read_unlock(); rcu_read_unlock();
return;
drop:
kfree_skb(skb);
} }
EXPORT_SYMBOL(ieee802154_rx);
void void
ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi) ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi)
......
...@@ -30,23 +30,11 @@ ...@@ -30,23 +30,11 @@
#include "ieee802154_i.h" #include "ieee802154_i.h"
#include "driver-ops.h" #include "driver-ops.h"
/* IEEE 802.15.4 transceivers can sleep during the xmit session, so process void ieee802154_xmit_worker(struct work_struct *work)
* packets through the workqueue.
*/
struct ieee802154_xmit_cb {
struct sk_buff *skb;
struct work_struct work;
struct ieee802154_local *local;
};
static struct ieee802154_xmit_cb ieee802154_xmit_cb;
static void ieee802154_xmit_worker(struct work_struct *work)
{ {
struct ieee802154_xmit_cb *cb = struct ieee802154_local *local =
container_of(work, struct ieee802154_xmit_cb, work); container_of(work, struct ieee802154_local, tx_work);
struct ieee802154_local *local = cb->local; struct sk_buff *skb = local->tx_skb;
struct sk_buff *skb = cb->skb;
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
int res; int res;
...@@ -106,11 +94,8 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb) ...@@ -106,11 +94,8 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
dev->stats.tx_packets++; dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len; dev->stats.tx_bytes += skb->len;
} else { } else {
INIT_WORK(&ieee802154_xmit_cb.work, ieee802154_xmit_worker); local->tx_skb = skb;
ieee802154_xmit_cb.skb = skb; queue_work(local->workqueue, &local->tx_work);
ieee802154_xmit_cb.local = local;
queue_work(local->workqueue, &ieee802154_xmit_cb.work);
} }
return NETDEV_TX_OK; return NETDEV_TX_OK;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
*/ */
#include "ieee802154_i.h" #include "ieee802154_i.h"
#include "driver-ops.h"
/* privid for wpan_phys to determine whether they belong to us or not */ /* privid for wpan_phys to determine whether they belong to us or not */
const void *const mac802154_wpan_phy_privid = &mac802154_wpan_phy_privid; const void *const mac802154_wpan_phy_privid = &mac802154_wpan_phy_privid;
...@@ -92,3 +93,10 @@ void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb, ...@@ -92,3 +93,10 @@ void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb,
dev_consume_skb_any(skb); dev_consume_skb_any(skb);
} }
EXPORT_SYMBOL(ieee802154_xmit_complete); EXPORT_SYMBOL(ieee802154_xmit_complete);
void ieee802154_stop_device(struct ieee802154_local *local)
{
flush_workqueue(local->workqueue);
hrtimer_cancel(&local->ifs_timer);
drv_stop(local);
}
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