From 50aa92a2b45c6e673590b9672119eec8aec54ad2 Mon Sep 17 00:00:00 2001 From: Sudha Bheemanna Date: Thu, 15 Sep 2016 12:53:03 +0530 Subject: [PATCH] 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 --- include/net/bluetooth/hci_core.h | 2 + include/net/bluetooth/l2cap.h | 6 ++ include/net/bluetooth/mgmt_tizen.h | 18 ++++ net/bluetooth/6lowpan.c | 23 +++++ net/bluetooth/mgmt.c | 150 +++++++++++++++++++++++++++++ 5 files changed, 199 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ecbdcb2be062..0df3493056c3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1550,6 +1550,8 @@ void mgmt_le_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len, u8 adv_type); void mgmt_multi_adv_state_change_evt(struct hci_dev *hdev, u8 adv_instance, u8 state_change_reason, u16 connection_handle); +void mgmt_6lowpan_conn_changed(struct hci_dev *hdev, char if_name[16], + bdaddr_t *bdaddr, u8 addr_type, bool connected); #endif u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 2239a3753092..83869fee6792 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -938,4 +938,10 @@ void l2cap_conn_put(struct l2cap_conn *conn); int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user); void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user); +#ifdef TIZEN_BT +/* IPSP: Connect and Disconnect */ +int _bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type); +int _bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type); +#endif + #endif /* __L2CAP_H */ diff --git a/include/net/bluetooth/mgmt_tizen.h b/include/net/bluetooth/mgmt_tizen.h index 2f48ab9abb4a..03a4d63ce84b 100644 --- a/include/net/bluetooth/mgmt_tizen.h +++ b/include/net/bluetooth/mgmt_tizen.h @@ -173,6 +173,18 @@ struct mgmt_cp_enable_6lowpan { } __packed; #define MGMT_ENABLE_BT_6LOWPAN_SIZE 1 +#define MGMT_OP_CONNECT_6LOWPAN (TIZEN_OP_CODE_BASE + 0x13) +struct mgmt_cp_connect_6lowpan { + struct mgmt_addr_info addr; +} __packed; +#define MGMT_CONNECT_6LOWPAN_SIZE 7 + +#define MGMT_OP_DISCONNECT_6LOWPAN (TIZEN_OP_CODE_BASE + 0x14) +struct mgmt_cp_disconnect_6lowpan { + struct mgmt_addr_info addr; +} __packed; +#define MGMT_DISCONNECT_6LOWPAN_SIZE 7 + /* EVENTS */ /* For device name update changes */ @@ -254,4 +266,10 @@ struct mgmt_ev_vendor_specific_multi_adv_state_changed { } __packed; /* LE advertisement state changed event */ +#define MGMT_EV_6LOWPAN_CONN_STATE_CHANGED (TIZEN_EV_BASE + 0x0c) +struct mgmt_ev_6lowpan_conn_state_changed { + struct mgmt_addr_info addr; + __u8 connected; + __u8 ifname[16]; +} __packed; #endif /* __MGMT_TIZEN_H */ 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 bef5f326f882..0d005e563410 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -7326,6 +7326,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) @@ -9217,6 +9365,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 -- 2.34.1