ieee80211_crypto.c revision 147870
1116742Ssam/*- 2116904Ssam * Copyright (c) 2001 Atsushi Onoe 3139530Ssam * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting 4116742Ssam * All rights reserved. 5116742Ssam * 6116742Ssam * Redistribution and use in source and binary forms, with or without 7116742Ssam * modification, are permitted provided that the following conditions 8116742Ssam * are met: 9116742Ssam * 1. Redistributions of source code must retain the above copyright 10116904Ssam * notice, this list of conditions and the following disclaimer. 11116904Ssam * 2. Redistributions in binary form must reproduce the above copyright 12116904Ssam * notice, this list of conditions and the following disclaimer in the 13116904Ssam * documentation and/or other materials provided with the distribution. 14116904Ssam * 3. The name of the author may not be used to endorse or promote products 15116904Ssam * derived from this software without specific prior written permission. 16116742Ssam * 17116742Ssam * Alternatively, this software may be distributed under the terms of the 18116742Ssam * GNU General Public License ("GPL") version 2 as published by the Free 19116742Ssam * Software Foundation. 20116742Ssam * 21116904Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22116904Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23116904Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24116904Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25116904Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26116904Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27116904Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28116904Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29116904Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30116904Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31116742Ssam */ 32116742Ssam 33116742Ssam#include <sys/cdefs.h> 34116742Ssam__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_crypto.c 147870 2005-07-09 23:15:30Z sam $"); 35116742Ssam 36138568Ssam/* 37138568Ssam * IEEE 802.11 generic crypto support. 38138568Ssam */ 39116742Ssam#include <sys/param.h> 40116742Ssam#include <sys/mbuf.h> 41138568Ssam 42116742Ssam#include <sys/socket.h> 43116742Ssam 44116742Ssam#include <net/if.h> 45116742Ssam#include <net/if_media.h> 46138568Ssam#include <net/ethernet.h> /* XXX ETHER_HDR_LEN */ 47116742Ssam 48116742Ssam#include <net80211/ieee80211_var.h> 49116742Ssam 50138568Ssam/* 51138568Ssam * Table of registered cipher modules. 52138568Ssam */ 53138568Ssamstatic const struct ieee80211_cipher *ciphers[IEEE80211_CIPHER_MAX]; 54116742Ssam 55138568Ssamstatic int _ieee80211_crypto_delkey(struct ieee80211com *, 56138568Ssam struct ieee80211_key *); 57116742Ssam 58138568Ssam/* 59138568Ssam * Default "null" key management routines. 60138568Ssam */ 61138568Ssamstatic int 62138568Ssamnull_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k) 63138568Ssam{ 64147870Ssam if (!(&ic->ic_nw_keys[0] <= k && 65147870Ssam k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) { 66147870Ssam /* 67147870Ssam * Not in the global key table, the driver should handle this 68147870Ssam * by allocating a slot in the h/w key table/cache. In 69147870Ssam * lieu of that return key slot 0 for any unicast key 70147870Ssam * request. We disallow the request if this is a group key. 71147870Ssam * This default policy does the right thing for legacy hardware 72147870Ssam * with a 4 key table. It also handles devices that pass 73147870Ssam * packets through untouched when marked with the WEP bit 74147870Ssam * and key index 0. 75147870Ssam */ 76147870Ssam if ((k->wk_flags & IEEE80211_KEY_GROUP) == 0) 77147870Ssam return 0; /* NB: use key index 0 for ucast key */ 78147870Ssam else 79147870Ssam return IEEE80211_KEYIX_NONE; 80147870Ssam } 81147870Ssam return k - ic->ic_nw_keys; 82138568Ssam} 83138568Ssamstatic int 84138568Ssamnull_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k) 85138568Ssam{ 86138568Ssam return 1; 87138568Ssam} 88138568Ssamstatic int 89138568Ssamnull_key_set(struct ieee80211com *ic, const struct ieee80211_key *k, 90138568Ssam const u_int8_t mac[IEEE80211_ADDR_LEN]) 91138568Ssam{ 92138568Ssam return 1; 93138568Ssam} 94138568Ssamstatic void null_key_update(struct ieee80211com *ic) {} 95116742Ssam 96138568Ssam/* 97138568Ssam * Write-arounds for common operations. 98138568Ssam */ 99138568Ssamstatic __inline void 100138568Ssamcipher_detach(struct ieee80211_key *key) 101138568Ssam{ 102138568Ssam key->wk_cipher->ic_detach(key); 103138568Ssam} 104116742Ssam 105138568Ssamstatic __inline void * 106138568Ssamcipher_attach(struct ieee80211com *ic, struct ieee80211_key *key) 107138568Ssam{ 108138568Ssam return key->wk_cipher->ic_attach(ic, key); 109138568Ssam} 110138568Ssam 111138568Ssam/* 112138568Ssam * Wrappers for driver key management methods. 113138568Ssam */ 114138568Ssamstatic __inline int 115138568Ssamdev_key_alloc(struct ieee80211com *ic, 116138568Ssam const struct ieee80211_key *key) 117138568Ssam{ 118138568Ssam return ic->ic_crypto.cs_key_alloc(ic, key); 119138568Ssam} 120138568Ssam 121138568Ssamstatic __inline int 122138568Ssamdev_key_delete(struct ieee80211com *ic, 123138568Ssam const struct ieee80211_key *key) 124138568Ssam{ 125138568Ssam return ic->ic_crypto.cs_key_delete(ic, key); 126138568Ssam} 127138568Ssam 128138568Ssamstatic __inline int 129138568Ssamdev_key_set(struct ieee80211com *ic, const struct ieee80211_key *key, 130138568Ssam const u_int8_t mac[IEEE80211_ADDR_LEN]) 131138568Ssam{ 132138568Ssam return ic->ic_crypto.cs_key_set(ic, key, mac); 133138568Ssam} 134138568Ssam 135138568Ssam/* 136138568Ssam * Setup crypto support. 137138568Ssam */ 138116742Ssamvoid 139138568Ssamieee80211_crypto_attach(struct ieee80211com *ic) 140116742Ssam{ 141138568Ssam struct ieee80211_crypto_state *cs = &ic->ic_crypto; 142138568Ssam int i; 143116742Ssam 144138568Ssam /* NB: we assume everything is pre-zero'd */ 145138568Ssam cs->cs_def_txkey = IEEE80211_KEYIX_NONE; 146138568Ssam ciphers[IEEE80211_CIPHER_NONE] = &ieee80211_cipher_none; 147138568Ssam for (i = 0; i < IEEE80211_WEP_NKID; i++) 148144960Ssam ieee80211_crypto_resetkey(ic, &cs->cs_nw_keys[i], 149144960Ssam IEEE80211_KEYIX_NONE); 150116742Ssam /* 151138568Ssam * Initialize the driver key support routines to noop entries. 152138568Ssam * This is useful especially for the cipher test modules. 153116742Ssam */ 154138568Ssam cs->cs_key_alloc = null_key_alloc; 155138568Ssam cs->cs_key_set = null_key_set; 156138568Ssam cs->cs_key_delete = null_key_delete; 157138568Ssam cs->cs_key_update_begin = null_key_update; 158138568Ssam cs->cs_key_update_end = null_key_update; 159116742Ssam} 160116742Ssam 161138568Ssam/* 162138568Ssam * Teardown crypto support. 163138568Ssam */ 164116742Ssamvoid 165138568Ssamieee80211_crypto_detach(struct ieee80211com *ic) 166116742Ssam{ 167138568Ssam ieee80211_crypto_delglobalkeys(ic); 168138568Ssam} 169116742Ssam 170138568Ssam/* 171138568Ssam * Register a crypto cipher module. 172138568Ssam */ 173138568Ssamvoid 174138568Ssamieee80211_crypto_register(const struct ieee80211_cipher *cip) 175138568Ssam{ 176138568Ssam if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) { 177138568Ssam printf("%s: cipher %s has an invalid cipher index %u\n", 178138568Ssam __func__, cip->ic_name, cip->ic_cipher); 179138568Ssam return; 180116742Ssam } 181138568Ssam if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) { 182138568Ssam printf("%s: cipher %s registered with a different template\n", 183138568Ssam __func__, cip->ic_name); 184138568Ssam return; 185138568Ssam } 186138568Ssam ciphers[cip->ic_cipher] = cip; 187116742Ssam} 188116742Ssam 189138568Ssam/* 190138568Ssam * Unregister a crypto cipher module. 191138568Ssam */ 192138568Ssamvoid 193138568Ssamieee80211_crypto_unregister(const struct ieee80211_cipher *cip) 194116742Ssam{ 195138568Ssam if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) { 196138568Ssam printf("%s: cipher %s has an invalid cipher index %u\n", 197138568Ssam __func__, cip->ic_name, cip->ic_cipher); 198138568Ssam return; 199116742Ssam } 200138568Ssam if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) { 201138568Ssam printf("%s: cipher %s registered with a different template\n", 202138568Ssam __func__, cip->ic_name); 203138568Ssam return; 204121180Ssam } 205138568Ssam /* NB: don't complain about not being registered */ 206138568Ssam /* XXX disallow if references */ 207138568Ssam ciphers[cip->ic_cipher] = NULL; 208138568Ssam} 209138568Ssam 210138568Ssamint 211138568Ssamieee80211_crypto_available(u_int cipher) 212138568Ssam{ 213138568Ssam return cipher < IEEE80211_CIPHER_MAX && ciphers[cipher] != NULL; 214138568Ssam} 215138568Ssam 216138568Ssam/* XXX well-known names! */ 217138568Ssamstatic const char *cipher_modnames[] = { 218138568Ssam "wlan_wep", /* IEEE80211_CIPHER_WEP */ 219138568Ssam "wlan_tkip", /* IEEE80211_CIPHER_TKIP */ 220138568Ssam "wlan_aes_ocb", /* IEEE80211_CIPHER_AES_OCB */ 221138568Ssam "wlan_ccmp", /* IEEE80211_CIPHER_AES_CCM */ 222138568Ssam "wlan_ckip", /* IEEE80211_CIPHER_CKIP */ 223138568Ssam}; 224138568Ssam 225138568Ssam/* 226138568Ssam * Establish a relationship between the specified key and cipher 227144960Ssam * and, if necessary, allocate a hardware index from the driver. 228144960Ssam * Note that when a fixed key index is required it must be specified 229144960Ssam * and we blindly assign it w/o consulting the driver (XXX). 230138568Ssam * 231138568Ssam * This must be the first call applied to a key; all the other key 232138568Ssam * routines assume wk_cipher is setup. 233138568Ssam * 234138568Ssam * Locking must be handled by the caller using: 235138568Ssam * ieee80211_key_update_begin(ic); 236138568Ssam * ieee80211_key_update_end(ic); 237138568Ssam */ 238138568Ssamint 239138568Ssamieee80211_crypto_newkey(struct ieee80211com *ic, 240144960Ssam int cipher, int flags, struct ieee80211_key *key) 241138568Ssam{ 242138568Ssam#define N(a) (sizeof(a) / sizeof(a[0])) 243138568Ssam const struct ieee80211_cipher *cip; 244138568Ssam void *keyctx; 245138568Ssam int oflags; 246138568Ssam 247138568Ssam /* 248138568Ssam * Validate cipher and set reference to cipher routines. 249138568Ssam */ 250138568Ssam if (cipher >= IEEE80211_CIPHER_MAX) { 251138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 252138568Ssam "%s: invalid cipher %u\n", __func__, cipher); 253138568Ssam ic->ic_stats.is_crypto_badcipher++; 254138568Ssam return 0; 255116742Ssam } 256138568Ssam cip = ciphers[cipher]; 257138568Ssam if (cip == NULL) { 258116742Ssam /* 259138568Ssam * Auto-load cipher module if we have a well-known name 260138568Ssam * for it. It might be better to use string names rather 261138568Ssam * than numbers and craft a module name based on the cipher 262138568Ssam * name; e.g. wlan_cipher_<cipher-name>. 263116742Ssam */ 264138568Ssam if (cipher < N(cipher_modnames)) { 265138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 266138568Ssam "%s: unregistered cipher %u, load module %s\n", 267138568Ssam __func__, cipher, cipher_modnames[cipher]); 268138568Ssam ieee80211_load_module(cipher_modnames[cipher]); 269138568Ssam /* 270138568Ssam * If cipher module loaded it should immediately 271138568Ssam * call ieee80211_crypto_register which will fill 272138568Ssam * in the entry in the ciphers array. 273138568Ssam */ 274138568Ssam cip = ciphers[cipher]; 275116742Ssam } 276138568Ssam if (cip == NULL) { 277138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 278138568Ssam "%s: unable to load cipher %u, module %s\n", 279138568Ssam __func__, cipher, 280138568Ssam cipher < N(cipher_modnames) ? 281138568Ssam cipher_modnames[cipher] : "<unknown>"); 282138568Ssam ic->ic_stats.is_crypto_nocipher++; 283138568Ssam return 0; 284138568Ssam } 285116742Ssam } 286116742Ssam 287138568Ssam oflags = key->wk_flags; 288144960Ssam flags &= IEEE80211_KEY_COMMON; 289138568Ssam /* 290138568Ssam * If the hardware does not support the cipher then 291138568Ssam * fallback to a host-based implementation. 292138568Ssam */ 293138568Ssam if ((ic->ic_caps & (1<<cipher)) == 0) { 294138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 295138568Ssam "%s: no h/w support for cipher %s, falling back to s/w\n", 296138568Ssam __func__, cip->ic_name); 297144960Ssam flags |= IEEE80211_KEY_SWCRYPT; 298138568Ssam } 299138568Ssam /* 300138568Ssam * Hardware TKIP with software MIC is an important 301138568Ssam * combination; we handle it by flagging each key, 302138568Ssam * the cipher modules honor it. 303138568Ssam */ 304138568Ssam if (cipher == IEEE80211_CIPHER_TKIP && 305138568Ssam (ic->ic_caps & IEEE80211_C_TKIPMIC) == 0) { 306138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 307138568Ssam "%s: no h/w support for TKIP MIC, falling back to s/w\n", 308138568Ssam __func__); 309144960Ssam flags |= IEEE80211_KEY_SWMIC; 310138568Ssam } 311138568Ssam 312138568Ssam /* 313138568Ssam * Bind cipher to key instance. Note we do this 314138568Ssam * after checking the device capabilities so the 315138568Ssam * cipher module can optimize space usage based on 316138568Ssam * whether or not it needs to do the cipher work. 317138568Ssam */ 318144960Ssam if (key->wk_cipher != cip || key->wk_flags != flags) { 319138568Ssamagain: 320144960Ssam /* 321144960Ssam * Fillin the flags so cipher modules can see s/w 322144960Ssam * crypto requirements and potentially allocate 323144960Ssam * different state and/or attach different method 324144960Ssam * pointers. 325144960Ssam * 326144960Ssam * XXX this is not right when s/w crypto fallback 327144960Ssam * fails and we try to restore previous state. 328144960Ssam */ 329144960Ssam key->wk_flags = flags; 330138568Ssam keyctx = cip->ic_attach(ic, key); 331138568Ssam if (keyctx == NULL) { 332138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 333138568Ssam "%s: unable to attach cipher %s\n", 334138568Ssam __func__, cip->ic_name); 335138568Ssam key->wk_flags = oflags; /* restore old flags */ 336138568Ssam ic->ic_stats.is_crypto_attachfail++; 337138568Ssam return 0; 338116742Ssam } 339138568Ssam cipher_detach(key); 340138568Ssam key->wk_cipher = cip; /* XXX refcnt? */ 341138568Ssam key->wk_private = keyctx; 342138568Ssam } 343144960Ssam /* 344144960Ssam * Commit to requested usage so driver can see the flags. 345144960Ssam */ 346144960Ssam key->wk_flags = flags; 347138568Ssam 348138568Ssam /* 349138568Ssam * Ask the driver for a key index if we don't have one. 350138568Ssam * Note that entries in the global key table always have 351138568Ssam * an index; this means it's safe to call this routine 352138568Ssam * for these entries just to setup the reference to the 353138568Ssam * cipher template. Note also that when using software 354138568Ssam * crypto we also call the driver to give us a key index. 355138568Ssam */ 356138568Ssam if (key->wk_keyix == IEEE80211_KEYIX_NONE) { 357138568Ssam key->wk_keyix = dev_key_alloc(ic, key); 358138568Ssam if (key->wk_keyix == IEEE80211_KEYIX_NONE) { 359138568Ssam /* 360138568Ssam * Driver has no room; fallback to doing crypto 361138568Ssam * in the host. We change the flags and start the 362138568Ssam * procedure over. If we get back here then there's 363138568Ssam * no hope and we bail. Note that this can leave 364138568Ssam * the key in a inconsistent state if the caller 365138568Ssam * continues to use it. 366138568Ssam */ 367138568Ssam if ((key->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) { 368138568Ssam ic->ic_stats.is_crypto_swfallback++; 369138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 370138568Ssam "%s: no h/w resources for cipher %s, " 371138568Ssam "falling back to s/w\n", __func__, 372138568Ssam cip->ic_name); 373138568Ssam oflags = key->wk_flags; 374144960Ssam flags |= IEEE80211_KEY_SWCRYPT; 375138568Ssam if (cipher == IEEE80211_CIPHER_TKIP) 376144960Ssam flags |= IEEE80211_KEY_SWMIC; 377138568Ssam goto again; 378116742Ssam } 379138568Ssam ic->ic_stats.is_crypto_keyfail++; 380138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 381138568Ssam "%s: unable to setup cipher %s\n", 382138568Ssam __func__, cip->ic_name); 383138568Ssam return 0; 384116742Ssam } 385116742Ssam } 386138568Ssam return 1; 387138568Ssam#undef N 388138568Ssam} 389138568Ssam 390138568Ssam/* 391138568Ssam * Remove the key (no locking, for internal use). 392138568Ssam */ 393138568Ssamstatic int 394138568Ssam_ieee80211_crypto_delkey(struct ieee80211com *ic, struct ieee80211_key *key) 395138568Ssam{ 396138568Ssam u_int16_t keyix; 397138568Ssam 398138568Ssam KASSERT(key->wk_cipher != NULL, ("No cipher!")); 399138568Ssam 400139504Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 401139504Ssam "%s: %s keyix %u flags 0x%x rsc %ju tsc %ju len %u\n", 402139504Ssam __func__, key->wk_cipher->ic_name, 403139504Ssam key->wk_keyix, key->wk_flags, 404139504Ssam key->wk_keyrsc, key->wk_keytsc, key->wk_keylen); 405139504Ssam 406138568Ssam keyix = key->wk_keyix; 407138568Ssam if (keyix != IEEE80211_KEYIX_NONE) { 408138568Ssam /* 409138568Ssam * Remove hardware entry. 410138568Ssam */ 411138568Ssam /* XXX key cache */ 412138568Ssam if (!dev_key_delete(ic, key)) { 413138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 414138568Ssam "%s: driver did not delete key index %u\n", 415138568Ssam __func__, keyix); 416138568Ssam ic->ic_stats.is_crypto_delkey++; 417138568Ssam /* XXX recovery? */ 418116742Ssam } 419116742Ssam } 420138568Ssam cipher_detach(key); 421138568Ssam memset(key, 0, sizeof(*key)); 422144960Ssam ieee80211_crypto_resetkey(ic, key, IEEE80211_KEYIX_NONE); 423138568Ssam return 1; 424138568Ssam} 425116742Ssam 426138568Ssam/* 427138568Ssam * Remove the specified key. 428138568Ssam */ 429138568Ssamint 430138568Ssamieee80211_crypto_delkey(struct ieee80211com *ic, struct ieee80211_key *key) 431138568Ssam{ 432138568Ssam int status; 433138568Ssam 434138568Ssam ieee80211_key_update_begin(ic); 435138568Ssam status = _ieee80211_crypto_delkey(ic, key); 436138568Ssam ieee80211_key_update_end(ic); 437138568Ssam return status; 438116742Ssam} 439116742Ssam 440116742Ssam/* 441138568Ssam * Clear the global key table. 442116742Ssam */ 443138568Ssamvoid 444138568Ssamieee80211_crypto_delglobalkeys(struct ieee80211com *ic) 445138568Ssam{ 446138568Ssam int i; 447116742Ssam 448138568Ssam ieee80211_key_update_begin(ic); 449138568Ssam for (i = 0; i < IEEE80211_WEP_NKID; i++) 450138568Ssam (void) _ieee80211_crypto_delkey(ic, &ic->ic_nw_keys[i]); 451138568Ssam ieee80211_key_update_end(ic); 452138568Ssam} 453116742Ssam 454138568Ssam/* 455138568Ssam * Set the contents of the specified key. 456138568Ssam * 457138568Ssam * Locking must be handled by the caller using: 458138568Ssam * ieee80211_key_update_begin(ic); 459138568Ssam * ieee80211_key_update_end(ic); 460138568Ssam */ 461138568Ssamint 462138568Ssamieee80211_crypto_setkey(struct ieee80211com *ic, struct ieee80211_key *key, 463138568Ssam const u_int8_t macaddr[IEEE80211_ADDR_LEN]) 464116742Ssam{ 465138568Ssam const struct ieee80211_cipher *cip = key->wk_cipher; 466116742Ssam 467138568Ssam KASSERT(cip != NULL, ("No cipher!")); 468138568Ssam 469139504Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 470139504Ssam "%s: %s keyix %u flags 0x%x mac %s rsc %ju tsc %ju len %u\n", 471139504Ssam __func__, cip->ic_name, key->wk_keyix, 472139504Ssam key->wk_flags, ether_sprintf(macaddr), 473139504Ssam key->wk_keyrsc, key->wk_keytsc, key->wk_keylen); 474139504Ssam 475138568Ssam /* 476138568Ssam * Give cipher a chance to validate key contents. 477138568Ssam * XXX should happen before modifying state. 478138568Ssam */ 479138568Ssam if (!cip->ic_setkey(key)) { 480138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 481138568Ssam "%s: cipher %s rejected key index %u len %u flags 0x%x\n", 482138568Ssam __func__, cip->ic_name, key->wk_keyix, 483138568Ssam key->wk_keylen, key->wk_flags); 484138568Ssam ic->ic_stats.is_crypto_setkey_cipher++; 485138568Ssam return 0; 486138568Ssam } 487138568Ssam if (key->wk_keyix == IEEE80211_KEYIX_NONE) { 488138568Ssam /* XXX nothing allocated, should not happen */ 489138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 490138568Ssam "%s: no key index; should not happen!\n", __func__); 491138568Ssam ic->ic_stats.is_crypto_setkey_nokey++; 492138568Ssam return 0; 493138568Ssam } 494138568Ssam return dev_key_set(ic, key, macaddr); 495138568Ssam} 496138568Ssam 497138568Ssam/* 498138568Ssam * Add privacy headers appropriate for the specified key. 499138568Ssam */ 500138568Ssamstruct ieee80211_key * 501138568Ssamieee80211_crypto_encap(struct ieee80211com *ic, 502138568Ssam struct ieee80211_node *ni, struct mbuf *m) 503138568Ssam{ 504138568Ssam struct ieee80211_key *k; 505138568Ssam struct ieee80211_frame *wh; 506138568Ssam const struct ieee80211_cipher *cip; 507144960Ssam u_int8_t keyid; 508138568Ssam 509138568Ssam /* 510138568Ssam * Multicast traffic always uses the multicast key. 511138568Ssam * Otherwise if a unicast key is set we use that and 512138568Ssam * it is always key index 0. When no unicast key is 513138568Ssam * set we fall back to the default transmit key. 514138568Ssam */ 515138568Ssam wh = mtod(m, struct ieee80211_frame *); 516138568Ssam if (IEEE80211_IS_MULTICAST(wh->i_addr1) || 517138568Ssam ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) { 518138568Ssam if (ic->ic_def_txkey == IEEE80211_KEYIX_NONE) { 519138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 520139504Ssam "[%s] no default transmit key (%s) deftxkey %u\n", 521139504Ssam ether_sprintf(wh->i_addr1), __func__, 522139504Ssam ic->ic_def_txkey); 523138568Ssam ic->ic_stats.is_tx_nodefkey++; 524138568Ssam return NULL; 525116742Ssam } 526144960Ssam keyid = ic->ic_def_txkey; 527138568Ssam k = &ic->ic_nw_keys[ic->ic_def_txkey]; 528138568Ssam } else { 529144960Ssam keyid = 0; 530138568Ssam k = &ni->ni_ucastkey; 531116742Ssam } 532138568Ssam cip = k->wk_cipher; 533144960Ssam return (cip->ic_encap(k, m, keyid<<6) ? k : NULL); 534116742Ssam} 535116742Ssam 536116742Ssam/* 537138568Ssam * Validate and strip privacy headers (and trailer) for a 538138568Ssam * received frame that has the WEP/Privacy bit set. 539116742Ssam */ 540138568Ssamstruct ieee80211_key * 541138568Ssamieee80211_crypto_decap(struct ieee80211com *ic, 542147252Ssam struct ieee80211_node *ni, struct mbuf *m, int hdrlen) 543116742Ssam{ 544138568Ssam#define IEEE80211_WEP_HDRLEN (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN) 545138568Ssam#define IEEE80211_WEP_MINLEN \ 546138568Ssam (sizeof(struct ieee80211_frame) + ETHER_HDR_LEN + \ 547138568Ssam IEEE80211_WEP_HDRLEN + IEEE80211_WEP_CRCLEN) 548138568Ssam struct ieee80211_key *k; 549138568Ssam struct ieee80211_frame *wh; 550138568Ssam const struct ieee80211_cipher *cip; 551139506Ssam const u_int8_t *ivp; 552138568Ssam u_int8_t keyid; 553116742Ssam 554138568Ssam /* NB: this minimum size data frame could be bigger */ 555138568Ssam if (m->m_pkthdr.len < IEEE80211_WEP_MINLEN) { 556138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, 557138568Ssam "%s: WEP data frame too short, len %u\n", 558138568Ssam __func__, m->m_pkthdr.len); 559138568Ssam ic->ic_stats.is_rx_tooshort++; /* XXX need unique stat? */ 560138568Ssam return NULL; 561138568Ssam } 562138568Ssam 563138568Ssam /* 564138568Ssam * Locate the key. If unicast and there is no unicast 565138568Ssam * key then we fall back to the key id in the header. 566138568Ssam * This assumes unicast keys are only configured when 567138568Ssam * the key id in the header is meaningless (typically 0). 568138568Ssam */ 569138568Ssam wh = mtod(m, struct ieee80211_frame *); 570139506Ssam ivp = mtod(m, const u_int8_t *) + hdrlen; /* XXX contig */ 571138568Ssam keyid = ivp[IEEE80211_WEP_IVLEN]; 572138568Ssam if (IEEE80211_IS_MULTICAST(wh->i_addr1) || 573138568Ssam ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) 574138568Ssam k = &ic->ic_nw_keys[keyid >> 6]; 575138568Ssam else 576138568Ssam k = &ni->ni_ucastkey; 577138568Ssam 578138568Ssam /* 579138568Ssam * Insure crypto header is contiguous for all decap work. 580138568Ssam */ 581138568Ssam cip = k->wk_cipher; 582138568Ssam if (m->m_len < hdrlen + cip->ic_header && 583138568Ssam (m = m_pullup(m, hdrlen + cip->ic_header)) == NULL) { 584138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 585138568Ssam "[%s] unable to pullup %s header\n", 586138568Ssam ether_sprintf(wh->i_addr2), cip->ic_name); 587138568Ssam ic->ic_stats.is_rx_wepfail++; /* XXX */ 588138568Ssam return 0; 589138568Ssam } 590138568Ssam 591147252Ssam return (cip->ic_decap(k, m, hdrlen) ? k : NULL); 592138568Ssam#undef IEEE80211_WEP_MINLEN 593138568Ssam#undef IEEE80211_WEP_HDRLEN 594116742Ssam} 595