Commit 27b3eb9c06a7193bdc9800cd00764a130343bc8a

Authored by Johannes Berg
1 parent d51b70ff51

mac80211: add APIs to allow keeping connections after WoWLAN

In order to be able to (securely) keep connections alive after
the system was suspended for WoWLAN, we need some additional
APIs. We already have API (ieee80211_gtk_rekey_notify) to tell
wpa_supplicant about the new replay counter if GTK rekeying
was done by the device while the host was asleep, but that's
not sufficient.

If GTK rekeying wasn't done, we need to tell the host about
sequence counters for the GTK (and PTK regardless of rekeying)
that was used while asleep, add ieee80211_set_key_rx_seq() for
that.

If GTK rekeying was done, then we need to be able to disable
the old keys (with ieee80211_remove_key()) and allocate the
new GTK key(s) in mac80211 (with ieee80211_gtk_rekey_add()).

If protocol offload (e.g. ARP) is implemented, then also the
TX sequence counter for the PTK must be updated, using the new
ieee80211_set_key_tx_seq() function.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>

Showing 3 changed files with 231 additions and 8 deletions Side-by-side Diff

include/net/mac80211.h
... ... @@ -3688,6 +3688,89 @@
3688 3688 int tid, struct ieee80211_key_seq *seq);
3689 3689  
3690 3690 /**
  3691 + * ieee80211_set_key_tx_seq - set key TX sequence counter
  3692 + *
  3693 + * @keyconf: the parameter passed with the set key
  3694 + * @seq: new sequence data
  3695 + *
  3696 + * This function allows a driver to set the current TX IV/PNs for the
  3697 + * given key. This is useful when resuming from WoWLAN sleep and the
  3698 + * device may have transmitted frames using the PTK, e.g. replies to
  3699 + * ARP requests.
  3700 + *
  3701 + * Note that this function may only be called when no TX processing
  3702 + * can be done concurrently.
  3703 + */
  3704 +void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf,
  3705 + struct ieee80211_key_seq *seq);
  3706 +
  3707 +/**
  3708 + * ieee80211_set_key_rx_seq - set key RX sequence counter
  3709 + *
  3710 + * @keyconf: the parameter passed with the set key
  3711 + * @tid: The TID, or -1 for the management frame value (CCMP only);
  3712 + * the value on TID 0 is also used for non-QoS frames. For
  3713 + * CMAC, only TID 0 is valid.
  3714 + * @seq: new sequence data
  3715 + *
  3716 + * This function allows a driver to set the current RX IV/PNs for the
  3717 + * given key. This is useful when resuming from WoWLAN sleep and GTK
  3718 + * rekey may have been done while suspended. It should not be called
  3719 + * if IV checking is done by the device and not by mac80211.
  3720 + *
  3721 + * Note that this function may only be called when no RX processing
  3722 + * can be done concurrently.
  3723 + */
  3724 +void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,
  3725 + int tid, struct ieee80211_key_seq *seq);
  3726 +
  3727 +/**
  3728 + * ieee80211_remove_key - remove the given key
  3729 + * @keyconf: the parameter passed with the set key
  3730 + *
  3731 + * Remove the given key. If the key was uploaded to the hardware at the
  3732 + * time this function is called, it is not deleted in the hardware but
  3733 + * instead assumed to have been removed already.
  3734 + *
  3735 + * Note that due to locking considerations this function can (currently)
  3736 + * only be called during key iteration (ieee80211_iter_keys().)
  3737 + */
  3738 +void ieee80211_remove_key(struct ieee80211_key_conf *keyconf);
  3739 +
  3740 +/**
  3741 + * ieee80211_gtk_rekey_add - add a GTK key from rekeying during WoWLAN
  3742 + * @vif: the virtual interface to add the key on
  3743 + * @keyconf: new key data
  3744 + *
  3745 + * When GTK rekeying was done while the system was suspended, (a) new
  3746 + * key(s) will be available. These will be needed by mac80211 for proper
  3747 + * RX processing, so this function allows setting them.
  3748 + *
  3749 + * The function returns the newly allocated key structure, which will
  3750 + * have similar contents to the passed key configuration but point to
  3751 + * mac80211-owned memory. In case of errors, the function returns an
  3752 + * ERR_PTR(), use IS_ERR() etc.
  3753 + *
  3754 + * Note that this function assumes the key isn't added to hardware
  3755 + * acceleration, so no TX will be done with the key. Since it's a GTK
  3756 + * on managed (station) networks, this is true anyway. If the driver
  3757 + * calls this function from the resume callback and subsequently uses
  3758 + * the return code 1 to reconfigure the device, this key will be part
  3759 + * of the reconfiguration.
  3760 + *
  3761 + * Note that the driver should also call ieee80211_set_key_rx_seq()
  3762 + * for the new key for each TID to set up sequence counters properly.
  3763 + *
  3764 + * IMPORTANT: If this replaces a key that is present in the hardware,
  3765 + * then it will attempt to remove it during this call. In many cases
  3766 + * this isn't what you want, so call ieee80211_remove_key() first for
  3767 + * the key that's being replaced.
  3768 + */
  3769 +struct ieee80211_key_conf *
  3770 +ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
  3771 + struct ieee80211_key_conf *keyconf);
  3772 +
  3773 +/**
3691 3774 * ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying
3692 3775 * @vif: virtual interface the rekeying was done on
3693 3776 * @bssid: The BSSID of the AP, for checking association
... ... @@ -93,6 +93,9 @@
93 93  
94 94 might_sleep();
95 95  
  96 + if (key->flags & KEY_FLAG_TAINTED)
  97 + return -EINVAL;
  98 +
96 99 if (!key->local->ops->set_key)
97 100 goto out_unsupported;
98 101  
... ... @@ -455,6 +458,7 @@
455 458 struct ieee80211_sub_if_data *sdata,
456 459 struct sta_info *sta)
457 460 {
  461 + struct ieee80211_local *local = sdata->local;
458 462 struct ieee80211_key *old_key;
459 463 int idx, ret;
460 464 bool pairwise;
461 465  
... ... @@ -484,11 +488,14 @@
484 488  
485 489 ieee80211_debugfs_key_add(key);
486 490  
487   - ret = ieee80211_key_enable_hw_accel(key);
  491 + if (!local->wowlan) {
  492 + ret = ieee80211_key_enable_hw_accel(key);
  493 + if (ret)
  494 + ieee80211_key_free(key, true);
  495 + } else {
  496 + ret = 0;
  497 + }
488 498  
489   - if (ret)
490   - ieee80211_key_free(key, true);
491   -
492 499 mutex_unlock(&sdata->local->key_mtx);
493 500  
494 501 return ret;
... ... @@ -540,7 +547,7 @@
540 547 void *iter_data)
541 548 {
542 549 struct ieee80211_local *local = hw_to_local(hw);
543   - struct ieee80211_key *key;
  550 + struct ieee80211_key *key, *tmp;
544 551 struct ieee80211_sub_if_data *sdata;
545 552  
546 553 ASSERT_RTNL();
547 554  
... ... @@ -548,13 +555,14 @@
548 555 mutex_lock(&local->key_mtx);
549 556 if (vif) {
550 557 sdata = vif_to_sdata(vif);
551   - list_for_each_entry(key, &sdata->key_list, list)
  558 + list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
552 559 iter(hw, &sdata->vif,
553 560 key->sta ? &key->sta->sta : NULL,
554 561 &key->conf, iter_data);
555 562 } else {
556 563 list_for_each_entry(sdata, &local->interfaces, list)
557   - list_for_each_entry(key, &sdata->key_list, list)
  564 + list_for_each_entry_safe(key, tmp,
  565 + &sdata->key_list, list)
558 566 iter(hw, &sdata->vif,
559 567 key->sta ? &key->sta->sta : NULL,
560 568 &key->conf, iter_data);
... ... @@ -751,4 +759,136 @@
751 759 }
752 760 }
753 761 EXPORT_SYMBOL(ieee80211_get_key_rx_seq);
  762 +
  763 +void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf,
  764 + struct ieee80211_key_seq *seq)
  765 +{
  766 + struct ieee80211_key *key;
  767 + u64 pn64;
  768 +
  769 + key = container_of(keyconf, struct ieee80211_key, conf);
  770 +
  771 + switch (key->conf.cipher) {
  772 + case WLAN_CIPHER_SUITE_TKIP:
  773 + key->u.tkip.tx.iv32 = seq->tkip.iv32;
  774 + key->u.tkip.tx.iv16 = seq->tkip.iv16;
  775 + break;
  776 + case WLAN_CIPHER_SUITE_CCMP:
  777 + pn64 = (u64)seq->ccmp.pn[5] |
  778 + ((u64)seq->ccmp.pn[4] << 8) |
  779 + ((u64)seq->ccmp.pn[3] << 16) |
  780 + ((u64)seq->ccmp.pn[2] << 24) |
  781 + ((u64)seq->ccmp.pn[1] << 32) |
  782 + ((u64)seq->ccmp.pn[0] << 40);
  783 + atomic64_set(&key->u.ccmp.tx_pn, pn64);
  784 + break;
  785 + case WLAN_CIPHER_SUITE_AES_CMAC:
  786 + pn64 = (u64)seq->aes_cmac.pn[5] |
  787 + ((u64)seq->aes_cmac.pn[4] << 8) |
  788 + ((u64)seq->aes_cmac.pn[3] << 16) |
  789 + ((u64)seq->aes_cmac.pn[2] << 24) |
  790 + ((u64)seq->aes_cmac.pn[1] << 32) |
  791 + ((u64)seq->aes_cmac.pn[0] << 40);
  792 + atomic64_set(&key->u.aes_cmac.tx_pn, pn64);
  793 + break;
  794 + default:
  795 + WARN_ON(1);
  796 + break;
  797 + }
  798 +}
  799 +EXPORT_SYMBOL_GPL(ieee80211_set_key_tx_seq);
  800 +
  801 +void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,
  802 + int tid, struct ieee80211_key_seq *seq)
  803 +{
  804 + struct ieee80211_key *key;
  805 + u8 *pn;
  806 +
  807 + key = container_of(keyconf, struct ieee80211_key, conf);
  808 +
  809 + switch (key->conf.cipher) {
  810 + case WLAN_CIPHER_SUITE_TKIP:
  811 + if (WARN_ON(tid < 0 || tid >= IEEE80211_NUM_TIDS))
  812 + return;
  813 + key->u.tkip.rx[tid].iv32 = seq->tkip.iv32;
  814 + key->u.tkip.rx[tid].iv16 = seq->tkip.iv16;
  815 + break;
  816 + case WLAN_CIPHER_SUITE_CCMP:
  817 + if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS))
  818 + return;
  819 + if (tid < 0)
  820 + pn = key->u.ccmp.rx_pn[IEEE80211_NUM_TIDS];
  821 + else
  822 + pn = key->u.ccmp.rx_pn[tid];
  823 + memcpy(pn, seq->ccmp.pn, IEEE80211_CCMP_PN_LEN);
  824 + break;
  825 + case WLAN_CIPHER_SUITE_AES_CMAC:
  826 + if (WARN_ON(tid != 0))
  827 + return;
  828 + pn = key->u.aes_cmac.rx_pn;
  829 + memcpy(pn, seq->aes_cmac.pn, IEEE80211_CMAC_PN_LEN);
  830 + break;
  831 + default:
  832 + WARN_ON(1);
  833 + break;
  834 + }
  835 +}
  836 +EXPORT_SYMBOL_GPL(ieee80211_set_key_rx_seq);
  837 +
  838 +void ieee80211_remove_key(struct ieee80211_key_conf *keyconf)
  839 +{
  840 + struct ieee80211_key *key;
  841 +
  842 + key = container_of(keyconf, struct ieee80211_key, conf);
  843 +
  844 + assert_key_lock(key->local);
  845 +
  846 + /*
  847 + * if key was uploaded, we assume the driver will/has remove(d)
  848 + * it, so adjust bookkeeping accordingly
  849 + */
  850 + if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
  851 + key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
  852 +
  853 + if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
  854 + (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
  855 + (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
  856 + increment_tailroom_need_count(key->sdata);
  857 + }
  858 +
  859 + ieee80211_key_free(key, false);
  860 +}
  861 +EXPORT_SYMBOL_GPL(ieee80211_remove_key);
  862 +
  863 +struct ieee80211_key_conf *
  864 +ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
  865 + struct ieee80211_key_conf *keyconf)
  866 +{
  867 + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
  868 + struct ieee80211_local *local = sdata->local;
  869 + struct ieee80211_key *key;
  870 + int err;
  871 +
  872 + if (WARN_ON(!local->wowlan))
  873 + return ERR_PTR(-EINVAL);
  874 +
  875 + if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
  876 + return ERR_PTR(-EINVAL);
  877 +
  878 + key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx,
  879 + keyconf->keylen, keyconf->key,
  880 + 0, NULL);
  881 + if (IS_ERR(key))
  882 + return ERR_PTR(PTR_ERR(key));
  883 +
  884 + if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED)
  885 + key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;
  886 +
  887 + err = ieee80211_key_link(key, sdata, NULL);
  888 + if (err)
  889 + return ERR_PTR(err);
  890 +
  891 + return &key->conf;
  892 +}
  893 +EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_add);
... ... @@ -1453,8 +1453,8 @@
1453 1453 local->resuming = true;
1454 1454  
1455 1455 if (local->wowlan) {
1456   - local->wowlan = false;
1457 1456 res = drv_resume(local);
  1457 + local->wowlan = false;
1458 1458 if (res < 0) {
1459 1459 local->resuming = false;
1460 1460 return res;