/*
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
#include <asm/uaccess.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
#include "ieee80211_rate.h"
#include "wpa.h"
#include "aes_ccm.h"
static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
int idx, int alg, int remove,
int set_tx_key, const u8 *_key,
size_t key_len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
int ret = 0;
struct sta_info *sta;
struct ieee80211_key *key;
struct ieee80211_sub_if_data *sdata;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (idx < 0 || idx >= NUM_DEFAULT_KEYS) {
printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
dev->name, idx);
return -EINVAL;
}
if (is_broadcast_ether_addr(sta_addr)) {
sta = NULL;
key = sdata->keys[idx];
} else {
set_tx_key = 0;
/*
* According to the standard, the key index of a pairwise
* key must be zero. However, some AP are broken when it
* comes to WEP key indices, so we work around this.
*/
if (idx != 0 && alg != ALG_WEP) {
printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for "
"individual key\n", dev->name);
return -EINVAL;
}
sta = sta_info_get(local, sta_addr);
if (!sta) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
"%s\n",
dev->name, print_mac(mac, sta_addr));
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
return -ENOENT;
}
key = sta->key;
}
if (remove) {
ieee80211_key_free(key);
key = NULL;
} else {
/*
* Automatically frees any old key if present.
*/
key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key);
if (!key) {
ret = -ENOMEM;
goto err_out;
}
}
if (set_tx_key || (!sta && !sdata->default_key && key))
ieee80211_set_default_key(sdata, idx);
ret = 0;
err_out:
if (sta)
sta_info_put(sta);
return ret;
}
static int ieee80211_ioctl_siwgenie(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
{
struct ieee80211_sub_if_data *sdata;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
return -EOPNOTSUPP;
if (sdata->type == IEEE80211_IF_TYPE_STA ||
sdata->type == IEEE80211_IF_TYPE_IBSS) {
int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length);
if (ret)
return ret;
sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
ieee80211_sta_req_auth(