1 // SPDX-License-Identifier: GPL-2.0
3 * Wireless USB - Cable Based Association
6 * Copyright (C) 2006 Intel Corporation
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8 * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
10 * WUSB devices have to be paired (associated in WUSB lingo) so
11 * that they can connect to the system.
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.
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.
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.
29 * The process goes like this:
31 * 1. Device plugs, cbaf is loaded, notifications happen.
33 * 2. The connection manager (CM) sees a device with CBAF capability
34 * (the wusb_chid etc. files in /sys/devices/blah/OURDEVICE).
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.
41 * 4. The CM can verify that the device's supported band groups
42 * (wusb_device_band_groups) are compatible with the host.
44 * 5. The CM reads the wusb_cdid file.
46 * 6. The CM looks up its database
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
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).
58 * CMD may choose to prompt the user before associating with a new
61 * 7. Device is unplugged.
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.
72 * [WUSB-AM] Association Models Supplement to the Certified Wireless
73 * Universal Serial Bus Specification, version 1.0.
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>
87 #define CBA_NAME_LEN 0x40 /* [WUSB-AM] table 4-7 */
89 /* An instance of a Cable-Based-Association-Framework device */
91 struct usb_device
*usb_dev
;
92 struct usb_interface
*usb_iface
;
96 struct wusb_ckhdid chid
;
97 char host_name
[CBA_NAME_LEN
];
100 struct wusb_ckhdid cdid
;
101 char device_name
[CBA_NAME_LEN
];
102 u16 device_band_groups
;
104 struct wusb_ckhdid ck
;
108 * Verify that a CBAF USB-interface has what we need
110 * According to [WUSB-AM], CBA devices should provide at least two
112 * - RETRIEVE_HOST_INFO
115 * If the device doesn't provide these interfaces, we do not know how
118 static int cbaf_check(struct cbaf
*cbaf
)
121 struct device
*dev
= &cbaf
->usb_iface
->dev
;
122 struct wusb_cbaf_assoc_info
*assoc_info
;
123 struct wusb_cbaf_assoc_request
*assoc_request
;
126 int ar_rhi
= 0, ar_assoc
= 0;
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
);
135 dev_err(dev
, "Cannot get available association types: %d\n",
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
));
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
));
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}
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
);
166 u16 ar_type
, ar_subtype
;
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
));
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
);
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";
192 case AR_TYPE_WUSB_ASSOCIATE
:
193 /* send assoc data */
194 ar_name
= "ASSOCIATE";
201 dev_dbg(dev
, "Association request #%02u: 0x%04x/%04x "
203 assoc_request
->AssociationDataIndex
, ar_type
,
204 ar_subtype
, (size_t)ar_size
, ar_name
);
206 itr
+= sizeof(*assoc_request
);
210 dev_err(dev
, "Missing RETRIEVE_HOST_INFO association "
215 dev_err(dev
, "Missing ASSOCIATE association request\n");
222 static 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
,
232 /* Send WUSB host information (CHID and name) to a CBAF device */
233 static int cbaf_send_host_info(struct cbaf
*cbaf
)
235 struct wusb_cbaf_host_info
*hi
;
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
;
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
,
254 cbaf
->usb_iface
->cur_altsetting
->desc
.bInterfaceNumber
,
255 hi
, hi_size
, USB_CTRL_SET_TIMEOUT
);
259 * Get device's information (CDID) associated to CHID
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.
265 static int cbaf_cdid_get(struct cbaf
*cbaf
)
268 struct device
*dev
= &cbaf
->usb_iface
->dev
;
269 struct wusb_cbaf_device_info
*di
;
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
);
280 dev_err(dev
, "Cannot request device information: %d\n",
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
);
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
);
299 static ssize_t
cbaf_wusb_chid_show(struct device
*dev
,
300 struct device_attribute
*attr
,
303 struct usb_interface
*iface
= to_usb_interface(dev
);
304 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
305 char pr_chid
[WUSB_CKHDID_STRSIZE
];
307 ckhdid_printf(pr_chid
, sizeof(pr_chid
), &cbaf
->chid
);
308 return scnprintf(buf
, PAGE_SIZE
, "%s\n", pr_chid
);
311 static ssize_t
cbaf_wusb_chid_store(struct device
*dev
,
312 struct device_attribute
*attr
,
313 const char *buf
, size_t size
)
316 struct usb_interface
*iface
= to_usb_interface(dev
);
317 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
320 "%02hhx %02hhx %02hhx %02hhx "
321 "%02hhx %02hhx %02hhx %02hhx "
322 "%02hhx %02hhx %02hhx %02hhx "
323 "%02hhx %02hhx %02hhx %02hhx",
324 &cbaf
->chid
.data
[0] , &cbaf
->chid
.data
[1],
325 &cbaf
->chid
.data
[2] , &cbaf
->chid
.data
[3],
326 &cbaf
->chid
.data
[4] , &cbaf
->chid
.data
[5],
327 &cbaf
->chid
.data
[6] , &cbaf
->chid
.data
[7],
328 &cbaf
->chid
.data
[8] , &cbaf
->chid
.data
[9],
329 &cbaf
->chid
.data
[10], &cbaf
->chid
.data
[11],
330 &cbaf
->chid
.data
[12], &cbaf
->chid
.data
[13],
331 &cbaf
->chid
.data
[14], &cbaf
->chid
.data
[15]);
336 result
= cbaf_send_host_info(cbaf
);
339 result
= cbaf_cdid_get(cbaf
);
344 static DEVICE_ATTR(wusb_chid
, 0600, cbaf_wusb_chid_show
, cbaf_wusb_chid_store
);
346 static ssize_t
cbaf_wusb_host_name_show(struct device
*dev
,
347 struct device_attribute
*attr
,
350 struct usb_interface
*iface
= to_usb_interface(dev
);
351 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
353 return scnprintf(buf
, PAGE_SIZE
, "%s\n", cbaf
->host_name
);
356 static ssize_t
cbaf_wusb_host_name_store(struct device
*dev
,
357 struct device_attribute
*attr
,
358 const char *buf
, size_t size
)
361 struct usb_interface
*iface
= to_usb_interface(dev
);
362 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
364 result
= sscanf(buf
, "%63s", cbaf
->host_name
);
370 static DEVICE_ATTR(wusb_host_name
, 0600, cbaf_wusb_host_name_show
,
371 cbaf_wusb_host_name_store
);
373 static ssize_t
cbaf_wusb_host_band_groups_show(struct device
*dev
,
374 struct device_attribute
*attr
,
377 struct usb_interface
*iface
= to_usb_interface(dev
);
378 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
380 return scnprintf(buf
, PAGE_SIZE
, "0x%04x\n", cbaf
->host_band_groups
);
383 static ssize_t
cbaf_wusb_host_band_groups_store(struct device
*dev
,
384 struct device_attribute
*attr
,
385 const char *buf
, size_t size
)
388 struct usb_interface
*iface
= to_usb_interface(dev
);
389 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
392 result
= sscanf(buf
, "%04hx", &band_groups
);
396 cbaf
->host_band_groups
= band_groups
;
401 static DEVICE_ATTR(wusb_host_band_groups
, 0600,
402 cbaf_wusb_host_band_groups_show
,
403 cbaf_wusb_host_band_groups_store
);
405 static const struct wusb_cbaf_device_info cbaf_device_info_defaults
= {
406 .Length_hdr
= WUSB_AR_Length
,
407 .CDID_hdr
= WUSB_AR_CDID
,
408 .BandGroups_hdr
= WUSB_AR_BandGroups
,
409 .LangID_hdr
= WUSB_AR_LangID
,
410 .DeviceFriendlyName_hdr
= WUSB_AR_DeviceFriendlyName
,
413 static ssize_t
cbaf_wusb_cdid_show(struct device
*dev
,
414 struct device_attribute
*attr
, char *buf
)
416 struct usb_interface
*iface
= to_usb_interface(dev
);
417 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
418 char pr_cdid
[WUSB_CKHDID_STRSIZE
];
420 ckhdid_printf(pr_cdid
, sizeof(pr_cdid
), &cbaf
->cdid
);
421 return scnprintf(buf
, PAGE_SIZE
, "%s\n", pr_cdid
);
424 static ssize_t
cbaf_wusb_cdid_store(struct device
*dev
,
425 struct device_attribute
*attr
,
426 const char *buf
, size_t size
)
429 struct usb_interface
*iface
= to_usb_interface(dev
);
430 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
431 struct wusb_ckhdid cdid
;
434 "%02hhx %02hhx %02hhx %02hhx "
435 "%02hhx %02hhx %02hhx %02hhx "
436 "%02hhx %02hhx %02hhx %02hhx "
437 "%02hhx %02hhx %02hhx %02hhx",
438 &cdid
.data
[0] , &cdid
.data
[1],
439 &cdid
.data
[2] , &cdid
.data
[3],
440 &cdid
.data
[4] , &cdid
.data
[5],
441 &cdid
.data
[6] , &cdid
.data
[7],
442 &cdid
.data
[8] , &cdid
.data
[9],
443 &cdid
.data
[10], &cdid
.data
[11],
444 &cdid
.data
[12], &cdid
.data
[13],
445 &cdid
.data
[14], &cdid
.data
[15]);
453 static DEVICE_ATTR(wusb_cdid
, 0600, cbaf_wusb_cdid_show
, cbaf_wusb_cdid_store
);
455 static ssize_t
cbaf_wusb_device_band_groups_show(struct device
*dev
,
456 struct device_attribute
*attr
,
459 struct usb_interface
*iface
= to_usb_interface(dev
);
460 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
462 return scnprintf(buf
, PAGE_SIZE
, "0x%04x\n", cbaf
->device_band_groups
);
465 static DEVICE_ATTR(wusb_device_band_groups
, 0600,
466 cbaf_wusb_device_band_groups_show
,
469 static ssize_t
cbaf_wusb_device_name_show(struct device
*dev
,
470 struct device_attribute
*attr
,
473 struct usb_interface
*iface
= to_usb_interface(dev
);
474 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
476 return scnprintf(buf
, PAGE_SIZE
, "%s\n", cbaf
->device_name
);
478 static DEVICE_ATTR(wusb_device_name
, 0600, cbaf_wusb_device_name_show
, NULL
);
480 static const struct wusb_cbaf_cc_data cbaf_cc_data_defaults
= {
481 .AssociationTypeId_hdr
= WUSB_AR_AssociationTypeId
,
482 .AssociationTypeId
= cpu_to_le16(AR_TYPE_WUSB
),
483 .AssociationSubTypeId_hdr
= WUSB_AR_AssociationSubTypeId
,
484 .AssociationSubTypeId
= cpu_to_le16(AR_TYPE_WUSB_ASSOCIATE
),
485 .Length_hdr
= WUSB_AR_Length
,
486 .Length
= cpu_to_le32(sizeof(struct wusb_cbaf_cc_data
)),
487 .ConnectionContext_hdr
= WUSB_AR_ConnectionContext
,
488 .BandGroups_hdr
= WUSB_AR_BandGroups
,
491 static const struct wusb_cbaf_cc_data_fail cbaf_cc_data_fail_defaults
= {
492 .AssociationTypeId_hdr
= WUSB_AR_AssociationTypeId
,
493 .AssociationSubTypeId_hdr
= WUSB_AR_AssociationSubTypeId
,
494 .Length_hdr
= WUSB_AR_Length
,
495 .AssociationStatus_hdr
= WUSB_AR_AssociationStatus
,
499 * Send a new CC to the device.
501 static int cbaf_cc_upload(struct cbaf
*cbaf
)
504 struct device
*dev
= &cbaf
->usb_iface
->dev
;
505 struct wusb_cbaf_cc_data
*ccd
;
506 char pr_cdid
[WUSB_CKHDID_STRSIZE
];
509 *ccd
= cbaf_cc_data_defaults
;
510 ccd
->CHID
= cbaf
->chid
;
511 ccd
->CDID
= cbaf
->cdid
;
513 ccd
->BandGroups
= cpu_to_le16(cbaf
->host_band_groups
);
515 dev_dbg(dev
, "Trying to upload CC:\n");
516 ckhdid_printf(pr_cdid
, sizeof(pr_cdid
), &ccd
->CHID
);
517 dev_dbg(dev
, " CHID %s\n", pr_cdid
);
518 ckhdid_printf(pr_cdid
, sizeof(pr_cdid
), &ccd
->CDID
);
519 dev_dbg(dev
, " CDID %s\n", pr_cdid
);
520 dev_dbg(dev
, " Bandgroups 0x%04x\n", cbaf
->host_band_groups
);
522 result
= usb_control_msg(
523 cbaf
->usb_dev
, usb_sndctrlpipe(cbaf
->usb_dev
, 0),
524 CBAF_REQ_SET_ASSOCIATION_RESPONSE
,
525 USB_DIR_OUT
| USB_TYPE_CLASS
| USB_RECIP_INTERFACE
,
526 0x0201, cbaf
->usb_iface
->cur_altsetting
->desc
.bInterfaceNumber
,
527 ccd
, sizeof(*ccd
), USB_CTRL_SET_TIMEOUT
);
532 static ssize_t
cbaf_wusb_ck_store(struct device
*dev
,
533 struct device_attribute
*attr
,
534 const char *buf
, size_t size
)
537 struct usb_interface
*iface
= to_usb_interface(dev
);
538 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
541 "%02hhx %02hhx %02hhx %02hhx "
542 "%02hhx %02hhx %02hhx %02hhx "
543 "%02hhx %02hhx %02hhx %02hhx "
544 "%02hhx %02hhx %02hhx %02hhx",
545 &cbaf
->ck
.data
[0] , &cbaf
->ck
.data
[1],
546 &cbaf
->ck
.data
[2] , &cbaf
->ck
.data
[3],
547 &cbaf
->ck
.data
[4] , &cbaf
->ck
.data
[5],
548 &cbaf
->ck
.data
[6] , &cbaf
->ck
.data
[7],
549 &cbaf
->ck
.data
[8] , &cbaf
->ck
.data
[9],
550 &cbaf
->ck
.data
[10], &cbaf
->ck
.data
[11],
551 &cbaf
->ck
.data
[12], &cbaf
->ck
.data
[13],
552 &cbaf
->ck
.data
[14], &cbaf
->ck
.data
[15]);
556 result
= cbaf_cc_upload(cbaf
);
562 static DEVICE_ATTR(wusb_ck
, 0600, NULL
, cbaf_wusb_ck_store
);
564 static struct attribute
*cbaf_dev_attrs
[] = {
565 &dev_attr_wusb_host_name
.attr
,
566 &dev_attr_wusb_host_band_groups
.attr
,
567 &dev_attr_wusb_chid
.attr
,
568 &dev_attr_wusb_cdid
.attr
,
569 &dev_attr_wusb_device_name
.attr
,
570 &dev_attr_wusb_device_band_groups
.attr
,
571 &dev_attr_wusb_ck
.attr
,
575 static const struct attribute_group cbaf_dev_attr_group
= {
576 .name
= NULL
, /* we want them in the same directory */
577 .attrs
= cbaf_dev_attrs
,
580 static int cbaf_probe(struct usb_interface
*iface
,
581 const struct usb_device_id
*id
)
584 struct device
*dev
= &iface
->dev
;
585 int result
= -ENOMEM
;
587 cbaf
= kzalloc(sizeof(*cbaf
), GFP_KERNEL
);
590 cbaf
->buffer
= kmalloc(512, GFP_KERNEL
);
591 if (cbaf
->buffer
== NULL
)
592 goto error_kmalloc_buffer
;
594 cbaf
->buffer_size
= 512;
595 cbaf
->usb_dev
= usb_get_dev(interface_to_usbdev(iface
));
596 cbaf
->usb_iface
= usb_get_intf(iface
);
597 result
= cbaf_check(cbaf
);
599 dev_err(dev
, "This device is not WUSB-CBAF compliant and is not supported yet.\n");
603 result
= sysfs_create_group(&dev
->kobj
, &cbaf_dev_attr_group
);
605 dev_err(dev
, "Can't register sysfs attr group: %d\n", result
);
606 goto error_create_group
;
608 usb_set_intfdata(iface
, cbaf
);
614 usb_put_dev(cbaf
->usb_dev
);
616 error_kmalloc_buffer
:
622 static void cbaf_disconnect(struct usb_interface
*iface
)
624 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
625 struct device
*dev
= &iface
->dev
;
626 sysfs_remove_group(&dev
->kobj
, &cbaf_dev_attr_group
);
627 usb_set_intfdata(iface
, NULL
);
629 usb_put_dev(cbaf
->usb_dev
);
631 /* paranoia: clean up crypto keys */
635 static const struct usb_device_id cbaf_id_table
[] = {
636 { USB_INTERFACE_INFO(0xef, 0x03, 0x01), },
639 MODULE_DEVICE_TABLE(usb
, cbaf_id_table
);
641 static struct usb_driver cbaf_driver
= {
643 .id_table
= cbaf_id_table
,
645 .disconnect
= cbaf_disconnect
,
648 module_usb_driver(cbaf_driver
);
650 MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
651 MODULE_DESCRIPTION("Wireless USB Cable Based Association");
652 MODULE_LICENSE("GPL");