mac80211: support separate default keys
Johannes Berg [Thu, 9 Dec 2010 18:49:02 +0000 (19:49 +0100)]
Add support for split default keys (unicast
and multicast) in mac80211.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

net/mac80211/cfg.c
net/mac80211/debugfs_key.c
net/mac80211/debugfs_key.h
net/mac80211/ieee80211_i.h
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/main.c
net/mac80211/tx.c

index 12f7dc0..ea06f92 100644 (file)
@@ -300,7 +300,7 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       ieee80211_set_default_key(sdata, key_idx);
+       ieee80211_set_default_key(sdata, key_idx, uni, multi);
 
        return 0;
 }
index 5822a6c..f7ef347 100644 (file)
@@ -274,7 +274,8 @@ void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
        debugfs_remove_recursive(key->debugfs.dir);
        key->debugfs.dir = NULL;
 }
-void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata)
+
+void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
 {
        char buf[50];
        struct ieee80211_key *key;
@@ -282,25 +283,29 @@ void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata)
        if (!sdata->debugfs.dir)
                return;
 
-       /* this is running under the key lock */
+       lockdep_assert_held(&sdata->local->key_mtx);
 
-       key = sdata->default_key;
-       if (key) {
+       if (sdata->default_unicast_key) {
+               key = sdata->default_unicast_key;
                sprintf(buf, "../keys/%d", key->debugfs.cnt);
-               sdata->debugfs.default_key =
-                       debugfs_create_symlink("default_key",
+               sdata->debugfs.default_unicast_key =
+                       debugfs_create_symlink("default_unicast_key",
                                               sdata->debugfs.dir, buf);
-       } else
-               ieee80211_debugfs_key_remove_default(sdata);
-}
-
-void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata)
-{
-       if (!sdata)
-               return;
+       } else {
+               debugfs_remove(sdata->debugfs.default_unicast_key);
+               sdata->debugfs.default_unicast_key = NULL;
+       }
 
-       debugfs_remove(sdata->debugfs.default_key);
-       sdata->debugfs.default_key = NULL;
+       if (sdata->default_multicast_key) {
+               key = sdata->default_multicast_key;
+               sprintf(buf, "../keys/%d", key->debugfs.cnt);
+               sdata->debugfs.default_multicast_key =
+                       debugfs_create_symlink("default_multicast_key",
+                                              sdata->debugfs.dir, buf);
+       } else {
+               debugfs_remove(sdata->debugfs.default_multicast_key);
+               sdata->debugfs.default_multicast_key = NULL;
+       }
 }
 
 void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata)
index 54717b4..32adc77 100644 (file)
@@ -4,8 +4,7 @@
 #ifdef CONFIG_MAC80211_DEBUGFS
 void ieee80211_debugfs_key_add(struct ieee80211_key *key);
 void ieee80211_debugfs_key_remove(struct ieee80211_key *key);
-void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata);
-void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata);
+void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata);
 void ieee80211_debugfs_key_add_mgmt_default(
        struct ieee80211_sub_if_data *sdata);
 void ieee80211_debugfs_key_remove_mgmt_default(
@@ -17,10 +16,7 @@ static inline void ieee80211_debugfs_key_add(struct ieee80211_key *key)
 {}
 static inline void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
 {}
-static inline void ieee80211_debugfs_key_add_default(
-       struct ieee80211_sub_if_data *sdata)
-{}
-static inline void ieee80211_debugfs_key_remove_default(
+static inline void ieee80211_debugfs_key_update_default(
        struct ieee80211_sub_if_data *sdata)
 {}
 static inline void ieee80211_debugfs_key_add_mgmt_default(
index 72499fe..ce58b2a 100644 (file)
@@ -557,7 +557,7 @@ struct ieee80211_sub_if_data {
        unsigned int fragment_next;
 
        struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
-       struct ieee80211_key *default_key;
+       struct ieee80211_key *default_unicast_key, *default_multicast_key;
        struct ieee80211_key *default_mgmt_key;
 
        u16 sequence_number;
@@ -595,7 +595,8 @@ struct ieee80211_sub_if_data {
        struct {
                struct dentry *dir;
                struct dentry *subdir_stations;
-               struct dentry *default_key;
+               struct dentry *default_unicast_key;
+               struct dentry *default_multicast_key;
                struct dentry *default_mgmt_key;
        } debugfs;
 #endif
index 72df1ca..84cf919 100644 (file)
@@ -178,7 +178,7 @@ void ieee80211_key_removed(struct ieee80211_key_conf *key_conf)
 EXPORT_SYMBOL_GPL(ieee80211_key_removed);
 
 static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
-                                       int idx)
+                                       int idx, bool uni, bool multi)
 {
        struct ieee80211_key *key = NULL;
 
@@ -187,18 +187,19 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
        if (idx >= 0 && idx < NUM_DEFAULT_KEYS)
                key = sdata->keys[idx];
 
-       rcu_assign_pointer(sdata->default_key, key);
+       if (uni)
+               rcu_assign_pointer(sdata->default_unicast_key, key);
+       if (multi)
+               rcu_assign_pointer(sdata->default_multicast_key, key);
 
-       if (key) {
-               ieee80211_debugfs_key_remove_default(key->sdata);
-               ieee80211_debugfs_key_add_default(key->sdata);
-       }
+       ieee80211_debugfs_key_update_default(sdata);
 }
 
-void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx)
+void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
+                              bool uni, bool multi)
 {
        mutex_lock(&sdata->local->key_mtx);
-       __ieee80211_set_default_key(sdata, idx);
+       __ieee80211_set_default_key(sdata, idx, uni, multi);
        mutex_unlock(&sdata->local->key_mtx);
 }
 
@@ -215,10 +216,7 @@ __ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx)
 
        rcu_assign_pointer(sdata->default_mgmt_key, key);
 
-       if (key) {
-               ieee80211_debugfs_key_remove_mgmt_default(key->sdata);
-               ieee80211_debugfs_key_add_mgmt_default(key->sdata);
-       }
+       ieee80211_debugfs_key_update_default(sdata);
 }
 
 void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
@@ -236,7 +234,8 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_key *old,
                                    struct ieee80211_key *new)
 {
-       int idx, defkey, defmgmtkey;
+       int idx;
+       bool defunikey, defmultikey, defmgmtkey;
 
        if (new)
                list_add(&new->list, &sdata->key_list);
@@ -257,17 +256,24 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
                else
                        idx = new->conf.keyidx;
 
-               defkey = old && sdata->default_key == old;
+               defunikey = old && sdata->default_unicast_key == old;
+               defmultikey = old && sdata->default_multicast_key == old;
                defmgmtkey = old && sdata->default_mgmt_key == old;
 
-               if (defkey && !new)
-                       __ieee80211_set_default_key(sdata, -1);
+               if (defunikey && !new)
+                       __ieee80211_set_default_key(sdata, -1, true, false);
+               if (defmultikey && !new)
+                       __ieee80211_set_default_key(sdata, -1, false, true);
                if (defmgmtkey && !new)
                        __ieee80211_set_default_mgmt_key(sdata, -1);
 
                rcu_assign_pointer(sdata->keys[idx], new);
-               if (defkey && new)
-                       __ieee80211_set_default_key(sdata, new->conf.keyidx);
+               if (defunikey && new)
+                       __ieee80211_set_default_key(sdata, new->conf.keyidx,
+                                                   true, false);
+               if (defmultikey && new)
+                       __ieee80211_set_default_key(sdata, new->conf.keyidx,
+                                                   false, true);
                if (defmgmtkey && new)
                        __ieee80211_set_default_mgmt_key(sdata,
                                                         new->conf.keyidx);
@@ -509,11 +515,12 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
 
        mutex_lock(&sdata->local->key_mtx);
 
-       ieee80211_debugfs_key_remove_default(sdata);
        ieee80211_debugfs_key_remove_mgmt_default(sdata);
 
        list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
                __ieee80211_key_free(key);
 
+       ieee80211_debugfs_key_update_default(sdata);
+
        mutex_unlock(&sdata->local->key_mtx);
 }
index 0db1c0f..8106aa1 100644 (file)
@@ -138,7 +138,8 @@ int __must_check ieee80211_key_link(struct ieee80211_key *key,
                                    struct sta_info *sta);
 void ieee80211_key_free(struct ieee80211_local *local,
                        struct ieee80211_key *key);
-void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx);
+void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
+                              bool uni, bool multi);
 void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
                                    int idx);
 void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
index 973fee9..ae656b6 100644 (file)
@@ -519,7 +519,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        wiphy->flags |= WIPHY_FLAG_NETNS_OK |
                        WIPHY_FLAG_4ADDR_AP |
-                       WIPHY_FLAG_4ADDR_STATION;
+                       WIPHY_FLAG_4ADDR_STATION |
+                       WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS;
        wiphy->privid = mac80211_wiphy_privid;
 
        wiphy->bss_priv_size = sizeof(struct ieee80211_bss);
index 0ee56bb..157bde9 100644 (file)
@@ -539,7 +539,11 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                 ieee80211_is_robust_mgmt_frame(hdr) &&
                 (key = rcu_dereference(tx->sdata->default_mgmt_key)))
                tx->key = key;
-       else if ((key = rcu_dereference(tx->sdata->default_key)))
+       else if (is_multicast_ether_addr(hdr->addr1) &&
+                (key = rcu_dereference(tx->sdata->default_multicast_key)))
+               tx->key = key;
+       else if (!is_multicast_ether_addr(hdr->addr1) &&
+                (key = rcu_dereference(tx->sdata->default_unicast_key)))
                tx->key = key;
        else if (tx->sdata->drop_unencrypted &&
                 (tx->skb->protocol != tx->sdata->control_port_protocol) &&