Bluetooth: IPSP Connect/Disconnect apis
authorSudha Bheemanna <b.sudha@samsung.com>
Thu, 15 Sep 2016 07:23:03 +0000 (12:53 +0530)
committerJaehoon Chung <jh80.chung@samsung.com>
Mon, 19 Feb 2024 00:13:52 +0000 (09:13 +0900)
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>
Signed-off-by: Amit Purwar <amit.purwar@samsung.com>
Signed-off-by: Wootak Jung <wootak.jung@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 fc9ad74..6dd3d0f 100644 (file)
@@ -2424,6 +2424,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
 
 int hci_abort_conn(struct hci_conn *conn, u8 reason);
index a13d22a..4bd23ae 100644 (file)
@@ -1011,9 +1011,14 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user);
 /* 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 /* TIZEN_BT */
 
index 6549be1..52a36f9 100644 (file)
@@ -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,5 +266,11 @@ 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 */
index fd15bff..bcb4407 100644 (file)
@@ -732,6 +732,12 @@ static inline void chan_ready_cb(struct l2cap_chan *chan)
 
        add_peer_chan(chan, dev, new_netdev);
        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)
@@ -1291,6 +1297,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 bc4614b..caaf1f4 100644 (file)
@@ -8985,6 +8985,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)
@@ -11321,6 +11469,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