forked from luck/tmp_suning_uos_patched
Bluetooth: Add support for PIN code handling in the management interface
This patch adds the necessary commands and events needed to communicate PIN code related actions between the kernel and userspace. This includes a pin_code_request event as well as pin_code_reply and pin_code_negative_reply commands. Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
This commit is contained in:
parent
a38528f111
commit
980e1a537f
@ -309,11 +309,19 @@ struct hci_cp_pin_code_reply {
|
||||
__u8 pin_len;
|
||||
__u8 pin_code[16];
|
||||
} __packed;
|
||||
struct hci_rp_pin_code_reply {
|
||||
__u8 status;
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_PIN_CODE_NEG_REPLY 0x040e
|
||||
struct hci_cp_pin_code_neg_reply {
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
struct hci_rp_pin_code_neg_reply {
|
||||
__u8 status;
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_CHANGE_CONN_PTYPE 0x040f
|
||||
struct hci_cp_change_conn_ptype {
|
||||
|
@ -213,6 +213,7 @@ struct hci_conn {
|
||||
__u8 auth_type;
|
||||
__u8 sec_level;
|
||||
__u8 pending_sec_level;
|
||||
__u8 pin_length;
|
||||
__u8 power_save;
|
||||
__u16 disc_timeout;
|
||||
unsigned long pend;
|
||||
@ -718,6 +719,9 @@ int mgmt_connected(u16 index, bdaddr_t *bdaddr);
|
||||
int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
|
||||
int mgmt_disconnect_failed(u16 index);
|
||||
int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
|
||||
int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr);
|
||||
int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
|
||||
int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
|
||||
|
||||
/* HCI info for socket */
|
||||
#define hci_pi(sk) ((struct hci_pinfo *) sk)
|
||||
|
@ -140,6 +140,20 @@ struct mgmt_rp_get_connections {
|
||||
bdaddr_t conn[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_PIN_CODE_REPLY 0x0011
|
||||
struct mgmt_cp_pin_code_reply {
|
||||
__le16 index;
|
||||
bdaddr_t bdaddr;
|
||||
__u8 pin_len;
|
||||
__u8 pin_code[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_PIN_CODE_NEG_REPLY 0x0012
|
||||
struct mgmt_cp_pin_code_neg_reply {
|
||||
__le16 index;
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CMD_COMPLETE 0x0001
|
||||
struct mgmt_ev_cmd_complete {
|
||||
__le16 opcode;
|
||||
@ -201,3 +215,9 @@ struct mgmt_ev_connect_failed {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 status;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_PIN_CODE_REQUEST 0x000E
|
||||
struct mgmt_ev_pin_code_request {
|
||||
__le16 index;
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
@ -743,6 +743,40 @@ static void hci_cc_set_event_flt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_req_complete(hdev, HCI_OP_SET_EVENT_FLT, status);
|
||||
}
|
||||
|
||||
static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_pin_code_reply *rp = (void *) skb->data;
|
||||
struct hci_cp_pin_code_reply *cp;
|
||||
struct hci_conn *conn;
|
||||
|
||||
BT_DBG("%s status 0x%x", hdev->name, rp->status);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_pin_code_reply_complete(hdev->id, &rp->bdaddr, rp->status);
|
||||
|
||||
if (rp->status != 0)
|
||||
return;
|
||||
|
||||
cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
|
||||
if (!cp)
|
||||
return;
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
|
||||
if (conn)
|
||||
conn->pin_length = cp->pin_len;
|
||||
}
|
||||
|
||||
static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_pin_code_neg_reply *rp = (void *) skb->data;
|
||||
|
||||
BT_DBG("%s status 0x%x", hdev->name, rp->status);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_pin_code_neg_reply_complete(hdev->id, &rp->bdaddr,
|
||||
rp->status);
|
||||
}
|
||||
|
||||
static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
|
||||
{
|
||||
BT_DBG("%s status 0x%x", hdev->name, status);
|
||||
@ -1619,6 +1653,14 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
|
||||
hci_cc_set_event_flt(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_PIN_CODE_REPLY:
|
||||
hci_cc_pin_code_reply(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_PIN_CODE_NEG_REPLY:
|
||||
hci_cc_pin_code_neg_reply(hdev, skb);
|
||||
break;
|
||||
|
||||
default:
|
||||
BT_DBG("%s opcode 0x%x", hdev->name, opcode);
|
||||
break;
|
||||
@ -1821,6 +1863,9 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
|
||||
hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
|
||||
sizeof(ev->bdaddr), &ev->bdaddr);
|
||||
|
||||
if (test_bit(HCI_MGMT, &hdev->flags))
|
||||
mgmt_pin_code_request(hdev->id, &ev->bdaddr);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
@ -1889,6 +1934,7 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
|
||||
if (conn) {
|
||||
hci_conn_hold(conn);
|
||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
pin_len = conn->pin_length;
|
||||
hci_conn_put(conn);
|
||||
}
|
||||
|
||||
|
@ -933,6 +933,89 @@ static int get_connections(struct sock *sk, unsigned char *data, u16 len)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int pin_code_reply(struct sock *sk, unsigned char *data, u16 len)
|
||||
{
|
||||
struct hci_dev *hdev;
|
||||
struct mgmt_cp_pin_code_reply *cp;
|
||||
struct hci_cp_pin_code_reply reply;
|
||||
u16 dev_id;
|
||||
int err;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
cp = (void *) data;
|
||||
dev_id = get_unaligned_le16(&cp->index);
|
||||
|
||||
hdev = hci_dev_get(dev_id);
|
||||
if (!hdev)
|
||||
return cmd_status(sk, MGMT_OP_DISCONNECT, ENODEV);
|
||||
|
||||
hci_dev_lock_bh(hdev);
|
||||
|
||||
if (!test_bit(HCI_UP, &hdev->flags)) {
|
||||
err = cmd_status(sk, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
err = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, dev_id, data, len);
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
|
||||
bacpy(&reply.bdaddr, &cp->bdaddr);
|
||||
reply.pin_len = cp->pin_len;
|
||||
memcpy(reply.pin_code, cp->pin_code, 16);
|
||||
|
||||
err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
|
||||
if (err < 0)
|
||||
mgmt_pending_remove(MGMT_OP_PIN_CODE_REPLY, dev_id);
|
||||
|
||||
failed:
|
||||
hci_dev_unlock_bh(hdev);
|
||||
hci_dev_put(hdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int pin_code_neg_reply(struct sock *sk, unsigned char *data, u16 len)
|
||||
{
|
||||
struct hci_dev *hdev;
|
||||
struct mgmt_cp_pin_code_neg_reply *cp;
|
||||
u16 dev_id;
|
||||
int err;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
cp = (void *) data;
|
||||
dev_id = get_unaligned_le16(&cp->index);
|
||||
|
||||
hdev = hci_dev_get(dev_id);
|
||||
if (!hdev)
|
||||
return cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENODEV);
|
||||
|
||||
hci_dev_lock_bh(hdev);
|
||||
|
||||
if (!test_bit(HCI_UP, &hdev->flags)) {
|
||||
err = cmd_status(sk, MGMT_OP_PIN_CODE_NEG_REPLY, ENETDOWN);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
err = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, dev_id,
|
||||
data, len);
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
|
||||
err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(bdaddr_t),
|
||||
&cp->bdaddr);
|
||||
if (err < 0)
|
||||
mgmt_pending_remove(MGMT_OP_PIN_CODE_NEG_REPLY, dev_id);
|
||||
|
||||
failed:
|
||||
hci_dev_unlock_bh(hdev);
|
||||
hci_dev_put(hdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
|
||||
{
|
||||
unsigned char *buf;
|
||||
@ -1009,6 +1092,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
|
||||
case MGMT_OP_GET_CONNECTIONS:
|
||||
err = get_connections(sk, buf + sizeof(*hdr), len);
|
||||
break;
|
||||
case MGMT_OP_PIN_CODE_REPLY:
|
||||
err = pin_code_reply(sk, buf + sizeof(*hdr), len);
|
||||
break;
|
||||
case MGMT_OP_PIN_CODE_NEG_REPLY:
|
||||
err = pin_code_neg_reply(sk, buf + sizeof(*hdr), len);
|
||||
break;
|
||||
default:
|
||||
BT_DBG("Unknown op %u", opcode);
|
||||
err = cmd_status(sk, opcode, 0x01);
|
||||
@ -1217,3 +1306,55 @@ int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
|
||||
|
||||
return mgmt_event(MGMT_EV_CONNECT_FAILED, &ev, sizeof(ev), NULL);
|
||||
}
|
||||
|
||||
int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
|
||||
{
|
||||
struct mgmt_ev_pin_code_request ev;
|
||||
|
||||
put_unaligned_le16(index, &ev.index);
|
||||
bacpy(&ev.bdaddr, bdaddr);
|
||||
|
||||
return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, &ev, sizeof(ev), NULL);
|
||||
}
|
||||
|
||||
int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
|
||||
{
|
||||
struct pending_cmd *cmd;
|
||||
int err;
|
||||
|
||||
cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
|
||||
if (!cmd)
|
||||
return -ENOENT;
|
||||
|
||||
if (status != 0)
|
||||
err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_REPLY, status);
|
||||
else
|
||||
err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_REPLY,
|
||||
bdaddr, sizeof(*bdaddr));
|
||||
|
||||
list_del(&cmd->list);
|
||||
mgmt_pending_free(cmd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
|
||||
{
|
||||
struct pending_cmd *cmd;
|
||||
int err;
|
||||
|
||||
cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
|
||||
if (!cmd)
|
||||
return -ENOENT;
|
||||
|
||||
if (status != 0)
|
||||
err = cmd_status(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY, status);
|
||||
else
|
||||
err = cmd_complete(cmd->sk, MGMT_OP_PIN_CODE_NEG_REPLY,
|
||||
bdaddr, sizeof(*bdaddr));
|
||||
|
||||
list_del(&cmd->list);
|
||||
mgmt_pending_free(cmd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user