Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v5.2-rc7 645 lines 19 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Wireless USB - Cable Based Association 4 * 5 * 6 * Copyright (C) 2006 Intel Corporation 7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> 8 * Copyright (C) 2008 Cambridge Silicon Radio Ltd. 9 * 10 * WUSB devices have to be paired (associated in WUSB lingo) so 11 * that they can connect to the system. 12 * 13 * One way of pairing is using CBA-Cable Based Association. First 14 * time you plug the device with a cable, association is done between 15 * host and device and subsequent times, you can connect wirelessly 16 * without having to associate again. That's the idea. 17 * 18 * This driver does nothing Earth shattering. It just provides an 19 * interface to chat with the wire-connected device so we can get a 20 * CDID (device ID) that might have been previously associated to a 21 * CHID (host ID) and to set up a new <CHID,CDID,CK> triplet 22 * (connection context), with the CK being the secret, or connection 23 * key. This is the pairing data. 24 * 25 * When a device with the CBA capability connects, the probe routine 26 * just creates a bunch of sysfs files that a user space enumeration 27 * manager uses to allow it to connect wirelessly to the system or not. 28 * 29 * The process goes like this: 30 * 31 * 1. Device plugs, cbaf is loaded, notifications happen. 32 * 33 * 2. The connection manager (CM) sees a device with CBAF capability 34 * (the wusb_chid etc. files in /sys/devices/blah/OURDEVICE). 35 * 36 * 3. The CM writes the host name, supported band groups, and the CHID 37 * (host ID) into the wusb_host_name, wusb_host_band_groups and 38 * wusb_chid files. These get sent to the device and the CDID (if 39 * any) for this host is requested. 40 * 41 * 4. The CM can verify that the device's supported band groups 42 * (wusb_device_band_groups) are compatible with the host. 43 * 44 * 5. The CM reads the wusb_cdid file. 45 * 46 * 6. The CM looks up its database 47 * 48 * 6.1 If it has a matching CHID,CDID entry, the device has been 49 * authorized before (paired) and nothing further needs to be 50 * done. 51 * 52 * 6.2 If the CDID is zero (or the CM doesn't find a matching CDID in 53 * its database), the device is assumed to be not known. The CM 54 * may associate the host with device by: writing a randomly 55 * generated CDID to wusb_cdid and then a random CK to wusb_ck 56 * (this uploads the new CC to the device). 57 * 58 * CMD may choose to prompt the user before associating with a new 59 * device. 60 * 61 * 7. Device is unplugged. 62 * 63 * When the device tries to connect wirelessly, it will present its 64 * CDID to the WUSB host controller. The CM will query the 65 * database. If the CHID/CDID pair found, it will (with a 4-way 66 * handshake) challenge the device to demonstrate it has the CK secret 67 * key (from our database) without actually exchanging it. Once 68 * satisfied, crypto keys are derived from the CK, the device is 69 * connected and all communication is encrypted. 70 * 71 * References: 72 * [WUSB-AM] Association Models Supplement to the Certified Wireless 73 * Universal Serial Bus Specification, version 1.0. 74 */ 75#include <linux/module.h> 76#include <linux/ctype.h> 77#include <linux/usb.h> 78#include <linux/interrupt.h> 79#include <linux/delay.h> 80#include <linux/random.h> 81#include <linux/slab.h> 82#include <linux/mutex.h> 83#include <linux/uwb.h> 84#include <linux/usb/wusb.h> 85#include <linux/usb/association.h> 86 87#define CBA_NAME_LEN 0x40 /* [WUSB-AM] table 4-7 */ 88 89/* An instance of a Cable-Based-Association-Framework device */ 90struct cbaf { 91 struct usb_device *usb_dev; 92 struct usb_interface *usb_iface; 93 void *buffer; 94 size_t buffer_size; 95 96 struct wusb_ckhdid chid; 97 char host_name[CBA_NAME_LEN]; 98 u16 host_band_groups; 99 100 struct wusb_ckhdid cdid; 101 char device_name[CBA_NAME_LEN]; 102 u16 device_band_groups; 103 104 struct wusb_ckhdid ck; 105}; 106 107/* 108 * Verify that a CBAF USB-interface has what we need 109 * 110 * According to [WUSB-AM], CBA devices should provide at least two 111 * interfaces: 112 * - RETRIEVE_HOST_INFO 113 * - ASSOCIATE 114 * 115 * If the device doesn't provide these interfaces, we do not know how 116 * to deal with it. 117 */ 118static int cbaf_check(struct cbaf *cbaf) 119{ 120 int result; 121 struct device *dev = &cbaf->usb_iface->dev; 122 struct wusb_cbaf_assoc_info *assoc_info; 123 struct wusb_cbaf_assoc_request *assoc_request; 124 size_t assoc_size; 125 void *itr, *top; 126 int ar_rhi = 0, ar_assoc = 0; 127 128 result = usb_control_msg( 129 cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0), 130 CBAF_REQ_GET_ASSOCIATION_INFORMATION, 131 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 132 0, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, 133 cbaf->buffer, cbaf->buffer_size, USB_CTRL_GET_TIMEOUT); 134 if (result < 0) { 135 dev_err(dev, "Cannot get available association types: %d\n", 136 result); 137 return result; 138 } 139 140 assoc_info = cbaf->buffer; 141 if (result < sizeof(*assoc_info)) { 142 dev_err(dev, "Not enough data to decode association info " 143 "header (%zu vs %zu bytes required)\n", 144 (size_t)result, sizeof(*assoc_info)); 145 return result; 146 } 147 148 assoc_size = le16_to_cpu(assoc_info->Length); 149 if (result < assoc_size) { 150 dev_err(dev, "Not enough data to decode association info " 151 "(%zu vs %zu bytes required)\n", 152 (size_t)assoc_size, sizeof(*assoc_info)); 153 return result; 154 } 155 /* 156 * From now on, we just verify, but won't error out unless we 157 * don't find the AR_TYPE_WUSB_{RETRIEVE_HOST_INFO,ASSOCIATE} 158 * types. 159 */ 160 itr = cbaf->buffer + sizeof(*assoc_info); 161 top = cbaf->buffer + assoc_size; 162 dev_dbg(dev, "Found %u association requests (%zu bytes)\n", 163 assoc_info->NumAssociationRequests, assoc_size); 164 165 while (itr < top) { 166 u16 ar_type, ar_subtype; 167 u32 ar_size; 168 const char *ar_name; 169 170 assoc_request = itr; 171 172 if (top - itr < sizeof(*assoc_request)) { 173 dev_err(dev, "Not enough data to decode association " 174 "request (%zu vs %zu bytes needed)\n", 175 top - itr, sizeof(*assoc_request)); 176 break; 177 } 178 179 ar_type = le16_to_cpu(assoc_request->AssociationTypeId); 180 ar_subtype = le16_to_cpu(assoc_request->AssociationSubTypeId); 181 ar_size = le32_to_cpu(assoc_request->AssociationTypeInfoSize); 182 ar_name = "unknown"; 183 184 switch (ar_type) { 185 case AR_TYPE_WUSB: 186 /* Verify we have what is mandated by [WUSB-AM]. */ 187 switch (ar_subtype) { 188 case AR_TYPE_WUSB_RETRIEVE_HOST_INFO: 189 ar_name = "RETRIEVE_HOST_INFO"; 190 ar_rhi = 1; 191 break; 192 case AR_TYPE_WUSB_ASSOCIATE: 193 /* send assoc data */ 194 ar_name = "ASSOCIATE"; 195 ar_assoc = 1; 196 break; 197 } 198 break; 199 } 200 201 dev_dbg(dev, "Association request #%02u: 0x%04x/%04x " 202 "(%zu bytes): %s\n", 203 assoc_request->AssociationDataIndex, ar_type, 204 ar_subtype, (size_t)ar_size, ar_name); 205 206 itr += sizeof(*assoc_request); 207 } 208 209 if (!ar_rhi) { 210 dev_err(dev, "Missing RETRIEVE_HOST_INFO association " 211 "request\n"); 212 return -EINVAL; 213 } 214 if (!ar_assoc) { 215 dev_err(dev, "Missing ASSOCIATE association request\n"); 216 return -EINVAL; 217 } 218 219 return 0; 220} 221 222static const struct wusb_cbaf_host_info cbaf_host_info_defaults = { 223 .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId, 224 .AssociationTypeId = cpu_to_le16(AR_TYPE_WUSB), 225 .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId, 226 .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_RETRIEVE_HOST_INFO), 227 .CHID_hdr = WUSB_AR_CHID, 228 .LangID_hdr = WUSB_AR_LangID, 229 .HostFriendlyName_hdr = WUSB_AR_HostFriendlyName, 230}; 231 232/* Send WUSB host information (CHID and name) to a CBAF device */ 233static int cbaf_send_host_info(struct cbaf *cbaf) 234{ 235 struct wusb_cbaf_host_info *hi; 236 size_t name_len; 237 size_t hi_size; 238 239 hi = cbaf->buffer; 240 memset(hi, 0, sizeof(*hi)); 241 *hi = cbaf_host_info_defaults; 242 hi->CHID = cbaf->chid; 243 hi->LangID = 0; /* FIXME: I guess... */ 244 strlcpy(hi->HostFriendlyName, cbaf->host_name, CBA_NAME_LEN); 245 name_len = strlen(cbaf->host_name); 246 hi->HostFriendlyName_hdr.len = cpu_to_le16(name_len); 247 hi_size = sizeof(*hi) + name_len; 248 249 return usb_control_msg(cbaf->usb_dev, 250 usb_sndctrlpipe(cbaf->usb_dev, 0), 251 CBAF_REQ_SET_ASSOCIATION_RESPONSE, 252 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 253 0x0101, 254 cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, 255 hi, hi_size, USB_CTRL_SET_TIMEOUT); 256} 257 258/* 259 * Get device's information (CDID) associated to CHID 260 * 261 * The device will return it's information (CDID, name, bandgroups) 262 * associated to the CHID we have set before, or 0 CDID and default 263 * name and bandgroup if no CHID set or unknown. 264 */ 265static int cbaf_cdid_get(struct cbaf *cbaf) 266{ 267 int result; 268 struct device *dev = &cbaf->usb_iface->dev; 269 struct wusb_cbaf_device_info *di; 270 size_t needed; 271 272 di = cbaf->buffer; 273 result = usb_control_msg( 274 cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0), 275 CBAF_REQ_GET_ASSOCIATION_REQUEST, 276 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 277 0x0200, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, 278 di, cbaf->buffer_size, USB_CTRL_GET_TIMEOUT); 279 if (result < 0) { 280 dev_err(dev, "Cannot request device information: %d\n", 281 result); 282 return result; 283 } 284 285 needed = result < sizeof(*di) ? sizeof(*di) : le32_to_cpu(di->Length); 286 if (result < needed) { 287 dev_err(dev, "Not enough data in DEVICE_INFO reply (%zu vs " 288 "%zu bytes needed)\n", (size_t)result, needed); 289 return -ENOENT; 290 } 291 292 strlcpy(cbaf->device_name, di->DeviceFriendlyName, CBA_NAME_LEN); 293 cbaf->cdid = di->CDID; 294 cbaf->device_band_groups = le16_to_cpu(di->BandGroups); 295 296 return 0; 297} 298 299static ssize_t cbaf_wusb_chid_show(struct device *dev, 300 struct device_attribute *attr, 301 char *buf) 302{ 303 struct usb_interface *iface = to_usb_interface(dev); 304 struct cbaf *cbaf = usb_get_intfdata(iface); 305 306 return sprintf(buf, "%16ph\n", cbaf->chid.data); 307} 308 309static ssize_t cbaf_wusb_chid_store(struct device *dev, 310 struct device_attribute *attr, 311 const char *buf, size_t size) 312{ 313 ssize_t result; 314 struct usb_interface *iface = to_usb_interface(dev); 315 struct cbaf *cbaf = usb_get_intfdata(iface); 316 317 result = sscanf(buf, 318 "%02hhx %02hhx %02hhx %02hhx " 319 "%02hhx %02hhx %02hhx %02hhx " 320 "%02hhx %02hhx %02hhx %02hhx " 321 "%02hhx %02hhx %02hhx %02hhx", 322 &cbaf->chid.data[0] , &cbaf->chid.data[1], 323 &cbaf->chid.data[2] , &cbaf->chid.data[3], 324 &cbaf->chid.data[4] , &cbaf->chid.data[5], 325 &cbaf->chid.data[6] , &cbaf->chid.data[7], 326 &cbaf->chid.data[8] , &cbaf->chid.data[9], 327 &cbaf->chid.data[10], &cbaf->chid.data[11], 328 &cbaf->chid.data[12], &cbaf->chid.data[13], 329 &cbaf->chid.data[14], &cbaf->chid.data[15]); 330 331 if (result != 16) 332 return -EINVAL; 333 334 result = cbaf_send_host_info(cbaf); 335 if (result < 0) 336 return result; 337 result = cbaf_cdid_get(cbaf); 338 if (result < 0) 339 return result; 340 return size; 341} 342static DEVICE_ATTR(wusb_chid, 0600, cbaf_wusb_chid_show, cbaf_wusb_chid_store); 343 344static ssize_t cbaf_wusb_host_name_show(struct device *dev, 345 struct device_attribute *attr, 346 char *buf) 347{ 348 struct usb_interface *iface = to_usb_interface(dev); 349 struct cbaf *cbaf = usb_get_intfdata(iface); 350 351 return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->host_name); 352} 353 354static ssize_t cbaf_wusb_host_name_store(struct device *dev, 355 struct device_attribute *attr, 356 const char *buf, size_t size) 357{ 358 ssize_t result; 359 struct usb_interface *iface = to_usb_interface(dev); 360 struct cbaf *cbaf = usb_get_intfdata(iface); 361 362 result = sscanf(buf, "%63s", cbaf->host_name); 363 if (result != 1) 364 return -EINVAL; 365 366 return size; 367} 368static DEVICE_ATTR(wusb_host_name, 0600, cbaf_wusb_host_name_show, 369 cbaf_wusb_host_name_store); 370 371static ssize_t cbaf_wusb_host_band_groups_show(struct device *dev, 372 struct device_attribute *attr, 373 char *buf) 374{ 375 struct usb_interface *iface = to_usb_interface(dev); 376 struct cbaf *cbaf = usb_get_intfdata(iface); 377 378 return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->host_band_groups); 379} 380 381static ssize_t cbaf_wusb_host_band_groups_store(struct device *dev, 382 struct device_attribute *attr, 383 const char *buf, size_t size) 384{ 385 ssize_t result; 386 struct usb_interface *iface = to_usb_interface(dev); 387 struct cbaf *cbaf = usb_get_intfdata(iface); 388 u16 band_groups = 0; 389 390 result = sscanf(buf, "%04hx", &band_groups); 391 if (result != 1) 392 return -EINVAL; 393 394 cbaf->host_band_groups = band_groups; 395 396 return size; 397} 398 399static DEVICE_ATTR(wusb_host_band_groups, 0600, 400 cbaf_wusb_host_band_groups_show, 401 cbaf_wusb_host_band_groups_store); 402 403static const struct wusb_cbaf_device_info cbaf_device_info_defaults = { 404 .Length_hdr = WUSB_AR_Length, 405 .CDID_hdr = WUSB_AR_CDID, 406 .BandGroups_hdr = WUSB_AR_BandGroups, 407 .LangID_hdr = WUSB_AR_LangID, 408 .DeviceFriendlyName_hdr = WUSB_AR_DeviceFriendlyName, 409}; 410 411static ssize_t cbaf_wusb_cdid_show(struct device *dev, 412 struct device_attribute *attr, char *buf) 413{ 414 struct usb_interface *iface = to_usb_interface(dev); 415 struct cbaf *cbaf = usb_get_intfdata(iface); 416 417 return sprintf(buf, "%16ph\n", cbaf->cdid.data); 418} 419 420static ssize_t cbaf_wusb_cdid_store(struct device *dev, 421 struct device_attribute *attr, 422 const char *buf, size_t size) 423{ 424 ssize_t result; 425 struct usb_interface *iface = to_usb_interface(dev); 426 struct cbaf *cbaf = usb_get_intfdata(iface); 427 struct wusb_ckhdid cdid; 428 429 result = sscanf(buf, 430 "%02hhx %02hhx %02hhx %02hhx " 431 "%02hhx %02hhx %02hhx %02hhx " 432 "%02hhx %02hhx %02hhx %02hhx " 433 "%02hhx %02hhx %02hhx %02hhx", 434 &cdid.data[0] , &cdid.data[1], 435 &cdid.data[2] , &cdid.data[3], 436 &cdid.data[4] , &cdid.data[5], 437 &cdid.data[6] , &cdid.data[7], 438 &cdid.data[8] , &cdid.data[9], 439 &cdid.data[10], &cdid.data[11], 440 &cdid.data[12], &cdid.data[13], 441 &cdid.data[14], &cdid.data[15]); 442 if (result != 16) 443 return -EINVAL; 444 445 cbaf->cdid = cdid; 446 447 return size; 448} 449static DEVICE_ATTR(wusb_cdid, 0600, cbaf_wusb_cdid_show, cbaf_wusb_cdid_store); 450 451static ssize_t cbaf_wusb_device_band_groups_show(struct device *dev, 452 struct device_attribute *attr, 453 char *buf) 454{ 455 struct usb_interface *iface = to_usb_interface(dev); 456 struct cbaf *cbaf = usb_get_intfdata(iface); 457 458 return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->device_band_groups); 459} 460 461static DEVICE_ATTR(wusb_device_band_groups, 0600, 462 cbaf_wusb_device_band_groups_show, 463 NULL); 464 465static ssize_t cbaf_wusb_device_name_show(struct device *dev, 466 struct device_attribute *attr, 467 char *buf) 468{ 469 struct usb_interface *iface = to_usb_interface(dev); 470 struct cbaf *cbaf = usb_get_intfdata(iface); 471 472 return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->device_name); 473} 474static DEVICE_ATTR(wusb_device_name, 0600, cbaf_wusb_device_name_show, NULL); 475 476static const struct wusb_cbaf_cc_data cbaf_cc_data_defaults = { 477 .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId, 478 .AssociationTypeId = cpu_to_le16(AR_TYPE_WUSB), 479 .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId, 480 .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_ASSOCIATE), 481 .Length_hdr = WUSB_AR_Length, 482 .Length = cpu_to_le32(sizeof(struct wusb_cbaf_cc_data)), 483 .ConnectionContext_hdr = WUSB_AR_ConnectionContext, 484 .BandGroups_hdr = WUSB_AR_BandGroups, 485}; 486 487static const struct wusb_cbaf_cc_data_fail cbaf_cc_data_fail_defaults = { 488 .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId, 489 .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId, 490 .Length_hdr = WUSB_AR_Length, 491 .AssociationStatus_hdr = WUSB_AR_AssociationStatus, 492}; 493 494/* 495 * Send a new CC to the device. 496 */ 497static int cbaf_cc_upload(struct cbaf *cbaf) 498{ 499 int result; 500 struct device *dev = &cbaf->usb_iface->dev; 501 struct wusb_cbaf_cc_data *ccd; 502 503 ccd = cbaf->buffer; 504 *ccd = cbaf_cc_data_defaults; 505 ccd->CHID = cbaf->chid; 506 ccd->CDID = cbaf->cdid; 507 ccd->CK = cbaf->ck; 508 ccd->BandGroups = cpu_to_le16(cbaf->host_band_groups); 509 510 dev_dbg(dev, "Trying to upload CC:\n"); 511 dev_dbg(dev, " CHID %16ph\n", ccd->CHID.data); 512 dev_dbg(dev, " CDID %16ph\n", ccd->CDID.data); 513 dev_dbg(dev, " Bandgroups 0x%04x\n", cbaf->host_band_groups); 514 515 result = usb_control_msg( 516 cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0), 517 CBAF_REQ_SET_ASSOCIATION_RESPONSE, 518 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 519 0x0201, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, 520 ccd, sizeof(*ccd), USB_CTRL_SET_TIMEOUT); 521 522 return result; 523} 524 525static ssize_t cbaf_wusb_ck_store(struct device *dev, 526 struct device_attribute *attr, 527 const char *buf, size_t size) 528{ 529 ssize_t result; 530 struct usb_interface *iface = to_usb_interface(dev); 531 struct cbaf *cbaf = usb_get_intfdata(iface); 532 533 result = sscanf(buf, 534 "%02hhx %02hhx %02hhx %02hhx " 535 "%02hhx %02hhx %02hhx %02hhx " 536 "%02hhx %02hhx %02hhx %02hhx " 537 "%02hhx %02hhx %02hhx %02hhx", 538 &cbaf->ck.data[0] , &cbaf->ck.data[1], 539 &cbaf->ck.data[2] , &cbaf->ck.data[3], 540 &cbaf->ck.data[4] , &cbaf->ck.data[5], 541 &cbaf->ck.data[6] , &cbaf->ck.data[7], 542 &cbaf->ck.data[8] , &cbaf->ck.data[9], 543 &cbaf->ck.data[10], &cbaf->ck.data[11], 544 &cbaf->ck.data[12], &cbaf->ck.data[13], 545 &cbaf->ck.data[14], &cbaf->ck.data[15]); 546 if (result != 16) 547 return -EINVAL; 548 549 result = cbaf_cc_upload(cbaf); 550 if (result < 0) 551 return result; 552 553 return size; 554} 555static DEVICE_ATTR(wusb_ck, 0600, NULL, cbaf_wusb_ck_store); 556 557static struct attribute *cbaf_dev_attrs[] = { 558 &dev_attr_wusb_host_name.attr, 559 &dev_attr_wusb_host_band_groups.attr, 560 &dev_attr_wusb_chid.attr, 561 &dev_attr_wusb_cdid.attr, 562 &dev_attr_wusb_device_name.attr, 563 &dev_attr_wusb_device_band_groups.attr, 564 &dev_attr_wusb_ck.attr, 565 NULL, 566}; 567 568static const struct attribute_group cbaf_dev_attr_group = { 569 .name = NULL, /* we want them in the same directory */ 570 .attrs = cbaf_dev_attrs, 571}; 572 573static int cbaf_probe(struct usb_interface *iface, 574 const struct usb_device_id *id) 575{ 576 struct cbaf *cbaf; 577 struct device *dev = &iface->dev; 578 int result = -ENOMEM; 579 580 cbaf = kzalloc(sizeof(*cbaf), GFP_KERNEL); 581 if (cbaf == NULL) 582 goto error_kzalloc; 583 cbaf->buffer = kmalloc(512, GFP_KERNEL); 584 if (cbaf->buffer == NULL) 585 goto error_kmalloc_buffer; 586 587 cbaf->buffer_size = 512; 588 cbaf->usb_dev = usb_get_dev(interface_to_usbdev(iface)); 589 cbaf->usb_iface = usb_get_intf(iface); 590 result = cbaf_check(cbaf); 591 if (result < 0) { 592 dev_err(dev, "This device is not WUSB-CBAF compliant and is not supported yet.\n"); 593 goto error_check; 594 } 595 596 result = sysfs_create_group(&dev->kobj, &cbaf_dev_attr_group); 597 if (result < 0) { 598 dev_err(dev, "Can't register sysfs attr group: %d\n", result); 599 goto error_create_group; 600 } 601 usb_set_intfdata(iface, cbaf); 602 return 0; 603 604error_create_group: 605error_check: 606 usb_put_intf(iface); 607 usb_put_dev(cbaf->usb_dev); 608 kfree(cbaf->buffer); 609error_kmalloc_buffer: 610 kfree(cbaf); 611error_kzalloc: 612 return result; 613} 614 615static void cbaf_disconnect(struct usb_interface *iface) 616{ 617 struct cbaf *cbaf = usb_get_intfdata(iface); 618 struct device *dev = &iface->dev; 619 sysfs_remove_group(&dev->kobj, &cbaf_dev_attr_group); 620 usb_set_intfdata(iface, NULL); 621 usb_put_intf(iface); 622 usb_put_dev(cbaf->usb_dev); 623 kfree(cbaf->buffer); 624 /* paranoia: clean up crypto keys */ 625 kzfree(cbaf); 626} 627 628static const struct usb_device_id cbaf_id_table[] = { 629 { USB_INTERFACE_INFO(0xef, 0x03, 0x01), }, 630 { }, 631}; 632MODULE_DEVICE_TABLE(usb, cbaf_id_table); 633 634static struct usb_driver cbaf_driver = { 635 .name = "wusb-cbaf", 636 .id_table = cbaf_id_table, 637 .probe = cbaf_probe, 638 .disconnect = cbaf_disconnect, 639}; 640 641module_usb_driver(cbaf_driver); 642 643MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); 644MODULE_DESCRIPTION("Wireless USB Cable Based Association"); 645MODULE_LICENSE("GPL");