diff options
Diffstat (limited to 'net/bluetooth/mgmt.c')
| -rw-r--r-- | net/bluetooth/mgmt.c | 131 | 
1 files changed, 64 insertions, 67 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3e5e3362ea0..ad6613d17ca 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -24,8 +24,6 @@  /* Bluetooth HCI Management interface */ -#include <linux/kernel.h> -#include <linux/uaccess.h>  #include <linux/module.h>  #include <asm/unaligned.h> @@ -212,7 +210,7 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)  	BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status); -	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC); +	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);  	if (!skb)  		return -ENOMEM; @@ -243,7 +241,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,  	BT_DBG("sock %p", sk); -	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC); +	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);  	if (!skb)  		return -ENOMEM; @@ -689,14 +687,14 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,  {  	struct pending_cmd *cmd; -	cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); +	cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);  	if (!cmd)  		return NULL;  	cmd->opcode = opcode;  	cmd->index = hdev->id; -	cmd->param = kmalloc(len, GFP_ATOMIC); +	cmd->param = kmalloc(len, GFP_KERNEL);  	if (!cmd->param) {  		kfree(cmd);  		return NULL; @@ -714,7 +712,8 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,  }  static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, -				 void (*cb)(struct pending_cmd *cmd, void *data), +				 void (*cb)(struct pending_cmd *cmd, +					    void *data),  				 void *data)  {  	struct list_head *p, *n; @@ -813,7 +812,7 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,  	struct sk_buff *skb;  	struct mgmt_hdr *hdr; -	skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC); +	skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);  	if (!skb)  		return -ENOMEM; @@ -871,7 +870,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,  	}  	if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || -			mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { +	    mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {  		err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,  				 MGMT_STATUS_BUSY);  		goto failed; @@ -978,7 +977,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,  	}  	if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || -			mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { +	    mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {  		err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,  				 MGMT_STATUS_BUSY);  		goto failed; @@ -1001,7 +1000,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,  		scan = 0;  		if (test_bit(HCI_ISCAN, &hdev->flags) && -						hdev->discov_timeout > 0) +		    hdev->discov_timeout > 0)  			cancel_delayed_work(&hdev->discov_off);  	} @@ -1056,7 +1055,7 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,  		bool changed = false;  		if (!!cp->val != test_bit(HCI_LINK_SECURITY, -							&hdev->dev_flags)) { +					  &hdev->dev_flags)) {  			change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);  			changed = true;  		} @@ -1269,7 +1268,7 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)  		goto failed;  	} -	uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); +	uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);  	if (!uuid) {  		err = -ENOMEM;  		goto failed; @@ -1317,7 +1316,7 @@ static bool enable_service_cache(struct hci_dev *hdev)  }  static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, -								u16 len) +		       u16 len)  {  	struct mgmt_cp_remove_uuid *cp = data;  	struct pending_cmd *cmd; @@ -1442,7 +1441,7 @@ unlock:  }  static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, -								u16 len) +			  u16 len)  {  	struct mgmt_cp_load_link_keys *cp = data;  	u16 key_count, expected_len; @@ -1454,13 +1453,13 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,  					sizeof(struct mgmt_link_key_info);  	if (expected_len != len) {  		BT_ERR("load_link_keys: expected %u bytes, got %u bytes", -							len, expected_len); +		       len, expected_len);  		return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,  				  MGMT_STATUS_INVALID_PARAMS);  	}  	BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys, -								key_count); +	       key_count);  	hci_dev_lock(hdev); @@ -1535,10 +1534,10 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,  	if (cp->disconnect) {  		if (cp->addr.type == BDADDR_BREDR)  			conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, -							&cp->addr.bdaddr); +						       &cp->addr.bdaddr);  		else  			conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, -							&cp->addr.bdaddr); +						       &cp->addr.bdaddr);  	} else {  		conn = NULL;  	} @@ -1594,7 +1593,8 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,  	}  	if (cp->addr.type == BDADDR_BREDR) -		conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); +		conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, +					       &cp->addr.bdaddr);  	else  		conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); @@ -1611,7 +1611,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,  	}  	dc.handle = cpu_to_le16(conn->handle); -	dc.reason = 0x13; /* Remote User Terminated Connection */ +	dc.reason = HCI_ERROR_REMOTE_USER_TERM;  	err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);  	if (err < 0) @@ -1667,7 +1667,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,  	}  	rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info)); -	rp = kmalloc(rp_len, GFP_ATOMIC); +	rp = kmalloc(rp_len, GFP_KERNEL);  	if (!rp) {  		err = -ENOMEM;  		goto unlock; @@ -1778,29 +1778,6 @@ failed:  	return err;  } -static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, -			      void *data, u16 len) -{ -	struct mgmt_cp_pin_code_neg_reply *cp = data; -	int err; - -	BT_DBG(""); - -	hci_dev_lock(hdev); - -	if (!hdev_is_powered(hdev)) { -		err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, -				 MGMT_STATUS_NOT_POWERED); -		goto failed; -	} - -	err = send_pin_code_neg_reply(sk, hdev, cp); - -failed: -	hci_dev_unlock(hdev); -	return err; -} -  static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,  			     u16 len)  { @@ -1813,7 +1790,7 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,  	hdev->io_capability = cp->io_capability;  	BT_DBG("%s IO capability set to 0x%02x", hdev->name, -							hdev->io_capability); +	       hdev->io_capability);  	hci_dev_unlock(hdev); @@ -1821,7 +1798,7 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,  			    0);  } -static inline struct pending_cmd *find_pairing(struct hci_conn *conn) +static struct pending_cmd *find_pairing(struct hci_conn *conn)  {  	struct hci_dev *hdev = conn->hdev;  	struct pending_cmd *cmd; @@ -1927,8 +1904,15 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,  	rp.addr.type = cp->addr.type;  	if (IS_ERR(conn)) { +		int status; + +		if (PTR_ERR(conn) == -EBUSY) +			status = MGMT_STATUS_BUSY; +		else +			status = MGMT_STATUS_CONNECT_FAILED; +  		err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, -				   MGMT_STATUS_CONNECT_FAILED, &rp, +				   status, &rp,  				   sizeof(rp));  		goto unlock;  	} @@ -1959,7 +1943,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,  	cmd->user_data = conn;  	if (conn->state == BT_CONNECTED && -				hci_conn_security(conn, sec_level, auth_type)) +	    hci_conn_security(conn, sec_level, auth_type))  		pairing_complete(cmd, 0);  	err = 0; @@ -2076,6 +2060,18 @@ done:  	return err;  } +static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, +			      void *data, u16 len) +{ +	struct mgmt_cp_pin_code_neg_reply *cp = data; + +	BT_DBG(""); + +	return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, +				MGMT_OP_PIN_CODE_NEG_REPLY, +				HCI_OP_PIN_CODE_NEG_REPLY, 0); +} +  static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,  			      u16 len)  { @@ -2256,7 +2252,7 @@ unlock:  }  static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev, -						void *data, u16 len) +				  void *data, u16 len)  {  	struct mgmt_cp_remove_remote_oob_data *cp = data;  	u8 status; @@ -2425,7 +2421,7 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,  	case DISCOVERY_RESOLVING:  		e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, -							NAME_PENDING); +						     NAME_PENDING);  		if (!e) {  			mgmt_pending_remove(cmd);  			err = cmd_complete(sk, hdev->id, @@ -2600,8 +2596,8 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,  	if (cp->val) {  		type = PAGE_SCAN_TYPE_INTERLACED; -		/* 22.5 msec page scan interval */ -		acp.interval = __constant_cpu_to_le16(0x0024); +		/* 160 msec page scan interval */ +		acp.interval = __constant_cpu_to_le16(0x0100);  	} else {  		type = PAGE_SCAN_TYPE_STANDARD;	/* default */ @@ -2647,7 +2643,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,  					sizeof(struct mgmt_ltk_info);  	if (expected_len != len) {  		BT_ERR("load_keys: expected %u bytes, got %u bytes", -							len, expected_len); +		       len, expected_len);  		return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,  				  EINVAL);  	} @@ -2772,7 +2768,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)  	}  	if (opcode >= ARRAY_SIZE(mgmt_handlers) || -					mgmt_handlers[opcode].func == NULL) { +	    mgmt_handlers[opcode].func == NULL) {  		BT_DBG("Unknown op %u", opcode);  		err = cmd_status(sk, index, opcode,  				 MGMT_STATUS_UNKNOWN_COMMAND); @@ -2780,7 +2776,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)  	}  	if ((hdev && opcode < MGMT_OP_READ_INFO) || -			(!hdev && opcode >= MGMT_OP_READ_INFO)) { +	    (!hdev && opcode >= MGMT_OP_READ_INFO)) {  		err = cmd_status(sk, index, opcode,  				 MGMT_STATUS_INVALID_INDEX);  		goto done; @@ -2789,7 +2785,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)  	handler = &mgmt_handlers[opcode];  	if ((handler->var_len && len < handler->data_len) || -			(!handler->var_len && len != handler->data_len)) { +	    (!handler->var_len && len != handler->data_len)) {  		err = cmd_status(sk, index, opcode,  				 MGMT_STATUS_INVALID_PARAMS);  		goto done; @@ -2973,7 +2969,7 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,  	bacpy(&ev.key.addr.bdaddr, &key->bdaddr);  	ev.key.addr.type = BDADDR_BREDR;  	ev.key.type = key->type; -	memcpy(ev.key.val, key->val, 16); +	memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);  	ev.key.pin_len = key->pin_len;  	return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL); @@ -3108,7 +3104,7 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,  	mgmt_pending_remove(cmd);  	mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, -									hdev); +			     hdev);  	return err;  } @@ -3198,7 +3194,7 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,  }  int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, -						u8 link_type, u8 addr_type) +			      u8 link_type, u8 addr_type)  {  	struct mgmt_ev_user_passkey_request ev; @@ -3212,8 +3208,8 @@ int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,  }  static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, -					u8 link_type, u8 addr_type, u8 status, -					u8 opcode) +				      u8 link_type, u8 addr_type, u8 status, +				      u8 opcode)  {  	struct pending_cmd *cmd;  	struct mgmt_rp_user_confirm_reply rp; @@ -3244,7 +3240,8 @@ int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,  					 u8 link_type, u8 addr_type, u8 status)  {  	return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, -					  status, MGMT_OP_USER_CONFIRM_NEG_REPLY); +					  status, +					  MGMT_OP_USER_CONFIRM_NEG_REPLY);  }  int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, @@ -3258,7 +3255,8 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,  					 u8 link_type, u8 addr_type, u8 status)  {  	return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, -					  status, MGMT_OP_USER_PASSKEY_NEG_REPLY); +					  status, +					  MGMT_OP_USER_PASSKEY_NEG_REPLY);  }  int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, @@ -3537,9 +3535,9 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,  	ev->addr.type = link_to_bdaddr(link_type, addr_type);  	ev->rssi = rssi;  	if (cfm_name) -		ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME; +		ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);  	if (!ssp) -		ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING; +		ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);  	if (eir_len > 0)  		memcpy(ev->eir, eir, eir_len); @@ -3549,7 +3547,6 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,  					  dev_class, 3);  	ev->eir_len = cpu_to_le16(eir_len); -  	ev_size = sizeof(*ev) + eir_len;  	return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);  |