summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorSudha Bheemanna <b.sudha@samsung.com>2016-09-15 12:53:03 +0530
committerSeung-Woo Kim <sw0312.kim@samsung.com>2016-12-14 13:53:23 +0900
commitdea18f7ec613158bc2243e641555dc0499e97cf8 (patch)
tree28a6f7b47567d4cf59851d48f878d6fd15449fe1 /net
parent6cf64e5f18a973023fec47bcf47ce79aa4035cc4 (diff)
Bluetooth: IPSP Connect/Disconnect apis
This patch adds MGMT code to support IPSP connect and disconnect apis and handle connection state changed event. Change-Id: I1c41ec4f38cf9a108e443def3bc23c1b964e2985 Signed-off-by: Sudha Bheemanna <b.sudha@samsung.com>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/6lowpan.c23
-rw-r--r--net/bluetooth/mgmt.c150
2 files changed, 173 insertions, 0 deletions
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 593034eb897a..ba0da68e0961 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -907,6 +907,12 @@ static inline void chan_ready_cb(struct l2cap_chan *chan)
add_peer_chan(chan, dev);
ifup(dev->netdev);
+
+#ifdef TIZEN_BT
+ /* IPSP: Send connection changed state info to bluez */
+ mgmt_6lowpan_conn_changed(dev->hdev, dev->netdev->name, &chan->dst,
+ chan->dst_type, true);
+#endif
}
static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan)
@@ -965,6 +971,13 @@ static void chan_close_cb(struct l2cap_chan *chan)
BT_DBG("chan %p orig refcnt %d", chan,
atomic_read(&chan->kref.refcount));
+#ifdef TIZEN_BT
+ /* IPSP: Send connection changed state info to bluez */
+ mgmt_6lowpan_conn_changed(dev->hdev, dev->netdev->name,
+ &chan->dst, chan->dst_type,
+ false);
+#endif
+
l2cap_chan_put(chan);
break;
}
@@ -1477,6 +1490,16 @@ void bt_6lowpan_disable(void)
enable_6lowpan = false;
}
}
+
+int _bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type)
+{
+ return bt_6lowpan_connect(addr, dst_type);
+}
+
+int _bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type)
+{
+ return bt_6lowpan_disconnect(conn, dst_type);
+}
#endif
static void __exit bt_6lowpan_exit(void)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index f5b40ccfd2d9..13777872af3c 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7328,6 +7328,154 @@ unlocked:
hci_dev_unlock(hdev);
return err;
}
+
+static int connect_bt_6lowpan(struct sock *sk, struct hci_dev *hdev,
+ void *data, u16 len)
+{
+ struct mgmt_cp_connect_6lowpan *cp = data;
+ __u8 addr_type = ADDR_LE_DEV_PUBLIC;
+ int err;
+
+ BT_DBG("%s", hdev->name);
+
+ hci_dev_lock(hdev);
+
+ if (!lmp_le_capable(hdev)) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN,
+ MGMT_STATUS_NOT_SUPPORTED);
+ goto unlocked;
+ }
+
+ if (!hdev_is_powered(hdev)) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN,
+ MGMT_STATUS_REJECTED);
+ goto unlocked;
+ }
+
+ if (bdaddr_type_is_le(cp->addr.type)) {
+ if (cp->addr.type == BDADDR_LE_PUBLIC)
+ addr_type = ADDR_LE_DEV_PUBLIC;
+ else
+ addr_type = ADDR_LE_DEV_RANDOM;
+ } else {
+ err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN,
+ MGMT_STATUS_INVALID_PARAMS, NULL, 0);
+ goto unlocked;
+ }
+
+ hci_dev_unlock(hdev);
+
+ /* 6lowpan Connect */
+ err = _bt_6lowpan_connect(&cp->addr.bdaddr, cp->addr.type);
+
+ hci_dev_lock(hdev);
+
+ if (err < 0) {
+ err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN,
+ MGMT_STATUS_REJECTED, NULL, 0);
+
+ goto unlocked;
+ }
+
+ err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN, 0,
+ NULL, 0);
+unlocked:
+ hci_dev_unlock(hdev);
+ return err;
+}
+
+static int disconnect_bt_6lowpan(struct sock *sk, struct hci_dev *hdev,
+ void *data, u16 len)
+{
+ struct mgmt_cp_disconnect_6lowpan *cp = data;
+ struct hci_conn *conn = NULL;
+ __u8 addr_type = ADDR_LE_DEV_PUBLIC;
+ int err;
+
+ BT_DBG("%s", hdev->name);
+
+ hci_dev_lock(hdev);
+
+ if (!lmp_le_capable(hdev)) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT_6LOWPAN,
+ MGMT_STATUS_NOT_SUPPORTED);
+ goto unlocked;
+ }
+
+ if (!hdev_is_powered(hdev)) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT_6LOWPAN,
+ MGMT_STATUS_REJECTED);
+ goto unlocked;
+ }
+
+ if (bdaddr_type_is_le(cp->addr.type)) {
+ if (cp->addr.type == BDADDR_LE_PUBLIC)
+ addr_type = ADDR_LE_DEV_PUBLIC;
+ else
+ addr_type = ADDR_LE_DEV_RANDOM;
+ } else {
+ err = mgmt_cmd_complete(sk, hdev->id,
+ MGMT_OP_DISCONNECT_6LOWPAN,
+ MGMT_STATUS_INVALID_PARAMS, NULL, 0);
+ goto unlocked;
+ }
+
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
+ if (!conn) {
+ err = mgmt_cmd_complete(sk, hdev->id,
+ MGMT_OP_DISCONNECT_6LOWPAN,
+ MGMT_STATUS_NOT_CONNECTED, NULL, 0);
+ goto unlocked;
+ }
+
+ if (conn->dst_type != addr_type) {
+ err = mgmt_cmd_complete(sk, hdev->id,
+ MGMT_OP_DISCONNECT_6LOWPAN,
+ MGMT_STATUS_INVALID_PARAMS, NULL, 0);
+ goto unlocked;
+ }
+
+ if (conn->state != BT_CONNECTED) {
+ err = mgmt_cmd_complete(sk, hdev->id,
+ MGMT_OP_DISCONNECT_6LOWPAN,
+ MGMT_STATUS_NOT_CONNECTED, NULL, 0);
+ goto unlocked;
+ }
+
+ /* 6lowpan Disconnect */
+ err = _bt_6lowpan_disconnect(conn->l2cap_data, cp->addr.type);
+ if (err < 0) {
+ err = mgmt_cmd_complete(sk, hdev->id,
+ MGMT_OP_DISCONNECT_6LOWPAN,
+ MGMT_STATUS_REJECTED, NULL, 0);
+ goto unlocked;
+ }
+
+ err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN, 0,
+ NULL, 0);
+
+unlocked:
+ hci_dev_unlock(hdev);
+ return err;
+}
+
+void mgmt_6lowpan_conn_changed(struct hci_dev *hdev, char if_name[16],
+ bdaddr_t *bdaddr, u8 addr_type, bool connected)
+{
+ char buf[512];
+ struct mgmt_ev_6lowpan_conn_state_changed *ev = (void *)buf;
+ size_t ev_size;
+
+ memset(buf, 0, sizeof(buf));
+ bacpy(&ev->addr.bdaddr, bdaddr);
+ ev->addr.type = addr_type;
+ ev->connected = connected;
+ memcpy(ev->ifname, (__u8 *)if_name, 16);
+
+ ev_size = sizeof(*ev);
+
+ mgmt_event(MGMT_EV_6LOWPAN_CONN_STATE_CHANGED, hdev, ev, ev_size, NULL);
+}
#endif /* TIZEN_BT */
static bool ltk_is_valid(struct mgmt_ltk_info *key)
@@ -9219,6 +9367,8 @@ static const struct hci_mgmt_handler tizen_mgmt_handlers[] = {
{ set_voice_setting, MGMT_SET_VOICE_SETTING_SIZE },
{ get_adv_tx_power, MGMT_GET_ADV_TX_POWER_SIZE },
{ enable_bt_6lowpan, MGMT_ENABLE_BT_6LOWPAN_SIZE },
+ { connect_bt_6lowpan, MGMT_CONNECT_6LOWPAN_SIZE },
+ { disconnect_bt_6lowpan, MGMT_DISCONNECT_6LOWPAN_SIZE },
};
#endif