aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>2008-09-17 11:34:27 -0400
committerDavid Vrabel <dv02@dv02pc01.europe.root.pri>2008-09-17 11:54:30 -0400
commit870d5395045bfe8e5213525152682c863a10f8d2 (patch)
tree6a5a0324231f99e3525ee6fd080f0c3507bc02b6 /drivers
parent470cc4150367d369bdc98ee04902b04baa2b2464 (diff)
wusb: add the USB wusb-cbaf driver
Add a driver for cable based associated of (Wireless) USB devices. Signed-off-by: David Vrabel <david.vrabel@csr.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/wusbcore/Makefile4
-rw-r--r--drivers/usb/wusbcore/cbaf.c620
2 files changed, 623 insertions, 1 deletions
diff --git a/drivers/usb/wusbcore/Makefile b/drivers/usb/wusbcore/Makefile
index ea1dbfca6135..6504f42ca367 100644
--- a/drivers/usb/wusbcore/Makefile
+++ b/drivers/usb/wusbcore/Makefile
@@ -1,4 +1,4 @@
1obj-$(CONFIG_USB_WUSB) += wusbcore.o 1obj-$(CONFIG_USB_WUSB) += wusbcore.o wusb-cbaf.o
2 2
3wusbcore-objs := \ 3wusbcore-objs := \
4 crypto.o \ 4 crypto.o \
@@ -10,3 +10,5 @@ wusbcore-objs := \
10 reservation.o \ 10 reservation.o \
11 security.o \ 11 security.o \
12 wusbhc.o 12 wusbhc.o
13
14wusb-cbaf-objs := cbaf.o
diff --git a/drivers/usb/wusbcore/cbaf.c b/drivers/usb/wusbcore/cbaf.c
new file mode 100644
index 000000000000..584eabe274b3
--- /dev/null
+++ b/drivers/usb/wusbcore/cbaf.c
@@ -0,0 +1,620 @@
1/*
2 * Wireless USB - Cable Based Association
3 *
4 *
5 * Copyright (C) 2006 Intel Corporation
6 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 *
23 * WUSB devices have to be paired (authenticated in WUSB lingo) so
24 * that they can connect to the system.
25 *
26 * One way of pairing is using CBA-Cable Based Authentication, devices
27 * that can connect via wired or wireless USB. First time you plug
28 * them with a cable, pairing is done between host and device and
29 * subsequent times, you can connect wirelessly without having to
30 * pair. That's the idea.
31 *
32 * This driver does nothing Earth shattering. It just provides an
33 * interface to chat with the wire-connected device so we can get a
34 * CDID (device ID) that might have been previously associated to a
35 * CHID (host ID) and to set up a new <CHID,CDID,CK> triplet
36 * (connection context), with the CK being the secret, or connection
37 * key. This is the pairing data.
38 *
39 * When a device with the CBA capability connects, the probe routine
40 * just creates a bunch of sysfs files that a user space enumeration
41 * manager uses to allow it to connect wirelessly to the system or not.
42 *
43 * The process goes like this:
44 *
45 * 1. device plugs, cbaf is loaded, notifications happen
46 *
47 * 2. the connection manager sees a device with CBAF capability (the
48 * wusb_{host_info,cdid,cc} files are in /sys/device/blah/OURDEVICE).
49 *
50 * 3. CM (connection manager) writes the CHID (host ID) and a host
51 * name into the wusb_host_info file. This gets sent to the device.
52 *
53 * 4. CM cats the wusb_cdid file; this asks the device if it has any
54 * CDID associated to the CHDI we just wrote before. If it does, it
55 * is printed, along with the device 'friendly name' and the band
56 * groups the device supports.
57 *
58 * 5. CM looks up its database
59 *
60 * 5.1 If it has a matching CHID,CDID entry, the device has been
61 * authorized before (paired). Now we can optionally ask the user
62 * if he wants to allow the device to connect. Then we generate a
63 * new CDID and CK, send it to the device and update the database
64 * (writing to the wusb_cc file so they are uploaded to the device).
65 *
66 * 5.2 If the CDID is zero (or we didn't find a matching CDID in our
67 * database), we assume the device is not known. We ask the user
68 * if s/he wants to allow the device to be connected wirelessly
69 * to the system. If nope, nothing else is done (FIXME: maybe
70 * send a zero CDID to clean up our CHID?). If yes, we generate
71 * random CDID and CKs (and write them to the wusb_cc file so
72 * they are uploaded to the device).
73 *
74 * 6. device is unplugged
75 *
76 * When the device tries to connect wirelessly, it will present it's
77 * CDID to the WUSB host controller with ID CHID, which will query the
78 * database. If found, the host will (with a 4way handshake) challenge
79 * the device to demonstrate it has the CK secret key (from our
80 * database) without actually exchanging it. Once satisfied, crypto
81 * keys are derived from the CK, the device is connected and all
82 * communication is crypted.
83 *
84 *
85 * NOTES ABOUT THE IMPLEMENTATION
86 *
87 * The descriptors sent back and forth use this horrible format from
88 * hell on which each field is actually a field ID, field length and
89 * then the field itself. How stupid can that get, taking into account
90 * the structures are defined by the spec?? oh well.
91 *
92 *
93 * FIXME: we don't provide a way to tell the device the pairing failed
94 * (ie: send a CC_DATA_FAIL). Should add some day.
95 */
96#include <linux/module.h>
97#include <linux/ctype.h>
98#include <linux/version.h>
99#include <linux/usb.h>
100#include <linux/interrupt.h>
101#include <linux/delay.h>
102#include <linux/random.h>
103#include <linux/mutex.h>
104#include <linux/uwb.h>
105#include <linux/usb/wusb.h>
106#include <linux/usb/association.h>
107
108#undef D_LOCAL
109#define D_LOCAL 6
110#include <linux/uwb/debug.h>
111
112/* An instance of a Cable-Based-Association-Framework device */
113struct cbaf {
114 struct usb_device *usb_dev;
115 struct usb_interface *usb_iface;
116 void *buffer;
117 size_t buffer_size;
118
119 struct wusb_ckhdid chid;/* Host Information */
120 char host_name[65]; /* max length:
121 Assoc Models Suplement 1.0[T4-7] */
122 u16 host_band_groups;
123
124 struct wusb_ckhdid cdid;/* Device Information */
125 char device_name[65]; /* max length:
126 Assoc Models Suplement 1.0[T4-7] */
127 u16 device_band_groups;
128 struct wusb_ckhdid ck; /* Connection Key */
129};
130
131/*
132 * Verify that a CBAF USB-interface has what we need
133 *
134 * (like we care, we are going to fail the enumeration if not :)
135 *
136 * FIXME: ugly function, need to split
137 */
138static int cbaf_check(struct cbaf *cbaf)
139{
140 int result;
141 struct device *dev = &cbaf->usb_iface->dev;
142 struct wusb_cbaf_assoc_info *assoc_info;
143 struct wusb_cbaf_assoc_request *assoc_request;
144 size_t assoc_size;
145 void *itr, *top;
146 unsigned ar_index;
147 int ar_rhi_idx = -1, ar_assoc_idx = -1;
148
149 result = usb_control_msg(
150 cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0),
151 CBAF_REQ_GET_ASSOCIATION_INFORMATION,
152 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
153 0, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
154 cbaf->buffer, cbaf->buffer_size, 1000 /* FIXME: arbitrary */);
155 if (result < 0) {
156 dev_err(dev, "cannot get available association types: %d\n",
157 result);
158 goto error_get_assoc_types;
159 }
160 assoc_info = cbaf->buffer;
161 if (result < sizeof(*assoc_info)) {
162 dev_err(dev, "not enough data to decode association info "
163 "header (%zu vs %zu bytes required)\n",
164 (size_t)result, sizeof(*assoc_info));
165 goto error_bad_header;
166 }
167 assoc_size = le16_to_cpu(assoc_info->Length);
168 if (result < assoc_size) {
169 dev_err(dev, "not enough data to decode association info "
170 "(%zu vs %zu bytes required)\n",
171 (size_t)assoc_size, sizeof(*assoc_info));
172 goto error_bad_data;
173 }
174 /*
175 * From now on, we just verify, but won't error out unless we
176 * don't find the AR_TYPE_WUSB_{RETRIEVE_HOST_INFO,ASSOCIATE}
177 * types.
178 */
179 ar_index = 0;
180 itr = cbaf->buffer + sizeof(*assoc_info);
181 top = cbaf->buffer + assoc_size;
182 d_printf(1, dev, "Found %u association requests (%zu bytes)\n",
183 assoc_info->NumAssociationRequests, assoc_size);
184 while (itr < top) {
185 u16 ar_type, ar_subtype;
186 u32 ar_size;
187 const char *ar_name;
188
189 assoc_request = itr;
190 if (top - itr < sizeof(*assoc_request)) {
191 dev_err(dev, "not enough data to decode associaton "
192 "request (%zu vs %zu bytes needed)\n",
193 top - itr, sizeof(*assoc_request));
194 break;
195 }
196 ar_type = le16_to_cpu(assoc_request->AssociationTypeId);
197 ar_subtype = le16_to_cpu(assoc_request->AssociationSubTypeId);
198 ar_size = le32_to_cpu(assoc_request->AssociationTypeInfoSize);
199 switch (ar_type) {
200 case AR_TYPE_WUSB:
201 /* Verify we have what is mandated by AMS1.0 */
202 switch (ar_subtype) {
203 case AR_TYPE_WUSB_RETRIEVE_HOST_INFO:
204 ar_name = "retrieve_host_info";
205 ar_rhi_idx = ar_index;
206 break;
207 case AR_TYPE_WUSB_ASSOCIATE:
208 /* send assoc data */
209 ar_name = "associate";
210 ar_assoc_idx = ar_index;
211 break;
212 default:
213 ar_name = "unknown";
214 };
215 break;
216 default:
217 ar_name = "unknown";
218 };
219 d_printf(1, dev, "association request #%02u: 0x%04x/%04x "
220 "(%zu bytes): %s\n",
221 assoc_request->AssociationDataIndex, ar_type,
222 ar_subtype, (size_t)ar_size, ar_name);
223
224 itr += sizeof(*assoc_request);
225 ar_index++;
226 }
227 if (ar_rhi_idx == -1) {
228 dev_err(dev, "Missing RETRIEVE_HOST_INFO association "
229 "request\n");
230 goto error_bad_reqs;
231 }
232 if (ar_assoc_idx == -1) {
233 dev_err(dev, "Missing ASSOCIATE association request\n");
234 goto error_bad_reqs;
235 }
236 return 0;
237
238error_bad_header:
239error_bad_data:
240error_bad_reqs:
241error_get_assoc_types:
242 return -EINVAL;
243}
244
245static const struct wusb_cbaf_host_info cbaf_host_info_defaults = {
246 .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId,
247 .AssociationTypeId = cpu_to_le16(AR_TYPE_WUSB),
248 .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
249 .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_RETRIEVE_HOST_INFO),
250 .CHID_hdr = WUSB_AR_CHID,
251 .LangID_hdr = WUSB_AR_LangID,
252 .HostFriendlyName_hdr = WUSB_AR_HostFriendlyName,
253};
254
255/* Send WUSB host information (CHID and name) to a CBAF device */
256static int cbaf_send_host_info(struct cbaf *cbaf)
257{
258 struct wusb_cbaf_host_info *hi;
259 size_t hi_size;
260
261 hi = cbaf->buffer;
262 memset(hi, 0, sizeof(*hi));
263 *hi = cbaf_host_info_defaults;
264 hi->CHID = cbaf->chid;
265 hi->LangID = 0; /* FIXME: I guess... */
266 strncpy(hi->HostFriendlyName, cbaf->host_name,
267 hi->HostFriendlyName_hdr.len);
268 hi->HostFriendlyName_hdr.len =
269 cpu_to_le16(strlen(hi->HostFriendlyName));
270 hi_size = sizeof(*hi) + strlen(hi->HostFriendlyName);
271 return usb_control_msg(cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0),
272 CBAF_REQ_SET_ASSOCIATION_RESPONSE,
273 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
274 0x0101,
275 cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
276 hi, hi_size, 1000 /* FIXME: arbitrary */);
277}
278
279/* Show current CHID info we have set from user space */
280static ssize_t cbaf_wusb_host_info_show(struct device *dev,
281 struct device_attribute *attr,
282 char *buf)
283{
284 struct usb_interface *iface = to_usb_interface(dev);
285 struct cbaf *cbaf = usb_get_intfdata(iface);
286 char pr_chid[WUSB_CKHDID_STRSIZE];
287
288 ckhdid_printf(pr_chid, sizeof(pr_chid), &cbaf->chid);
289 return scnprintf(buf, PAGE_SIZE, "CHID: %s\nName: %s\n",
290 pr_chid, cbaf->host_name);
291}
292
293/*
294 * Get a host info CHID from user space and send it to the device.
295 *
296 * The user can recover a CC from the device associated to that CHID
297 * by cat'ing wusb_connection_context.
298 */
299static ssize_t cbaf_wusb_host_info_store(struct device *dev,
300 struct device_attribute *attr,
301 const char *buf, size_t size)
302{
303 ssize_t result;
304 struct usb_interface *iface = to_usb_interface(dev);
305 struct cbaf *cbaf = usb_get_intfdata(iface);
306
307 result = sscanf(buf,
308 "%02hhx %02hhx %02hhx %02hhx "
309 "%02hhx %02hhx %02hhx %02hhx "
310 "%02hhx %02hhx %02hhx %02hhx "
311 "%02hhx %02hhx %02hhx %02hhx "
312 "%04hx %64s\n",
313 &cbaf->chid.data[0] , &cbaf->chid.data[1],
314 &cbaf->chid.data[2] , &cbaf->chid.data[3],
315 &cbaf->chid.data[4] , &cbaf->chid.data[5],
316 &cbaf->chid.data[6] , &cbaf->chid.data[7],
317 &cbaf->chid.data[8] , &cbaf->chid.data[9],
318 &cbaf->chid.data[10], &cbaf->chid.data[11],
319 &cbaf->chid.data[12], &cbaf->chid.data[13],
320 &cbaf->chid.data[14], &cbaf->chid.data[15],
321 &cbaf->host_band_groups, cbaf->host_name);
322 if (result != 18) {
323 dev_err(dev, "Unrecognized CHID (need 16 8-bit hex digits, "
324 "a 16 bit hex band group mask "
325 "and a host name, got only %d)\n", (int)result);
326 return -EINVAL;
327 }
328 result = cbaf_send_host_info(cbaf);
329 if (result < 0)
330 dev_err(dev, "Couldn't send host information to device: %d\n",
331 (int)result);
332 else
333 d_printf(1, dev, "HI sent, wusb_cc can be read now\n");
334 return result < 0 ? result : size;
335}
336static DEVICE_ATTR(wusb_host_info, 0600, cbaf_wusb_host_info_show,
337 cbaf_wusb_host_info_store);
338
339static const struct wusb_cbaf_device_info cbaf_device_info_defaults = {
340 .Length_hdr = WUSB_AR_Length,
341 .CDID_hdr = WUSB_AR_CDID,
342 .BandGroups_hdr = WUSB_AR_BandGroups,
343 .LangID_hdr = WUSB_AR_LangID,
344 .DeviceFriendlyName_hdr = WUSB_AR_DeviceFriendlyName,
345};
346
347/*
348 * Get device's information (CDID) associated to CHID
349 *
350 * The device will return it's information (CDID, name, bandgroups)
351 * associated to the CHID we have set before, or 0 CDID and default
352 * name and bandgroup if no CHID set or unknown.
353 */
354static int cbaf_cdid_get(struct cbaf *cbaf)
355{
356 int result;
357 struct device *dev = &cbaf->usb_iface->dev;
358 struct wusb_cbaf_device_info *di;
359 size_t needed, dev_name_size;
360
361 di = cbaf->buffer;
362 result = usb_control_msg(
363 cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0),
364 CBAF_REQ_GET_ASSOCIATION_REQUEST,
365 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
366 0x0200, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
367 di, cbaf->buffer_size, 1000 /* FIXME: arbitrary */);
368 if (result < 0) {
369 dev_err(dev, "Cannot request device information: %d\n", result);
370 goto error_req_di;
371 }
372 needed = result < sizeof(*di) ? sizeof(*di) : le32_to_cpu(di->Length);
373 if (result < needed) {
374 dev_err(dev, "Not enough data in DEVICE_INFO reply (%zu vs "
375 "%zu bytes needed)\n", (size_t)result, needed);
376 goto error_bad_di;
377 }
378 cbaf->cdid = di->CDID;
379 dev_name_size = le16_to_cpu(di->DeviceFriendlyName_hdr.len);
380 dev_name_size = dev_name_size > 65 - 1 ? 65 - 1 : dev_name_size;
381 memcpy(cbaf->device_name, di->DeviceFriendlyName, dev_name_size);
382 cbaf->device_name[dev_name_size] = 0;
383 cbaf->device_band_groups = le16_to_cpu(di->BandGroups);
384 result = 0;
385error_req_di:
386error_bad_di:
387 return result;
388}
389
390/*
391 * Get device information and print it to sysfs
392 *
393 * See cbaf_cdid_get()
394 */
395static ssize_t cbaf_wusb_cdid_show(struct device *dev,
396 struct device_attribute *attr, char *buf)
397{
398 ssize_t result;
399 struct usb_interface *iface = to_usb_interface(dev);
400 struct cbaf *cbaf = usb_get_intfdata(iface);
401 char pr_cdid[WUSB_CKHDID_STRSIZE];
402
403 result = cbaf_cdid_get(cbaf);
404 if (result < 0) {
405 dev_err(dev, "Cannot read device information: %d\n",
406 (int)result);
407 goto error_get_di;
408 }
409 ckhdid_printf(pr_cdid, sizeof(pr_cdid), &cbaf->cdid);
410 result = scnprintf(buf, PAGE_SIZE,
411 "CDID: %s\nName: %s\nBand_groups: 0x%04x\n",
412 pr_cdid, cbaf->device_name,
413 cbaf->device_band_groups);
414error_get_di:
415 return result;
416}
417static DEVICE_ATTR(wusb_cdid, 0600, cbaf_wusb_cdid_show, NULL);
418
419static const struct wusb_cbaf_cc_data cbaf_cc_data_defaults = {
420 .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId,
421 .AssociationTypeId = cpu_to_le16(AR_TYPE_WUSB),
422 .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
423 .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_ASSOCIATE),
424 .Length_hdr = WUSB_AR_Length,
425 .Length = cpu_to_le32(sizeof(struct wusb_cbaf_cc_data)),
426 .ConnectionContext_hdr = WUSB_AR_ConnectionContext,
427 .BandGroups_hdr = WUSB_AR_BandGroups,
428};
429
430static const struct wusb_cbaf_cc_data_fail cbaf_cc_data_fail_defaults = {
431 .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId,
432 .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
433 .Length_hdr = WUSB_AR_Length,
434 .AssociationStatus_hdr = WUSB_AR_AssociationStatus,
435};
436
437/*
438 * Send a new CC to the device
439 *
440 * So we update the CK and send the whole thing to the device
441 */
442static int cbaf_cc_upload(struct cbaf *cbaf)
443{
444 int result;
445 struct device *dev = &cbaf->usb_iface->dev;
446 struct wusb_cbaf_cc_data *ccd;
447 char pr_cdid[WUSB_CKHDID_STRSIZE];
448
449 ccd = cbaf->buffer;
450 *ccd = cbaf_cc_data_defaults;
451 ccd->CHID = cbaf->chid;
452 ccd->CDID = cbaf->cdid;
453 ccd->CK = cbaf->ck;
454 ccd->BandGroups = cpu_to_le16(cbaf->host_band_groups);
455 result = usb_control_msg(
456 cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0),
457 CBAF_REQ_SET_ASSOCIATION_RESPONSE,
458 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
459 0x0201, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
460 ccd, sizeof(*ccd), 1000 /* FIXME: arbitrary */);
461 d_printf(1, dev, "Uploaded CC:\n");
462 ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CHID);
463 d_printf(1, dev, " CHID %s\n", pr_cdid);
464 ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CDID);
465 d_printf(1, dev, " CDID %s\n", pr_cdid);
466 ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CK);
467 d_printf(1, dev, " CK %s\n", pr_cdid);
468 d_printf(1, dev, " bandgroups 0x%04x\n", cbaf->host_band_groups);
469 return result;
470}
471
472/*
473 * Send a new CC to the device
474 *
475 * We take the CDID and CK from user space, the rest from the info we
476 * set with host_info.
477 */
478static ssize_t cbaf_wusb_cc_store(struct device *dev,
479 struct device_attribute *attr,
480 const char *buf, size_t size)
481{
482 ssize_t result;
483 struct usb_interface *iface = to_usb_interface(dev);
484 struct cbaf *cbaf = usb_get_intfdata(iface);
485
486 result = sscanf(buf,
487 "CDID: %02hhx %02hhx %02hhx %02hhx "
488 "%02hhx %02hhx %02hhx %02hhx "
489 "%02hhx %02hhx %02hhx %02hhx "
490 "%02hhx %02hhx %02hhx %02hhx\n"
491 "CK: %02hhx %02hhx %02hhx %02hhx "
492 "%02hhx %02hhx %02hhx %02hhx "
493 "%02hhx %02hhx %02hhx %02hhx "
494 "%02hhx %02hhx %02hhx %02hhx\n",
495 &cbaf->cdid.data[0] , &cbaf->cdid.data[1],
496 &cbaf->cdid.data[2] , &cbaf->cdid.data[3],
497 &cbaf->cdid.data[4] , &cbaf->cdid.data[5],
498 &cbaf->cdid.data[6] , &cbaf->cdid.data[7],
499 &cbaf->cdid.data[8] , &cbaf->cdid.data[9],
500 &cbaf->cdid.data[10], &cbaf->cdid.data[11],
501 &cbaf->cdid.data[12], &cbaf->cdid.data[13],
502 &cbaf->cdid.data[14], &cbaf->cdid.data[15],
503
504 &cbaf->ck.data[0] , &cbaf->ck.data[1],
505 &cbaf->ck.data[2] , &cbaf->ck.data[3],
506 &cbaf->ck.data[4] , &cbaf->ck.data[5],
507 &cbaf->ck.data[6] , &cbaf->ck.data[7],
508 &cbaf->ck.data[8] , &cbaf->ck.data[9],
509 &cbaf->ck.data[10], &cbaf->ck.data[11],
510 &cbaf->ck.data[12], &cbaf->ck.data[13],
511 &cbaf->ck.data[14], &cbaf->ck.data[15]);
512 if (result != 32) {
513 dev_err(dev, "Unrecognized CHID/CK (need 32 8-bit "
514 "hex digits, got only %d)\n", (int)result);
515 return -EINVAL;
516 }
517 result = cbaf_cc_upload(cbaf);
518 if (result < 0)
519 dev_err(dev, "Couldn't upload connection context: %d\n",
520 (int)result);
521 else
522 d_printf(1, dev, "Connection context uploaded\n");
523 return result < 0 ? result : size;
524}
525static DEVICE_ATTR(wusb_cc, 0600, NULL, cbaf_wusb_cc_store);
526
527static struct attribute *cbaf_dev_attrs[] = {
528 &dev_attr_wusb_host_info.attr,
529 &dev_attr_wusb_cdid.attr,
530 &dev_attr_wusb_cc.attr,
531 NULL,
532};
533
534static struct attribute_group cbaf_dev_attr_group = {
535 .name = NULL, /* we want them in the same directory */
536 .attrs = cbaf_dev_attrs,
537};
538
539static int cbaf_probe(struct usb_interface *iface,
540 const struct usb_device_id *id)
541{
542 int result;
543 struct cbaf *cbaf;
544 struct device *dev = &iface->dev;
545
546 result = -ENOMEM;
547 cbaf = kzalloc(sizeof(*cbaf), GFP_KERNEL);
548 if (cbaf == NULL) {
549 dev_err(dev, "Unable to allocate instance\n");
550 goto error_kzalloc;
551 }
552 cbaf->buffer = kmalloc(512, GFP_KERNEL);
553 if (cbaf->buffer == NULL)
554 goto error_kmalloc_buffer;
555 cbaf->buffer_size = 512;
556 cbaf->usb_dev = usb_get_dev(interface_to_usbdev(iface));
557 cbaf->usb_iface = usb_get_intf(iface);
558 result = cbaf_check(cbaf);
559 if (result < 0)
560 goto error_check;
561 result = sysfs_create_group(&dev->kobj, &cbaf_dev_attr_group);
562 if (result < 0) {
563 dev_err(dev, "Can't register sysfs attr group: %d\n", result);
564 goto error_create_group;
565 }
566 usb_set_intfdata(iface, cbaf);
567 d_printf(2, dev, "CBA attached\n");
568 return 0;
569
570error_create_group:
571error_check:
572 kfree(cbaf->buffer);
573error_kmalloc_buffer:
574 kfree(cbaf);
575error_kzalloc:
576 return result;
577}
578
579static void cbaf_disconnect(struct usb_interface *iface)
580{
581 struct cbaf *cbaf = usb_get_intfdata(iface);
582 struct device *dev = &iface->dev;
583 sysfs_remove_group(&dev->kobj, &cbaf_dev_attr_group);
584 usb_set_intfdata(iface, NULL);
585 usb_put_intf(iface);
586 kfree(cbaf->buffer);
587 /* paranoia: clean up crypto keys */
588 memset(cbaf, 0, sizeof(*cbaf));
589 kfree(cbaf);
590 d_printf(1, dev, "CBA detached\n");
591}
592
593static struct usb_device_id cbaf_id_table[] = {
594 { USB_INTERFACE_INFO(0xef, 0x03, 0x01), },
595 { },
596};
597MODULE_DEVICE_TABLE(usb, cbaf_id_table);
598
599static struct usb_driver cbaf_driver = {
600 .name = "wusb-cbaf",
601 .id_table = cbaf_id_table,
602 .probe = cbaf_probe,
603 .disconnect = cbaf_disconnect,
604};
605
606static int __init cbaf_driver_init(void)
607{
608 return usb_register(&cbaf_driver);
609}
610module_init(cbaf_driver_init);
611
612static void __exit cbaf_driver_exit(void)
613{
614 usb_deregister(&cbaf_driver);
615}
616module_exit(cbaf_driver_exit);
617
618MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
619MODULE_DESCRIPTION("Wireless USB Cable Based Association");
620MODULE_LICENSE("GPL");