linux/net/mac80211/key.c
<<
>>
Prefs
   1/*
   2 * Copyright 2002-2005, Instant802 Networks, Inc.
   3 * Copyright 2005-2006, Devicescape Software, Inc.
   4 * Copyright 2006-2007  Jiri Benc <jbenc@suse.cz>
   5 * Copyright 2007-2008  Johannes Berg <johannes@sipsolutions.net>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11
  12#include <linux/if_ether.h>
  13#include <linux/etherdevice.h>
  14#include <linux/list.h>
  15#include <linux/rcupdate.h>
  16#include <linux/rtnetlink.h>
  17#include <linux/slab.h>
  18#include <linux/export.h>
  19#include <net/mac80211.h>
  20#include <asm/unaligned.h>
  21#include "ieee80211_i.h"
  22#include "driver-ops.h"
  23#include "debugfs_key.h"
  24#include "aes_ccm.h"
  25#include "aes_cmac.h"
  26
  27
  28/**
  29 * DOC: Key handling basics
  30 *
  31 * Key handling in mac80211 is done based on per-interface (sub_if_data)
  32 * keys and per-station keys. Since each station belongs to an interface,
  33 * each station key also belongs to that interface.
  34 *
  35 * Hardware acceleration is done on a best-effort basis for algorithms
  36 * that are implemented in software,  for each key the hardware is asked
  37 * to enable that key for offloading but if it cannot do that the key is
  38 * simply kept for software encryption (unless it is for an algorithm
  39 * that isn't implemented in software).
  40 * There is currently no way of knowing whether a key is handled in SW
  41 * or HW except by looking into debugfs.
  42 *
  43 * All key management is internally protected by a mutex. Within all
  44 * other parts of mac80211, key references are, just as STA structure
  45 * references, protected by RCU. Note, however, that some things are
  46 * unprotected, namely the key->sta dereferences within the hardware
  47 * acceleration functions. This means that sta_info_destroy() must
  48 * remove the key which waits for an RCU grace period.
  49 */
  50
  51static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  52
  53static void assert_key_lock(struct ieee80211_local *local)
  54{
  55        lockdep_assert_held(&local->key_mtx);
  56}
  57
  58static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
  59{
  60        /*
  61         * When this count is zero, SKB resizing for allocating tailroom
  62         * for IV or MMIC is skipped. But, this check has created two race
  63         * cases in xmit path while transiting from zero count to one:
  64         *
  65         * 1. SKB resize was skipped because no key was added but just before
  66         * the xmit key is added and SW encryption kicks off.
  67         *
  68         * 2. SKB resize was skipped because all the keys were hw planted but
  69         * just before xmit one of the key is deleted and SW encryption kicks
  70         * off.
  71         *
  72         * In both the above case SW encryption will find not enough space for
  73         * tailroom and exits with WARN_ON. (See WARN_ONs at wpa.c)
  74         *
  75         * Solution has been explained at
  76         * http://mid.gmane.org/1308590980.4322.19.camel@jlt3.sipsolutions.net
  77         */
  78
  79        if (!sdata->crypto_tx_tailroom_needed_cnt++) {
  80                /*
  81                 * Flush all XMIT packets currently using HW encryption or no
  82                 * encryption at all if the count transition is from 0 -> 1.
  83                 */
  84                synchronize_net();
  85        }
  86}
  87
  88static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
  89{
  90        struct ieee80211_sub_if_data *sdata;
  91        struct sta_info *sta;
  92        int ret;
  93
  94        might_sleep();
  95
  96        if (!key->local->ops->set_key)
  97                goto out_unsupported;
  98
  99        assert_key_lock(key->local);
 100
 101        sta = key->sta;
 102
 103        /*
 104         * If this is a per-STA GTK, check if it
 105         * is supported; if not, return.
 106         */
 107        if (sta && !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE) &&
 108            !(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK))
 109                goto out_unsupported;
 110
 111        if (sta && !sta->uploaded)
 112                goto out_unsupported;
 113
 114        sdata = key->sdata;
 115        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
 116                /*
 117                 * The driver doesn't know anything about VLAN interfaces.
 118                 * Hence, don't send GTKs for VLAN interfaces to the driver.
 119                 */
 120                if (!(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE))
 121                        goto out_unsupported;
 122        }
 123
 124        ret = drv_set_key(key->local, SET_KEY, sdata,
 125                          sta ? &sta->sta : NULL, &key->conf);
 126
 127        if (!ret) {
 128                key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
 129
 130                if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
 131                      (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
 132                      (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
 133                        sdata->crypto_tx_tailroom_needed_cnt--;
 134
 135                WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
 136                        (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV));
 137
 138                return 0;
 139        }
 140
 141        if (ret != -ENOSPC && ret != -EOPNOTSUPP)
 142                sdata_err(sdata,
 143                          "failed to set key (%d, %pM) to hardware (%d)\n",
 144                          key->conf.keyidx,
 145                          sta ? sta->sta.addr : bcast_addr, ret);
 146
 147 out_unsupported:
 148        switch (key->conf.cipher) {
 149        case WLAN_CIPHER_SUITE_WEP40:
 150        case WLAN_CIPHER_SUITE_WEP104:
 151        case WLAN_CIPHER_SUITE_TKIP:
 152        case WLAN_CIPHER_SUITE_CCMP:
 153        case WLAN_CIPHER_SUITE_AES_CMAC:
 154                /* all of these we can do in software */
 155                return 0;
 156        default:
 157                return -EINVAL;
 158        }
 159}
 160
 161static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
 162{
 163        struct ieee80211_sub_if_data *sdata;
 164        struct sta_info *sta;
 165        int ret;
 166
 167        might_sleep();
 168
 169        if (!key || !key->local->ops->set_key)
 170                return;
 171
 172        assert_key_lock(key->local);
 173
 174        if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
 175                return;
 176
 177        sta = key->sta;
 178        sdata = key->sdata;
 179
 180        if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
 181              (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
 182              (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
 183                increment_tailroom_need_count(sdata);
 184
 185        ret = drv_set_key(key->local, DISABLE_KEY, sdata,
 186                          sta ? &sta->sta : NULL, &key->conf);
 187
 188        if (ret)
 189                sdata_err(sdata,
 190                          "failed to remove key (%d, %pM) from hardware (%d)\n",
 191                          key->conf.keyidx,
 192                          sta ? sta->sta.addr : bcast_addr, ret);
 193
 194        key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
 195}
 196
 197static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
 198                                        int idx, bool uni, bool multi)
 199{
 200        struct ieee80211_key *key = NULL;
 201
 202        assert_key_lock(sdata->local);
 203
 204        if (idx >= 0 && idx < NUM_DEFAULT_KEYS)
 205                key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
 206
 207        if (uni)
 208                rcu_assign_pointer(sdata->default_unicast_key, key);
 209        if (multi)
 210                rcu_assign_pointer(sdata->default_multicast_key, key);
 211
 212        ieee80211_debugfs_key_update_default(sdata);
 213}
 214
 215void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
 216                               bool uni, bool multi)
 217{
 218        mutex_lock(&sdata->local->key_mtx);
 219        __ieee80211_set_default_key(sdata, idx, uni, multi);
 220        mutex_unlock(&sdata->local->key_mtx);
 221}
 222
 223static void
 224__ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx)
 225{
 226        struct ieee80211_key *key = NULL;
 227
 228        assert_key_lock(sdata->local);
 229
 230        if (idx >= NUM_DEFAULT_KEYS &&
 231            idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
 232                key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
 233
 234        rcu_assign_pointer(sdata->default_mgmt_key, key);
 235
 236        ieee80211_debugfs_key_update_default(sdata);
 237}
 238
 239void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
 240                                    int idx)
 241{
 242        mutex_lock(&sdata->local->key_mtx);
 243        __ieee80211_set_default_mgmt_key(sdata, idx);
 244        mutex_unlock(&sdata->local->key_mtx);
 245}
 246
 247
 248static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
 249                                    struct sta_info *sta,
 250                                    bool pairwise,
 251                                    struct ieee80211_key *old,
 252                                    struct ieee80211_key *new)
 253{
 254        int idx;
 255        bool defunikey, defmultikey, defmgmtkey;
 256
 257        if (new)
 258                list_add_tail(&new->list, &sdata->key_list);
 259
 260        if (sta && pairwise) {
 261                rcu_assign_pointer(sta->ptk, new);
 262        } else if (sta) {
 263                if (old)
 264                        idx = old->conf.keyidx;
 265                else
 266                        idx = new->conf.keyidx;
 267                rcu_assign_pointer(sta->gtk[idx], new);
 268        } else {
 269                WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
 270
 271                if (old)
 272                        idx = old->conf.keyidx;
 273                else
 274                        idx = new->conf.keyidx;
 275
 276                defunikey = old &&
 277                        old == key_mtx_dereference(sdata->local,
 278                                                sdata->default_unicast_key);
 279                defmultikey = old &&
 280                        old == key_mtx_dereference(sdata->local,
 281                                                sdata->default_multicast_key);
 282                defmgmtkey = old &&
 283                        old == key_mtx_dereference(sdata->local,
 284                                                sdata->default_mgmt_key);
 285
 286                if (defunikey && !new)
 287                        __ieee80211_set_default_key(sdata, -1, true, false);
 288                if (defmultikey && !new)
 289                        __ieee80211_set_default_key(sdata, -1, false, true);
 290                if (defmgmtkey && !new)
 291                        __ieee80211_set_default_mgmt_key(sdata, -1);
 292
 293                rcu_assign_pointer(sdata->keys[idx], new);
 294                if (defunikey && new)
 295                        __ieee80211_set_default_key(sdata, new->conf.keyidx,
 296                                                    true, false);
 297                if (defmultikey && new)
 298                        __ieee80211_set_default_key(sdata, new->conf.keyidx,
 299                                                    false, true);
 300                if (defmgmtkey && new)
 301                        __ieee80211_set_default_mgmt_key(sdata,
 302                                                         new->conf.keyidx);
 303        }
 304
 305        if (old)
 306                list_del(&old->list);
 307}
 308
 309struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
 310                                          const u8 *key_data,
 311                                          size_t seq_len, const u8 *seq)
 312{
 313        struct ieee80211_key *key;
 314        int i, j, err;
 315
 316        BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS);
 317
 318        key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL);
 319        if (!key)
 320                return ERR_PTR(-ENOMEM);
 321
 322        /*
 323         * Default to software encryption; we'll later upload the
 324         * key to the hardware if possible.
 325         */
 326        key->conf.flags = 0;
 327        key->flags = 0;
 328
 329        key->conf.cipher = cipher;
 330        key->conf.keyidx = idx;
 331        key->conf.keylen = key_len;
 332        switch (cipher) {
 333        case WLAN_CIPHER_SUITE_WEP40:
 334        case WLAN_CIPHER_SUITE_WEP104:
 335                key->conf.iv_len = WEP_IV_LEN;
 336                key->conf.icv_len = WEP_ICV_LEN;
 337                break;
 338        case WLAN_CIPHER_SUITE_TKIP:
 339                key->conf.iv_len = TKIP_IV_LEN;
 340                key->conf.icv_len = TKIP_ICV_LEN;
 341                if (seq) {
 342                        for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
 343                                key->u.tkip.rx[i].iv32 =
 344                                        get_unaligned_le32(&seq[2]);
 345                                key->u.tkip.rx[i].iv16 =
 346                                        get_unaligned_le16(seq);
 347                        }
 348                }
 349                spin_lock_init(&key->u.tkip.txlock);
 350                break;
 351        case WLAN_CIPHER_SUITE_CCMP:
 352                key->conf.iv_len = CCMP_HDR_LEN;
 353                key->conf.icv_len = CCMP_MIC_LEN;
 354                if (seq) {
 355                        for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++)
 356                                for (j = 0; j < CCMP_PN_LEN; j++)
 357                                        key->u.ccmp.rx_pn[i][j] =
 358                                                seq[CCMP_PN_LEN - j - 1];
 359                }
 360                /*
 361                 * Initialize AES key state here as an optimization so that
 362                 * it does not need to be initialized for every packet.
 363                 */
 364                key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data);
 365                if (IS_ERR(key->u.ccmp.tfm)) {
 366                        err = PTR_ERR(key->u.ccmp.tfm);
 367                        kfree(key);
 368                        return ERR_PTR(err);
 369                }
 370                break;
 371        case WLAN_CIPHER_SUITE_AES_CMAC:
 372                key->conf.iv_len = 0;
 373                key->conf.icv_len = sizeof(struct ieee80211_mmie);
 374                if (seq)
 375                        for (j = 0; j < 6; j++)
 376                                key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1];
 377                /*
 378                 * Initialize AES key state here as an optimization so that
 379                 * it does not need to be initialized for every packet.
 380                 */
 381                key->u.aes_cmac.tfm =
 382                        ieee80211_aes_cmac_key_setup(key_data);
 383                if (IS_ERR(key->u.aes_cmac.tfm)) {
 384                        err = PTR_ERR(key->u.aes_cmac.tfm);
 385                        kfree(key);
 386                        return ERR_PTR(err);
 387                }
 388                break;
 389        }
 390        memcpy(key->conf.key, key_data, key_len);
 391        INIT_LIST_HEAD(&key->list);
 392
 393        return key;
 394}
 395
 396static void __ieee80211_key_destroy(struct ieee80211_key *key)
 397{
 398        if (!key)
 399                return;
 400
 401        /*
 402         * Synchronize so the TX path can no longer be using
 403         * this key before we free/remove it.
 404         */
 405        synchronize_net();
 406
 407        if (key->local)
 408                ieee80211_key_disable_hw_accel(key);
 409
 410        if (key->conf.cipher == WLAN_CIPHER_SUITE_CCMP)
 411                ieee80211_aes_key_free(key->u.ccmp.tfm);
 412        if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
 413                ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
 414        if (key->local) {
 415                ieee80211_debugfs_key_remove(key);
 416                key->sdata->crypto_tx_tailroom_needed_cnt--;
 417        }
 418
 419        kfree(key);
 420}
 421
 422int ieee80211_key_link(struct ieee80211_key *key,
 423                       struct ieee80211_sub_if_data *sdata,
 424                       struct sta_info *sta)
 425{
 426        struct ieee80211_key *old_key;
 427        int idx, ret;
 428        bool pairwise;
 429
 430        BUG_ON(!sdata);
 431        BUG_ON(!key);
 432
 433        pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
 434        idx = key->conf.keyidx;
 435        key->local = sdata->local;
 436        key->sdata = sdata;
 437        key->sta = sta;
 438
 439        if (sta) {
 440                /*
 441                 * some hardware cannot handle TKIP with QoS, so
 442                 * we indicate whether QoS could be in use.
 443                 */
 444                if (test_sta_flag(sta, WLAN_STA_WME))
 445                        key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
 446        } else {
 447                if (sdata->vif.type == NL80211_IFTYPE_STATION) {
 448                        struct sta_info *ap;
 449
 450                        /*
 451                         * We're getting a sta pointer in, so must be under
 452                         * appropriate locking for sta_info_get().
 453                         */
 454
 455                        /* same here, the AP could be using QoS */
 456                        ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid);
 457                        if (ap) {
 458                                if (test_sta_flag(ap, WLAN_STA_WME))
 459                                        key->conf.flags |=
 460                                                IEEE80211_KEY_FLAG_WMM_STA;
 461                        }
 462                }
 463        }
 464
 465        mutex_lock(&sdata->local->key_mtx);
 466
 467        if (sta && pairwise)
 468                old_key = key_mtx_dereference(sdata->local, sta->ptk);
 469        else if (sta)
 470                old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]);
 471        else
 472                old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
 473
 474        increment_tailroom_need_count(sdata);
 475
 476        __ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
 477        __ieee80211_key_destroy(old_key);
 478
 479        ieee80211_debugfs_key_add(key);
 480
 481        ret = ieee80211_key_enable_hw_accel(key);
 482
 483        mutex_unlock(&sdata->local->key_mtx);
 484
 485        return ret;
 486}
 487
 488void __ieee80211_key_free(struct ieee80211_key *key)
 489{
 490        if (!key)
 491                return;
 492
 493        /*
 494         * Replace key with nothingness if it was ever used.
 495         */
 496        if (key->sdata)
 497                __ieee80211_key_replace(key->sdata, key->sta,
 498                                key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
 499                                key, NULL);
 500        __ieee80211_key_destroy(key);
 501}
 502
 503void ieee80211_key_free(struct ieee80211_local *local,
 504                        struct ieee80211_key *key)
 505{
 506        mutex_lock(&local->key_mtx);
 507        __ieee80211_key_free(key);
 508        mutex_unlock(&local->key_mtx);
 509}
 510
 511void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
 512{
 513        struct ieee80211_key *key;
 514
 515        ASSERT_RTNL();
 516
 517        if (WARN_ON(!ieee80211_sdata_running(sdata)))
 518                return;
 519
 520        mutex_lock(&sdata->local->key_mtx);
 521
 522        sdata->crypto_tx_tailroom_needed_cnt = 0;
 523
 524        list_for_each_entry(key, &sdata->key_list, list) {
 525                increment_tailroom_need_count(sdata);
 526                ieee80211_key_enable_hw_accel(key);
 527        }
 528
 529        mutex_unlock(&sdata->local->key_mtx);
 530}
 531
 532void ieee80211_iter_keys(struct ieee80211_hw *hw,
 533                         struct ieee80211_vif *vif,
 534                         void (*iter)(struct ieee80211_hw *hw,
 535                                      struct ieee80211_vif *vif,
 536                                      struct ieee80211_sta *sta,
 537                                      struct ieee80211_key_conf *key,
 538                                      void *data),
 539                         void *iter_data)
 540{
 541        struct ieee80211_local *local = hw_to_local(hw);
 542        struct ieee80211_key *key;
 543        struct ieee80211_sub_if_data *sdata;
 544
 545        ASSERT_RTNL();
 546
 547        mutex_lock(&local->key_mtx);
 548        if (vif) {
 549                sdata = vif_to_sdata(vif);
 550                list_for_each_entry(key, &sdata->key_list, list)
 551                        iter(hw, &sdata->vif,
 552                             key->sta ? &key->sta->sta : NULL,
 553                             &key->conf, iter_data);
 554        } else {
 555                list_for_each_entry(sdata, &local->interfaces, list)
 556                        list_for_each_entry(key, &sdata->key_list, list)
 557                                iter(hw, &sdata->vif,
 558                                     key->sta ? &key->sta->sta : NULL,
 559                                     &key->conf, iter_data);
 560        }
 561        mutex_unlock(&local->key_mtx);
 562}
 563EXPORT_SYMBOL(ieee80211_iter_keys);
 564
 565void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
 566{
 567        struct ieee80211_key *key;
 568
 569        ASSERT_RTNL();
 570
 571        mutex_lock(&sdata->local->key_mtx);
 572
 573        list_for_each_entry(key, &sdata->key_list, list)
 574                ieee80211_key_disable_hw_accel(key);
 575
 576        mutex_unlock(&sdata->local->key_mtx);
 577}
 578
 579void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
 580{
 581        struct ieee80211_key *key, *tmp;
 582
 583        mutex_lock(&sdata->local->key_mtx);
 584
 585        ieee80211_debugfs_key_remove_mgmt_default(sdata);
 586
 587        list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
 588                __ieee80211_key_free(key);
 589
 590        ieee80211_debugfs_key_update_default(sdata);
 591
 592        mutex_unlock(&sdata->local->key_mtx);
 593}
 594
 595
 596void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
 597                                const u8 *replay_ctr, gfp_t gfp)
 598{
 599        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 600
 601        trace_api_gtk_rekey_notify(sdata, bssid, replay_ctr);
 602
 603        cfg80211_gtk_rekey_notify(sdata->dev, bssid, replay_ctr, gfp);
 604}
 605EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_notify);
 606
 607void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
 608                              struct ieee80211_key_seq *seq)
 609{
 610        struct ieee80211_key *key;
 611        u64 pn64;
 612
 613        if (WARN_ON(!(keyconf->flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
 614                return;
 615
 616        key = container_of(keyconf, struct ieee80211_key, conf);
 617
 618        switch (key->conf.cipher) {
 619        case WLAN_CIPHER_SUITE_TKIP:
 620                seq->tkip.iv32 = key->u.tkip.tx.iv32;
 621                seq->tkip.iv16 = key->u.tkip.tx.iv16;
 622                break;
 623        case WLAN_CIPHER_SUITE_CCMP:
 624                pn64 = atomic64_read(&key->u.ccmp.tx_pn);
 625                seq->ccmp.pn[5] = pn64;
 626                seq->ccmp.pn[4] = pn64 >> 8;
 627                seq->ccmp.pn[3] = pn64 >> 16;
 628                seq->ccmp.pn[2] = pn64 >> 24;
 629                seq->ccmp.pn[1] = pn64 >> 32;
 630                seq->ccmp.pn[0] = pn64 >> 40;
 631                break;
 632        case WLAN_CIPHER_SUITE_AES_CMAC:
 633                pn64 = atomic64_read(&key->u.aes_cmac.tx_pn);
 634                seq->ccmp.pn[5] = pn64;
 635                seq->ccmp.pn[4] = pn64 >> 8;
 636                seq->ccmp.pn[3] = pn64 >> 16;
 637                seq->ccmp.pn[2] = pn64 >> 24;
 638                seq->ccmp.pn[1] = pn64 >> 32;
 639                seq->ccmp.pn[0] = pn64 >> 40;
 640                break;
 641        default:
 642                WARN_ON(1);
 643        }
 644}
 645EXPORT_SYMBOL(ieee80211_get_key_tx_seq);
 646
 647void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
 648                              int tid, struct ieee80211_key_seq *seq)
 649{
 650        struct ieee80211_key *key;
 651        const u8 *pn;
 652
 653        key = container_of(keyconf, struct ieee80211_key, conf);
 654
 655        switch (key->conf.cipher) {
 656        case WLAN_CIPHER_SUITE_TKIP:
 657                if (WARN_ON(tid < 0 || tid >= NUM_RX_DATA_QUEUES))
 658                        return;
 659                seq->tkip.iv32 = key->u.tkip.rx[tid].iv32;
 660                seq->tkip.iv16 = key->u.tkip.rx[tid].iv16;
 661                break;
 662        case WLAN_CIPHER_SUITE_CCMP:
 663                if (WARN_ON(tid < -1 || tid >= NUM_RX_DATA_QUEUES))
 664                        return;
 665                if (tid < 0)
 666                        pn = key->u.ccmp.rx_pn[NUM_RX_DATA_QUEUES];
 667                else
 668                        pn = key->u.ccmp.rx_pn[tid];
 669                memcpy(seq->ccmp.pn, pn, CCMP_PN_LEN);
 670                break;
 671        case WLAN_CIPHER_SUITE_AES_CMAC:
 672                if (WARN_ON(tid != 0))
 673                        return;
 674                pn = key->u.aes_cmac.rx_pn;
 675                memcpy(seq->aes_cmac.pn, pn, CMAC_PN_LEN);
 676                break;
 677        }
 678}
 679EXPORT_SYMBOL(ieee80211_get_key_rx_seq);
 680
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.