Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Bluetooth: Add generic mgmt helper API

There are several mgmt protocol features that will be needed by more
than just the current HCI_CHANNEL_CONTROL. These include sending generic
events as well as handling pending commands. This patch moves these
functions out from mgmt.c to a new mgmt_util.c file.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

authored by

Johan Hedberg and committed by
Marcel Holtmann
a380b6cf 333ae95d

+265 -197
+1 -1
net/bluetooth/Makefile
··· 13 13 14 14 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ 15 15 hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ 16 - a2mp.o amp.o ecc.o hci_request.o 16 + a2mp.o amp.o ecc.o hci_request.o mgmt_util.o 17 17 18 18 bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o 19 19 bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o
+1 -196
net/bluetooth/mgmt.c
··· 35 35 36 36 #include "hci_request.h" 37 37 #include "smp.h" 38 + #include "mgmt_util.h" 38 39 39 40 #define MGMT_VERSION 1 40 41 #define MGMT_REVISION 9 ··· 142 141 #define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \ 143 142 "\x00\x00\x00\x00\x00\x00\x00\x00" 144 143 145 - struct mgmt_pending_cmd { 146 - struct list_head list; 147 - u16 opcode; 148 - int index; 149 - void *param; 150 - size_t param_len; 151 - struct sock *sk; 152 - void *user_data; 153 - int (*cmd_complete)(struct mgmt_pending_cmd *cmd, u8 status); 154 - }; 155 - 156 144 /* HCI to MGMT error code conversion table */ 157 145 static u8 mgmt_status_table[] = { 158 146 MGMT_STATUS_SUCCESS, ··· 215 225 return MGMT_STATUS_FAILED; 216 226 } 217 227 218 - static int mgmt_send_event(u16 event, struct hci_dev *hdev, 219 - unsigned short channel, void *data, u16 data_len, 220 - int flag, struct sock *skip_sk) 221 - { 222 - struct sk_buff *skb; 223 - struct mgmt_hdr *hdr; 224 - 225 - skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL); 226 - if (!skb) 227 - return -ENOMEM; 228 - 229 - hdr = (void *) skb_put(skb, sizeof(*hdr)); 230 - hdr->opcode = cpu_to_le16(event); 231 - if (hdev) 232 - hdr->index = cpu_to_le16(hdev->id); 233 - else 234 - hdr->index = cpu_to_le16(MGMT_INDEX_NONE); 235 - hdr->len = cpu_to_le16(data_len); 236 - 237 - if (data) 238 - memcpy(skb_put(skb, data_len), data, data_len); 239 - 240 - /* Time stamp */ 241 - __net_timestamp(skb); 242 - 243 - hci_send_to_channel(channel, skb, flag, skip_sk); 244 - kfree_skb(skb); 245 - 246 - return 0; 247 - } 248 - 249 228 static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data, 250 229 u16 len, int flag) 251 230 { ··· 241 282 { 242 283 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len, 243 284 HCI_SOCK_TRUSTED, skip_sk); 244 - } 245 - 246 - static int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) 247 - { 248 - struct sk_buff *skb; 249 - struct mgmt_hdr *hdr; 250 - struct mgmt_ev_cmd_status *ev; 251 - int err; 252 - 253 - BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status); 254 - 255 - skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL); 256 - if (!skb) 257 - return -ENOMEM; 258 - 259 - hdr = (void *) skb_put(skb, sizeof(*hdr)); 260 - 261 - hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS); 262 - hdr->index = cpu_to_le16(index); 263 - hdr->len = cpu_to_le16(sizeof(*ev)); 264 - 265 - ev = (void *) skb_put(skb, sizeof(*ev)); 266 - ev->status = status; 267 - ev->opcode = cpu_to_le16(cmd); 268 - 269 - err = sock_queue_rcv_skb(sk, skb); 270 - if (err < 0) 271 - kfree_skb(skb); 272 - 273 - return err; 274 - } 275 - 276 - static int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, 277 - void *rp, size_t rp_len) 278 - { 279 - struct sk_buff *skb; 280 - struct mgmt_hdr *hdr; 281 - struct mgmt_ev_cmd_complete *ev; 282 - int err; 283 - 284 - BT_DBG("sock %p", sk); 285 - 286 - skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL); 287 - if (!skb) 288 - return -ENOMEM; 289 - 290 - hdr = (void *) skb_put(skb, sizeof(*hdr)); 291 - 292 - hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE); 293 - hdr->index = cpu_to_le16(index); 294 - hdr->len = cpu_to_le16(sizeof(*ev) + rp_len); 295 - 296 - ev = (void *) skb_put(skb, sizeof(*ev) + rp_len); 297 - ev->opcode = cpu_to_le16(cmd); 298 - ev->status = status; 299 - 300 - if (rp) 301 - memcpy(ev->data, rp, rp_len); 302 - 303 - err = sock_queue_rcv_skb(sk, skb); 304 - if (err < 0) 305 - kfree_skb(skb); 306 - 307 - return err; 308 285 } 309 286 310 287 static int read_version(struct sock *sk, struct hci_dev *hdev, void *data, ··· 777 882 return ptr; 778 883 } 779 884 780 - static struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, 781 - u16 opcode, 782 - struct hci_dev *hdev) 783 - { 784 - struct mgmt_pending_cmd *cmd; 785 - 786 - list_for_each_entry(cmd, &hdev->mgmt_pending, list) { 787 - if (hci_sock_get_channel(cmd->sk) != channel) 788 - continue; 789 - if (cmd->opcode == opcode) 790 - return cmd; 791 - } 792 - 793 - return NULL; 794 - } 795 - 796 885 static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev) 797 886 { 798 887 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev); 799 - } 800 - 801 - static struct mgmt_pending_cmd *mgmt_pending_find_data(unsigned short channel, 802 - u16 opcode, 803 - struct hci_dev *hdev, 804 - const void *data) 805 - { 806 - struct mgmt_pending_cmd *cmd; 807 - 808 - list_for_each_entry(cmd, &hdev->mgmt_pending, list) { 809 - if (cmd->user_data != data) 810 - continue; 811 - if (cmd->opcode == opcode) 812 - return cmd; 813 - } 814 - 815 - return NULL; 816 888 } 817 889 818 890 static struct mgmt_pending_cmd *pending_find_data(u16 opcode, ··· 1201 1339 1202 1340 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp, 1203 1341 sizeof(rp)); 1204 - } 1205 - 1206 - static void mgmt_pending_free(struct mgmt_pending_cmd *cmd) 1207 - { 1208 - sock_put(cmd->sk); 1209 - kfree(cmd->param); 1210 - kfree(cmd); 1211 - } 1212 - 1213 - static struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, 1214 - struct hci_dev *hdev, 1215 - void *data, u16 len) 1216 - { 1217 - struct mgmt_pending_cmd *cmd; 1218 - 1219 - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 1220 - if (!cmd) 1221 - return NULL; 1222 - 1223 - cmd->opcode = opcode; 1224 - cmd->index = hdev->id; 1225 - 1226 - cmd->param = kmemdup(data, len, GFP_KERNEL); 1227 - if (!cmd->param) { 1228 - kfree(cmd); 1229 - return NULL; 1230 - } 1231 - 1232 - cmd->param_len = len; 1233 - 1234 - cmd->sk = sk; 1235 - sock_hold(sk); 1236 - 1237 - list_add(&cmd->list, &hdev->mgmt_pending); 1238 - 1239 - return cmd; 1240 - } 1241 - 1242 - static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, 1243 - void (*cb)(struct mgmt_pending_cmd *cmd, 1244 - void *data), 1245 - void *data) 1246 - { 1247 - struct mgmt_pending_cmd *cmd, *tmp; 1248 - 1249 - list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) { 1250 - if (opcode > 0 && cmd->opcode != opcode) 1251 - continue; 1252 - 1253 - cb(cmd, data); 1254 - } 1255 - } 1256 - 1257 - static void mgmt_pending_remove(struct mgmt_pending_cmd *cmd) 1258 - { 1259 - list_del(&cmd->list); 1260 - mgmt_pending_free(cmd); 1261 1342 } 1262 1343 1263 1344 static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
+210
net/bluetooth/mgmt_util.c
··· 1 + /* 2 + BlueZ - Bluetooth protocol stack for Linux 3 + 4 + Copyright (C) 2015 Intel Corporation 5 + 6 + This program is free software; you can redistribute it and/or modify 7 + it under the terms of the GNU General Public License version 2 as 8 + published by the Free Software Foundation; 9 + 10 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 11 + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. 13 + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY 14 + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 15 + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 + 19 + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 20 + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 21 + SOFTWARE IS DISCLAIMED. 22 + */ 23 + 24 + #include <net/bluetooth/bluetooth.h> 25 + #include <net/bluetooth/hci_core.h> 26 + #include <net/bluetooth/mgmt.h> 27 + 28 + #include "mgmt_util.h" 29 + 30 + int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel, 31 + void *data, u16 data_len, int flag, struct sock *skip_sk) 32 + { 33 + struct sk_buff *skb; 34 + struct mgmt_hdr *hdr; 35 + 36 + skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL); 37 + if (!skb) 38 + return -ENOMEM; 39 + 40 + hdr = (void *) skb_put(skb, sizeof(*hdr)); 41 + hdr->opcode = cpu_to_le16(event); 42 + if (hdev) 43 + hdr->index = cpu_to_le16(hdev->id); 44 + else 45 + hdr->index = cpu_to_le16(MGMT_INDEX_NONE); 46 + hdr->len = cpu_to_le16(data_len); 47 + 48 + if (data) 49 + memcpy(skb_put(skb, data_len), data, data_len); 50 + 51 + /* Time stamp */ 52 + __net_timestamp(skb); 53 + 54 + hci_send_to_channel(channel, skb, flag, skip_sk); 55 + kfree_skb(skb); 56 + 57 + return 0; 58 + } 59 + 60 + int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) 61 + { 62 + struct sk_buff *skb; 63 + struct mgmt_hdr *hdr; 64 + struct mgmt_ev_cmd_status *ev; 65 + int err; 66 + 67 + BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status); 68 + 69 + skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL); 70 + if (!skb) 71 + return -ENOMEM; 72 + 73 + hdr = (void *) skb_put(skb, sizeof(*hdr)); 74 + 75 + hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS); 76 + hdr->index = cpu_to_le16(index); 77 + hdr->len = cpu_to_le16(sizeof(*ev)); 78 + 79 + ev = (void *) skb_put(skb, sizeof(*ev)); 80 + ev->status = status; 81 + ev->opcode = cpu_to_le16(cmd); 82 + 83 + err = sock_queue_rcv_skb(sk, skb); 84 + if (err < 0) 85 + kfree_skb(skb); 86 + 87 + return err; 88 + } 89 + 90 + int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, 91 + void *rp, size_t rp_len) 92 + { 93 + struct sk_buff *skb; 94 + struct mgmt_hdr *hdr; 95 + struct mgmt_ev_cmd_complete *ev; 96 + int err; 97 + 98 + BT_DBG("sock %p", sk); 99 + 100 + skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL); 101 + if (!skb) 102 + return -ENOMEM; 103 + 104 + hdr = (void *) skb_put(skb, sizeof(*hdr)); 105 + 106 + hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE); 107 + hdr->index = cpu_to_le16(index); 108 + hdr->len = cpu_to_le16(sizeof(*ev) + rp_len); 109 + 110 + ev = (void *) skb_put(skb, sizeof(*ev) + rp_len); 111 + ev->opcode = cpu_to_le16(cmd); 112 + ev->status = status; 113 + 114 + if (rp) 115 + memcpy(ev->data, rp, rp_len); 116 + 117 + err = sock_queue_rcv_skb(sk, skb); 118 + if (err < 0) 119 + kfree_skb(skb); 120 + 121 + return err; 122 + } 123 + 124 + struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode, 125 + struct hci_dev *hdev) 126 + { 127 + struct mgmt_pending_cmd *cmd; 128 + 129 + list_for_each_entry(cmd, &hdev->mgmt_pending, list) { 130 + if (hci_sock_get_channel(cmd->sk) != channel) 131 + continue; 132 + if (cmd->opcode == opcode) 133 + return cmd; 134 + } 135 + 136 + return NULL; 137 + } 138 + 139 + struct mgmt_pending_cmd *mgmt_pending_find_data(unsigned short channel, 140 + u16 opcode, 141 + struct hci_dev *hdev, 142 + const void *data) 143 + { 144 + struct mgmt_pending_cmd *cmd; 145 + 146 + list_for_each_entry(cmd, &hdev->mgmt_pending, list) { 147 + if (cmd->user_data != data) 148 + continue; 149 + if (cmd->opcode == opcode) 150 + return cmd; 151 + } 152 + 153 + return NULL; 154 + } 155 + 156 + void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, 157 + void (*cb)(struct mgmt_pending_cmd *cmd, void *data), 158 + void *data) 159 + { 160 + struct mgmt_pending_cmd *cmd, *tmp; 161 + 162 + list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) { 163 + if (opcode > 0 && cmd->opcode != opcode) 164 + continue; 165 + 166 + cb(cmd, data); 167 + } 168 + } 169 + 170 + struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, 171 + struct hci_dev *hdev, 172 + void *data, u16 len) 173 + { 174 + struct mgmt_pending_cmd *cmd; 175 + 176 + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 177 + if (!cmd) 178 + return NULL; 179 + 180 + cmd->opcode = opcode; 181 + cmd->index = hdev->id; 182 + 183 + cmd->param = kmemdup(data, len, GFP_KERNEL); 184 + if (!cmd->param) { 185 + kfree(cmd); 186 + return NULL; 187 + } 188 + 189 + cmd->param_len = len; 190 + 191 + cmd->sk = sk; 192 + sock_hold(sk); 193 + 194 + list_add(&cmd->list, &hdev->mgmt_pending); 195 + 196 + return cmd; 197 + } 198 + 199 + void mgmt_pending_free(struct mgmt_pending_cmd *cmd) 200 + { 201 + sock_put(cmd->sk); 202 + kfree(cmd->param); 203 + kfree(cmd); 204 + } 205 + 206 + void mgmt_pending_remove(struct mgmt_pending_cmd *cmd) 207 + { 208 + list_del(&cmd->list); 209 + mgmt_pending_free(cmd); 210 + }
+53
net/bluetooth/mgmt_util.h
··· 1 + /* 2 + BlueZ - Bluetooth protocol stack for Linux 3 + Copyright (C) 2015 Intel Coropration 4 + 5 + This program is free software; you can redistribute it and/or modify 6 + it under the terms of the GNU General Public License version 2 as 7 + published by the Free Software Foundation; 8 + 9 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 10 + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 11 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. 12 + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY 13 + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 14 + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 + 18 + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 19 + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 20 + SOFTWARE IS DISCLAIMED. 21 + */ 22 + 23 + struct mgmt_pending_cmd { 24 + struct list_head list; 25 + u16 opcode; 26 + int index; 27 + void *param; 28 + size_t param_len; 29 + struct sock *sk; 30 + void *user_data; 31 + int (*cmd_complete)(struct mgmt_pending_cmd *cmd, u8 status); 32 + }; 33 + 34 + int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel, 35 + void *data, u16 data_len, int flag, struct sock *skip_sk); 36 + int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status); 37 + int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, 38 + void *rp, size_t rp_len); 39 + 40 + struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode, 41 + struct hci_dev *hdev); 42 + struct mgmt_pending_cmd *mgmt_pending_find_data(unsigned short channel, 43 + u16 opcode, 44 + struct hci_dev *hdev, 45 + const void *data); 46 + void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, 47 + void (*cb)(struct mgmt_pending_cmd *cmd, void *data), 48 + void *data); 49 + struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, 50 + struct hci_dev *hdev, 51 + void *data, u16 len); 52 + void mgmt_pending_free(struct mgmt_pending_cmd *cmd); 53 + void mgmt_pending_remove(struct mgmt_pending_cmd *cmd);