Inaky Perez-Gonzalez | c7f7364 | 2008-09-17 16:34:22 +0100 | [diff] [blame] | 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 | * |
Adam Buchbinder | 6070d81 | 2009-12-04 15:47:01 -0500 | [diff] [blame] | 77 | * Make it packed, as we use it in some hw definitions. |
Inaky Perez-Gonzalez | c7f7364 | 2008-09-17 16:34:22 +0100 | [diff] [blame] | 78 | */ |
| 79 | struct wusb_ckhdid { |
| 80 | u8 data[16]; |
| 81 | } __attribute__((packed)); |
| 82 | |
Tobias Klauser | 39db4b8 | 2009-02-09 23:07:35 +0100 | [diff] [blame] | 83 | static const struct wusb_ckhdid wusb_ckhdid_zero = { .data = { 0 } }; |
Inaky Perez-Gonzalez | c7f7364 | 2008-09-17 16:34:22 +0100 | [diff] [blame] | 84 | |
| 85 | #define WUSB_CKHDID_STRSIZE (3 * sizeof(struct wusb_ckhdid) + 1) |
| 86 | |
| 87 | /** |
| 88 | * WUSB IE: Host Information (WUSB1.0[7.5.2]) |
| 89 | * |
| 90 | * Used to provide information about the host to the Wireless USB |
| 91 | * devices in range (CHID can be used as an ASCII string). |
| 92 | */ |
| 93 | struct wuie_host_info { |
| 94 | struct wuie_hdr hdr; |
| 95 | __le16 attributes; |
| 96 | struct wusb_ckhdid CHID; |
| 97 | } __attribute__((packed)); |
| 98 | |
| 99 | /** |
| 100 | * WUSB IE: Connect Ack (WUSB1.0[7.5.1]) |
| 101 | * |
| 102 | * Used to acknowledge device connect requests. See note for |
| 103 | * WUIE_ELT_MAX. |
| 104 | */ |
| 105 | struct wuie_connect_ack { |
| 106 | struct wuie_hdr hdr; |
| 107 | struct { |
| 108 | struct wusb_ckhdid CDID; |
| 109 | u8 bDeviceAddress; /* 0 means unused */ |
| 110 | u8 bReserved; |
| 111 | } blk[WUIE_ELT_MAX]; |
| 112 | } __attribute__((packed)); |
| 113 | |
| 114 | /** |
| 115 | * WUSB IE Host Information Element, Connect Availability |
| 116 | * |
| 117 | * WUSB1.0[7.5.2], bmAttributes description |
| 118 | */ |
| 119 | enum { |
| 120 | WUIE_HI_CAP_RECONNECT = 0, |
| 121 | WUIE_HI_CAP_LIMITED, |
| 122 | WUIE_HI_CAP_RESERVED, |
| 123 | WUIE_HI_CAP_ALL, |
| 124 | }; |
| 125 | |
| 126 | /** |
| 127 | * WUSB IE: Channel Stop (WUSB1.0[7.5.8]) |
| 128 | * |
| 129 | * Tells devices the host is going to stop sending MMCs and will dissapear. |
| 130 | */ |
| 131 | struct wuie_channel_stop { |
| 132 | struct wuie_hdr hdr; |
| 133 | u8 attributes; |
| 134 | u8 timestamp[3]; |
| 135 | } __attribute__((packed)); |
| 136 | |
| 137 | /** |
| 138 | * WUSB IE: Keepalive (WUSB1.0[7.5.9]) |
| 139 | * |
| 140 | * Ask device(s) to send keepalives. |
| 141 | */ |
| 142 | struct wuie_keep_alive { |
| 143 | struct wuie_hdr hdr; |
| 144 | u8 bDeviceAddress[WUIE_ELT_MAX]; |
| 145 | } __attribute__((packed)); |
| 146 | |
| 147 | /** |
| 148 | * WUSB IE: Reset device (WUSB1.0[7.5.11]) |
| 149 | * |
| 150 | * Tell device to reset; in all truth, we can fit 4 CDIDs, but we only |
| 151 | * use it for one at the time... |
| 152 | * |
| 153 | * In any case, this request is a wee bit silly: why don't they target |
| 154 | * by address?? |
| 155 | */ |
| 156 | struct wuie_reset { |
| 157 | struct wuie_hdr hdr; |
| 158 | struct wusb_ckhdid CDID; |
| 159 | } __attribute__((packed)); |
| 160 | |
| 161 | /** |
| 162 | * WUSB IE: Disconnect device (WUSB1.0[7.5.11]) |
| 163 | * |
| 164 | * Tell device to disconnect; we can fit 4 addresses, but we only use |
| 165 | * it for one at the time... |
| 166 | */ |
| 167 | struct wuie_disconnect { |
| 168 | struct wuie_hdr hdr; |
| 169 | u8 bDeviceAddress; |
| 170 | u8 padding; |
| 171 | } __attribute__((packed)); |
| 172 | |
| 173 | /** |
| 174 | * WUSB IE: Host disconnect ([WUSB] section 7.5.5) |
| 175 | * |
| 176 | * Tells all connected devices to disconnect. |
| 177 | */ |
| 178 | struct wuie_host_disconnect { |
| 179 | struct wuie_hdr hdr; |
| 180 | } __attribute__((packed)); |
| 181 | |
| 182 | /** |
| 183 | * WUSB Device Notification header (WUSB1.0[7.6]) |
| 184 | */ |
| 185 | struct wusb_dn_hdr { |
| 186 | u8 bType; |
| 187 | u8 notifdata[]; |
| 188 | } __attribute__((packed)); |
| 189 | |
| 190 | /** Device Notification codes (WUSB1.0[Table 7-54]) */ |
| 191 | enum WUSB_DN { |
| 192 | WUSB_DN_CONNECT = 0x01, |
| 193 | WUSB_DN_DISCONNECT = 0x02, |
| 194 | WUSB_DN_EPRDY = 0x03, |
| 195 | WUSB_DN_MASAVAILCHANGED = 0x04, |
| 196 | WUSB_DN_RWAKE = 0x05, |
| 197 | WUSB_DN_SLEEP = 0x06, |
| 198 | WUSB_DN_ALIVE = 0x07, |
| 199 | }; |
| 200 | |
| 201 | /** WUSB Device Notification Connect */ |
| 202 | struct wusb_dn_connect { |
| 203 | struct wusb_dn_hdr hdr; |
| 204 | __le16 attributes; |
| 205 | struct wusb_ckhdid CDID; |
| 206 | } __attribute__((packed)); |
| 207 | |
| 208 | static inline int wusb_dn_connect_prev_dev_addr(const struct wusb_dn_connect *dn) |
| 209 | { |
| 210 | return le16_to_cpu(dn->attributes) & 0xff; |
| 211 | } |
| 212 | |
| 213 | static inline int wusb_dn_connect_new_connection(const struct wusb_dn_connect *dn) |
| 214 | { |
| 215 | return (le16_to_cpu(dn->attributes) >> 8) & 0x1; |
| 216 | } |
| 217 | |
| 218 | static inline int wusb_dn_connect_beacon_behavior(const struct wusb_dn_connect *dn) |
| 219 | { |
| 220 | return (le16_to_cpu(dn->attributes) >> 9) & 0x03; |
| 221 | } |
| 222 | |
| 223 | /** Device is alive (aka: pong) (WUSB1.0[7.6.7]) */ |
| 224 | struct wusb_dn_alive { |
| 225 | struct wusb_dn_hdr hdr; |
| 226 | } __attribute__((packed)); |
| 227 | |
| 228 | /** Device is disconnecting (WUSB1.0[7.6.2]) */ |
| 229 | struct wusb_dn_disconnect { |
| 230 | struct wusb_dn_hdr hdr; |
| 231 | } __attribute__((packed)); |
| 232 | |
| 233 | /* General constants */ |
| 234 | enum { |
| 235 | WUSB_TRUST_TIMEOUT_MS = 4000, /* [WUSB] section 4.15.1 */ |
| 236 | }; |
| 237 | |
| 238 | static inline size_t ckhdid_printf(char *pr_ckhdid, size_t size, |
| 239 | const struct wusb_ckhdid *ckhdid) |
| 240 | { |
| 241 | return scnprintf(pr_ckhdid, size, |
| 242 | "%02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx " |
| 243 | "%02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx", |
| 244 | ckhdid->data[0], ckhdid->data[1], |
| 245 | ckhdid->data[2], ckhdid->data[3], |
| 246 | ckhdid->data[4], ckhdid->data[5], |
| 247 | ckhdid->data[6], ckhdid->data[7], |
| 248 | ckhdid->data[8], ckhdid->data[9], |
| 249 | ckhdid->data[10], ckhdid->data[11], |
| 250 | ckhdid->data[12], ckhdid->data[13], |
| 251 | ckhdid->data[14], ckhdid->data[15]); |
| 252 | } |
| 253 | |
| 254 | /* |
| 255 | * WUSB Crypto stuff (WUSB1.0[6]) |
| 256 | */ |
| 257 | |
| 258 | extern const char *wusb_et_name(u8); |
| 259 | |
| 260 | /** |
| 261 | * WUSB key index WUSB1.0[7.3.2.4], for usage when setting keys for |
| 262 | * the host or the device. |
| 263 | */ |
| 264 | static inline u8 wusb_key_index(int index, int type, int originator) |
| 265 | { |
| 266 | return (originator << 6) | (type << 4) | index; |
| 267 | } |
| 268 | |
| 269 | #define WUSB_KEY_INDEX_TYPE_PTK 0 /* for HWA only */ |
| 270 | #define WUSB_KEY_INDEX_TYPE_ASSOC 1 |
| 271 | #define WUSB_KEY_INDEX_TYPE_GTK 2 |
| 272 | #define WUSB_KEY_INDEX_ORIGINATOR_HOST 0 |
| 273 | #define WUSB_KEY_INDEX_ORIGINATOR_DEVICE 1 |
| 274 | |
| 275 | /* A CCM Nonce, defined in WUSB1.0[6.4.1] */ |
| 276 | struct aes_ccm_nonce { |
| 277 | u8 sfn[6]; /* Little Endian */ |
| 278 | u8 tkid[3]; /* LE */ |
| 279 | struct uwb_dev_addr dest_addr; |
| 280 | struct uwb_dev_addr src_addr; |
| 281 | } __attribute__((packed)); |
| 282 | |
| 283 | /* A CCM operation label, defined on WUSB1.0[6.5.x] */ |
| 284 | struct aes_ccm_label { |
| 285 | u8 data[14]; |
| 286 | } __attribute__((packed)); |
| 287 | |
| 288 | /* |
| 289 | * Input to the key derivation sequence defined in |
| 290 | * WUSB1.0[6.5.1]. Rest of the data is in the CCM Nonce passed to the |
| 291 | * PRF function. |
| 292 | */ |
| 293 | struct wusb_keydvt_in { |
| 294 | u8 hnonce[16]; |
| 295 | u8 dnonce[16]; |
| 296 | } __attribute__((packed)); |
| 297 | |
| 298 | /* |
| 299 | * Output from the key derivation sequence defined in |
| 300 | * WUSB1.0[6.5.1]. |
| 301 | */ |
| 302 | struct wusb_keydvt_out { |
| 303 | u8 kck[16]; |
| 304 | u8 ptk[16]; |
| 305 | } __attribute__((packed)); |
| 306 | |
| 307 | /* Pseudo Random Function WUSB1.0[6.5] */ |
| 308 | extern int wusb_crypto_init(void); |
| 309 | extern void wusb_crypto_exit(void); |
| 310 | extern ssize_t wusb_prf(void *out, size_t out_size, |
| 311 | const u8 key[16], const struct aes_ccm_nonce *_n, |
| 312 | const struct aes_ccm_label *a, |
| 313 | const void *b, size_t blen, size_t len); |
| 314 | |
| 315 | static inline int wusb_prf_64(void *out, size_t out_size, const u8 key[16], |
| 316 | const struct aes_ccm_nonce *n, |
| 317 | const struct aes_ccm_label *a, |
| 318 | const void *b, size_t blen) |
| 319 | { |
| 320 | return wusb_prf(out, out_size, key, n, a, b, blen, 64); |
| 321 | } |
| 322 | |
| 323 | static inline int wusb_prf_128(void *out, size_t out_size, const u8 key[16], |
| 324 | const struct aes_ccm_nonce *n, |
| 325 | const struct aes_ccm_label *a, |
| 326 | const void *b, size_t blen) |
| 327 | { |
| 328 | return wusb_prf(out, out_size, key, n, a, b, blen, 128); |
| 329 | } |
| 330 | |
| 331 | static inline int wusb_prf_256(void *out, size_t out_size, const u8 key[16], |
| 332 | const struct aes_ccm_nonce *n, |
| 333 | const struct aes_ccm_label *a, |
| 334 | const void *b, size_t blen) |
| 335 | { |
| 336 | return wusb_prf(out, out_size, key, n, a, b, blen, 256); |
| 337 | } |
| 338 | |
| 339 | /* Key derivation WUSB1.0[6.5.1] */ |
| 340 | static inline int wusb_key_derive(struct wusb_keydvt_out *keydvt_out, |
| 341 | const u8 key[16], |
| 342 | const struct aes_ccm_nonce *n, |
| 343 | const struct wusb_keydvt_in *keydvt_in) |
| 344 | { |
| 345 | const struct aes_ccm_label a = { .data = "Pair-wise keys" }; |
| 346 | return wusb_prf_256(keydvt_out, sizeof(*keydvt_out), key, n, &a, |
| 347 | keydvt_in, sizeof(*keydvt_in)); |
| 348 | } |
| 349 | |
| 350 | /* |
| 351 | * Out-of-band MIC Generation WUSB1.0[6.5.2] |
| 352 | * |
| 353 | * Compute the MIC over @key, @n and @hs and place it in @mic_out. |
| 354 | * |
| 355 | * @mic_out: Where to place the 8 byte MIC tag |
| 356 | * @key: KCK from the derivation process |
| 357 | * @n: CCM nonce, n->sfn == 0, TKID as established in the |
| 358 | * process. |
| 359 | * @hs: Handshake struct for phase 2 of the 4-way. |
| 360 | * hs->bStatus and hs->bReserved are zero. |
| 361 | * hs->bMessageNumber is 2 (WUSB1.0[7.3.2.5.2] |
| 362 | * hs->dest_addr is the device's USB address padded with 0 |
| 363 | * hs->src_addr is the hosts's UWB device address |
| 364 | * hs->mic is ignored (as we compute that value). |
| 365 | */ |
| 366 | static inline int wusb_oob_mic(u8 mic_out[8], const u8 key[16], |
| 367 | const struct aes_ccm_nonce *n, |
| 368 | const struct usb_handshake *hs) |
| 369 | { |
| 370 | const struct aes_ccm_label a = { .data = "out-of-bandMIC" }; |
| 371 | return wusb_prf_64(mic_out, 8, key, n, &a, |
| 372 | hs, sizeof(*hs) - sizeof(hs->MIC)); |
| 373 | } |
| 374 | |
| 375 | #endif /* #ifndef __WUSB_H__ */ |