From patchwork Wed Aug 5 20:32:51 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave X-Patchwork-Id: 39441 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n75KXFRX008699 for ; Wed, 5 Aug 2009 20:33:15 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752642AbZHEUdN (ORCPT ); Wed, 5 Aug 2009 16:33:13 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752629AbZHEUdM (ORCPT ); Wed, 5 Aug 2009 16:33:12 -0400 Received: from mail-ew0-f214.google.com ([209.85.219.214]:35125 "EHLO mail-ew0-f214.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752641AbZHEUdL (ORCPT ); Wed, 5 Aug 2009 16:33:11 -0400 Received: by mail-ew0-f214.google.com with SMTP id 10so291644ewy.37 for ; Wed, 05 Aug 2009 13:33:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=gamma; h=domainkey-signature:received:received:received:from:to:cc:subject :date:message-id:x-mailer:in-reply-to:references; bh=2x+Zr4kKObe658w7zQN2fBPVkihEzZtcLw/HkPLGW+s=; b=nSWzxUjfxiu1nvTtVgc/CpFuSCLqP0fgGYEfMNXlTtuK9Cw3QUg/IfhLkn2/mnyb4b JXE/Njj0QuvW84m4zIhjhMTX/zQpLhmIr5mVjfD36RaUsCwtQKZCsinqIbnivIdsPp9U IogYRN28TJE2iMzo+js6PyrBoFAQyC0iWMKqs= DomainKey-Signature: a=rsa-sha1; c=nofws; d=googlemail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=ww2ZQBSQPnRF82CMyUnglURIHKMkLoPUFLnpnhq6oqtGp8s9foyeyUR0Wp68wcn3Xs fyGbQw2ndk2YHyvNkiIHeDl86oT6Fy8mvjjblOekqVJYLXYmr7mlb/nlvLYb1LU8GupL nDHy5Ew6zKXM6ak1QgpPIFYIeVJ9NZORvPArg= Received: by 10.210.51.10 with SMTP id y10mr8689258eby.4.1249504392005; Wed, 05 Aug 2009 13:33:12 -0700 (PDT) Received: from borken (5ac998cf.bb.sky.com [90.201.152.207]) by mx.google.com with ESMTPS id 7sm1431371eyb.0.2009.08.05.13.33.10 (version=TLSv1/SSLv3 cipher=RC4-MD5); Wed, 05 Aug 2009 13:33:11 -0700 (PDT) Received: by borken (sSMTP sendmail emulation); Wed, 05 Aug 2009 21:33:08 +0100 From: David Kilroy To: linux-wireless@vger.kernel.org Cc: orinoco-devel@lists.sourceforge.net, David Kilroy Subject: [RFC 3/4] orinoco: implement cfg80211 key manipulation functions Date: Wed, 5 Aug 2009 21:32:51 +0100 Message-Id: <1249504372-17063-4-git-send-email-kilroyd@googlemail.com> X-Mailer: git-send-email 1.6.3.3 In-Reply-To: <1249504372-17063-1-git-send-email-kilroyd@googlemail.com> References: <1249504372-17063-1-git-send-email-kilroyd@googlemail.com> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org Signed-off-by: David Kilroy --- drivers/net/wireless/orinoco/cfg.c | 199 ++++++++++++++++++++++++++++++++++++ 1 files changed, 199 insertions(+), 0 deletions(-) diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index 84a7884..9ed690e 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c @@ -439,6 +439,201 @@ 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) { + /* We don't know if this is the tx key yet. + * We'll reprogram it when we find out. */ + err = __orinoco_hw_set_tkip_key(priv, key_index, 0, + priv->keys[key_index].key, + priv->keys[key_index].seq, + priv->keys[key_index].seq_len, + NULL, 0); + + priv->wpa_enabled = 1; + } + + 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); + + /* HACK */ + if (key_index == priv->tx_key) + priv->wpa_enabled = 0; + } + + 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, .scan = orinoco_scan, @@ -446,4 +641,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, };