Skip to content

Commit

Permalink
[MAC80211]: rework key handling
Browse files Browse the repository at this point in the history
This moves all the key handling code out from ieee80211_ioctl.c
into key.c and also does the following changes including documentation
updates in mac80211.h:

 1) Turn off hardware acceleration for keys when the interface
    is down. This is necessary because otherwise monitor
    interfaces could be decrypting frames for other interfaces
    that are down at the moment. Also, it should go some way
    towards better suspend/resume support, in any case the
    routines used here could be used for that as well.
    Additionally, this makes the driver interface nicer, keys
    for a specific local MAC address are only ever present
    while an interface with that MAC address is enabled.

 2) Change driver set_key() callback interface to allow only
    return values of -ENOSPC, -EOPNOTSUPP and 0, warn on all
    other return values. This allows debugging the stack when
    a driver notices it's handed a key while it is down.

 3) Invert the flag meaning to KEY_FLAG_UPLOADED_TO_HARDWARE.

 4) Remove REMOVE_ALL_KEYS command as it isn't used nor do we
    want to use it, we'll use DISABLE_KEY for each key. It is
    hard to use REMOVE_ALL_KEYS because we can handle multiple
    virtual interfaces with different key configuration, so we'd
    have to keep track of a lot of state for this and that isn't
    worth it.

 5) Warn when disabling a key fails, it musn't.

 6) Remove IEEE80211_HW_NO_TKIP_WMM_HWACCEL in favour of per-key
    IEEE80211_KEY_FLAG_WMM_STA to let driver sort it out itself.

 7) Tell driver that a (non-WEP) key is used only for transmission
    by using an all-zeroes station MAC address when configuring.

 8) Change the set_key() callback to have access to the local MAC
    address the key is being added for.

Signed-off-by: Johannes Berg <[email protected]>
Acked-by: Michael Wu <[email protected]>
Signed-off-by: John W. Linville <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
jmberg authored and David S. Miller committed Oct 10, 2007
1 parent 3aefaa3 commit 11a843b
Show file tree
Hide file tree
Showing 12 changed files with 366 additions and 229 deletions.
59 changes: 48 additions & 11 deletions include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -399,27 +399,42 @@ typedef enum {
ALG_CCMP,
} ieee80211_key_alg;

/*
* This flag indiciates that the station this key is being
* configured for may use QoS. If your hardware cannot handle
* that situation it should reject that key.
*/
#define IEEE80211_KEY_FLAG_WMM_STA (1<<0)

struct ieee80211_key_conf {
/* shall be changed by the driver to anything but HW_KEY_IDX_INVALID */
/*
* To be set by the driver to the key index it would like to
* get in the ieee80211_tx_control.key_idx which defaults
* to HW_KEY_IDX_INVALID so that shouldn't be used.
*/
int hw_key_idx;

/* key algorithm, ALG_NONE should never be seen by the driver */
ieee80211_key_alg alg;

int keylen;
/* key flags, see above */
u8 flags;

/* key index: 0-3 */
s8 keyidx;

#define IEEE80211_KEY_FORCE_SW_ENCRYPT (1<<0) /* to be cleared by low-level
driver */
u32 flags; /* key configuration flags defined above */
/* length of key material */
u8 keylen;

s8 keyidx; /* WEP key index */
/* the key material */
u8 key[0];
};

#define IEEE80211_SEQ_COUNTER_RX 0
#define IEEE80211_SEQ_COUNTER_TX 1

typedef enum {
SET_KEY, DISABLE_KEY, REMOVE_ALL_KEYS,
SET_KEY, DISABLE_KEY,
} set_key_cmd;

/* This is driver-visible part of the per-hw state the stack keeps. */
Expand Down Expand Up @@ -492,8 +507,7 @@ struct ieee80211_hw {

/* hole at 6 */

/* Force software encryption for TKIP packets if WMM is enabled. */
#define IEEE80211_HW_NO_TKIP_WMM_HWACCEL (1<<7)
/* hole at 7 */

/*
* Some devices handle Michael MIC internally and do not include MIC in
Expand Down Expand Up @@ -627,19 +641,42 @@ struct ieee80211_ops {
*
* This is called to enable hardware acceleration of encryption and
* decryption. The address will be the broadcast address for default
* keys and the other station's hardware address for individual keys.
* keys, the other station's hardware address for individual keys or
* the zero address for keys that will be used only for transmission.
*
* The local_address parameter will always be set to our own address,
* this is only relevant if you support multiple local addresses.
*
* When transmitting, the TX control data will use the hw_key_idx
* selected by the low-level driver.
*
* Return 0 if the key is now in use, -EOPNOTSUPP or -ENOSPC if it
* couldn't be added; if you return 0 then hw_key_idx must be
* assigned to something other than HW_KEY_IDX_INVALID. When the cmd
* is DISABLE_KEY then it must succeed.
*
* This callback can sleep, and is only called between add_interface
* and remove_interface calls, i.e. while the interface with the
* given local_address is enabled.
*
* The ieee80211_key_conf structure pointed to by the key parameter
* is guaranteed to be valid until another call to set_key removes
* it, but it can only be used as a cookie to differentiate keys.
*/
int (*set_key)(struct ieee80211_hw *hw, set_key_cmd cmd,
u8 *address, struct ieee80211_key_conf *key);
const u8 *local_address, const u8 *address,
struct ieee80211_key_conf *key);

/*
* Set TX key index for default/broadcast keys. This is needed in cases
* where wlan card is doing full WEP/TKIP encapsulation (wep_include_iv
* is not set), in other cases, this function pointer can be set to
* NULL since the IEEE 802.11 module takes care of selecting the key
* index for each TX frame.
*
* TODO: If you use this callback in your driver tell us if you need
* any other information from it to make it easier, like the
* key_conf instead.
*/
int (*set_key_idx)(struct ieee80211_hw *hw, int idx);

Expand Down
4 changes: 2 additions & 2 deletions net/mac80211/debugfs_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ static ssize_t key_##name##_read(struct file *file, \
return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
}
#define KEY_READ_D(name) KEY_READ(name, name, 20, "%d\n")
#define KEY_READ_X(name) KEY_READ(name, name, 20, "0x%x\n")

#define KEY_OPS(name) \
static const struct file_operations key_ ##name## _ops = { \
Expand All @@ -39,7 +40,6 @@ static const struct file_operations key_ ##name## _ops = { \
#define KEY_CONF_READ(name, buflen, format_string) \
KEY_READ(conf_##name, conf.name, buflen, format_string)
#define KEY_CONF_READ_D(name) KEY_CONF_READ(name, 20, "%d\n")
#define KEY_CONF_READ_X(name) KEY_CONF_READ(name, 20, "0x%x\n")

#define KEY_CONF_OPS(name) \
static const struct file_operations key_ ##name## _ops = { \
Expand All @@ -54,7 +54,7 @@ static const struct file_operations key_ ##name## _ops = { \
KEY_CONF_FILE(keylen, D);
KEY_CONF_FILE(keyidx, D);
KEY_CONF_FILE(hw_key_idx, D);
KEY_CONF_FILE(flags, X);
KEY_FILE(flags, X);
KEY_FILE(tx_rx_count, D);

static ssize_t key_algorithm_read(struct file *file,
Expand Down
6 changes: 5 additions & 1 deletion net/mac80211/ieee80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ static int ieee80211_open(struct net_device *dev)
} else {
ieee80211_if_config(dev);
ieee80211_reset_erp_info(dev);
ieee80211_enable_keys(sdata);
}

if (sdata->type == IEEE80211_IF_TYPE_STA &&
Expand Down Expand Up @@ -510,6 +511,9 @@ static int ieee80211_stop(struct net_device *dev)
local->monitors--;
if (!local->monitors)
local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
} else {
/* disable all keys for as long as this netdev is down */
ieee80211_disable_keys(sdata);
}

local->open_count--;
Expand Down Expand Up @@ -908,7 +912,7 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
}

if (skb->len >= mic_len &&
(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT))
!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
skb_trim(skb, skb->len - mic_len);
if (skb->len >= iv_len && skb->len > hdrlen) {
memmove(skb->data + iv_len, skb->data, hdrlen);
Expand Down
8 changes: 3 additions & 5 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,9 @@ struct ieee80211_sub_if_data {

struct wireless_dev wdev;

/* keys */
struct list_head key_list;

struct net_device *dev;
struct ieee80211_local *local;

Expand Down Expand Up @@ -810,11 +813,6 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev);

/* key handling */
struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
int idx, size_t key_len, gfp_t flags);
void ieee80211_key_free(struct ieee80211_key *key);

/* utility functions/constants */
extern void *mac80211_wiphy_privid; /* for wiphy privid */
extern const unsigned char rfc1042_header[6];
Expand Down
21 changes: 5 additions & 16 deletions net/mac80211/ieee80211_iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
sdata->eapol = 1;
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
skb_queue_head_init(&sdata->fragments[i].skb_list);

INIT_LIST_HEAD(&sdata->key_list);
}

static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata)
Expand Down Expand Up @@ -210,25 +212,12 @@ void ieee80211_if_reinit(struct net_device *dev)
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sta_info *sta;
int i;

ASSERT_RTNL();

ieee80211_free_keys(sdata);

ieee80211_if_sdata_deinit(sdata);
for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
if (!sdata->keys[i])
continue;
#if 0
/* The interface is down at the moment, so there is not
* really much point in disabling the keys at this point. */
memset(addr, 0xff, ETH_ALEN);
if (local->ops->set_key)
local->ops->set_key(local_to_hw(local), DISABLE_KEY, addr,
local->keys[i],
local->default_wep_only);
#endif
ieee80211_key_free(sdata->keys[i]);
sdata->keys[i] = NULL;
}

switch (sdata->type) {
case IEEE80211_IF_TYPE_AP: {
Expand Down
Loading

0 comments on commit 11a843b

Please sign in to comment.