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-10-08 Here's another set of Bluetooth & 802.15.4 patches for the 4.4 kernel. 802.15.4: - Many improvements & fixes to the mrf24j40 driver - Fixes and cleanups to nl802154, mac802154 & ieee802154 code Bluetooth: - New chipset support in btmrvl driver - Fixes & cleanups to btbcm, btmrvl, bpa10x & btintel drivers - Support for vendor specific diagnostic data through common API - Cleanups to the 6lowpan code - New events & message types for monitor channel Please let me know if there are any issues pulling. Thanks. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -35,7 +35,6 @@ static struct dentry *lowpan_enable_debugfs;
|
||||
static struct dentry *lowpan_control_debugfs;
|
||||
|
||||
#define IFACE_NAME_TEMPLATE "bt%d"
|
||||
#define EUI64_ADDR_LEN 8
|
||||
|
||||
struct skb_cb {
|
||||
struct in6_addr addr;
|
||||
@@ -674,13 +673,8 @@ static struct header_ops header_ops = {
|
||||
|
||||
static void netdev_setup(struct net_device *dev)
|
||||
{
|
||||
dev->addr_len = EUI64_ADDR_LEN;
|
||||
dev->type = ARPHRD_6LOWPAN;
|
||||
|
||||
dev->hard_header_len = 0;
|
||||
dev->needed_tailroom = 0;
|
||||
dev->mtu = IPV6_MIN_MTU;
|
||||
dev->tx_queue_len = 0;
|
||||
dev->flags = IFF_RUNNING | IFF_POINTOPOINT |
|
||||
IFF_MULTICAST;
|
||||
dev->watchdog_timeo = 0;
|
||||
@@ -775,24 +769,7 @@ static struct l2cap_chan *chan_create(void)
|
||||
|
||||
chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
|
||||
chan->mode = L2CAP_MODE_LE_FLOWCTL;
|
||||
chan->omtu = 65535;
|
||||
chan->imtu = chan->omtu;
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
static struct l2cap_chan *chan_open(struct l2cap_chan *pchan)
|
||||
{
|
||||
struct l2cap_chan *chan;
|
||||
|
||||
chan = chan_create();
|
||||
if (!chan)
|
||||
return NULL;
|
||||
|
||||
chan->remote_mps = chan->omtu;
|
||||
chan->mps = chan->omtu;
|
||||
|
||||
chan->state = BT_CONNECTED;
|
||||
chan->imtu = 1280;
|
||||
|
||||
return chan;
|
||||
}
|
||||
@@ -919,7 +896,10 @@ static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan)
|
||||
{
|
||||
struct l2cap_chan *chan;
|
||||
|
||||
chan = chan_open(pchan);
|
||||
chan = chan_create();
|
||||
if (!chan)
|
||||
return NULL;
|
||||
|
||||
chan->ops = pchan->ops;
|
||||
|
||||
BT_DBG("chan %p pchan %p", chan, pchan);
|
||||
@@ -1065,34 +1045,23 @@ static inline __u8 bdaddr_type(__u8 type)
|
||||
return BDADDR_LE_RANDOM;
|
||||
}
|
||||
|
||||
static struct l2cap_chan *chan_get(void)
|
||||
{
|
||||
struct l2cap_chan *pchan;
|
||||
|
||||
pchan = chan_create();
|
||||
if (!pchan)
|
||||
return NULL;
|
||||
|
||||
pchan->ops = &bt_6lowpan_chan_ops;
|
||||
|
||||
return pchan;
|
||||
}
|
||||
|
||||
static int bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type)
|
||||
{
|
||||
struct l2cap_chan *pchan;
|
||||
struct l2cap_chan *chan;
|
||||
int err;
|
||||
|
||||
pchan = chan_get();
|
||||
if (!pchan)
|
||||
chan = chan_create();
|
||||
if (!chan)
|
||||
return -EINVAL;
|
||||
|
||||
err = l2cap_chan_connect(pchan, cpu_to_le16(L2CAP_PSM_IPSP), 0,
|
||||
chan->ops = &bt_6lowpan_chan_ops;
|
||||
|
||||
err = l2cap_chan_connect(chan, cpu_to_le16(L2CAP_PSM_IPSP), 0,
|
||||
addr, dst_type);
|
||||
|
||||
BT_DBG("chan %p err %d", pchan, err);
|
||||
BT_DBG("chan %p err %d", chan, err);
|
||||
if (err < 0)
|
||||
l2cap_chan_put(pchan);
|
||||
l2cap_chan_put(chan);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -1117,31 +1086,32 @@ static int bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type)
|
||||
static struct l2cap_chan *bt_6lowpan_listen(void)
|
||||
{
|
||||
bdaddr_t *addr = BDADDR_ANY;
|
||||
struct l2cap_chan *pchan;
|
||||
struct l2cap_chan *chan;
|
||||
int err;
|
||||
|
||||
if (!enable_6lowpan)
|
||||
return NULL;
|
||||
|
||||
pchan = chan_get();
|
||||
if (!pchan)
|
||||
chan = chan_create();
|
||||
if (!chan)
|
||||
return NULL;
|
||||
|
||||
pchan->state = BT_LISTEN;
|
||||
pchan->src_type = BDADDR_LE_PUBLIC;
|
||||
chan->ops = &bt_6lowpan_chan_ops;
|
||||
chan->state = BT_LISTEN;
|
||||
chan->src_type = BDADDR_LE_PUBLIC;
|
||||
|
||||
atomic_set(&pchan->nesting, L2CAP_NESTING_PARENT);
|
||||
atomic_set(&chan->nesting, L2CAP_NESTING_PARENT);
|
||||
|
||||
BT_DBG("chan %p src type %d", pchan, pchan->src_type);
|
||||
BT_DBG("chan %p src type %d", chan, chan->src_type);
|
||||
|
||||
err = l2cap_add_psm(pchan, addr, cpu_to_le16(L2CAP_PSM_IPSP));
|
||||
err = l2cap_add_psm(chan, addr, cpu_to_le16(L2CAP_PSM_IPSP));
|
||||
if (err) {
|
||||
l2cap_chan_put(pchan);
|
||||
l2cap_chan_put(chan);
|
||||
BT_ERR("psm cannot be added err %d", err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pchan;
|
||||
return chan;
|
||||
}
|
||||
|
||||
static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
|
||||
|
@@ -134,6 +134,66 @@ static const struct file_operations dut_mode_fops = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t vendor_diag_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct hci_dev *hdev = file->private_data;
|
||||
char buf[3];
|
||||
|
||||
buf[0] = hci_dev_test_flag(hdev, HCI_VENDOR_DIAG) ? 'Y': 'N';
|
||||
buf[1] = '\n';
|
||||
buf[2] = '\0';
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
|
||||
}
|
||||
|
||||
static ssize_t vendor_diag_write(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct hci_dev *hdev = file->private_data;
|
||||
char buf[32];
|
||||
size_t buf_size = min(count, (sizeof(buf)-1));
|
||||
bool enable;
|
||||
int err;
|
||||
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
|
||||
buf[buf_size] = '\0';
|
||||
if (strtobool(buf, &enable))
|
||||
return -EINVAL;
|
||||
|
||||
hci_req_lock(hdev);
|
||||
err = hdev->set_diag(hdev, enable);
|
||||
hci_req_unlock(hdev);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (enable)
|
||||
hci_dev_set_flag(hdev, HCI_VENDOR_DIAG);
|
||||
else
|
||||
hci_dev_clear_flag(hdev, HCI_VENDOR_DIAG);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations vendor_diag_fops = {
|
||||
.open = simple_open,
|
||||
.read = vendor_diag_read,
|
||||
.write = vendor_diag_write,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static void hci_debugfs_create_basic(struct hci_dev *hdev)
|
||||
{
|
||||
debugfs_create_file("dut_mode", 0644, hdev->debugfs, hdev,
|
||||
&dut_mode_fops);
|
||||
|
||||
if (hdev->set_diag)
|
||||
debugfs_create_file("vendor_diag", 0644, hdev->debugfs, hdev,
|
||||
&vendor_diag_fops);
|
||||
}
|
||||
|
||||
/* ---- HCI requests ---- */
|
||||
|
||||
static void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
|
||||
@@ -850,13 +910,8 @@ static int __hci_init(struct hci_dev *hdev)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* The Device Under Test (DUT) mode is special and available for
|
||||
* all controller types. So just create it early on.
|
||||
*/
|
||||
if (hci_dev_test_flag(hdev, HCI_SETUP)) {
|
||||
debugfs_create_file("dut_mode", 0644, hdev->debugfs, hdev,
|
||||
&dut_mode_fops);
|
||||
}
|
||||
if (hci_dev_test_flag(hdev, HCI_SETUP))
|
||||
hci_debugfs_create_basic(hdev);
|
||||
|
||||
err = __hci_req_sync(hdev, hci_init2_req, 0, HCI_INIT_TIMEOUT);
|
||||
if (err < 0)
|
||||
@@ -933,6 +988,9 @@ static int __hci_unconf_init(struct hci_dev *hdev)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (hci_dev_test_flag(hdev, HCI_SETUP))
|
||||
hci_debugfs_create_basic(hdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1385,6 +1443,9 @@ static int hci_dev_do_open(struct hci_dev *hdev)
|
||||
goto done;
|
||||
}
|
||||
|
||||
set_bit(HCI_RUNNING, &hdev->flags);
|
||||
hci_notify(hdev, HCI_DEV_OPEN);
|
||||
|
||||
atomic_set(&hdev->cmd_cnt, 1);
|
||||
set_bit(HCI_INIT, &hdev->flags);
|
||||
|
||||
@@ -1466,6 +1527,9 @@ static int hci_dev_do_open(struct hci_dev *hdev)
|
||||
hdev->sent_cmd = NULL;
|
||||
}
|
||||
|
||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
||||
hci_notify(hdev, HCI_DEV_CLOSE);
|
||||
|
||||
hdev->close(hdev);
|
||||
hdev->flags &= BIT(HCI_RAW);
|
||||
}
|
||||
@@ -1551,6 +1615,8 @@ static void hci_pend_le_actions_clear(struct hci_dev *hdev)
|
||||
|
||||
int hci_dev_do_close(struct hci_dev *hdev)
|
||||
{
|
||||
bool auto_off;
|
||||
|
||||
BT_DBG("%s %p", hdev->name, hdev);
|
||||
|
||||
if (!hci_dev_test_flag(hdev, HCI_UNREGISTER) &&
|
||||
@@ -1606,10 +1672,10 @@ int hci_dev_do_close(struct hci_dev *hdev)
|
||||
|
||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||
|
||||
if (!hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
|
||||
if (hdev->dev_type == HCI_BREDR)
|
||||
mgmt_powered(hdev, 0);
|
||||
}
|
||||
auto_off = hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF);
|
||||
|
||||
if (!auto_off && hdev->dev_type == HCI_BREDR)
|
||||
mgmt_powered(hdev, 0);
|
||||
|
||||
hci_inquiry_cache_flush(hdev);
|
||||
hci_pend_le_actions_clear(hdev);
|
||||
@@ -1626,9 +1692,8 @@ int hci_dev_do_close(struct hci_dev *hdev)
|
||||
/* Reset device */
|
||||
skb_queue_purge(&hdev->cmd_q);
|
||||
atomic_set(&hdev->cmd_cnt, 1);
|
||||
if (!hci_dev_test_flag(hdev, HCI_AUTO_OFF) &&
|
||||
!hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
|
||||
test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
|
||||
if (test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks) &&
|
||||
!auto_off && !hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
|
||||
set_bit(HCI_INIT, &hdev->flags);
|
||||
__hci_req_sync(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT);
|
||||
clear_bit(HCI_INIT, &hdev->flags);
|
||||
@@ -1649,6 +1714,9 @@ int hci_dev_do_close(struct hci_dev *hdev)
|
||||
hdev->sent_cmd = NULL;
|
||||
}
|
||||
|
||||
clear_bit(HCI_RUNNING, &hdev->flags);
|
||||
hci_notify(hdev, HCI_DEV_CLOSE);
|
||||
|
||||
/* After this point our queues are empty
|
||||
* and no tasks are scheduled. */
|
||||
hdev->close(hdev);
|
||||
@@ -3471,6 +3539,13 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (bt_cb(skb)->pkt_type != HCI_EVENT_PKT &&
|
||||
bt_cb(skb)->pkt_type != HCI_ACLDATA_PKT &&
|
||||
bt_cb(skb)->pkt_type != HCI_SCODATA_PKT) {
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Incoming skb */
|
||||
bt_cb(skb)->incoming = 1;
|
||||
|
||||
@@ -3484,6 +3559,21 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
}
|
||||
EXPORT_SYMBOL(hci_recv_frame);
|
||||
|
||||
/* Receive diagnostic message from HCI drivers */
|
||||
int hci_recv_diag(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
/* Time stamp */
|
||||
__net_timestamp(skb);
|
||||
|
||||
/* Mark as diagnostic packet and send to monitor */
|
||||
bt_cb(skb)->pkt_type = HCI_DIAG_PKT;
|
||||
hci_send_to_monitor(hdev, skb);
|
||||
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hci_recv_diag);
|
||||
|
||||
/* ---- Interface to upper protocols ---- */
|
||||
|
||||
int hci_register_cb(struct hci_cb *cb)
|
||||
@@ -3530,6 +3620,11 @@ static void hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
/* Get rid of skb owner, prior to sending to the driver. */
|
||||
skb_orphan(skb);
|
||||
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags)) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
err = hdev->send(hdev, skb);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s sending frame failed (%d)", hdev->name, err);
|
||||
@@ -3580,6 +3675,25 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
|
||||
return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
|
||||
}
|
||||
|
||||
/* Send HCI command and wait for command commplete event */
|
||||
struct sk_buff *hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
|
||||
const void *param, u32 timeout)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!test_bit(HCI_UP, &hdev->flags))
|
||||
return ERR_PTR(-ENETDOWN);
|
||||
|
||||
bt_dev_dbg(hdev, "opcode 0x%4.4x plen %d", opcode, plen);
|
||||
|
||||
hci_req_lock(hdev);
|
||||
skb = __hci_cmd_sync(hdev, opcode, plen, param, timeout);
|
||||
hci_req_unlock(hdev);
|
||||
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL(hci_cmd_sync);
|
||||
|
||||
/* Send ACL data */
|
||||
static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
|
||||
{
|
||||
|
@@ -279,6 +279,9 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
else
|
||||
opcode = cpu_to_le16(HCI_MON_SCO_TX_PKT);
|
||||
break;
|
||||
case HCI_DIAG_PKT:
|
||||
opcode = cpu_to_le16(HCI_MON_VENDOR_DIAG);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
@@ -303,6 +306,7 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
|
||||
{
|
||||
struct hci_mon_hdr *hdr;
|
||||
struct hci_mon_new_index *ni;
|
||||
struct hci_mon_index_info *ii;
|
||||
struct sk_buff *skb;
|
||||
__le16 opcode;
|
||||
|
||||
@@ -312,7 +316,7 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
||||
ni = (void *) skb_put(skb, HCI_MON_NEW_INDEX_SIZE);
|
||||
ni = (void *)skb_put(skb, HCI_MON_NEW_INDEX_SIZE);
|
||||
ni->type = hdev->dev_type;
|
||||
ni->bus = hdev->bus;
|
||||
bacpy(&ni->bdaddr, &hdev->bdaddr);
|
||||
@@ -329,6 +333,34 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
|
||||
opcode = cpu_to_le16(HCI_MON_DEL_INDEX);
|
||||
break;
|
||||
|
||||
case HCI_DEV_UP:
|
||||
skb = bt_skb_alloc(HCI_MON_INDEX_INFO_SIZE, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
||||
ii = (void *)skb_put(skb, HCI_MON_INDEX_INFO_SIZE);
|
||||
bacpy(&ii->bdaddr, &hdev->bdaddr);
|
||||
ii->manufacturer = cpu_to_le16(hdev->manufacturer);
|
||||
|
||||
opcode = cpu_to_le16(HCI_MON_INDEX_INFO);
|
||||
break;
|
||||
|
||||
case HCI_DEV_OPEN:
|
||||
skb = bt_skb_alloc(0, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
||||
opcode = cpu_to_le16(HCI_MON_OPEN_INDEX);
|
||||
break;
|
||||
|
||||
case HCI_DEV_CLOSE:
|
||||
skb = bt_skb_alloc(0, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
||||
opcode = cpu_to_le16(HCI_MON_CLOSE_INDEX);
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@@ -358,6 +390,26 @@ static void send_monitor_replay(struct sock *sk)
|
||||
|
||||
if (sock_queue_rcv_skb(sk, skb))
|
||||
kfree_skb(skb);
|
||||
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||
continue;
|
||||
|
||||
skb = create_monitor_event(hdev, HCI_DEV_OPEN);
|
||||
if (!skb)
|
||||
continue;
|
||||
|
||||
if (sock_queue_rcv_skb(sk, skb))
|
||||
kfree_skb(skb);
|
||||
|
||||
if (!test_bit(HCI_UP, &hdev->flags))
|
||||
continue;
|
||||
|
||||
skb = create_monitor_event(hdev, HCI_DEV_UP);
|
||||
if (!skb)
|
||||
continue;
|
||||
|
||||
if (sock_queue_rcv_skb(sk, skb))
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
read_unlock(&hci_dev_list_lock);
|
||||
@@ -392,14 +444,12 @@ static void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
|
||||
|
||||
void hci_sock_dev_event(struct hci_dev *hdev, int event)
|
||||
{
|
||||
struct hci_ev_si_device ev;
|
||||
|
||||
BT_DBG("hdev %s event %d", hdev->name, event);
|
||||
|
||||
/* Send event to monitor */
|
||||
if (atomic_read(&monitor_promisc)) {
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* Send event to monitor */
|
||||
skb = create_monitor_event(hdev, event);
|
||||
if (skb) {
|
||||
hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
|
||||
@@ -408,10 +458,14 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event)
|
||||
}
|
||||
}
|
||||
|
||||
/* Send event to sockets */
|
||||
ev.event = event;
|
||||
ev.dev_id = hdev->id;
|
||||
hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev);
|
||||
if (event <= HCI_DEV_DOWN) {
|
||||
struct hci_ev_si_device ev;
|
||||
|
||||
/* Send event to sockets */
|
||||
ev.event = event;
|
||||
ev.dev_id = hdev->id;
|
||||
hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev);
|
||||
}
|
||||
|
||||
if (event == HCI_DEV_UNREG) {
|
||||
struct sock *sk;
|
||||
|
@@ -151,6 +151,22 @@ void bt_info(const char *format, ...)
|
||||
}
|
||||
EXPORT_SYMBOL(bt_info);
|
||||
|
||||
void bt_warn(const char *format, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
vaf.fmt = format;
|
||||
vaf.va = &args;
|
||||
|
||||
pr_warn("%pV", &vaf);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
EXPORT_SYMBOL(bt_warn);
|
||||
|
||||
void bt_err(const char *format, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
|
Reference in New Issue
Block a user