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
config BT_HCIUART_INTEL
bool "Intel protocol support"
depends on BT_HCIUART
select BT_HCIUART_H4
select BT_INTEL
help
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)
case HCI_SCODATA_PKT:
hdev->stat.sco_tx++;
break;
};
}
/* Prepend skb with frame type */
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)
case HCI_SCODATA_PKT:
hdev->stat.sco_tx++;
break;
};
}
/* Prepend skb with frame type */
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
......
......@@ -34,6 +34,7 @@
#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}})
#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)
{
......@@ -66,9 +67,13 @@ int btbcm_check_bdaddr(struct hci_dev *hdev)
*
* The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller
* 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) ||
!bacmp(&bda->bdaddr, BDADDR_BCM4324B3)) {
!bacmp(&bda->bdaddr, BDADDR_BCM4324B3) ||
!bacmp(&bda->bdaddr, BDADDR_BCM4330B1)) {
BT_INFO("%s: BCM: Using default device address (%pMR)",
hdev->name, &bda->bdaddr);
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
......@@ -241,6 +246,7 @@ static const struct {
u16 subver;
const char *name;
} bcm_uart_subver_table[] = {
{ 0x4103, "BCM4330B1" }, /* 002.001.003 */
{ 0x410e, "BCM43341B0" }, /* 002.001.014 */
{ 0x4406, "BCM4324B3" }, /* 002.004.006 */
{ 0x610c, "BCM4354" }, /* 003.001.012 */
......
......@@ -89,6 +89,86 @@ int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *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_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
MODULE_VERSION(VERSION);
......
......@@ -73,6 +73,11 @@ struct intel_secure_send_result {
int btintel_check_bdaddr(struct hci_dev *hdev);
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
......@@ -86,4 +91,18 @@ static inline int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdadd
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
......@@ -95,10 +95,10 @@ struct btmrvl_private {
struct btmrvl_device btmrvl_dev;
struct btmrvl_adapter *adapter;
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);
int (*hw_wakeup_firmware) (struct btmrvl_private *priv);
int (*hw_process_int_status) (struct btmrvl_private *priv);
int (*hw_wakeup_firmware)(struct btmrvl_private *priv);
int (*hw_process_int_status)(struct btmrvl_private *priv);
void (*firmware_dump)(struct btmrvl_private *priv);
spinlock_t driver_lock; /* spinlock used by driver */
#ifdef CONFIG_DEBUG_FS
......
......@@ -68,6 +68,9 @@ static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth AMP device */
{ USB_DEVICE_INFO(0xe0, 0x01, 0x04), .driver_info = BTUSB_AMP },
/* Generic Bluetooth USB interface */
{ USB_INTERFACE_INFO(0xe0, 0x01, 0x01) },
/* Apple-specific (Broadcom) devices */
{ USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01),
.driver_info = BTUSB_BCM_APPLE },
......@@ -1878,51 +1881,6 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb)
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 const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01,
......@@ -1984,7 +1942,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
return -EINVAL;
}
btusb_intel_version_info(hdev, ver);
btintel_version_info(hdev, ver);
/* The firmware variant determines if the device is in bootloader
* mode or is running operational firmware. The value 0x06 identifies
......@@ -2104,7 +2062,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
/* Start the firmware download transaction with the Init fragment
* 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) {
BT_ERR("%s: Failed to send firmware header (%d)",
hdev->name, err);
......@@ -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
* 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) {
BT_ERR("%s: Failed to send firmware public key (%d)",
hdev->name, err);
......@@ -2124,7 +2082,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
/* Send the 256 bytes of signature information from the firmware
* 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) {
BT_ERR("%s: Failed to send firmware signature (%d)",
hdev->name, err);
......@@ -2148,8 +2106,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
* firmware data buffer as a single Data fragement.
*/
if (!(frag_len % 4)) {
err = btusb_intel_secure_send(hdev, 0x01, frag_len,
fw_ptr);
err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr);
if (err < 0) {
BT_ERR("%s: Failed to send firmware data (%d)",
hdev->name, err);
......@@ -2291,39 +2248,6 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
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)
{
struct sk_buff *skb;
......@@ -2783,7 +2707,7 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_INTEL_NEW) {
hdev->send = btusb_send_frame_intel;
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;
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)
int i;
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("\n");
/* transition to active state */
......@@ -406,7 +406,7 @@ static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
break;
default:
return -EILSEQ;
};
}
nsh.zero = 0;
nsh.len = skb->len;
......
......@@ -75,7 +75,7 @@ struct h5 {
size_t rx_pending; /* Expecting more bytes */
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 */
......
This diff is collapsed.
......@@ -770,7 +770,7 @@ static int __init hci_uart_init(void)
/* 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.name = "n_hci";
hci_uart_ldisc.open = hci_uart_tty_open;
......@@ -804,6 +804,9 @@ static int __init hci_uart_init(void)
#ifdef CONFIG_BT_HCIUART_3WIRE
h5_init();
#endif
#ifdef CONFIG_BT_HCIUART_INTEL
intel_init();
#endif
#ifdef CONFIG_BT_HCIUART_BCM
bcm_init();
#endif
......@@ -830,6 +833,9 @@ static void __exit hci_uart_exit(void)
#ifdef CONFIG_BT_HCIUART_3WIRE
h5_deinit();
#endif
#ifdef CONFIG_BT_HCIUART_INTEL
intel_deinit();
#endif
#ifdef CONFIG_BT_HCIUART_BCM
bcm_deinit();
#endif
......
......@@ -167,6 +167,11 @@ int h5_init(void);
int h5_deinit(void);
#endif
#ifdef CONFIG_BT_HCIUART_INTEL
int intel_init(void);
int intel_deinit(void);
#endif
#ifdef CONFIG_BT_HCIUART_BCM
int bcm_init(void);
int bcm_deinit(void);
......
......@@ -545,7 +545,9 @@ at86rf230_async_state_delay(void *context)
}
/* 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:
hrtimer_start(&ctx->timer, tim, HRTIMER_MODE_REL);
......
......@@ -1151,7 +1151,6 @@ MODULE_DEVICE_TABLE(of, cc2520_of_ids);
static struct spi_driver cc2520_driver = {
.driver = {
.name = "cc2520",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(cc2520_of_ids),
},
......
......@@ -812,7 +812,6 @@ MODULE_DEVICE_TABLE(spi, mrf24j40_ids);
static struct spi_driver mrf24j40_driver = {
.driver = {
.name = "mrf24j40",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.id_table = mrf24j40_ids,
......
......@@ -1297,7 +1297,7 @@ static inline int hci_check_conn_params(u16 min, u16 max, u16 latency,
if (max >= to_multiplier * 8)
return -EINVAL;
max_latency = (to_multiplier * 8 / max) - 1;
max_latency = (to_multiplier * 4 / max) - 1;
if (latency > 499 || latency > max_latency)
return -EINVAL;
......
......@@ -55,6 +55,8 @@
#define L2CAP_INFO_TIMEOUT msecs_to_jiffies(4000)
#define L2CAP_MOVE_TIMEOUT msecs_to_jiffies(4000)
#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
......
......@@ -34,6 +34,8 @@ struct cfg802154_ops {
int type);
void (*del_virtual_intf_deprecated)(struct wpan_phy *wpan_phy,
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,
const char *name,
unsigned char name_assign_type,
......
......@@ -320,23 +320,6 @@ int ieee802154_register_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
*
......
......@@ -613,6 +613,8 @@ EXPORT_SYMBOL_GPL(lowpan_header_compress);
static int __init lowpan_module_init(void)
{
request_module_nowait("ipv6");
request_module_nowait("nhc_dest");
request_module_nowait("nhc_fragment");
request_module_nowait("nhc_hop");
......
......@@ -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_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);
if (err < 0) {
BT_INFO("register_netdev failed %d", err);
spin_lock(&devices_lock);
list_del_rcu(&(*dev)->list);
spin_unlock(&devices_lock);
free_netdev(netdev);
goto out;
}
......@@ -871,16 +884,6 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev)
&chan->src, chan->src_type);
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;
out:
......
......@@ -53,6 +53,11 @@ source "net/bluetooth/cmtp/Kconfig"
source "net/bluetooth/hidp/Kconfig"
config BT_HS
bool "Bluetooth High Speed (HS) features"
depends on BT_BREDR
default y
config BT_LE
bool "Bluetooth Low Energy (LE) features"
depends on BT
......
......@@ -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 \
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_HS) += a2mp.o amp.o
bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o
bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o
......
......@@ -16,6 +16,7 @@
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include "hci_request.h"
#include "a2mp.h"
#include "amp.h"
......@@ -286,11 +287,21 @@ static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
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,
struct a2mp_cmd *hdr)
{
struct a2mp_info_req *req = (void *) skb->data;
struct hci_dev *hdev;
struct hci_request hreq;
int err = 0;
if (le16_to_cpu(hdr->len) < sizeof(*req))
return -EINVAL;
......@@ -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);
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:
if (hdev)
......
......@@ -130,10 +130,29 @@ struct a2mp_physlink_rsp {
#define A2MP_STATUS_SECURITY_VIOLATION 0x06
struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr);
#if IS_ENABLED(CONFIG_BT_HS)
int amp_mgr_put(struct amp_mgr *mgr);
struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
struct sk_buff *skb);
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_getampassoc_rsp(struct hci_dev *hdev, u8 status);
void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status);
......
......@@ -16,6 +16,7 @@
#include <net/bluetooth/hci_core.h>
#include <crypto/hash.h>
#include "hci_request.h"
#include "a2mp.h"
#include "amp.h"
......@@ -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);
}
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)
{
struct hci_cp_read_local_amp_assoc cp;
struct amp_assoc *loc_assoc = &hdev->loc_assoc;
struct hci_request req;
int err = 0;
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)
cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
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)
{
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(&cp, 0, sizeof(cp));
......@@ -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);
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,
......@@ -252,6 +302,8 @@ void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
{
struct hci_cp_read_local_amp_assoc cp;
struct amp_mgr *mgr = hcon->amp_mgr;
struct hci_request req;
int err = 0;
cp.phy_handle = hcon->handle;
cp.len_so_far = cpu_to_le16(0);
......@@ -260,7 +312,25 @@ void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
set_bit(READ_LOC_AMP_ASSOC_FINAL, &mgr->state);
/* 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*/
......@@ -270,6 +340,7 @@ static bool amp_write_rem_assoc_frag(struct hci_dev *hdev,
struct hci_cp_write_remote_amp_assoc *cp;
struct amp_mgr *mgr = hcon->amp_mgr;
struct amp_ctrl *ctrl;
struct hci_request req;
u16 frag_len, len;
ctrl = amp_ctrl_lookup(mgr, hcon->remote_id);
......@@ -307,7 +378,9 @@ static bool amp_write_rem_assoc_frag(struct hci_dev *hdev,
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);
......@@ -344,10 +417,37 @@ void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle)
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,
struct hci_conn *hcon)
{
struct hci_cp_create_phy_link cp;
struct hci_request req;
cp.phy_handle = hcon->handle;
......@@ -360,13 +460,33 @@ void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
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,
struct hci_conn *hcon)
{
struct hci_cp_accept_phy_link cp;
struct hci_request req;
cp.phy_handle = hcon->handle;
......@@ -379,7 +499,9 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
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)
......
......@@ -44,6 +44,20 @@ void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon);
void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
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_rem_assoc_continue(struct hci_dev *hdev, u8 handle);
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
static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
{
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);
switch (pattern) {
case CMTP_MSGNUM:
......@@ -511,13 +511,13 @@ static int cmtp_proc_show(struct seq_file *m, void *v)
struct capi_ctr *ctrl = m->private;
struct cmtp_session *session = ctrl->driverdata;
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, "addr %s\n", session->name);
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);
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,
{
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) {
if (bacmp(&params->addr, addr) == 0 &&
params->addr_type == addr_type) {
......@@ -2842,10 +2838,6 @@ struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list,
{
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) {
if (bacmp(&param->addr, addr) == 0 &&
param->addr_type == addr_type)
......@@ -2861,9 +2853,6 @@ struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev,
{
struct hci_conn_params *params;
if (!hci_is_identity_address(addr, addr_type))
return NULL;
params = hci_conn_params_lookup(hdev, addr, addr_type);
if (params)
return params;
......
......@@ -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);
if (rp->status)
goto a2mp_rsp;
return;
hdev->amp_status = rp->amp_status;
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,
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_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,
......@@ -1409,20 +1369,6 @@ static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
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)
{
struct hci_rp_read_rssi *rp = (void *) skb->data;
......@@ -1944,47 +1890,6 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
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)
{
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,
hci_cc_read_clock(hdev, skb);
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:
hci_cc_read_inq_rsp_tx_power(hdev, skb);
break;
......@@ -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);
break;
case HCI_OP_WRITE_REMOTE_AMP_ASSOC:
hci_cc_write_remote_amp_assoc(hdev, skb);
break;
case HCI_OP_READ_RSSI:
hci_cc_read_rssi(hdev, skb);
break;
......@@ -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);
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:
hci_cs_sniff_mode(hdev, ev->status);
break;
......@@ -4399,6 +4288,23 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *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,
struct sk_buff *skb)
{
......@@ -4522,6 +4428,7 @@ static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev,
hci_dev_unlock(hdev);
}
#endif
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)
}
}
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,
u8 event, 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);
break;
case HCI_EV_CHANNEL_SELECTED:
hci_chan_selected_evt(hdev, skb);
break;
case HCI_EV_REMOTE_OOB_DATA_REQUEST:
hci_remote_oob_data_request_evt(hdev, skb);
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:
hci_phy_link_complete_evt(hdev, skb);
break;
......@@ -5465,6 +5357,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
case HCI_EV_DISCONN_PHY_LINK_COMPLETE:
hci_disconn_phylink_complete_evt(hdev, skb);
break;
#endif
case HCI_EV_NUM_COMP_BLOCKS:
hci_num_comp_blocks_evt(hdev, skb);
......
......@@ -1054,18 +1054,23 @@ static void l2cap_sock_kill(struct sock *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);
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);
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)
timeo = HZ/5;
timeo = L2CAP_WAIT_ACK_POLL_PERIOD;
if (signal_pending(current)) {
err = sock_intr_errno(timeo);
......@@ -1080,7 +1085,15 @@ static int __l2cap_wait_ack(struct sock *sk)
err = sock_error(sk);
if (err)
break;
}
if (time_after(jiffies, timeout)) {
err = -ENOLINK;
break;
}
} while (chan->unacked_frames > 0 &&
chan->state == BT_CONNECTED);
set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
return err;
......@@ -1098,7 +1111,12 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
if (!sk)
return 0;
/* prevent sk structure from being freed whilst unlocked */
sock_hold(sk);
chan = l2cap_pi(sk)->chan;
/* prevent chan structure from being freed whilst unlocked */
l2cap_chan_hold(chan);
conn = chan->conn;
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)
lock_sock(sk);
if (!sk->sk_shutdown) {
if (chan->mode == L2CAP_MODE_ERTM)
err = __l2cap_wait_ack(sk);
if (chan->mode == L2CAP_MODE_ERTM &&
chan->unacked_frames > 0 &&
chan->state == BT_CONNECTED)
err = __l2cap_wait_ack(sk, chan);
sk->sk_shutdown = SHUTDOWN_MASK;
......@@ -1134,6 +1154,11 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
if (conn)
mutex_unlock(&conn->chan_lock);
l2cap_chan_put(chan);
sock_put(sk);
BT_DBG("err: %d", err);
return err;
}
......
......@@ -6226,6 +6226,17 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
else
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,
* they will be created and configured with defaults.
*/
......@@ -6340,6 +6351,18 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
else
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,
addr_type);
if (!params) {
......
......@@ -23,6 +23,26 @@ rdev_del_virtual_intf_deprecated(struct cfg802154_registered_device *rdev,
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
rdev_add_virtual_intf(struct cfg802154_registered_device *rdev, char *name,
unsigned char name_assign_type,
......
......@@ -14,11 +14,13 @@
*/
#include <linux/device.h>
#include <linux/rtnetlink.h>
#include <net/cfg802154.h>
#include "core.h"
#include "sysfs.h"
#include "rdev-ops.h"
static inline struct cfg802154_registered_device *
dev_to_rdev(struct device *dev)
......@@ -62,10 +64,46 @@ static struct attribute *pmib_attrs[] = {
};
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 = {
.name = "ieee802154",
.dev_release = wpan_phy_release,
.dev_groups = pmib_groups,
.pm = WPAN_PHY_PM_OPS,
};
int wpan_phy_sysfs_init(void)
......
......@@ -40,6 +40,28 @@
* 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,
TP_PROTO(struct wpan_phy *wpan_phy, char *name,
enum nl802154_iftype type, __le64 extended_addr),
......
......@@ -44,6 +44,49 @@ static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy,
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
ieee802154_add_iface(struct wpan_phy *phy, const char *name,
unsigned char name_assign_type,
......@@ -145,13 +188,18 @@ static int
ieee802154_set_pan_id(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
__le16 pan_id)
{
int ret;
ASSERT_RTNL();
if (wpan_dev->pan_id == pan_id)
return 0;
wpan_dev->pan_id = pan_id;
return 0;
ret = mac802154_wpan_update_llsec(wpan_dev->netdev);
if (!ret)
wpan_dev->pan_id = pan_id;
return ret;
}
static int
......@@ -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 = {
.add_virtual_intf_deprecated = ieee802154_add_iface_deprecated,
.del_virtual_intf_deprecated = ieee802154_del_iface_deprecated,
.suspend = ieee802154_suspend,
.resume = ieee802154_resume,
.add_virtual_intf = ieee802154_add_iface,
.del_virtual_intf = ieee802154_del_iface,
.set_channel = ieee802154_set_channel,
......
......@@ -56,9 +56,13 @@ struct ieee802154_local {
struct hrtimer ifs_timer;
bool started;
bool suspended;
struct tasklet_struct tasklet;
struct sk_buff_head skb_queue;
struct sk_buff *tx_skb;
struct work_struct tx_work;
};
enum {
......@@ -94,8 +98,6 @@ struct ieee802154_sub_if_data {
struct mac802154_llsec sec;
};
#define MAC802154_CHAN_NONE 0xff /* No channel is assigned */
/* utility functions/constants */
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)
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
ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
netdev_tx_t
......@@ -167,6 +171,8 @@ void mac802154_get_table(struct net_device *dev,
struct ieee802154_llsec_table **t);
void mac802154_unlock_table(struct net_device *dev);
int mac802154_wpan_update_llsec(struct net_device *dev);
/* interface handling */
int ieee802154_iface_init(void);
void ieee802154_iface_exit(void);
......@@ -176,5 +182,6 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name,
unsigned char name_assign_type, enum nl802154_iftype type,
__le64 extended_addr);
void ieee802154_remove_interfaces(struct ieee802154_local *local);
void ieee802154_stop_device(struct ieee802154_local *local);
#endif /* __IEEE802154_I_H */
......@@ -30,7 +30,7 @@
#include "ieee802154_i.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_mlme_ops *ops = ieee802154_mlme_ops(dev);
......@@ -314,11 +314,8 @@ static int mac802154_slave_close(struct net_device *dev)
clear_bit(SDATA_STATE_RUNNING, &sdata->state);
if (!local->open_count) {
flush_workqueue(local->workqueue);
hrtimer_cancel(&local->ifs_timer);
drv_stop(local);
}
if (!local->open_count)
ieee802154_stop_device(local);
return 0;
}
......@@ -471,6 +468,7 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
enum nl802154_iftype type)
{
struct wpan_dev *wpan_dev = &sdata->wpan_dev;
int ret;
u8 tmp;
/* set some type-dependent values */
......@@ -505,6 +503,10 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
mutex_init(&sdata->sec_mtx);
mac802154_llsec_init(&sdata->sec);
ret = mac802154_wpan_update_llsec(sdata->dev);
if (ret < 0)
return ret;
break;
case NL802154_IFTYPE_MONITOR:
sdata->dev->destructor = free_netdev;
......
......@@ -40,7 +40,7 @@ static void ieee802154_tasklet_handler(unsigned long data)
* netstack.
*/
skb->pkt_type = 0;
ieee802154_rx(&local->hw, skb);
ieee802154_rx(local, skb);
break;
default:
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)
struct ieee802154_local *local;
size_t priv_size;
if (!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed ||
!ops->start || !ops->stop || !ops->set_channel) {
pr_err("undefined IEEE802.15.4 device operations\n");
if (WARN_ON(!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed ||
!ops->start || !ops->stop || !ops->set_channel))
return NULL;
}
/* 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
......@@ -107,6 +105,8 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
skb_queue_head_init(&local->skb_queue);
INIT_WORK(&local->tx_work, ieee802154_xmit_worker);
/* init supported flags with 802.15.4 default ranges */
phy->supported.max_minbe = 8;
phy->supported.min_maxbe = 3;
......
......@@ -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;
WARN_ON_ONCE(softirq_count() == 0);
if (local->suspended)
goto drop;
/* TODO: When a transceiver omits the checksum here, we
* add an own calculated one. This is currently an ugly
* solution because the monitor needs a crc here.
......@@ -273,8 +275,7 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb)
crc = crc_ccitt(0, skb->data, skb->len);
if (crc) {
rcu_read_unlock();
kfree_skb(skb);
return;
goto drop;
}
}
/* remove crc */
......@@ -283,8 +284,11 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb)
__ieee802154_rx_handle_packet(local, skb);
rcu_read_unlock();
return;
drop:
kfree_skb(skb);
}
EXPORT_SYMBOL(ieee802154_rx);
void
ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi)
......
......@@ -30,23 +30,11 @@
#include "ieee802154_i.h"
#include "driver-ops.h"
/* IEEE 802.15.4 transceivers can sleep during the xmit session, so process
* 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)
void ieee802154_xmit_worker(struct work_struct *work)
{
struct ieee802154_xmit_cb *cb =
container_of(work, struct ieee802154_xmit_cb, work);
struct ieee802154_local *local = cb->local;
struct sk_buff *skb = cb->skb;
struct ieee802154_local *local =
container_of(work, struct ieee802154_local, tx_work);
struct sk_buff *skb = local->tx_skb;
struct net_device *dev = skb->dev;
int res;
......@@ -106,11 +94,8 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
} else {
INIT_WORK(&ieee802154_xmit_cb.work, ieee802154_xmit_worker);
ieee802154_xmit_cb.skb = skb;
ieee802154_xmit_cb.local = local;
queue_work(local->workqueue, &ieee802154_xmit_cb.work);
local->tx_skb = skb;
queue_work(local->workqueue, &local->tx_work);
}
return NETDEV_TX_OK;
......
......@@ -14,6 +14,7 @@
*/
#include "ieee802154_i.h"
#include "driver-ops.h"
/* privid for wpan_phys to determine whether they belong to us or not */
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,
dev_consume_skb_any(skb);
}
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