aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/p54
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@web.de>2008-11-29 16:34:37 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-12-05 09:35:43 -0500
commit25900ef0191af98bbb24d8088c6887af31c1ba27 (patch)
treeed054c65ad207c5e9cb12215964dcb200b7e4b84 /drivers/net/wireless/p54
parentc772a08ba7192fa5450f85ef53adcbc6e0c5e1c9 (diff)
p54: utilize cryptographic accelerator
This patch allows p54 to utilize its WEP, TKIP and CCMP accelerator. Tested-by: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: Christian Lamparter <chunkeey@web.de> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/p54')
-rw-r--r--drivers/net/wireless/p54/p54.h2
-rw-r--r--drivers/net/wireless/p54/p54common.c179
2 files changed, 168 insertions, 13 deletions
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index 491ab96c7b67..ebe1ea1f565b 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -115,6 +115,8 @@ struct p54_common {
115 int noise; 115 int noise;
116 void *eeprom; 116 void *eeprom;
117 struct completion eeprom_comp; 117 struct completion eeprom_comp;
118 u8 privacy_caps;
119 u8 rx_keycache_size;
118}; 120};
119 121
120int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); 122int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index de92b58d4508..6f7e82b56cbe 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -25,6 +25,9 @@
25#include "p54.h" 25#include "p54.h"
26#include "p54common.h" 26#include "p54common.h"
27 27
28static int modparam_nohwcrypt;
29module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
30MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
28MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>"); 31MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
29MODULE_DESCRIPTION("Softmac Prism54 common code"); 32MODULE_DESCRIPTION("Softmac Prism54 common code");
30MODULE_LICENSE("GPL"); 33MODULE_LICENSE("GPL");
@@ -185,6 +188,8 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
185 priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500; 188 priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
186 priv->headroom = desc->headroom; 189 priv->headroom = desc->headroom;
187 priv->tailroom = desc->tailroom; 190 priv->tailroom = desc->tailroom;
191 priv->privacy_caps = desc->privacy_caps;
192 priv->rx_keycache_size = desc->rx_keycache_size;
188 if (le32_to_cpu(bootrec->len) == 11) 193 if (le32_to_cpu(bootrec->len) == 11)
189 priv->rx_mtu = le16_to_cpu(desc->rx_mtu); 194 priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
190 else 195 else
@@ -228,6 +233,16 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
228 dev->queues = 4; 233 dev->queues = 4;
229 } 234 }
230 235
236 if (!modparam_nohwcrypt)
237 printk(KERN_INFO "%s: cryptographic accelerator "
238 "WEP:%s, TKIP:%s, CCMP:%s\n",
239 wiphy_name(dev->wiphy),
240 (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" :
241 "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP |
242 BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no",
243 (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
244 "YES" : "no");
245
231 return 0; 246 return 0;
232} 247}
233EXPORT_SYMBOL_GPL(p54_parse_firmware); 248EXPORT_SYMBOL_GPL(p54_parse_firmware);
@@ -526,6 +541,12 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
526 return 0; 541 return 0;
527 } 542 }
528 543
544 if (hdr->decrypt_status == P54_DECRYPT_OK)
545 rx_status.flag |= RX_FLAG_DECRYPTED;
546 if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
547 (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
548 rx_status.flag |= RX_FLAG_MMIC_ERROR;
549
529 rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi); 550 rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi);
530 rx_status.noise = priv->noise; 551 rx_status.noise = priv->noise;
531 /* XX correct? */ 552 /* XX correct? */
@@ -1107,6 +1128,20 @@ static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb,
1107 return ret; 1128 return ret;
1108} 1129}
1109 1130
1131static u8 p54_convert_algo(enum ieee80211_key_alg alg)
1132{
1133 switch (alg) {
1134 case ALG_WEP:
1135 return P54_CRYPTO_WEP;
1136 case ALG_TKIP:
1137 return P54_CRYPTO_TKIPMICHAEL;
1138 case ALG_CCMP:
1139 return P54_CRYPTO_AESCCMP;
1140 default:
1141 return 0;
1142 }
1143}
1144
1110static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) 1145static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
1111{ 1146{
1112 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 1147 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1117,7 +1152,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
1117 size_t padding, len, tim_len = 0; 1152 size_t padding, len, tim_len = 0;
1118 int i, j, ridx, ret; 1153 int i, j, ridx, ret;
1119 u16 hdr_flags = 0, aid = 0; 1154 u16 hdr_flags = 0, aid = 0;
1120 u8 rate, queue; 1155 u8 rate, queue, crypt_offset = 0;
1121 u8 cts_rate = 0x20; 1156 u8 cts_rate = 0x20;
1122 u8 rc_flags; 1157 u8 rc_flags;
1123 u8 calculated_tries[4]; 1158 u8 calculated_tries[4];
@@ -1137,12 +1172,25 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
1137 padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; 1172 padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
1138 len = skb->len; 1173 len = skb->len;
1139 1174
1175 if (info->control.hw_key) {
1176 crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
1177 if (info->control.hw_key->alg == ALG_TKIP) {
1178 u8 *iv = (u8 *)(skb->data + crypt_offset);
1179 /*
1180 * The firmware excepts that the IV has to have
1181 * this special format
1182 */
1183 iv[1] = iv[0];
1184 iv[0] = iv[2];
1185 iv[2] = 0;
1186 }
1187 }
1188
1140 txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); 1189 txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
1141 hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); 1190 hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
1142 1191
1143 if (padding) 1192 if (padding)
1144 hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; 1193 hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
1145 hdr->len = cpu_to_le16(len);
1146 hdr->type = cpu_to_le16(aid); 1194 hdr->type = cpu_to_le16(aid);
1147 hdr->rts_tries = info->control.rates[0].count; 1195 hdr->rts_tries = info->control.rates[0].count;
1148 1196
@@ -1217,10 +1265,27 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
1217 /* TODO: enable bursting */ 1265 /* TODO: enable bursting */
1218 hdr->flags = cpu_to_le16(hdr_flags); 1266 hdr->flags = cpu_to_le16(hdr_flags);
1219 hdr->tries = ridx; 1267 hdr->tries = ridx;
1220 txhdr->crypt_offset = 0;
1221 txhdr->rts_rate_idx = 0; 1268 txhdr->rts_rate_idx = 0;
1222 txhdr->key_type = 0; 1269 if (info->control.hw_key) {
1223 txhdr->key_len = 0; 1270 crypt_offset += info->control.hw_key->iv_len;
1271 txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
1272 txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
1273 memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
1274 if (info->control.hw_key->alg == ALG_TKIP) {
1275 if (unlikely(skb_tailroom(skb) < 12))
1276 goto err;
1277 /* reserve space for the MIC key */
1278 len += 8;
1279 memcpy(skb_put(skb, 8), &(info->control.hw_key->key
1280 [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8);
1281 }
1282 /* reserve some space for ICV */
1283 len += info->control.hw_key->icv_len;
1284 } else {
1285 txhdr->key_type = 0;
1286 txhdr->key_len = 0;
1287 }
1288 txhdr->crypt_offset = crypt_offset;
1224 txhdr->hw_queue = queue; 1289 txhdr->hw_queue = queue;
1225 if (current_queue) 1290 if (current_queue)
1226 txhdr->backlog = current_queue->len; 1291 txhdr->backlog = current_queue->len;
@@ -1234,17 +1299,20 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
1234 if (padding) 1299 if (padding)
1235 txhdr->align[0] = padding; 1300 txhdr->align[0] = padding;
1236 1301
1302 hdr->len = cpu_to_le16(len);
1237 /* modifies skb->cb and with it info, so must be last! */ 1303 /* modifies skb->cb and with it info, so must be last! */
1238 if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) { 1304 if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len)))
1239 skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding); 1305 goto err;
1240 if (current_queue) {
1241 current_queue->len--;
1242 current_queue->count--;
1243 }
1244 return NETDEV_TX_BUSY;
1245 }
1246 priv->tx(dev, skb, 0); 1306 priv->tx(dev, skb, 0);
1247 return 0; 1307 return 0;
1308
1309 err:
1310 skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding);
1311 if (current_queue) {
1312 current_queue->len--;
1313 current_queue->count--;
1314 }
1315 return NETDEV_TX_BUSY;
1248} 1316}
1249 1317
1250static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid) 1318static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid)
@@ -1848,6 +1916,90 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev,
1848 1916
1849} 1917}
1850 1918
1919static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
1920 const u8 *local_address, const u8 *address,
1921 struct ieee80211_key_conf *key)
1922{
1923 struct p54_common *priv = dev->priv;
1924 struct sk_buff *skb;
1925 struct p54_keycache *rxkey;
1926 u8 algo = 0;
1927
1928 if (modparam_nohwcrypt)
1929 return -EOPNOTSUPP;
1930
1931 if (cmd == DISABLE_KEY)
1932 algo = 0;
1933 else {
1934 switch (key->alg) {
1935 case ALG_TKIP:
1936 if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
1937 BR_DESC_PRIV_CAP_TKIP)))
1938 return -EOPNOTSUPP;
1939 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
1940 algo = P54_CRYPTO_TKIPMICHAEL;
1941 break;
1942 case ALG_WEP:
1943 if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP))
1944 return -EOPNOTSUPP;
1945 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
1946 algo = P54_CRYPTO_WEP;
1947 break;
1948 case ALG_CCMP:
1949 if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP))
1950 return -EOPNOTSUPP;
1951 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
1952 algo = P54_CRYPTO_AESCCMP;
1953 break;
1954 default:
1955 return -EINVAL;
1956 }
1957 }
1958
1959 if (key->keyidx > priv->rx_keycache_size) {
1960 /*
1961 * The device supports the choosen algorithm, but the firmware
1962 * does not provide enough key slots to store all of them.
1963 * So, incoming frames have to be decoded by the mac80211 stack,
1964 * but we can still offload encryption for outgoing frames.
1965 */
1966
1967 return 0;
1968 }
1969
1970 mutex_lock(&priv->conf_mutex);
1971 skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey) +
1972 sizeof(struct p54_hdr), P54_CONTROL_TYPE_RX_KEYCACHE,
1973 GFP_ATOMIC);
1974 if (!skb) {
1975 mutex_unlock(&priv->conf_mutex);
1976 return -ENOMEM;
1977 }
1978
1979 /* TODO: some devices have 4 more free slots for rx keys */
1980 rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
1981 rxkey->entry = key->keyidx;
1982 rxkey->key_id = key->keyidx;
1983 rxkey->key_type = algo;
1984 if (address)
1985 memcpy(rxkey->mac, address, ETH_ALEN);
1986 else
1987 memset(rxkey->mac, ~0, ETH_ALEN);
1988 if (key->alg != ALG_TKIP) {
1989 rxkey->key_len = min((u8)16, key->keylen);
1990 memcpy(rxkey->key, key->key, rxkey->key_len);
1991 } else {
1992 rxkey->key_len = 24;
1993 memcpy(rxkey->key, key->key, 16);
1994 memcpy(&(rxkey->key[16]), &(key->key
1995 [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
1996 }
1997
1998 priv->tx(dev, skb, 1);
1999 mutex_unlock(&priv->conf_mutex);
2000 return 0;
2001}
2002
1851static const struct ieee80211_ops p54_ops = { 2003static const struct ieee80211_ops p54_ops = {
1852 .tx = p54_tx, 2004 .tx = p54_tx,
1853 .start = p54_start, 2005 .start = p54_start,
@@ -1857,6 +2009,7 @@ static const struct ieee80211_ops p54_ops = {
1857 .set_tim = p54_set_tim, 2009 .set_tim = p54_set_tim,
1858 .sta_notify_ps = p54_sta_notify_ps, 2010 .sta_notify_ps = p54_sta_notify_ps,
1859 .sta_notify = p54_sta_notify, 2011 .sta_notify = p54_sta_notify,
2012 .set_key = p54_set_key,
1860 .config = p54_config, 2013 .config = p54_config,
1861 .config_interface = p54_config_interface, 2014 .config_interface = p54_config_interface,
1862 .bss_info_changed = p54_bss_info_changed, 2015 .bss_info_changed = p54_bss_info_changed,