diff options
author | John W. Linville <linville@tuxdriver.com> | 2014-07-18 13:35:45 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-07-18 13:35:45 -0400 |
commit | fd29d2cdd5866fd64f2704663535274f5fcaf0af (patch) | |
tree | 4b1f98d1d59e655135c1017c3698292bf2182a4d /net | |
parent | f95f59fe5d2b05a0333214eeba78690081ee5f70 (diff) | |
parent | 4d042654afb342386cb5c33e29843b76d598ab61 (diff) | |
download | linux-fd29d2cdd5866fd64f2704663535274f5fcaf0af.tar.bz2 |
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Diffstat (limited to 'net')
-rw-r--r-- | net/6lowpan/Kconfig | 6 | ||||
-rw-r--r-- | net/6lowpan/Makefile | 3 | ||||
-rw-r--r-- | net/6lowpan/iphc.c (renamed from net/ieee802154/6lowpan_iphc.c) | 0 | ||||
-rw-r--r-- | net/Kconfig | 1 | ||||
-rw-r--r-- | net/Makefile | 3 | ||||
-rw-r--r-- | net/bluetooth/Kconfig | 3 | ||||
-rw-r--r-- | net/bluetooth/cmtp/capi.c | 6 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 134 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 45 | ||||
-rw-r--r-- | net/bluetooth/hci_sock.c | 21 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 8 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 116 | ||||
-rw-r--r-- | net/bluetooth/sco.c | 119 | ||||
-rw-r--r-- | net/bluetooth/smp.c | 40 | ||||
-rw-r--r-- | net/ieee802154/Kconfig | 9 | ||||
-rw-r--r-- | net/ieee802154/Makefile | 5 |
16 files changed, 276 insertions, 243 deletions
diff --git a/net/6lowpan/Kconfig b/net/6lowpan/Kconfig new file mode 100644 index 000000000000..028a5c6d1f61 --- /dev/null +++ b/net/6lowpan/Kconfig @@ -0,0 +1,6 @@ +config 6LOWPAN + bool "6LoWPAN Support" + depends on IPV6 + ---help--- + This enables IPv6 over Low power Wireless Personal Area Network - + "6LoWPAN" which is supported by IEEE 802.15.4 or Bluetooth stacks. diff --git a/net/6lowpan/Makefile b/net/6lowpan/Makefile new file mode 100644 index 000000000000..415886bb456a --- /dev/null +++ b/net/6lowpan/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_6LOWPAN) := 6lowpan.o + +6lowpan-y := iphc.o diff --git a/net/ieee802154/6lowpan_iphc.c b/net/6lowpan/iphc.c index 211b5686d719..211b5686d719 100644 --- a/net/ieee802154/6lowpan_iphc.c +++ b/net/6lowpan/iphc.c diff --git a/net/Kconfig b/net/Kconfig index d92afe4204d9..4051fdfa4367 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -214,6 +214,7 @@ source "drivers/net/appletalk/Kconfig" source "net/x25/Kconfig" source "net/lapb/Kconfig" source "net/phonet/Kconfig" +source "net/6lowpan/Kconfig" source "net/ieee802154/Kconfig" source "net/mac802154/Kconfig" source "net/sched/Kconfig" diff --git a/net/Makefile b/net/Makefile index cbbbe6d657ca..7ed1970074b0 100644 --- a/net/Makefile +++ b/net/Makefile @@ -57,7 +57,8 @@ obj-$(CONFIG_CAIF) += caif/ ifneq ($(CONFIG_DCB),) obj-y += dcb/ endif -obj-y += ieee802154/ +obj-$(CONFIG_6LOWPAN) += 6lowpan/ +obj-$(CONFIG_IEEE802154) += ieee802154/ obj-$(CONFIG_MAC802154) += mac802154/ ifeq ($(CONFIG_NET),y) diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index f5afaa22f6ec..600fb29288f4 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -41,8 +41,7 @@ menuconfig BT config BT_6LOWPAN tristate "Bluetooth 6LoWPAN support" - depends on BT && IPV6 - select 6LOWPAN_IPHC if BT_6LOWPAN + depends on BT && 6LOWPAN help IPv6 compression over Bluetooth Low Energy. diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index cd75e4d64b90..1ca8a87a0787 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -362,12 +362,6 @@ void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb) CAPIMSG_SETCONTROL(skb->data, contr); } - if (!ctrl) { - BT_ERR("Can't find controller %d for message", session->num); - kfree_skb(skb); - return; - } - capi_ctr_handle_message(ctrl, appl, skb); } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 84431b86af96..172041e2b15a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -54,6 +54,15 @@ DEFINE_RWLOCK(hci_cb_list_lock); /* HCI ID Numbering */ static DEFINE_IDA(hci_index_ida); +/* ----- HCI requests ----- */ + +#define HCI_REQ_DONE 0 +#define HCI_REQ_PEND 1 +#define HCI_REQ_CANCELED 2 + +#define hci_req_lock(d) mutex_lock(&d->req_lock) +#define hci_req_unlock(d) mutex_unlock(&d->req_lock) + /* ---- HCI notifications ---- */ static void hci_notify(struct hci_dev *hdev, int event) @@ -1339,9 +1348,6 @@ static void le_setup(struct hci_request *req) /* Read LE Supported States */ hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL); - /* Read LE Advertising Channel TX Power */ - hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL); - /* Read LE White List Size */ hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL); @@ -1416,14 +1422,17 @@ static void hci_setup_event_mask(struct hci_request *req) /* Use a different default for LE-only devices */ memset(events, 0, sizeof(events)); events[0] |= 0x10; /* Disconnection Complete */ - events[0] |= 0x80; /* Encryption Change */ events[1] |= 0x08; /* Read Remote Version Information Complete */ events[1] |= 0x20; /* Command Complete */ events[1] |= 0x40; /* Command Status */ events[1] |= 0x80; /* Hardware Error */ events[2] |= 0x04; /* Number of Completed Packets */ events[3] |= 0x02; /* Data Buffer Overflow */ - events[5] |= 0x80; /* Encryption Key Refresh Complete */ + + if (hdev->le_features[0] & HCI_LE_ENCRYPTION) { + events[0] |= 0x80; /* Encryption Change */ + events[5] |= 0x80; /* Encryption Key Refresh Complete */ + } } if (lmp_inq_rssi_capable(hdev)) @@ -1476,8 +1485,6 @@ static void hci_init2_req(struct hci_request *req, unsigned long opt) if (lmp_le_capable(hdev)) le_setup(req); - hci_setup_event_mask(req); - /* AVM Berlin (31), aka "BlueFRITZ!", doesn't support the read * local supported commands HCI command. */ @@ -1605,6 +1612,8 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) struct hci_dev *hdev = req->hdev; u8 p; + hci_setup_event_mask(req); + /* Some Broadcom based Bluetooth controllers do not support the * Delete Stored Link Key command. They are clearly indicating its * absence in the bit mask of supported commands. @@ -1635,7 +1644,10 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) u8 events[8]; memset(events, 0, sizeof(events)); - events[0] = 0x1f; + events[0] = 0x0f; + + if (hdev->le_features[0] & HCI_LE_ENCRYPTION) + events[0] |= 0x10; /* LE Long Term Key Request */ /* If controller supports the Connection Parameters Request * Link Layer Procedure, enable the corresponding event. @@ -1648,6 +1660,11 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events), events); + if (hdev->commands[25] & 0x40) { + /* Read LE Advertising Channel TX Power */ + hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL); + } + hci_set_le_support(req); } @@ -2071,7 +2088,7 @@ u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, } /* Entry not in the cache. Add new one. */ - ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC); + ie = kzalloc(sizeof(struct inquiry_entry), GFP_KERNEL); if (!ie) { flags |= MGMT_DEV_FOUND_CONFIRM_NAME; goto done; @@ -2435,6 +2452,16 @@ int hci_dev_open(__u16 dev) */ flush_workqueue(hdev->req_workqueue); + /* For controllers not using the management interface and that + * are brought up using legacy ioctl, set the HCI_PAIRABLE bit + * so that pairing works for them. Once the management interface + * is in use this bit will be cleared again and userspace has + * to explicitly enable it. + */ + if (!test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) && + !test_bit(HCI_MGMT, &hdev->dev_flags)) + set_bit(HCI_PAIRABLE, &hdev->dev_flags); + err = hci_dev_do_open(hdev); done: @@ -2655,6 +2682,42 @@ done: return ret; } +static void hci_update_scan_state(struct hci_dev *hdev, u8 scan) +{ + bool conn_changed, discov_changed; + + BT_DBG("%s scan 0x%02x", hdev->name, scan); + + if ((scan & SCAN_PAGE)) + conn_changed = !test_and_set_bit(HCI_CONNECTABLE, + &hdev->dev_flags); + else + conn_changed = test_and_clear_bit(HCI_CONNECTABLE, + &hdev->dev_flags); + + if ((scan & SCAN_INQUIRY)) { + discov_changed = !test_and_set_bit(HCI_DISCOVERABLE, + &hdev->dev_flags); + } else { + clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags); + discov_changed = test_and_clear_bit(HCI_DISCOVERABLE, + &hdev->dev_flags); + } + + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) + return; + + if (conn_changed || discov_changed) { + /* In case this was disabled through mgmt */ + set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags); + + if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) + mgmt_update_adv_data(hdev); + + mgmt_new_settings(hdev); + } +} + int hci_dev_cmd(unsigned int cmd, void __user *arg) { struct hci_dev *hdev; @@ -2716,22 +2779,11 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) err = hci_req_sync(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT); - /* Ensure that the connectable state gets correctly - * notified if the whitelist is in use. + /* Ensure that the connectable and discoverable states + * get correctly modified as this was a non-mgmt change. */ - if (!err && !list_empty(&hdev->whitelist)) { - bool changed; - - if ((dr.dev_opt & SCAN_PAGE)) - changed = !test_and_set_bit(HCI_CONNECTABLE, - &hdev->dev_flags); - else - changed = test_and_set_bit(HCI_CONNECTABLE, - &hdev->dev_flags); - - if (changed) - mgmt_new_settings(hdev); - } + if (!err) + hci_update_scan_state(hdev, dr.dev_opt); break; case HCISETLINKPOL: @@ -2792,14 +2844,17 @@ int hci_get_dev_list(void __user *arg) read_lock(&hci_dev_list_lock); list_for_each_entry(hdev, &hci_dev_list, list) { - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) - cancel_delayed_work(&hdev->power_off); + unsigned long flags = hdev->flags; - if (!test_bit(HCI_MGMT, &hdev->dev_flags)) - set_bit(HCI_PAIRABLE, &hdev->dev_flags); + /* When the auto-off is configured it means the transport + * is running, but in that case still indicate that the + * device is actually down. + */ + if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + flags &= ~BIT(HCI_UP); (dr + n)->dev_id = hdev->id; - (dr + n)->dev_opt = hdev->flags; + (dr + n)->dev_opt = flags; if (++n >= dev_num) break; @@ -2819,6 +2874,7 @@ int hci_get_dev_info(void __user *arg) { struct hci_dev *hdev; struct hci_dev_info di; + unsigned long flags; int err = 0; if (copy_from_user(&di, arg, sizeof(di))) @@ -2828,16 +2884,19 @@ int hci_get_dev_info(void __user *arg) if (!hdev) return -ENODEV; - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) - cancel_delayed_work_sync(&hdev->power_off); - - if (!test_bit(HCI_MGMT, &hdev->dev_flags)) - set_bit(HCI_PAIRABLE, &hdev->dev_flags); + /* When the auto-off is configured it means the transport + * is running, but in that case still indicate that the + * device is actually down. + */ + if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + flags = hdev->flags & ~BIT(HCI_UP); + else + flags = hdev->flags; strcpy(di.name, hdev->name); di.bdaddr = hdev->bdaddr; di.type = (hdev->bus & 0x0f) | ((hdev->dev_type & 0x03) << 4); - di.flags = hdev->flags; + di.flags = flags; di.pkt_type = hdev->pkt_type; if (lmp_bredr_capable(hdev)) { di.acl_mtu = hdev->acl_mtu; @@ -4390,6 +4449,11 @@ int hci_req_run(struct hci_request *req, hci_req_complete_t complete) return 0; } +bool hci_req_pending(struct hci_dev *hdev) +{ + return (hdev->req_status == HCI_REQ_PEND); +} + static struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen, const void *param) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c8ae9ee3cb12..8980bd24b8c0 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -296,7 +296,6 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); __u8 param; - int old_pscan, old_iscan; void *sent; BT_DBG("%s status 0x%2.2x", hdev->name, status); @@ -310,32 +309,19 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); if (status) { - mgmt_write_scan_failed(hdev, param, status); hdev->discov_timeout = 0; goto done; } - /* We need to ensure that we set this back on if someone changed - * the scan mode through a raw HCI socket. - */ - set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags); - - old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags); - old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags); - - if (param & SCAN_INQUIRY) { + if (param & SCAN_INQUIRY) set_bit(HCI_ISCAN, &hdev->flags); - if (!old_iscan) - mgmt_discoverable(hdev, 1); - } else if (old_iscan) - mgmt_discoverable(hdev, 0); + else + clear_bit(HCI_ISCAN, &hdev->flags); - if (param & SCAN_PAGE) { + if (param & SCAN_PAGE) set_bit(HCI_PSCAN, &hdev->flags); - if (!old_pscan) - mgmt_connectable(hdev, 1); - } else if (old_pscan) - mgmt_connectable(hdev, 0); + else + clear_bit(HCI_ISCAN, &hdev->flags); done: hci_dev_unlock(hdev); @@ -3678,18 +3664,14 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) /* If we are initiators, there is no remote information yet */ if (conn->remote_auth == 0xff) { - cp.authentication = conn->auth_type; - /* Request MITM protection if our IO caps allow it * except for the no-bonding case. - * conn->auth_type is not updated here since - * that might cause the user confirmation to be - * rejected in case the remote doesn't have the - * IO capabilities for MITM. */ if (conn->io_capability != HCI_IO_NO_INPUT_OUTPUT && cp.authentication != HCI_AT_NO_BONDING) - cp.authentication |= 0x01; + conn->auth_type |= 0x01; + + cp.authentication = conn->auth_type; } else { conn->auth_type = hci_get_auth_req(conn); cp.authentication = conn->auth_type; @@ -3761,9 +3743,12 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev, rem_mitm = (conn->remote_auth & 0x01); /* If we require MITM but the remote device can't provide that - * (it has NoInputNoOutput) then reject the confirmation request + * (it has NoInputNoOutput) then reject the confirmation + * request. We check the security level here since it doesn't + * necessarily match conn->auth_type. */ - if (loc_mitm && conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) { + if (conn->pending_sec_level > BT_SECURITY_MEDIUM && + conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) { BT_DBG("Rejecting request: remote device can't provide MITM"); hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); @@ -4638,7 +4623,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) /* Received events are (currently) only needed when a request is * ongoing so avoid unnecessary memory allocation. */ - if (hdev->req_status == HCI_REQ_PEND) { + if (hci_req_pending(hdev)) { kfree_skb(hdev->recv_evt); hdev->recv_evt = skb_clone(skb, GFP_KERNEL); } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index c64728d571ae..115f149362ba 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -35,13 +35,32 @@ static atomic_t monitor_promisc = ATOMIC_INIT(0); /* ----- HCI socket interface ----- */ +/* Socket info */ +#define hci_pi(sk) ((struct hci_pinfo *) sk) + +struct hci_pinfo { + struct bt_sock bt; + struct hci_dev *hdev; + struct hci_filter filter; + __u32 cmsg_mask; + unsigned short channel; +}; + static inline int hci_test_bit(int nr, void *addr) { return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31)); } /* Security filter */ -static struct hci_sec_filter hci_sec_filter = { +#define HCI_SFLT_MAX_OGF 5 + +struct hci_sec_filter { + __u32 type_mask; + __u32 event_mask[2]; + __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4]; +}; + +static const struct hci_sec_filter hci_sec_filter = { /* Packet types */ 0x10, /* Events */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8680aae678ce..8538cb07b0c0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -46,7 +46,7 @@ bool disable_ertm; static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD; -static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP | L2CAP_FC_CONNLESS, }; +static u8 l2cap_fixed_chan[8] = { L2CAP_FC_SIG_BREDR | L2CAP_FC_CONNLESS, }; static LIST_HEAD(chan_list); static DEFINE_RWLOCK(chan_list_lock); @@ -798,14 +798,14 @@ static u8 l2cap_get_ident(struct l2cap_conn *conn) * 200 - 254 are used by utilities like l2ping, etc. */ - spin_lock(&conn->lock); + mutex_lock(&conn->ident_lock); if (++conn->tx_ident > 128) conn->tx_ident = 1; id = conn->tx_ident; - spin_unlock(&conn->lock); + mutex_unlock(&conn->ident_lock); return id; } @@ -7016,7 +7016,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) conn->hs_enabled = test_bit(HCI_HS_ENABLED, &hcon->hdev->dev_flags); - spin_lock_init(&conn->lock); + mutex_init(&conn->ident_lock); mutex_init(&conn->chan_lock); INIT_LIST_HEAD(&conn->chan_l); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 91b1f92c681e..7703b72653ff 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -906,6 +906,16 @@ static void update_adv_data(struct hci_request *req) hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); } +int mgmt_update_adv_data(struct hci_dev *hdev) +{ + struct hci_request req; + + hci_req_init(&req, hdev); + update_adv_data(&req); + + return hci_req_run(&req, NULL); +} + static void create_eir(struct hci_dev *hdev, u8 *data) { u8 *ptr = data; @@ -1743,7 +1753,7 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status) { struct pending_cmd *cmd; struct mgmt_mode *cp; - bool changed; + bool conn_changed, discov_changed; BT_DBG("status 0x%02x", status); @@ -1760,15 +1770,23 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status) } cp = cmd->param; - if (cp->val) - changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags); - else - changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); + if (cp->val) { + conn_changed = !test_and_set_bit(HCI_CONNECTABLE, + &hdev->dev_flags); + discov_changed = false; + } else { + conn_changed = test_and_clear_bit(HCI_CONNECTABLE, + &hdev->dev_flags); + discov_changed = test_and_clear_bit(HCI_DISCOVERABLE, + &hdev->dev_flags); + } send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev); - if (changed) { + if (conn_changed || discov_changed) { new_settings(hdev, cmd->sk); + if (discov_changed) + mgmt_update_adv_data(hdev); hci_update_background_scan(hdev); } @@ -1882,8 +1900,8 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) write_fast_connectable(&req, false); - if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && - !test_bit(HCI_LE_ADV, &hdev->dev_flags)) + /* Update the advertising parameters if necessary */ + if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) enable_advertising(&req); err = hci_req_run(&req, set_connectable_complete); @@ -6031,88 +6049,6 @@ void mgmt_discoverable_timeout(struct hci_dev *hdev) hci_dev_unlock(hdev); } -void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) -{ - bool changed; - - /* Nothing needed here if there's a pending command since that - * commands request completion callback takes care of everything - * necessary. - */ - if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev)) - return; - - /* Powering off may clear the scan mode - don't let that interfere */ - if (!discoverable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) - return; - - if (discoverable) { - changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags); - } else { - clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags); - changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); - } - - if (changed) { - struct hci_request req; - - /* In case this change in discoverable was triggered by - * a disabling of connectable there could be a need to - * update the advertising flags. - */ - hci_req_init(&req, hdev); - update_adv_data(&req); - hci_req_run(&req, NULL); - - new_settings(hdev, NULL); - } -} - -void mgmt_connectable(struct hci_dev *hdev, u8 connectable) -{ - bool changed; - - /* Nothing needed here if there's a pending command since that - * commands request completion callback takes care of everything - * necessary. - */ - if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) - return; - - /* Powering off may clear the scan mode - don't let that interfere */ - if (!connectable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) - return; - - /* If something else than mgmt changed the page scan state we - * can't differentiate this from a change triggered by adding - * the first element to the whitelist. Therefore, avoid - * incorrectly setting HCI_CONNECTABLE. - */ - if (connectable && !list_empty(&hdev->whitelist)) - return; - - if (connectable) - changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags); - else - changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); - - if (changed) - new_settings(hdev, NULL); -} - -void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) -{ - u8 mgmt_err = mgmt_status(status); - - if (scan & SCAN_PAGE) - mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, - cmd_status_rsp, &mgmt_err); - - if (scan & SCAN_INQUIRY) - mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, - cmd_status_rsp, &mgmt_err); -} - void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent) { diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index c06dbd3938e8..ebf7ee6a446c 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -40,13 +40,38 @@ static struct bt_sock_list sco_sk_list = { .lock = __RW_LOCK_UNLOCKED(sco_sk_list.lock) }; -static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent); -static void sco_chan_del(struct sock *sk, int err); +/* ---- SCO connections ---- */ +struct sco_conn { + struct hci_conn *hcon; + + spinlock_t lock; + struct sock *sk; + + unsigned int mtu; +}; + +#define sco_conn_lock(c) spin_lock(&c->lock); +#define sco_conn_unlock(c) spin_unlock(&c->lock); static void sco_sock_close(struct sock *sk); static void sco_sock_kill(struct sock *sk); +/* ----- SCO socket info ----- */ +#define sco_pi(sk) ((struct sco_pinfo *) sk) + +struct sco_pinfo { + struct bt_sock bt; + bdaddr_t src; + bdaddr_t dst; + __u32 flags; + __u16 setting; + struct sco_conn *conn; +}; + /* ---- SCO timers ---- */ +#define SCO_CONN_TIMEOUT (HZ * 40) +#define SCO_DISCONN_TIMEOUT (HZ * 2) + static void sco_sock_timeout(unsigned long arg) { struct sock *sk = (struct sock *) arg; @@ -102,13 +127,31 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon) return conn; } -static struct sock *sco_chan_get(struct sco_conn *conn) +/* Delete channel. + * Must be called on the locked socket. */ +static void sco_chan_del(struct sock *sk, int err) { - struct sock *sk = NULL; - sco_conn_lock(conn); - sk = conn->sk; - sco_conn_unlock(conn); - return sk; + struct sco_conn *conn; + + conn = sco_pi(sk)->conn; + + BT_DBG("sk %p, conn %p, err %d", sk, conn, err); + + if (conn) { + sco_conn_lock(conn); + conn->sk = NULL; + sco_pi(sk)->conn = NULL; + sco_conn_unlock(conn); + + if (conn->hcon) + hci_conn_drop(conn->hcon); + } + + sk->sk_state = BT_CLOSED; + sk->sk_err = err; + sk->sk_state_change(sk); + + sock_set_flag(sk, SOCK_ZAPPED); } static int sco_conn_del(struct hci_conn *hcon, int err) @@ -122,7 +165,10 @@ static int sco_conn_del(struct hci_conn *hcon, int err) BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); /* Kill socket */ - sk = sco_chan_get(conn); + sco_conn_lock(conn); + sk = conn->sk; + sco_conn_unlock(conn); + if (sk) { bh_lock_sock(sk); sco_sock_clear_timer(sk); @@ -136,6 +182,17 @@ static int sco_conn_del(struct hci_conn *hcon, int err) return 0; } +static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) +{ + BT_DBG("conn %p", conn); + + sco_pi(sk)->conn = conn; + conn->sk = sk; + + if (parent) + bt_accept_enqueue(parent, sk); +} + static int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) { @@ -240,7 +297,11 @@ static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) { - struct sock *sk = sco_chan_get(conn); + struct sock *sk; + + sco_conn_lock(conn); + sk = conn->sk; + sco_conn_unlock(conn); if (!sk) goto drop; @@ -940,44 +1001,6 @@ static int sco_sock_release(struct socket *sock) return err; } -static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) -{ - BT_DBG("conn %p", conn); - - sco_pi(sk)->conn = conn; - conn->sk = sk; - - if (parent) - bt_accept_enqueue(parent, sk); -} - -/* Delete channel. - * Must be called on the locked socket. */ -static void sco_chan_del(struct sock *sk, int err) -{ - struct sco_conn *conn; - - conn = sco_pi(sk)->conn; - - BT_DBG("sk %p, conn %p, err %d", sk, conn, err); - - if (conn) { - sco_conn_lock(conn); - conn->sk = NULL; - sco_pi(sk)->conn = NULL; - sco_conn_unlock(conn); - - if (conn->hcon) - hci_conn_drop(conn->hcon); - } - - sk->sk_state = BT_CLOSED; - sk->sk_err = err; - sk->sk_state_change(sk); - - sock_set_flag(sk, SOCK_ZAPPED); -} - static void sco_conn_ready(struct sco_conn *conn) { struct sock *parent; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 55c41de2f5a0..8339d6b0f2b8 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -391,10 +391,12 @@ static const u8 gen_method[5][5] = { static u8 get_auth_method(struct smp_chan *smp, u8 local_io, u8 remote_io) { - /* If either side has unknown io_caps, use JUST WORKS */ + /* If either side has unknown io_caps, use JUST_CFM (which gets + * converted later to JUST_WORKS if we're initiators. + */ if (local_io > SMP_IO_KEYBOARD_DISPLAY || remote_io > SMP_IO_KEYBOARD_DISPLAY) - return JUST_WORKS; + return JUST_CFM; return gen_method[remote_io][local_io]; } @@ -414,17 +416,17 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io); - /* If neither side wants MITM, use JUST WORKS */ - /* Otherwise, look up method from the table */ + /* If neither side wants MITM, either "just" confirm an incoming + * request or use just-works for outgoing ones. The JUST_CFM + * will be converted to JUST_WORKS if necessary later in this + * function. If either side has MITM look up the method from the + * table. + */ if (!(auth & SMP_AUTH_MITM)) - method = JUST_WORKS; + method = JUST_CFM; else method = get_auth_method(smp, local_io, remote_io); - /* If not bonding, don't ask user to confirm a Zero TK */ - if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM) - method = JUST_WORKS; - /* Don't confirm locally initiated pairing attempts */ if (method == JUST_CFM && test_bit(SMP_FLAG_INITIATOR, &smp->flags)) method = JUST_WORKS; @@ -674,6 +676,7 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing rsp, *req = (void *) skb->data; + struct hci_dev *hdev = conn->hcon->hdev; struct smp_chan *smp; u8 key_size, auth, sec_level; int ret; @@ -694,6 +697,10 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (!smp) return SMP_UNSPECIFIED; + if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags) && + (req->auth_req & SMP_AUTH_BONDING)) + return SMP_PAIRING_NOTSUPP; + smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); @@ -733,8 +740,6 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (ret) return SMP_UNSPECIFIED; - clear_bit(SMP_FLAG_INITIATOR, &smp->flags); - return 0; } @@ -871,9 +876,12 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level) /* If we're encrypted with an STK always claim insufficient * security. This way we allow the connection to be re-encrypted * with an LTK, even if the LTK provides the same level of - * security. + * security. Only exception is if we don't have an LTK (e.g. + * because of key distribution bits). */ - if (test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags)) + if (test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags) && + hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type, + hcon->out)) return false; if (hcon->sec_level >= sec_level) @@ -911,6 +919,10 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; + if (!test_bit(HCI_PAIRABLE, &hcon->hdev->dev_flags) && + (rp->auth_req & SMP_AUTH_BONDING)) + return SMP_PAIRING_NOTSUPP; + smp = smp_chan_create(conn); if (!smp) return SMP_UNSPECIFIED; @@ -925,8 +937,6 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); - clear_bit(SMP_FLAG_INITIATOR, &smp->flags); - return 0; } diff --git a/net/ieee802154/Kconfig b/net/ieee802154/Kconfig index 8af1330b3137..c0d4154d144f 100644 --- a/net/ieee802154/Kconfig +++ b/net/ieee802154/Kconfig @@ -12,13 +12,6 @@ config IEEE802154 config IEEE802154_6LOWPAN tristate "6lowpan support over IEEE 802.15.4" - depends on IEEE802154 && IPV6 - select 6LOWPAN_IPHC + depends on IEEE802154 && 6LOWPAN ---help--- IPv6 compression over IEEE 802.15.4. - -config 6LOWPAN_IPHC - tristate - ---help--- - 6lowpan compression code which is shared between IEEE 802.15.4 and Bluetooth - stacks. diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index bf1b51497a41..3914b1ed4274 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -1,8 +1,7 @@ obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o -obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o -obj-$(CONFIG_6LOWPAN_IPHC) += 6lowpan_iphc.o +obj-$(CONFIG_IEEE802154_6LOWPAN) += ieee802154_6lowpan.o -6lowpan-y := 6lowpan_rtnl.o reassembly.o +ieee802154_6lowpan-y := 6lowpan_rtnl.o reassembly.o ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o \ header_ops.o af_802154-y := af_ieee802154.o raw.o dgram.o |