diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2011-03-16 12:29:37 (GMT) |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-03-31 17:22:54 (GMT) |
commit | b312b161ecb833b1bce5c4a97853f4a4f40c7901 (patch) | |
tree | 7700417fc16114030316a3a2ba2fcd58ea37a25d /net/bluetooth | |
parent | dc4fe30b8675033e538e2dea50be8af9c75f1b6a (diff) | |
download | linux-fsl-qoriq-b312b161ecb833b1bce5c4a97853f4a4f40c7901.tar.xz |
Bluetooth: mgmt: Add support for setting the local name
This patch adds a new set_local_name management command as well as a
local_name_changed management event. With these user space can both
change the local name as well as monitor changes to it by others.
Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/hci_event.c | 9 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 75 |
2 files changed, 81 insertions, 3 deletions
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 91ef526..0def3e1 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -193,13 +193,16 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); - if (status) - return; - sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME); if (!sent) return; + if (test_bit(HCI_MGMT, &hdev->flags)) + mgmt_set_local_name_complete(hdev->id, sent, status); + + if (status) + return; + memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ffdb2f4..f7ce782 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1256,6 +1256,45 @@ failed: return err; } +static int set_local_name(struct sock *sk, u16 index, unsigned char *data, + u16 len) +{ + struct mgmt_cp_set_local_name *mgmt_cp = (void *) data; + struct hci_cp_write_local_name hci_cp; + struct hci_dev *hdev; + struct pending_cmd *cmd; + int err; + + BT_DBG(""); + + if (len != sizeof(*mgmt_cp)) + return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV); + + hci_dev_lock_bh(hdev); + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name)); + err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp), + &hci_cp); + if (err < 0) + mgmt_pending_remove(cmd); + +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; @@ -1351,6 +1390,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_USER_CONFIRM_NEG_REPLY: err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0); break; + case MGMT_OP_SET_LOCAL_NAME: + err = set_local_name(sk, index, buf + sizeof(*hdr), len); + break; default: BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, 0x01); @@ -1647,3 +1689,36 @@ int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status) return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL); } + +int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status) +{ + struct pending_cmd *cmd; + struct mgmt_cp_set_local_name ev; + int err; + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); + + cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index); + if (!cmd) + goto send_event; + + if (status) { + err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO); + goto failed; + } + + err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev, + sizeof(ev)); + if (err < 0) + goto failed; + +send_event: + err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev), + cmd ? cmd->sk : NULL); + +failed: + if (cmd) + mgmt_pending_remove(cmd); + return err; +} |