|
@@ -422,6 +422,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
|
|
|
* TODO: When WPA is added this is one place that needs to change */
|
|
|
sec.flags |= SEC_LEVEL;
|
|
|
sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
|
|
|
+ sec.encode_alg[key] = SEC_ALG_WEP;
|
|
|
|
|
|
done:
|
|
|
if (ieee->set_security)
|
|
@@ -469,14 +470,6 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- if (sec->level != SEC_LEVEL_1) {
|
|
|
- /* only WEP is supported with wireless extensions, so just
|
|
|
- * report that encryption is used */
|
|
|
- erq->length = 0;
|
|
|
- erq->flags |= IW_ENCODE_ENABLED;
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
len = sec->key_sizes[key];
|
|
|
memcpy(keybuf, sec->keys[key], len);
|
|
|
|
|
@@ -491,6 +484,235 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#if WIRELESS_EXT > 17
|
|
|
+int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
|
|
|
+ struct iw_request_info *info,
|
|
|
+ union iwreq_data *wrqu, char *extra)
|
|
|
+{
|
|
|
+ struct net_device *dev = ieee->dev;
|
|
|
+ struct iw_point *encoding = &wrqu->encoding;
|
|
|
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
|
|
|
+ int i, idx, ret = 0;
|
|
|
+ const char *alg, *module;
|
|
|
+ struct ieee80211_crypto_ops *ops;
|
|
|
+ struct ieee80211_crypt_data **crypt;
|
|
|
+
|
|
|
+ struct ieee80211_security sec = {
|
|
|
+ .flags = 0,
|
|
|
+ };
|
|
|
+
|
|
|
+ idx = encoding->flags & IW_ENCODE_INDEX;
|
|
|
+ if (idx) {
|
|
|
+ if (idx < 1 || idx > WEP_KEYS)
|
|
|
+ return -EINVAL;
|
|
|
+ idx--;
|
|
|
+ } else
|
|
|
+ idx = ieee->tx_keyidx;
|
|
|
+
|
|
|
+ if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
|
|
|
+ crypt = &ieee->crypt[idx];
|
|
|
+ else {
|
|
|
+ if (idx != 0)
|
|
|
+ return -EINVAL;
|
|
|
+ if (ieee->iw_mode == IW_MODE_INFRA)
|
|
|
+ crypt = &ieee->crypt[idx];
|
|
|
+ else
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
|
|
|
+ if ((encoding->flags & IW_ENCODE_DISABLED) ||
|
|
|
+ ext->alg == IW_ENCODE_ALG_NONE) {
|
|
|
+ if (*crypt)
|
|
|
+ ieee80211_crypt_delayed_deinit(ieee, crypt);
|
|
|
+
|
|
|
+ for (i = 0; i < WEP_KEYS; i++)
|
|
|
+ if (ieee->crypt[i] != NULL)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (i == WEP_KEYS) {
|
|
|
+ sec.enabled = 0;
|
|
|
+ sec.encrypt = 0;
|
|
|
+ sec.level = SEC_LEVEL_0;
|
|
|
+ sec.flags |= SEC_LEVEL;
|
|
|
+ }
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
+ sec.enabled = 1;
|
|
|
+ sec.encrypt = 1;
|
|
|
+
|
|
|
+ if (!(ieee->host_encrypt || ieee->host_decrypt))
|
|
|
+ goto skip_host_crypt;
|
|
|
+
|
|
|
+ switch (ext->alg) {
|
|
|
+ case IW_ENCODE_ALG_WEP:
|
|
|
+ alg = "WEP";
|
|
|
+ module = "ieee80211_crypt_wep";
|
|
|
+ break;
|
|
|
+ case IW_ENCODE_ALG_TKIP:
|
|
|
+ alg = "TKIP";
|
|
|
+ module = "ieee80211_crypt_tkip";
|
|
|
+ break;
|
|
|
+ case IW_ENCODE_ALG_CCMP:
|
|
|
+ alg = "CCMP";
|
|
|
+ module = "ieee80211_crypt_ccmp";
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
|
|
|
+ dev->name, ext->alg);
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
+ ops = ieee80211_get_crypto_ops(alg);
|
|
|
+ if (ops == NULL) {
|
|
|
+ request_module(module);
|
|
|
+ ops = ieee80211_get_crypto_ops(alg);
|
|
|
+ }
|
|
|
+ if (ops == NULL) {
|
|
|
+ IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
|
|
|
+ dev->name, ext->alg);
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (*crypt == NULL || (*crypt)->ops != ops) {
|
|
|
+ struct ieee80211_crypt_data *new_crypt;
|
|
|
+
|
|
|
+ ieee80211_crypt_delayed_deinit(ieee, crypt);
|
|
|
+
|
|
|
+ new_crypt = (struct ieee80211_crypt_data *)
|
|
|
+ kmalloc(sizeof(*new_crypt), GFP_KERNEL);
|
|
|
+ if (new_crypt == NULL) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
|
|
|
+ new_crypt->ops = ops;
|
|
|
+ if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
|
|
|
+ new_crypt->priv = new_crypt->ops->init(ieee, idx);
|
|
|
+ if (new_crypt->priv == NULL) {
|
|
|
+ kfree(new_crypt);
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ *crypt = new_crypt;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ext->key_len > 0 && (*crypt)->ops->set_key &&
|
|
|
+ (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
|
|
|
+ (*crypt)->priv) < 0) {
|
|
|
+ IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
+ skip_host_crypt:
|
|
|
+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
|
|
|
+ ieee->tx_keyidx = idx;
|
|
|
+ sec.active_key = idx;
|
|
|
+ sec.flags |= SEC_ACTIVE_KEY;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ext->alg != IW_ENCODE_ALG_NONE) {
|
|
|
+ memcpy(sec.keys[idx], ext->key, ext->key_len);
|
|
|
+ sec.key_sizes[idx] = ext->key_len;
|
|
|
+ sec.flags |= (1 << idx);
|
|
|
+ if (ext->alg == IW_ENCODE_ALG_WEP) {
|
|
|
+ sec.encode_alg[idx] = SEC_ALG_WEP;
|
|
|
+ sec.flags |= SEC_LEVEL;
|
|
|
+ sec.level = SEC_LEVEL_1;
|
|
|
+ } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
|
|
|
+ sec.encode_alg[idx] = SEC_ALG_TKIP;
|
|
|
+ sec.flags |= SEC_LEVEL;
|
|
|
+ sec.level = SEC_LEVEL_2;
|
|
|
+ } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
|
|
|
+ sec.encode_alg[idx] = SEC_ALG_CCMP;
|
|
|
+ sec.flags |= SEC_LEVEL;
|
|
|
+ sec.level = SEC_LEVEL_3;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ done:
|
|
|
+ if (ieee->set_security)
|
|
|
+ ieee->set_security(ieee->dev, &sec);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Do not reset port if card is in Managed mode since resetting will
|
|
|
+ * generate new IEEE 802.11 authentication which may end up in looping
|
|
|
+ * with IEEE 802.1X. If your hardware requires a reset after WEP
|
|
|
+ * configuration (for example... Prism2), implement the reset_port in
|
|
|
+ * the callbacks structures used to initialize the 802.11 stack.
|
|
|
+ */
|
|
|
+ if (ieee->reset_on_keychange &&
|
|
|
+ ieee->iw_mode != IW_MODE_INFRA &&
|
|
|
+ ieee->reset_port && ieee->reset_port(dev)) {
|
|
|
+ IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
|
|
|
+ struct iw_request_info *info,
|
|
|
+ union iwreq_data *wrqu, char *extra)
|
|
|
+{
|
|
|
+ struct iw_point *encoding = &wrqu->encoding;
|
|
|
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
|
|
|
+ struct ieee80211_security *sec = &ieee->sec;
|
|
|
+ int idx, max_key_len;
|
|
|
+
|
|
|
+ max_key_len = encoding->length - sizeof(*ext);
|
|
|
+ if (max_key_len < 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ idx = encoding->flags & IW_ENCODE_INDEX;
|
|
|
+ if (idx) {
|
|
|
+ if (idx < 1 || idx > WEP_KEYS)
|
|
|
+ return -EINVAL;
|
|
|
+ idx--;
|
|
|
+ } else
|
|
|
+ idx = ieee->tx_keyidx;
|
|
|
+
|
|
|
+ if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
|
|
|
+ if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ encoding->flags = idx + 1;
|
|
|
+ memset(ext, 0, sizeof(*ext));
|
|
|
+
|
|
|
+ if (!sec->enabled) {
|
|
|
+ ext->alg = IW_ENCODE_ALG_NONE;
|
|
|
+ ext->key_len = 0;
|
|
|
+ encoding->flags |= IW_ENCODE_DISABLED;
|
|
|
+ } else {
|
|
|
+ if (sec->encode_alg[idx] == SEC_ALG_WEP)
|
|
|
+ ext->alg = IW_ENCODE_ALG_WEP;
|
|
|
+ else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
|
|
|
+ ext->alg = IW_ENCODE_ALG_TKIP;
|
|
|
+ else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
|
|
|
+ ext->alg = IW_ENCODE_ALG_CCMP;
|
|
|
+ else
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ ext->key_len = sec->key_sizes[idx];
|
|
|
+ memcpy(ext->key, sec->keys[idx], ext->key_len);
|
|
|
+ encoding->flags |= IW_ENCODE_ENABLED;
|
|
|
+ if (ext->key_len &&
|
|
|
+ (ext->alg == IW_ENCODE_ALG_TKIP ||
|
|
|
+ ext->alg == IW_ENCODE_ALG_CCMP))
|
|
|
+ ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
|
|
|
+EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
|
|
|
+#endif
|
|
|
+
|
|
|
EXPORT_SYMBOL(ieee80211_wx_get_scan);
|
|
|
EXPORT_SYMBOL(ieee80211_wx_set_encode);
|
|
|
EXPORT_SYMBOL(ieee80211_wx_get_encode);
|