ieee80211_crypto.c revision 139506
1116742Ssam/*- 2116904Ssam * Copyright (c) 2001 Atsushi Onoe 3138568Ssam * Copyright (c) 2002-2004 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 139506 2004-12-31 20:44:15Z 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{ 64138568Ssam return IEEE80211_KEYIX_NONE; 65138568Ssam} 66138568Ssamstatic int 67138568Ssamnull_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k) 68138568Ssam{ 69138568Ssam return 1; 70138568Ssam} 71138568Ssamstatic int 72138568Ssamnull_key_set(struct ieee80211com *ic, const struct ieee80211_key *k, 73138568Ssam const u_int8_t mac[IEEE80211_ADDR_LEN]) 74138568Ssam{ 75138568Ssam return 1; 76138568Ssam} 77138568Ssamstatic void null_key_update(struct ieee80211com *ic) {} 78116742Ssam 79138568Ssam/* 80138568Ssam * Write-arounds for common operations. 81138568Ssam */ 82138568Ssamstatic __inline void 83138568Ssamcipher_detach(struct ieee80211_key *key) 84138568Ssam{ 85138568Ssam key->wk_cipher->ic_detach(key); 86138568Ssam} 87116742Ssam 88138568Ssamstatic __inline void * 89138568Ssamcipher_attach(struct ieee80211com *ic, struct ieee80211_key *key) 90138568Ssam{ 91138568Ssam return key->wk_cipher->ic_attach(ic, key); 92138568Ssam} 93138568Ssam 94138568Ssam/* 95138568Ssam * Wrappers for driver key management methods. 96138568Ssam */ 97138568Ssamstatic __inline int 98138568Ssamdev_key_alloc(struct ieee80211com *ic, 99138568Ssam const struct ieee80211_key *key) 100138568Ssam{ 101138568Ssam return ic->ic_crypto.cs_key_alloc(ic, key); 102138568Ssam} 103138568Ssam 104138568Ssamstatic __inline int 105138568Ssamdev_key_delete(struct ieee80211com *ic, 106138568Ssam const struct ieee80211_key *key) 107138568Ssam{ 108138568Ssam return ic->ic_crypto.cs_key_delete(ic, key); 109138568Ssam} 110138568Ssam 111138568Ssamstatic __inline int 112138568Ssamdev_key_set(struct ieee80211com *ic, const struct ieee80211_key *key, 113138568Ssam const u_int8_t mac[IEEE80211_ADDR_LEN]) 114138568Ssam{ 115138568Ssam return ic->ic_crypto.cs_key_set(ic, key, mac); 116138568Ssam} 117138568Ssam 118138568Ssam/* 119138568Ssam * Setup crypto support. 120138568Ssam */ 121116742Ssamvoid 122138568Ssamieee80211_crypto_attach(struct ieee80211com *ic) 123116742Ssam{ 124138568Ssam struct ieee80211_crypto_state *cs = &ic->ic_crypto; 125138568Ssam int i; 126116742Ssam 127138568Ssam /* NB: we assume everything is pre-zero'd */ 128138568Ssam cs->cs_def_txkey = IEEE80211_KEYIX_NONE; 129138568Ssam ciphers[IEEE80211_CIPHER_NONE] = &ieee80211_cipher_none; 130138568Ssam for (i = 0; i < IEEE80211_WEP_NKID; i++) 131138568Ssam ieee80211_crypto_resetkey(ic, &cs->cs_nw_keys[i], i); 132116742Ssam /* 133138568Ssam * Initialize the driver key support routines to noop entries. 134138568Ssam * This is useful especially for the cipher test modules. 135116742Ssam */ 136138568Ssam cs->cs_key_alloc = null_key_alloc; 137138568Ssam cs->cs_key_set = null_key_set; 138138568Ssam cs->cs_key_delete = null_key_delete; 139138568Ssam cs->cs_key_update_begin = null_key_update; 140138568Ssam cs->cs_key_update_end = null_key_update; 141116742Ssam} 142116742Ssam 143138568Ssam/* 144138568Ssam * Teardown crypto support. 145138568Ssam */ 146116742Ssamvoid 147138568Ssamieee80211_crypto_detach(struct ieee80211com *ic) 148116742Ssam{ 149138568Ssam ieee80211_crypto_delglobalkeys(ic); 150138568Ssam} 151116742Ssam 152138568Ssam/* 153138568Ssam * Register a crypto cipher module. 154138568Ssam */ 155138568Ssamvoid 156138568Ssamieee80211_crypto_register(const struct ieee80211_cipher *cip) 157138568Ssam{ 158138568Ssam if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) { 159138568Ssam printf("%s: cipher %s has an invalid cipher index %u\n", 160138568Ssam __func__, cip->ic_name, cip->ic_cipher); 161138568Ssam return; 162116742Ssam } 163138568Ssam if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) { 164138568Ssam printf("%s: cipher %s registered with a different template\n", 165138568Ssam __func__, cip->ic_name); 166138568Ssam return; 167138568Ssam } 168138568Ssam ciphers[cip->ic_cipher] = cip; 169116742Ssam} 170116742Ssam 171138568Ssam/* 172138568Ssam * Unregister a crypto cipher module. 173138568Ssam */ 174138568Ssamvoid 175138568Ssamieee80211_crypto_unregister(const struct ieee80211_cipher *cip) 176116742Ssam{ 177138568Ssam if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) { 178138568Ssam printf("%s: cipher %s has an invalid cipher index %u\n", 179138568Ssam __func__, cip->ic_name, cip->ic_cipher); 180138568Ssam return; 181116742Ssam } 182138568Ssam if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) { 183138568Ssam printf("%s: cipher %s registered with a different template\n", 184138568Ssam __func__, cip->ic_name); 185138568Ssam return; 186121180Ssam } 187138568Ssam /* NB: don't complain about not being registered */ 188138568Ssam /* XXX disallow if references */ 189138568Ssam ciphers[cip->ic_cipher] = NULL; 190138568Ssam} 191138568Ssam 192138568Ssamint 193138568Ssamieee80211_crypto_available(u_int cipher) 194138568Ssam{ 195138568Ssam return cipher < IEEE80211_CIPHER_MAX && ciphers[cipher] != NULL; 196138568Ssam} 197138568Ssam 198138568Ssam/* XXX well-known names! */ 199138568Ssamstatic const char *cipher_modnames[] = { 200138568Ssam "wlan_wep", /* IEEE80211_CIPHER_WEP */ 201138568Ssam "wlan_tkip", /* IEEE80211_CIPHER_TKIP */ 202138568Ssam "wlan_aes_ocb", /* IEEE80211_CIPHER_AES_OCB */ 203138568Ssam "wlan_ccmp", /* IEEE80211_CIPHER_AES_CCM */ 204138568Ssam "wlan_ckip", /* IEEE80211_CIPHER_CKIP */ 205138568Ssam}; 206138568Ssam 207138568Ssam/* 208138568Ssam * Establish a relationship between the specified key and cipher 209138568Ssam * and, if not a global key, allocate a hardware index from the 210138568Ssam * driver. Note that we may be called for global keys but they 211138568Ssam * should have a key index already setup so the only work done 212138568Ssam * is to setup the cipher reference. 213138568Ssam * 214138568Ssam * This must be the first call applied to a key; all the other key 215138568Ssam * routines assume wk_cipher is setup. 216138568Ssam * 217138568Ssam * Locking must be handled by the caller using: 218138568Ssam * ieee80211_key_update_begin(ic); 219138568Ssam * ieee80211_key_update_end(ic); 220138568Ssam */ 221138568Ssamint 222138568Ssamieee80211_crypto_newkey(struct ieee80211com *ic, 223138568Ssam int cipher, struct ieee80211_key *key) 224138568Ssam{ 225138568Ssam#define N(a) (sizeof(a) / sizeof(a[0])) 226138568Ssam const struct ieee80211_cipher *cip; 227138568Ssam void *keyctx; 228138568Ssam int oflags; 229138568Ssam 230138568Ssam /* 231138568Ssam * Validate cipher and set reference to cipher routines. 232138568Ssam */ 233138568Ssam if (cipher >= IEEE80211_CIPHER_MAX) { 234138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 235138568Ssam "%s: invalid cipher %u\n", __func__, cipher); 236138568Ssam ic->ic_stats.is_crypto_badcipher++; 237138568Ssam return 0; 238116742Ssam } 239138568Ssam cip = ciphers[cipher]; 240138568Ssam if (cip == NULL) { 241116742Ssam /* 242138568Ssam * Auto-load cipher module if we have a well-known name 243138568Ssam * for it. It might be better to use string names rather 244138568Ssam * than numbers and craft a module name based on the cipher 245138568Ssam * name; e.g. wlan_cipher_<cipher-name>. 246116742Ssam */ 247138568Ssam if (cipher < N(cipher_modnames)) { 248138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 249138568Ssam "%s: unregistered cipher %u, load module %s\n", 250138568Ssam __func__, cipher, cipher_modnames[cipher]); 251138568Ssam ieee80211_load_module(cipher_modnames[cipher]); 252138568Ssam /* 253138568Ssam * If cipher module loaded it should immediately 254138568Ssam * call ieee80211_crypto_register which will fill 255138568Ssam * in the entry in the ciphers array. 256138568Ssam */ 257138568Ssam cip = ciphers[cipher]; 258116742Ssam } 259138568Ssam if (cip == NULL) { 260138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 261138568Ssam "%s: unable to load cipher %u, module %s\n", 262138568Ssam __func__, cipher, 263138568Ssam cipher < N(cipher_modnames) ? 264138568Ssam cipher_modnames[cipher] : "<unknown>"); 265138568Ssam ic->ic_stats.is_crypto_nocipher++; 266138568Ssam return 0; 267138568Ssam } 268116742Ssam } 269116742Ssam 270138568Ssam oflags = key->wk_flags; 271138568Ssam /* 272138568Ssam * If the hardware does not support the cipher then 273138568Ssam * fallback to a host-based implementation. 274138568Ssam */ 275138568Ssam key->wk_flags &= ~(IEEE80211_KEY_SWCRYPT|IEEE80211_KEY_SWMIC); 276138568Ssam if ((ic->ic_caps & (1<<cipher)) == 0) { 277138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 278138568Ssam "%s: no h/w support for cipher %s, falling back to s/w\n", 279138568Ssam __func__, cip->ic_name); 280138568Ssam key->wk_flags |= IEEE80211_KEY_SWCRYPT; 281138568Ssam } 282138568Ssam /* 283138568Ssam * Hardware TKIP with software MIC is an important 284138568Ssam * combination; we handle it by flagging each key, 285138568Ssam * the cipher modules honor it. 286138568Ssam */ 287138568Ssam if (cipher == IEEE80211_CIPHER_TKIP && 288138568Ssam (ic->ic_caps & IEEE80211_C_TKIPMIC) == 0) { 289138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 290138568Ssam "%s: no h/w support for TKIP MIC, falling back to s/w\n", 291138568Ssam __func__); 292138568Ssam key->wk_flags |= IEEE80211_KEY_SWMIC; 293138568Ssam } 294138568Ssam 295138568Ssam /* 296138568Ssam * Bind cipher to key instance. Note we do this 297138568Ssam * after checking the device capabilities so the 298138568Ssam * cipher module can optimize space usage based on 299138568Ssam * whether or not it needs to do the cipher work. 300138568Ssam */ 301138568Ssam if (key->wk_cipher != cip || key->wk_flags != oflags) { 302138568Ssamagain: 303138568Ssam keyctx = cip->ic_attach(ic, key); 304138568Ssam if (keyctx == NULL) { 305138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 306138568Ssam "%s: unable to attach cipher %s\n", 307138568Ssam __func__, cip->ic_name); 308138568Ssam key->wk_flags = oflags; /* restore old flags */ 309138568Ssam ic->ic_stats.is_crypto_attachfail++; 310138568Ssam return 0; 311116742Ssam } 312138568Ssam cipher_detach(key); 313138568Ssam key->wk_cipher = cip; /* XXX refcnt? */ 314138568Ssam key->wk_private = keyctx; 315138568Ssam } 316138568Ssam 317138568Ssam /* 318138568Ssam * Ask the driver for a key index if we don't have one. 319138568Ssam * Note that entries in the global key table always have 320138568Ssam * an index; this means it's safe to call this routine 321138568Ssam * for these entries just to setup the reference to the 322138568Ssam * cipher template. Note also that when using software 323138568Ssam * crypto we also call the driver to give us a key index. 324138568Ssam */ 325138568Ssam if (key->wk_keyix == IEEE80211_KEYIX_NONE) { 326138568Ssam key->wk_keyix = dev_key_alloc(ic, key); 327138568Ssam if (key->wk_keyix == IEEE80211_KEYIX_NONE) { 328138568Ssam /* 329138568Ssam * Driver has no room; fallback to doing crypto 330138568Ssam * in the host. We change the flags and start the 331138568Ssam * procedure over. If we get back here then there's 332138568Ssam * no hope and we bail. Note that this can leave 333138568Ssam * the key in a inconsistent state if the caller 334138568Ssam * continues to use it. 335138568Ssam */ 336138568Ssam if ((key->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) { 337138568Ssam ic->ic_stats.is_crypto_swfallback++; 338138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 339138568Ssam "%s: no h/w resources for cipher %s, " 340138568Ssam "falling back to s/w\n", __func__, 341138568Ssam cip->ic_name); 342138568Ssam oflags = key->wk_flags; 343138568Ssam key->wk_flags |= IEEE80211_KEY_SWCRYPT; 344138568Ssam if (cipher == IEEE80211_CIPHER_TKIP) 345138568Ssam key->wk_flags |= IEEE80211_KEY_SWMIC; 346138568Ssam goto again; 347116742Ssam } 348138568Ssam ic->ic_stats.is_crypto_keyfail++; 349138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 350138568Ssam "%s: unable to setup cipher %s\n", 351138568Ssam __func__, cip->ic_name); 352138568Ssam return 0; 353116742Ssam } 354116742Ssam } 355138568Ssam return 1; 356138568Ssam#undef N 357138568Ssam} 358138568Ssam 359138568Ssam/* 360138568Ssam * Remove the key (no locking, for internal use). 361138568Ssam */ 362138568Ssamstatic int 363138568Ssam_ieee80211_crypto_delkey(struct ieee80211com *ic, struct ieee80211_key *key) 364138568Ssam{ 365138568Ssam u_int16_t keyix; 366138568Ssam 367138568Ssam KASSERT(key->wk_cipher != NULL, ("No cipher!")); 368138568Ssam 369139504Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 370139504Ssam "%s: %s keyix %u flags 0x%x rsc %ju tsc %ju len %u\n", 371139504Ssam __func__, key->wk_cipher->ic_name, 372139504Ssam key->wk_keyix, key->wk_flags, 373139504Ssam key->wk_keyrsc, key->wk_keytsc, key->wk_keylen); 374139504Ssam 375138568Ssam keyix = key->wk_keyix; 376138568Ssam if (keyix != IEEE80211_KEYIX_NONE) { 377138568Ssam /* 378138568Ssam * Remove hardware entry. 379138568Ssam */ 380138568Ssam /* XXX key cache */ 381138568Ssam if (!dev_key_delete(ic, key)) { 382138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 383138568Ssam "%s: driver did not delete key index %u\n", 384138568Ssam __func__, keyix); 385138568Ssam ic->ic_stats.is_crypto_delkey++; 386138568Ssam /* XXX recovery? */ 387116742Ssam } 388116742Ssam } 389138568Ssam cipher_detach(key); 390138568Ssam memset(key, 0, sizeof(*key)); 391138568Ssam key->wk_cipher = &ieee80211_cipher_none; 392138568Ssam key->wk_private = cipher_attach(ic, key); 393138568Ssam /* NB: cannot depend on key index to decide this */ 394138568Ssam if (&ic->ic_nw_keys[0] <= key && 395138568Ssam key < &ic->ic_nw_keys[IEEE80211_WEP_NKID]) 396138568Ssam key->wk_keyix = keyix; /* preserve shared key state */ 397138568Ssam else 398138568Ssam key->wk_keyix = IEEE80211_KEYIX_NONE; 399138568Ssam return 1; 400138568Ssam} 401116742Ssam 402138568Ssam/* 403138568Ssam * Remove the specified key. 404138568Ssam */ 405138568Ssamint 406138568Ssamieee80211_crypto_delkey(struct ieee80211com *ic, struct ieee80211_key *key) 407138568Ssam{ 408138568Ssam int status; 409138568Ssam 410138568Ssam ieee80211_key_update_begin(ic); 411138568Ssam status = _ieee80211_crypto_delkey(ic, key); 412138568Ssam ieee80211_key_update_end(ic); 413138568Ssam return status; 414116742Ssam} 415116742Ssam 416116742Ssam/* 417138568Ssam * Clear the global key table. 418116742Ssam */ 419138568Ssamvoid 420138568Ssamieee80211_crypto_delglobalkeys(struct ieee80211com *ic) 421138568Ssam{ 422138568Ssam int i; 423116742Ssam 424138568Ssam ieee80211_key_update_begin(ic); 425138568Ssam for (i = 0; i < IEEE80211_WEP_NKID; i++) 426138568Ssam (void) _ieee80211_crypto_delkey(ic, &ic->ic_nw_keys[i]); 427138568Ssam ieee80211_key_update_end(ic); 428138568Ssam} 429116742Ssam 430138568Ssam/* 431138568Ssam * Set the contents of the specified key. 432138568Ssam * 433138568Ssam * Locking must be handled by the caller using: 434138568Ssam * ieee80211_key_update_begin(ic); 435138568Ssam * ieee80211_key_update_end(ic); 436138568Ssam */ 437138568Ssamint 438138568Ssamieee80211_crypto_setkey(struct ieee80211com *ic, struct ieee80211_key *key, 439138568Ssam const u_int8_t macaddr[IEEE80211_ADDR_LEN]) 440116742Ssam{ 441138568Ssam const struct ieee80211_cipher *cip = key->wk_cipher; 442116742Ssam 443138568Ssam KASSERT(cip != NULL, ("No cipher!")); 444138568Ssam 445139504Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 446139504Ssam "%s: %s keyix %u flags 0x%x mac %s rsc %ju tsc %ju len %u\n", 447139504Ssam __func__, cip->ic_name, key->wk_keyix, 448139504Ssam key->wk_flags, ether_sprintf(macaddr), 449139504Ssam key->wk_keyrsc, key->wk_keytsc, key->wk_keylen); 450139504Ssam 451138568Ssam /* 452138568Ssam * Give cipher a chance to validate key contents. 453138568Ssam * XXX should happen before modifying state. 454138568Ssam */ 455138568Ssam if (!cip->ic_setkey(key)) { 456138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 457138568Ssam "%s: cipher %s rejected key index %u len %u flags 0x%x\n", 458138568Ssam __func__, cip->ic_name, key->wk_keyix, 459138568Ssam key->wk_keylen, key->wk_flags); 460138568Ssam ic->ic_stats.is_crypto_setkey_cipher++; 461138568Ssam return 0; 462138568Ssam } 463138568Ssam if (key->wk_keyix == IEEE80211_KEYIX_NONE) { 464138568Ssam /* XXX nothing allocated, should not happen */ 465138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 466138568Ssam "%s: no key index; should not happen!\n", __func__); 467138568Ssam ic->ic_stats.is_crypto_setkey_nokey++; 468138568Ssam return 0; 469138568Ssam } 470138568Ssam return dev_key_set(ic, key, macaddr); 471138568Ssam} 472138568Ssam 473138568Ssam/* 474138568Ssam * Add privacy headers appropriate for the specified key. 475138568Ssam */ 476138568Ssamstruct ieee80211_key * 477138568Ssamieee80211_crypto_encap(struct ieee80211com *ic, 478138568Ssam struct ieee80211_node *ni, struct mbuf *m) 479138568Ssam{ 480138568Ssam struct ieee80211_key *k; 481138568Ssam struct ieee80211_frame *wh; 482138568Ssam const struct ieee80211_cipher *cip; 483138568Ssam u_int8_t keyix; 484138568Ssam 485138568Ssam /* 486138568Ssam * Multicast traffic always uses the multicast key. 487138568Ssam * Otherwise if a unicast key is set we use that and 488138568Ssam * it is always key index 0. When no unicast key is 489138568Ssam * set we fall back to the default transmit key. 490138568Ssam */ 491138568Ssam wh = mtod(m, struct ieee80211_frame *); 492138568Ssam if (IEEE80211_IS_MULTICAST(wh->i_addr1) || 493138568Ssam ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) { 494138568Ssam if (ic->ic_def_txkey == IEEE80211_KEYIX_NONE) { 495138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 496139504Ssam "[%s] no default transmit key (%s) deftxkey %u\n", 497139504Ssam ether_sprintf(wh->i_addr1), __func__, 498139504Ssam ic->ic_def_txkey); 499138568Ssam ic->ic_stats.is_tx_nodefkey++; 500138568Ssam return NULL; 501116742Ssam } 502138568Ssam keyix = ic->ic_def_txkey; 503138568Ssam k = &ic->ic_nw_keys[ic->ic_def_txkey]; 504138568Ssam } else { 505138568Ssam keyix = 0; 506138568Ssam k = &ni->ni_ucastkey; 507116742Ssam } 508138568Ssam cip = k->wk_cipher; 509138568Ssam return (cip->ic_encap(k, m, keyix<<6) ? k : NULL); 510116742Ssam} 511116742Ssam 512116742Ssam/* 513138568Ssam * Validate and strip privacy headers (and trailer) for a 514138568Ssam * received frame that has the WEP/Privacy bit set. 515116742Ssam */ 516138568Ssamstruct ieee80211_key * 517138568Ssamieee80211_crypto_decap(struct ieee80211com *ic, 518138568Ssam struct ieee80211_node *ni, struct mbuf *m) 519116742Ssam{ 520138568Ssam#define IEEE80211_WEP_HDRLEN (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN) 521138568Ssam#define IEEE80211_WEP_MINLEN \ 522138568Ssam (sizeof(struct ieee80211_frame) + ETHER_HDR_LEN + \ 523138568Ssam IEEE80211_WEP_HDRLEN + IEEE80211_WEP_CRCLEN) 524138568Ssam struct ieee80211_key *k; 525138568Ssam struct ieee80211_frame *wh; 526138568Ssam const struct ieee80211_cipher *cip; 527139506Ssam const u_int8_t *ivp; 528138568Ssam u_int8_t keyid; 529138568Ssam int hdrlen; 530116742Ssam 531138568Ssam /* NB: this minimum size data frame could be bigger */ 532138568Ssam if (m->m_pkthdr.len < IEEE80211_WEP_MINLEN) { 533138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, 534138568Ssam "%s: WEP data frame too short, len %u\n", 535138568Ssam __func__, m->m_pkthdr.len); 536138568Ssam ic->ic_stats.is_rx_tooshort++; /* XXX need unique stat? */ 537138568Ssam return NULL; 538138568Ssam } 539138568Ssam 540138568Ssam /* 541138568Ssam * Locate the key. If unicast and there is no unicast 542138568Ssam * key then we fall back to the key id in the header. 543138568Ssam * This assumes unicast keys are only configured when 544138568Ssam * the key id in the header is meaningless (typically 0). 545138568Ssam */ 546138568Ssam wh = mtod(m, struct ieee80211_frame *); 547138568Ssam hdrlen = ieee80211_hdrsize(wh); 548139506Ssam ivp = mtod(m, const u_int8_t *) + hdrlen; /* XXX contig */ 549138568Ssam keyid = ivp[IEEE80211_WEP_IVLEN]; 550138568Ssam if (IEEE80211_IS_MULTICAST(wh->i_addr1) || 551138568Ssam ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) 552138568Ssam k = &ic->ic_nw_keys[keyid >> 6]; 553138568Ssam else 554138568Ssam k = &ni->ni_ucastkey; 555138568Ssam 556138568Ssam /* 557138568Ssam * Insure crypto header is contiguous for all decap work. 558138568Ssam */ 559138568Ssam cip = k->wk_cipher; 560138568Ssam if (m->m_len < hdrlen + cip->ic_header && 561138568Ssam (m = m_pullup(m, hdrlen + cip->ic_header)) == NULL) { 562138568Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 563138568Ssam "[%s] unable to pullup %s header\n", 564138568Ssam ether_sprintf(wh->i_addr2), cip->ic_name); 565138568Ssam ic->ic_stats.is_rx_wepfail++; /* XXX */ 566138568Ssam return 0; 567138568Ssam } 568138568Ssam 569138568Ssam return (cip->ic_decap(k, m) ? k : NULL); 570138568Ssam#undef IEEE80211_WEP_MINLEN 571138568Ssam#undef IEEE80211_WEP_HDRLEN 572116742Ssam} 573