diff options
Diffstat (limited to 'include/linux/usb/wusb.h')
-rw-r--r-- | include/linux/usb/wusb.h | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/include/linux/usb/wusb.h b/include/linux/usb/wusb.h new file mode 100644 index 000000000000..5f401b644ed5 --- /dev/null +++ b/include/linux/usb/wusb.h | |||
@@ -0,0 +1,376 @@ | |||
1 | /* | ||
2 | * Wireless USB Standard Definitions | ||
3 | * Event Size Tables | ||
4 | * | ||
5 | * Copyright (C) 2005-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 | * FIXME: docs | ||
24 | * FIXME: organize properly, group logically | ||
25 | * | ||
26 | * All the event structures are defined in uwb/spec.h, as they are | ||
27 | * common to the WHCI and WUSB radio control interfaces. | ||
28 | */ | ||
29 | |||
30 | #ifndef __WUSB_H__ | ||
31 | #define __WUSB_H__ | ||
32 | |||
33 | #include <linux/types.h> | ||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/uwb/spec.h> | ||
36 | #include <linux/usb/ch9.h> | ||
37 | #include <linux/param.h> | ||
38 | |||
39 | /** | ||
40 | * WUSB Information Element header | ||
41 | * | ||
42 | * I don't know why, they decided to make it different to the MBOA MAC | ||
43 | * IE Header; beats me. | ||
44 | */ | ||
45 | struct wuie_hdr { | ||
46 | u8 bLength; | ||
47 | u8 bIEIdentifier; | ||
48 | } __attribute__((packed)); | ||
49 | |||
50 | enum { | ||
51 | WUIE_ID_WCTA = 0x80, | ||
52 | WUIE_ID_CONNECTACK, | ||
53 | WUIE_ID_HOST_INFO, | ||
54 | WUIE_ID_CHANGE_ANNOUNCE, | ||
55 | WUIE_ID_DEVICE_DISCONNECT, | ||
56 | WUIE_ID_HOST_DISCONNECT, | ||
57 | WUIE_ID_KEEP_ALIVE = 0x89, | ||
58 | WUIE_ID_ISOCH_DISCARD, | ||
59 | WUIE_ID_RESET_DEVICE, | ||
60 | }; | ||
61 | |||
62 | /** | ||
63 | * Maximum number of array elements in a WUSB IE. | ||
64 | * | ||
65 | * WUSB1.0[7.5 before table 7-38] says that in WUSB IEs that | ||
66 | * are "arrays" have to limited to 4 elements. So we define it | ||
67 | * like that to ease up and submit only the neeed size. | ||
68 | */ | ||
69 | #define WUIE_ELT_MAX 4 | ||
70 | |||
71 | /** | ||
72 | * Wrapper for the data that defines a CHID, a CDID or a CK | ||
73 | * | ||
74 | * WUSB defines that CHIDs, CDIDs and CKs are a 16 byte string of | ||
75 | * data. In order to avoid confusion and enforce types, we wrap it. | ||
76 | * | ||
77 | * Make it packed, as we use it in some hw defintions. | ||
78 | */ | ||
79 | struct wusb_ckhdid { | ||
80 | u8 data[16]; | ||
81 | } __attribute__((packed)); | ||
82 | |||
83 | const static | ||
84 | struct wusb_ckhdid wusb_ckhdid_zero = { .data = { 0 } }; | ||
85 | |||
86 | #define WUSB_CKHDID_STRSIZE (3 * sizeof(struct wusb_ckhdid) + 1) | ||
87 | |||
88 | /** | ||
89 | * WUSB IE: Host Information (WUSB1.0[7.5.2]) | ||
90 | * | ||
91 | * Used to provide information about the host to the Wireless USB | ||
92 | * devices in range (CHID can be used as an ASCII string). | ||
93 | */ | ||
94 | struct wuie_host_info { | ||
95 | struct wuie_hdr hdr; | ||
96 | __le16 attributes; | ||
97 | struct wusb_ckhdid CHID; | ||
98 | } __attribute__((packed)); | ||
99 | |||
100 | /** | ||
101 | * WUSB IE: Connect Ack (WUSB1.0[7.5.1]) | ||
102 | * | ||
103 | * Used to acknowledge device connect requests. See note for | ||
104 | * WUIE_ELT_MAX. | ||
105 | */ | ||
106 | struct wuie_connect_ack { | ||
107 | struct wuie_hdr hdr; | ||
108 | struct { | ||
109 | struct wusb_ckhdid CDID; | ||
110 | u8 bDeviceAddress; /* 0 means unused */ | ||
111 | u8 bReserved; | ||
112 | } blk[WUIE_ELT_MAX]; | ||
113 | } __attribute__((packed)); | ||
114 | |||
115 | /** | ||
116 | * WUSB IE Host Information Element, Connect Availability | ||
117 | * | ||
118 | * WUSB1.0[7.5.2], bmAttributes description | ||
119 | */ | ||
120 | enum { | ||
121 | WUIE_HI_CAP_RECONNECT = 0, | ||
122 | WUIE_HI_CAP_LIMITED, | ||
123 | WUIE_HI_CAP_RESERVED, | ||
124 | WUIE_HI_CAP_ALL, | ||
125 | }; | ||
126 | |||
127 | /** | ||
128 | * WUSB IE: Channel Stop (WUSB1.0[7.5.8]) | ||
129 | * | ||
130 | * Tells devices the host is going to stop sending MMCs and will dissapear. | ||
131 | */ | ||
132 | struct wuie_channel_stop { | ||
133 | struct wuie_hdr hdr; | ||
134 | u8 attributes; | ||
135 | u8 timestamp[3]; | ||
136 | } __attribute__((packed)); | ||
137 | |||
138 | /** | ||
139 | * WUSB IE: Keepalive (WUSB1.0[7.5.9]) | ||
140 | * | ||
141 | * Ask device(s) to send keepalives. | ||
142 | */ | ||
143 | struct wuie_keep_alive { | ||
144 | struct wuie_hdr hdr; | ||
145 | u8 bDeviceAddress[WUIE_ELT_MAX]; | ||
146 | } __attribute__((packed)); | ||
147 | |||
148 | /** | ||
149 | * WUSB IE: Reset device (WUSB1.0[7.5.11]) | ||
150 | * | ||
151 | * Tell device to reset; in all truth, we can fit 4 CDIDs, but we only | ||
152 | * use it for one at the time... | ||
153 | * | ||
154 | * In any case, this request is a wee bit silly: why don't they target | ||
155 | * by address?? | ||
156 | */ | ||
157 | struct wuie_reset { | ||
158 | struct wuie_hdr hdr; | ||
159 | struct wusb_ckhdid CDID; | ||
160 | } __attribute__((packed)); | ||
161 | |||
162 | /** | ||
163 | * WUSB IE: Disconnect device (WUSB1.0[7.5.11]) | ||
164 | * | ||
165 | * Tell device to disconnect; we can fit 4 addresses, but we only use | ||
166 | * it for one at the time... | ||
167 | */ | ||
168 | struct wuie_disconnect { | ||
169 | struct wuie_hdr hdr; | ||
170 | u8 bDeviceAddress; | ||
171 | u8 padding; | ||
172 | } __attribute__((packed)); | ||
173 | |||
174 | /** | ||
175 | * WUSB IE: Host disconnect ([WUSB] section 7.5.5) | ||
176 | * | ||
177 | * Tells all connected devices to disconnect. | ||
178 | */ | ||
179 | struct wuie_host_disconnect { | ||
180 | struct wuie_hdr hdr; | ||
181 | } __attribute__((packed)); | ||
182 | |||
183 | /** | ||
184 | * WUSB Device Notification header (WUSB1.0[7.6]) | ||
185 | */ | ||
186 | struct wusb_dn_hdr { | ||
187 | u8 bType; | ||
188 | u8 notifdata[]; | ||
189 | } __attribute__((packed)); | ||
190 | |||
191 | /** Device Notification codes (WUSB1.0[Table 7-54]) */ | ||
192 | enum WUSB_DN { | ||
193 | WUSB_DN_CONNECT = 0x01, | ||
194 | WUSB_DN_DISCONNECT = 0x02, | ||
195 | WUSB_DN_EPRDY = 0x03, | ||
196 | WUSB_DN_MASAVAILCHANGED = 0x04, | ||
197 | WUSB_DN_RWAKE = 0x05, | ||
198 | WUSB_DN_SLEEP = 0x06, | ||
199 | WUSB_DN_ALIVE = 0x07, | ||
200 | }; | ||
201 | |||
202 | /** WUSB Device Notification Connect */ | ||
203 | struct wusb_dn_connect { | ||
204 | struct wusb_dn_hdr hdr; | ||
205 | __le16 attributes; | ||
206 | struct wusb_ckhdid CDID; | ||
207 | } __attribute__((packed)); | ||
208 | |||
209 | static inline int wusb_dn_connect_prev_dev_addr(const struct wusb_dn_connect *dn) | ||
210 | { | ||
211 | return le16_to_cpu(dn->attributes) & 0xff; | ||
212 | } | ||
213 | |||
214 | static inline int wusb_dn_connect_new_connection(const struct wusb_dn_connect *dn) | ||
215 | { | ||
216 | return (le16_to_cpu(dn->attributes) >> 8) & 0x1; | ||
217 | } | ||
218 | |||
219 | static inline int wusb_dn_connect_beacon_behavior(const struct wusb_dn_connect *dn) | ||
220 | { | ||
221 | return (le16_to_cpu(dn->attributes) >> 9) & 0x03; | ||
222 | } | ||
223 | |||
224 | /** Device is alive (aka: pong) (WUSB1.0[7.6.7]) */ | ||
225 | struct wusb_dn_alive { | ||
226 | struct wusb_dn_hdr hdr; | ||
227 | } __attribute__((packed)); | ||
228 | |||
229 | /** Device is disconnecting (WUSB1.0[7.6.2]) */ | ||
230 | struct wusb_dn_disconnect { | ||
231 | struct wusb_dn_hdr hdr; | ||
232 | } __attribute__((packed)); | ||
233 | |||
234 | /* General constants */ | ||
235 | enum { | ||
236 | WUSB_TRUST_TIMEOUT_MS = 4000, /* [WUSB] section 4.15.1 */ | ||
237 | }; | ||
238 | |||
239 | static inline size_t ckhdid_printf(char *pr_ckhdid, size_t size, | ||
240 | const struct wusb_ckhdid *ckhdid) | ||
241 | { | ||
242 | return scnprintf(pr_ckhdid, size, | ||
243 | "%02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx " | ||
244 | "%02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx", | ||
245 | ckhdid->data[0], ckhdid->data[1], | ||
246 | ckhdid->data[2], ckhdid->data[3], | ||
247 | ckhdid->data[4], ckhdid->data[5], | ||
248 | ckhdid->data[6], ckhdid->data[7], | ||
249 | ckhdid->data[8], ckhdid->data[9], | ||
250 | ckhdid->data[10], ckhdid->data[11], | ||
251 | ckhdid->data[12], ckhdid->data[13], | ||
252 | ckhdid->data[14], ckhdid->data[15]); | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * WUSB Crypto stuff (WUSB1.0[6]) | ||
257 | */ | ||
258 | |||
259 | extern const char *wusb_et_name(u8); | ||
260 | |||
261 | /** | ||
262 | * WUSB key index WUSB1.0[7.3.2.4], for usage when setting keys for | ||
263 | * the host or the device. | ||
264 | */ | ||
265 | static inline u8 wusb_key_index(int index, int type, int originator) | ||
266 | { | ||
267 | return (originator << 6) | (type << 4) | index; | ||
268 | } | ||
269 | |||
270 | #define WUSB_KEY_INDEX_TYPE_PTK 0 /* for HWA only */ | ||
271 | #define WUSB_KEY_INDEX_TYPE_ASSOC 1 | ||
272 | #define WUSB_KEY_INDEX_TYPE_GTK 2 | ||
273 | #define WUSB_KEY_INDEX_ORIGINATOR_HOST 0 | ||
274 | #define WUSB_KEY_INDEX_ORIGINATOR_DEVICE 1 | ||
275 | |||
276 | /* A CCM Nonce, defined in WUSB1.0[6.4.1] */ | ||
277 | struct aes_ccm_nonce { | ||
278 | u8 sfn[6]; /* Little Endian */ | ||
279 | u8 tkid[3]; /* LE */ | ||
280 | struct uwb_dev_addr dest_addr; | ||
281 | struct uwb_dev_addr src_addr; | ||
282 | } __attribute__((packed)); | ||
283 | |||
284 | /* A CCM operation label, defined on WUSB1.0[6.5.x] */ | ||
285 | struct aes_ccm_label { | ||
286 | u8 data[14]; | ||
287 | } __attribute__((packed)); | ||
288 | |||
289 | /* | ||
290 | * Input to the key derivation sequence defined in | ||
291 | * WUSB1.0[6.5.1]. Rest of the data is in the CCM Nonce passed to the | ||
292 | * PRF function. | ||
293 | */ | ||
294 | struct wusb_keydvt_in { | ||
295 | u8 hnonce[16]; | ||
296 | u8 dnonce[16]; | ||
297 | } __attribute__((packed)); | ||
298 | |||
299 | /* | ||
300 | * Output from the key derivation sequence defined in | ||
301 | * WUSB1.0[6.5.1]. | ||
302 | */ | ||
303 | struct wusb_keydvt_out { | ||
304 | u8 kck[16]; | ||
305 | u8 ptk[16]; | ||
306 | } __attribute__((packed)); | ||
307 | |||
308 | /* Pseudo Random Function WUSB1.0[6.5] */ | ||
309 | extern int wusb_crypto_init(void); | ||
310 | extern void wusb_crypto_exit(void); | ||
311 | extern ssize_t wusb_prf(void *out, size_t out_size, | ||
312 | const u8 key[16], const struct aes_ccm_nonce *_n, | ||
313 | const struct aes_ccm_label *a, | ||
314 | const void *b, size_t blen, size_t len); | ||
315 | |||
316 | static inline int wusb_prf_64(void *out, size_t out_size, const u8 key[16], | ||
317 | const struct aes_ccm_nonce *n, | ||
318 | const struct aes_ccm_label *a, | ||
319 | const void *b, size_t blen) | ||
320 | { | ||
321 | return wusb_prf(out, out_size, key, n, a, b, blen, 64); | ||
322 | } | ||
323 | |||
324 | static inline int wusb_prf_128(void *out, size_t out_size, const u8 key[16], | ||
325 | const struct aes_ccm_nonce *n, | ||
326 | const struct aes_ccm_label *a, | ||
327 | const void *b, size_t blen) | ||
328 | { | ||
329 | return wusb_prf(out, out_size, key, n, a, b, blen, 128); | ||
330 | } | ||
331 | |||
332 | static inline int wusb_prf_256(void *out, size_t out_size, const u8 key[16], | ||
333 | const struct aes_ccm_nonce *n, | ||
334 | const struct aes_ccm_label *a, | ||
335 | const void *b, size_t blen) | ||
336 | { | ||
337 | return wusb_prf(out, out_size, key, n, a, b, blen, 256); | ||
338 | } | ||
339 | |||
340 | /* Key derivation WUSB1.0[6.5.1] */ | ||
341 | static inline int wusb_key_derive(struct wusb_keydvt_out *keydvt_out, | ||
342 | const u8 key[16], | ||
343 | const struct aes_ccm_nonce *n, | ||
344 | const struct wusb_keydvt_in *keydvt_in) | ||
345 | { | ||
346 | const struct aes_ccm_label a = { .data = "Pair-wise keys" }; | ||
347 | return wusb_prf_256(keydvt_out, sizeof(*keydvt_out), key, n, &a, | ||
348 | keydvt_in, sizeof(*keydvt_in)); | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * Out-of-band MIC Generation WUSB1.0[6.5.2] | ||
353 | * | ||
354 | * Compute the MIC over @key, @n and @hs and place it in @mic_out. | ||
355 | * | ||
356 | * @mic_out: Where to place the 8 byte MIC tag | ||
357 | * @key: KCK from the derivation process | ||
358 | * @n: CCM nonce, n->sfn == 0, TKID as established in the | ||
359 | * process. | ||
360 | * @hs: Handshake struct for phase 2 of the 4-way. | ||
361 | * hs->bStatus and hs->bReserved are zero. | ||
362 | * hs->bMessageNumber is 2 (WUSB1.0[7.3.2.5.2] | ||
363 | * hs->dest_addr is the device's USB address padded with 0 | ||
364 | * hs->src_addr is the hosts's UWB device address | ||
365 | * hs->mic is ignored (as we compute that value). | ||
366 | */ | ||
367 | static inline int wusb_oob_mic(u8 mic_out[8], const u8 key[16], | ||
368 | const struct aes_ccm_nonce *n, | ||
369 | const struct usb_handshake *hs) | ||
370 | { | ||
371 | const struct aes_ccm_label a = { .data = "out-of-bandMIC" }; | ||
372 | return wusb_prf_64(mic_out, 8, key, n, &a, | ||
373 | hs, sizeof(*hs) - sizeof(hs->MIC)); | ||
374 | } | ||
375 | |||
376 | #endif /* #ifndef __WUSB_H__ */ | ||