aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/mgmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r--net/bluetooth/mgmt.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index a08f4ce03182..bdb0e85f182e 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -794,6 +794,99 @@ static int set_service_cache(struct sock *sk, unsigned char *data, u16 len)
794 return err; 794 return err;
795} 795}
796 796
797static int load_keys(struct sock *sk, unsigned char *data, u16 len)
798{
799 struct hci_dev *hdev;
800 struct mgmt_cp_load_keys *cp;
801 u16 dev_id, key_count, expected_len;
802 int i;
803
804 cp = (void *) data;
805 dev_id = get_unaligned_le16(&cp->index);
806 key_count = get_unaligned_le16(&cp->key_count);
807
808 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
809 if (expected_len != len) {
810 BT_ERR("load_keys: expected %u bytes, got %u bytes",
811 len, expected_len);
812 return -EINVAL;
813 }
814
815 hdev = hci_dev_get(dev_id);
816 if (!hdev)
817 return cmd_status(sk, MGMT_OP_LOAD_KEYS, ENODEV);
818
819 BT_DBG("hci%u debug_keys %u key_count %u", dev_id, cp->debug_keys,
820 key_count);
821
822 hci_dev_lock_bh(hdev);
823
824 hci_link_keys_clear(hdev);
825
826 set_bit(HCI_LINK_KEYS, &hdev->flags);
827
828 if (cp->debug_keys)
829 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
830 else
831 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
832
833 for (i = 0; i < key_count; i++) {
834 struct mgmt_key_info *key = &cp->keys[i];
835
836 hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type,
837 key->pin_len);
838 }
839
840 hci_dev_unlock_bh(hdev);
841 hci_dev_put(hdev);
842
843 return 0;
844}
845
846static int remove_key(struct sock *sk, unsigned char *data, u16 len)
847{
848 struct hci_dev *hdev;
849 struct mgmt_cp_remove_key *cp;
850 struct hci_conn *conn;
851 u16 dev_id;
852 int err;
853
854 cp = (void *) data;
855 dev_id = get_unaligned_le16(&cp->index);
856
857 hdev = hci_dev_get(dev_id);
858 if (!hdev)
859 return cmd_status(sk, MGMT_OP_REMOVE_KEY, ENODEV);
860
861 hci_dev_lock_bh(hdev);
862
863 err = hci_remove_link_key(hdev, &cp->bdaddr);
864 if (err < 0) {
865 err = cmd_status(sk, MGMT_OP_REMOVE_KEY, -err);
866 goto unlock;
867 }
868
869 err = 0;
870
871 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
872 goto unlock;
873
874 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
875 if (conn) {
876 struct hci_cp_disconnect dc;
877
878 put_unaligned_le16(conn->handle, &dc.handle);
879 dc.reason = 0x13; /* Remote User Terminated Connection */
880 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, 0, NULL);
881 }
882
883unlock:
884 hci_dev_unlock_bh(hdev);
885 hci_dev_put(hdev);
886
887 return err;
888}
889
797int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) 890int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
798{ 891{
799 unsigned char *buf; 892 unsigned char *buf;
@@ -858,6 +951,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
858 case MGMT_OP_SET_SERVICE_CACHE: 951 case MGMT_OP_SET_SERVICE_CACHE:
859 err = set_service_cache(sk, buf + sizeof(*hdr), len); 952 err = set_service_cache(sk, buf + sizeof(*hdr), len);
860 break; 953 break;
954 case MGMT_OP_LOAD_KEYS:
955 err = load_keys(sk, buf + sizeof(*hdr), len);
956 break;
957 case MGMT_OP_REMOVE_KEY:
958 err = remove_key(sk, buf + sizeof(*hdr), len);
959 break;
861 default: 960 default:
862 BT_DBG("Unknown op %u", opcode); 961 BT_DBG("Unknown op %u", opcode);
863 err = cmd_status(sk, opcode, 0x01); 962 err = cmd_status(sk, opcode, 0x01);
@@ -974,3 +1073,20 @@ int mgmt_connectable(u16 index, u8 connectable)
974 1073
975 return ret; 1074 return ret;
976} 1075}
1076
1077int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
1078{
1079 struct mgmt_ev_new_key ev;
1080
1081 memset(&ev, 0, sizeof(ev));
1082
1083 put_unaligned_le16(index, &ev.index);
1084
1085 bacpy(&ev.key.bdaddr, &key->bdaddr);
1086 ev.key.type = key->type;
1087 memcpy(ev.key.val, key->val, 16);
1088 ev.key.pin_len = key->pin_len;
1089 ev.old_key_type = old_key_type;
1090
1091 return mgmt_event(MGMT_EV_NEW_KEY, &ev, sizeof(ev), NULL);
1092}