Bluetooth: IPSP Connect/Disconnect apis 33/90633/1
authorSudha Bheemanna <b.sudha@samsung.com>
Mon, 3 Oct 2016 09:16:09 +0000 (14:46 +0530)
committerSudha Bheemanna <b.sudha@samsung.com>
Mon, 3 Oct 2016 09:16:09 +0000 (14:46 +0530)
This patch adds MGMT code to support IPSP connect and
disconnect apis and handle connection state changed event.

Change-Id: I372ea923acd06c25cfa4c50094bf946e55dc30c8
Signed-off-by: Sudha Bheemanna <b.sudha@samsung.com>
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/bluetooth/mgmt_tizen.h
net/bluetooth/6lowpan.c
net/bluetooth/mgmt.c

index d1f3691..4b4aad0 100644 (file)
@@ -1562,6 +1562,8 @@ int mgmt_le_conn_updated(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
                u16 supervision_timeout);
 int mgmt_le_conn_update_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
                u8 link_type, u8 addr_type, u8 status);
+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,
index 7663026..18b30b2 100644 (file)
@@ -977,9 +977,14 @@ int l2cap_update_connection_param(struct l2cap_conn *conn, u16 min, u16 max,
 /* IPSP : initialize/deinitialize 6lowpan */
 void bt_6lowpan_enable(void);
 void bt_6lowpan_disable(void);
+/* 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);
 #else
 static inline void bt_6lowpan_enable(void) { }
 static inline void bt_6lowpan_disable(void) { }
+static inline int _bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type) { return -ENODEV; }
+static inline int _bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type) { return -ENODEV; }
 #endif
 #endif
 
index 809d416..27813b4 100644 (file)
@@ -171,6 +171,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
+
 /* BEGIN TIZEN_Bluetooth :: name update changes */
 #define MGMT_EV_DEVICE_NAME_UPDATE             (TIZEN_EV_BASE + 0x01)
 struct mgmt_ev_device_name_update {
@@ -246,4 +258,11 @@ struct mgmt_ev_vendor_specific_multi_adv_state_changed {
        __le16  connection_handle;
 } __packed;
 
+#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   /* CONFIG_TIZEN_WIP */
index b52b0f3..7f714d7 100644 (file)
@@ -907,6 +907,12 @@ static inline void chan_ready_cb(struct l2cap_chan *chan)
 
        add_peer_chan(chan, dev);
        ifup(dev->netdev);
+
+#ifdef CONFIG_TIZEN_WIP
+       /* 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 CONFIG_TIZEN_WIP
+                       /* 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;
                }
@@ -1480,6 +1493,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)
index 6de7555..007863d 100644 (file)
@@ -6840,6 +6840,153 @@ unlocked:
        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 = cmd_status(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN,
+                                     MGMT_STATUS_NOT_SUPPORTED);
+               goto unlocked;
+       }
+
+       if (!hdev_is_powered(hdev)) {
+               err = 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 = 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 = cmd_complete(sk, hdev->id, MGMT_OP_CONNECT_6LOWPAN,
+                                       MGMT_STATUS_REJECTED, NULL, 0);
+
+               goto unlocked;
+       }
+
+       err = 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 = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT_6LOWPAN,
+                                     MGMT_STATUS_NOT_SUPPORTED);
+               goto unlocked;
+       }
+
+       if (!hdev_is_powered(hdev)) {
+               err = 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 = 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 = cmd_complete(sk, hdev->id,
+                                       MGMT_OP_DISCONNECT_6LOWPAN,
+                                       MGMT_STATUS_NOT_CONNECTED, NULL, 0);
+               goto unlocked;
+       }
+
+       if (conn->dst_type != addr_type) {
+               err = cmd_complete(sk, hdev->id,
+                                       MGMT_OP_DISCONNECT_6LOWPAN,
+                                       MGMT_STATUS_INVALID_PARAMS, NULL, 0);
+               goto unlocked;
+       }
+
+       if (conn->state != BT_CONNECTED) {
+               err = 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 = cmd_complete(sk, hdev->id,
+                                       MGMT_OP_DISCONNECT_6LOWPAN,
+                                       MGMT_STATUS_REJECTED, NULL, 0);
+               goto unlocked;
+       }
+
+       err = 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);
+}
 /* END TIZEN_Bluetooth */
 #endif
 
@@ -7943,6 +8090,7 @@ static const struct mgmt_handler tizen_mgmt_handlers[] = {
        { set_voice_setting,       false, MGMT_SET_VOICE_SETTING_SIZE},
        { get_adv_tx_power,       false, MGMT_GET_ADV_TX_POWER_SIZE},
        { enable_bt_6lowpan,       false, MGMT_ENABLE_BT_6LOWPAN_SIZE },
+       { disconnect_bt_6lowpan,   false, MGMT_DISCONNECT_6LOWPAN_SIZE },
 };
 #endif