Signed-off-by: David Kilroy <kilroyd@xxxxxxxxxxxxxx> --- drivers/net/wireless/orinoco/cfg.c | 196 ++++++++++++++++++++++++++++++++++++ 1 files changed, 196 insertions(+), 0 deletions(-) diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index 253cb4e..07775b6 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c @@ -493,6 +493,198 @@ static int orinoco_leave_ibss(struct wiphy *wiphy, struct net_device *dev) return err; } +static int orinoco_add_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_index, const u8 *mac_addr, + struct key_params *params) +{ + struct orinoco_private *priv = wiphy_priv(wiphy); + int err = 0; + unsigned long lock; + enum orinoco_alg alg = ORINOCO_ALG_NONE; + int key_len; + + if (key_index >= ORINOCO_MAX_KEYS) + return -EINVAL; + + if (orinoco_lock(priv, &lock) != 0) + return -EBUSY; + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + alg = ORINOCO_ALG_WEP; + + if (!priv->has_wep) + err = -EOPNOTSUPP; + + if (params->key_len > ORINOCO_MAX_KEY_SIZE) + err = -E2BIG; + else if (params->key_len > SMALL_KEY_SIZE) + key_len = LARGE_KEY_SIZE; + else if (params->key_len > 0) + key_len = SMALL_KEY_SIZE; + else + err = -EINVAL; + + break; + + case WLAN_CIPHER_SUITE_TKIP: + alg = ORINOCO_ALG_TKIP; + + if (!priv->has_wpa) + err = -EOPNOTSUPP; + else if (params->key_len < WLAN_KEY_LEN_TKIP) + err = -EINVAL; + + key_len = WLAN_KEY_LEN_TKIP; + break; + + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_AES_CMAC: + default: + err = -EOPNOTSUPP; + } + + if (err) + goto out; + + /* Ensure existing keys are of the same cipher suite */ + orinoco_set_encoding(priv, alg); + + err = orinoco_set_key(priv, key_index, alg, + params->key, params->key_len, + params->seq, params->seq_len); + if (err) + goto out; + + if (alg == ORINOCO_ALG_TKIP) { + /* If this is a pairwise key, assume it is the transmit key */ + int set_tx = 0; + if (mac_addr) { + priv->tx_key = key_index; + set_tx = 1; + } + err = __orinoco_hw_set_tkip_key(priv, key_index, set_tx, + priv->keys[key_index].key, + priv->keys[key_index].seq, + priv->keys[key_index].seq_len, + NULL, 0); + } + + err = __orinoco_hw_setup_enc(priv); + + out: + orinoco_unlock(priv, &lock); + + return err; +} + +static int orinoco_get_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_index, const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, struct key_params*)) +{ + struct orinoco_private *priv = wiphy_priv(wiphy); + struct key_params params; + u8 key[WLAN_KEY_LEN_TKIP]; + u8 tsc[ORINOCO_SEQ_LEN]; + unsigned long lock; + int err = 0; + + if (key_index >= ORINOCO_MAX_KEYS) + return -EINVAL; + + if (orinoco_lock(priv, &lock) != 0) + return -EBUSY; + + /* Take a copy of the key info */ + memcpy(&key, priv->keys[key_index].key, priv->keys[key_index].key_len); + + params.cipher = priv->keys[key_index].cipher; + params.key = &key[0]; + params.key_len = priv->keys[key_index].key_len; + + if (params.cipher == WLAN_CIPHER_SUITE_TKIP) { + /* Populate the current TSC */ + orinoco_hw_get_tkip_iv(priv, key_index, &tsc[0]); + params.seq = &tsc[0]; + params.seq_len = ORINOCO_SEQ_LEN; + } else { + params.seq = NULL; + params.seq_len = 0; + } + + orinoco_unlock(priv, &lock); + + callback(cookie, ¶ms); + + return err; +} + +static int orinoco_del_key(struct wiphy *wiphy, struct net_device *dev, + u8 key_index, const u8 *mac_addr) +{ + struct orinoco_private *priv = wiphy_priv(wiphy); + int err = 0; + unsigned long lock; + + if (key_index >= ORINOCO_MAX_KEYS) + return -EINVAL; + + if (orinoco_lock(priv, &lock) != 0) + return -EBUSY; + + kzfree(priv->keys[key_index].key); + kzfree(priv->keys[key_index].seq); + priv->keys[key_index].key = NULL; + priv->keys[key_index].seq = NULL; + priv->keys[key_index].key_len = 0; + priv->keys[key_index].seq_len = 0; + priv->keys[key_index].cipher = 0; + + if (priv->has_wpa && + priv->keys[key_index].cipher == WLAN_CIPHER_SUITE_TKIP) + err = orinoco_clear_tkip_key(priv, key_index); + + err = __orinoco_hw_setup_enc(priv); + + orinoco_unlock(priv, &lock); + + return err; +} + +static int orinoco_set_default_key(struct wiphy *wiphy, + struct net_device *netdev, + u8 key_index) +{ + struct orinoco_private *priv = wiphy_priv(wiphy); + int err = 0; + unsigned long lock; + + if (key_index >= ORINOCO_MAX_KEYS) + return -EINVAL; + + if (orinoco_lock(priv, &lock) != 0) + return -EBUSY; + + priv->tx_key = key_index; + + if (priv->has_wpa && + priv->keys[key_index].cipher == WLAN_CIPHER_SUITE_TKIP) + err = __orinoco_hw_set_tkip_key(priv, key_index, 1, + priv->keys[key_index].key, + priv->keys[key_index].seq, + priv->keys[key_index].seq_len, + NULL, 0); + else if (priv->encode_alg == ORINOCO_ALG_WEP) + err = __orinoco_hw_setup_wepkeys(priv); + else + err = -EINVAL; + + orinoco_unlock(priv, &lock); + + return err; +} + const struct cfg80211_ops orinoco_cfg_ops = { .change_virtual_intf = orinoco_change_vif, .set_channel = orinoco_set_channel, @@ -501,4 +693,8 @@ const struct cfg80211_ops orinoco_cfg_ops = { .disconnect = orinoco_disconnect, .join_ibss = orinoco_join_ibss, .leave_ibss = orinoco_leave_ibss, + .add_key = orinoco_add_key, + .get_key = orinoco_get_key, + .del_key = orinoco_del_key, + .set_default_key = orinoco_set_default_key, }; -- 1.6.3.3 -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html