Re: [RFC 5/5] bluetooth: Implement Remove Network Management API command

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Patrik,

> Queue Remove Network Management API command and disconnect the L2CAP
> channel. Once the channel has been removed, reply to the command in
> l2cap_ops close callback. On error reply with a failure in the
> l2cap_ops status callback.
> 
> Remove the remaining part of the debugfs code handling the control
> file.
> 
> The MGMT_OP_REMOVE_NETWORK command is defined as:
> 
>       Command Code:           0x0044
>       Controller Index:       <controller id>
>       Command Parameters:     Address (6 Octets)
>                               Address_Type (1 Octet)
>       Return Parameters:      Address (6 Octets)
>                               Address_Type (1 Octet)
> 
>       This command is used to disconnect a network connection from a
>       remote BTLE node. A pre-requisite is that LE is already
>       enabled, otherwise this command will return a "rejected"
>       response.
> 
>       Possible values for the Address_Type parameter:
>               0       Reserved
>               1       LE Public
>               2       LE Random
> 
>       This command generates a Command Complete event on success
>       or failure.
> 
>       Possible errors:        Busy
>                               Not Connected
>                               Invalid Parameters
>                               Not Powered
>                               Invalid Index
> 
> The MGMT_EV_NETWORK_REMOVED event is defined as:
> 
>       Event Code:             0x0026
>       Controller Index:       <controller id>
>       Event Parameters:       Address (6 Octets)
>                               Address_Type (1 Octet)
> 
>       This event indicates that the BTLE network connection to a remote
>       node has been lost.
> 
>       Possible values for the Address_Type parameter:
>               1       LE Public
>               2       LE Random
> 
>       For devices using resolvable random addresses with a known
>       identity resolving key, the Address and Address_Type will
>       contain the identity information.
> ---
> include/net/bluetooth/mgmt.h |  14 ++++
> net/bluetooth/6lowpan.c      | 174 ++++++++++++++++++++++---------------------
> net/bluetooth/mgmt.c         |   3 +
> 3 files changed, 106 insertions(+), 85 deletions(-)
> 
> diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
> index f6bc80f..62d0583 100644
> --- a/include/net/bluetooth/mgmt.h
> +++ b/include/net/bluetooth/mgmt.h
> @@ -606,6 +606,15 @@ struct mgmt_rp_add_network {
> 	int ifindex;
> } __packed;
> 
> +#define MGMT_OP_REMOVE_NETWORK          0x0044
> +#define MGMT_REMOVE_NETWORK_SIZE        7
> +struct mgmt_cp_remove_network {
> +	struct mgmt_addr_info dst;
> +} __packed;
> +struct mgmt_rp_remove_network {
> +	struct mgmt_addr_info dst;
> +} __packed;
> +
> #define MGMT_EV_CMD_COMPLETE		0x0001
> struct mgmt_ev_cmd_complete {
> 	__le16	opcode;
> @@ -825,3 +834,8 @@ struct mgmt_ev_network_added {
> 	struct mgmt_addr_info dst;
> 	int ifindex;
> } __packed;
> +
> +#define MGMT_EV_NETWORK_REMOVED         0x0026
> +struct mgmt_ev_network_removed {
> +	struct mgmt_addr_info dst;
> +} __packed;
> diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
> index 9f12eb1..f62ac14 100644
> --- a/net/bluetooth/6lowpan.c
> +++ b/net/bluetooth/6lowpan.c
> @@ -33,7 +33,6 @@
> #define VERSION "0.1"
> 
> static struct dentry *lowpan_enable_debugfs;
> -static struct dentry *lowpan_control_debugfs;
> 
> #define IFACE_NAME_TEMPLATE "bt%d"
> 
> @@ -929,6 +928,46 @@ static void cmd_add_network_complete(struct l2cap_chan *chan, int status,
> 		mgmt_pending_remove(cmd);
> }
> 
> +static void cmd_remove_network_complete(struct l2cap_chan *chan, int status)
> +{
> +	struct hci_dev *hdev;
> +	struct mgmt_pending_cmd *cmd;
> +
> +	hdev = hci_get_route(NULL, &chan->src);
> +
> +	if (!hdev) {
> +		BT_DBG("No matching hci_dev for l2cap_chan %p", chan);
> +		return;
> +	}
> +
> +	cmd = mgmt_pending_find(HCI_CHANNEL_CONTROL, MGMT_OP_REMOVE_NETWORK,
> +				hdev);
> +	if (cmd) {
> +		struct mgmt_cp_remove_network *cp = cmd->param;
> +		struct mgmt_rp_remove_network rp;
> +
> +		bacpy(&rp.dst.bdaddr, &cp->dst.bdaddr);
> +		rp.dst.type = cp->dst.type;
> +
> +		mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> +				status, &rp, sizeof(rp));
> +	}
> +
> +	if (status == MGMT_STATUS_SUCCESS && chan->state == BT_DISCONN) {
> +		struct mgmt_ev_network_removed ep;
> +
> +		bacpy(&ep.dst.bdaddr, &chan->dst);
> +		ep.dst.type = chan->dst_type;
> +
> +		mgmt_send_event(MGMT_EV_NETWORK_REMOVED, hdev,
> +				HCI_CHANNEL_CONTROL, &ep, sizeof(ep),
> +				HCI_SOCK_TRUSTED, cmd? cmd->sk: NULL);
> +	}
> +
> +	if (cmd)
> +		mgmt_pending_remove(cmd);
> +}
> +
> static inline void chan_ready_cb(struct l2cap_chan *chan)
> {
> 	struct lowpan_dev *dev;
> @@ -1000,6 +1039,7 @@ static void chan_close_cb(struct l2cap_chan *chan)
> 	}
> 
> 	cmd_add_network_complete(chan, MGMT_STATUS_CONNECT_FAILED, 0);
> +	cmd_remove_network_complete(chan, MGMT_STATUS_SUCCESS);
> 
> 	spin_lock(&devices_lock);
> 
> @@ -1045,6 +1085,7 @@ static void chan_state_change_cb(struct l2cap_chan *chan, int state, int err)
> 
> 	if (err < 0) {
> 		cmd_add_network_complete(chan, MGMT_STATUS_CONNECT_FAILED, 0);
> +		cmd_remove_network_complete(chan, MGMT_STATUS_CONNECT_FAILED);
> 	}
> }
> 
> @@ -1270,21 +1311,60 @@ unlock:
> 	return err;
> }
> 
> -static int bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type)
> +int bt_6lowpan_remove_network(struct sock *sk, struct hci_dev *hdev,
> +			void *data, u16 data_len)
> {
> +	struct mgmt_cp_remove_network *cp = data;
> +	int err = 0;
> 	struct lowpan_peer *peer;
> +	struct mgmt_pending_cmd *cmd;
> 
> -	BT_DBG("conn %p dst type %d", conn, dst_type);
> +	BT_DBG("remove network hdev %p data %p data len %d",
> +		hdev, data, data_len);
> 
> -	peer = lookup_peer(conn);
> -	if (!peer)
> -		return -ENOENT;
> +	if (!lmp_le_capable(hdev)) {
> +		err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_NETWORK,
> +					MGMT_STATUS_NOT_SUPPORTED, cp,
> +					sizeof(*cp));
> +		goto failed;
> +	}
> 
> -	BT_DBG("peer %p chan %p", peer, peer->chan);
> +	if (!bdaddr_type_is_le(cp->dst.type)) {
> +		err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_NETWORK,
> +					MGMT_STATUS_INVALID_PARAMS, cp,
> +					sizeof(*cp));
> +		goto failed;
> +	}
> 
> -	l2cap_chan_close(peer->chan, ENOENT);
> +	hci_dev_lock(hdev);
> 
> -	return 0;
> +	if (mgmt_pending_find(HCI_CHANNEL_CONTROL, MGMT_OP_REMOVE_NETWORK,
> +				hdev)) {
> +		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_NETWORK,
> +				MGMT_STATUS_BUSY);
> +		goto unlock;
> +	}
> +
> +	peer = lookup_bdaddr(hdev, &cp->dst.bdaddr, cp->dst.type);
> +	if (!peer) {
> +		err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_NETWORK,
> +					MGMT_STATUS_FAILED,
> +					cp, sizeof(*cp));
> +		goto unlock;
> +	}
> +
> +	cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_NETWORK, hdev,
> +			data, data_len);
> +	if (!cmd)
> +		err = -ENOMEM;
> +
> +	l2cap_chan_close(peer->chan, 0);
> +
> +unlock:
> +	hci_dev_unlock(hdev);
> +
> +failed:
> +	return err;
> }
> 
> static struct l2cap_chan *bt_6lowpan_listen(void)
> @@ -1318,40 +1398,6 @@ static struct l2cap_chan *bt_6lowpan_listen(void)
> 	return chan;
> }
> 
> -static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
> -			  struct l2cap_conn **conn)
> -{
> -	struct hci_conn *hcon;
> -	struct hci_dev *hdev;
> -	bdaddr_t *src = BDADDR_ANY;
> -	int n;
> -
> -	n = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu",
> -		   &addr->b[5], &addr->b[4], &addr->b[3],
> -		   &addr->b[2], &addr->b[1], &addr->b[0],
> -		   addr_type);
> -
> -	if (n < 7)
> -		return -EINVAL;
> -
> -	hdev = hci_get_route(addr, src);
> -	if (!hdev)
> -		return -ENOENT;
> -
> -	hci_dev_lock(hdev);
> -	hcon = hci_conn_hash_lookup_le(hdev, addr, *addr_type);
> -	hci_dev_unlock(hdev);
> -
> -	if (!hcon)
> -		return -ENOENT;
> -
> -	*conn = (struct l2cap_conn *)hcon->l2cap_data;
> -
> -	BT_DBG("conn %p dst %pMR type %d", *conn, &hcon->dst, hcon->dst_type);
> -
> -	return 0;
> -}
> -
> static void disconnect_all_peers(void)
> {
> 	struct lowpan_dev *entry;
> @@ -1445,44 +1491,6 @@ static int lowpan_enable_get(void *data, u64 *val)
> DEFINE_SIMPLE_ATTRIBUTE(lowpan_enable_fops, lowpan_enable_get,
> 			lowpan_enable_set, "%llu\n");
> 
> -static ssize_t lowpan_control_write(struct file *fp,
> -				    const char __user *user_buffer,
> -				    size_t count,
> -				    loff_t *position)
> -{
> -	char buf[32];
> -	size_t buf_size = min(count, sizeof(buf) - 1);
> -	int ret;
> -	bdaddr_t addr;
> -	u8 addr_type;
> -	struct l2cap_conn *conn = NULL;
> -
> -	if (copy_from_user(buf, user_buffer, buf_size))
> -		return -EFAULT;
> -
> -	buf[buf_size] = '\0';
> -
> -	if (memcmp(buf, "disconnect ", 11) == 0) {
> -		ret = get_l2cap_conn(&buf[11], &addr, &addr_type, &conn);
> -		if (ret < 0)
> -			return ret;
> -
> -		ret = bt_6lowpan_disconnect(conn, addr_type);
> -		if (ret < 0)
> -			return ret;
> -
> -		return count;
> -	}
> -
> -	return count;
> -}
> -
> -static const struct file_operations lowpan_control_fops = {
> -	.write		= lowpan_control_write,
> -	.llseek		= seq_lseek,
> -	.release	= single_release,
> -};

removing the debugfs stuff should be a separate cleanup at the end of the series. I prefer we do not intermix this.

Regards

Marcel

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux