*
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/if_arp.h>
#include <linux/pci.h>
-#include <linux/moduleparam.h>
#include <asm/uaccess.h>
+#include "prismcompat.h"
#include "isl_ioctl.h"
#include "islpci_mgt.h"
#include "isl_oid.h" /* additional types and defs for isl38xx fw */
#include <net/iw_handler.h> /* New driver API */
-static int init_mode = CARD_DEFAULT_IW_MODE;
-static int init_channel = CARD_DEFAULT_CHANNEL;
-static int init_wep = CARD_DEFAULT_WEP;
-static int init_filter = CARD_DEFAULT_FILTER;
-static int init_authen = CARD_DEFAULT_AUTHEN;
-static int init_dot1x = CARD_DEFAULT_DOT1X;
-static int init_conformance = CARD_DEFAULT_CONFORMANCE;
-static int init_mlme = CARD_DEFAULT_MLME_MODE;
-module_param(init_mode, int, 0);
-MODULE_PARM_DESC(init_mode,
- "Set card mode:\n0: Auto\n1: Ad-Hoc\n2: Managed Client (Default)\n3: Master / Access Point\n4: Repeater (Not supported yet)\n5: Secondary (Not supported yet)\n6: Monitor");
+static void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
+ u8 *wpa_ie, size_t wpa_ie_len);
+static size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
+static int prism54_set_wpa(struct net_device *, struct iw_request_info *,
+ __u32 *, char *);
-module_param(init_channel, int, 0);
-MODULE_PARM_DESC(init_channel,
- "Check `iwpriv ethx channel` for available channels");
-
-module_param(init_wep, int, 0);
-module_param(init_filter, int, 0);
-
-module_param(init_authen, int, 0);
-MODULE_PARM_DESC(init_authen,
- "Authentication method. Can be of seven types:\n0 0x0000: None\n1 0x0001: DOT11_AUTH_OS (Default)\n2 0x0002: DOT11_AUTH_SK\n3 0x0003: DOT11_AUTH_BOTH");
-
-module_param(init_dot1x, int, 0);
-MODULE_PARM_DESC(init_dot1x,
- "\n0: None/not set (Default)\n1: DOT11_DOT1X_AUTHENABLED\n2: DOT11_DOT1X_KEYTXENABLED");
-
-module_param(init_mlme, int, 0);
-MODULE_PARM_DESC(init_mlme,
- "Sets the MAC layer management entity (MLME) mode of operation,\n0: DOT11_MLME_AUTO (Default)\n1: DOT11_MLME_INTERMEDIATE\n2: DOT11_MLME_EXTENDED");
/**
* prism54_mib_mode_helper - MIB change mode helper function
* Wireless API modes to Device firmware modes. It also checks for
* correct valid Linux wireless modes.
*/
-int
+static int
prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode)
{
u32 config = INL_CONFIG_MANUALRUN;
void
prism54_mib_init(islpci_private *priv)
{
- u32 t;
+ u32 channel, authen, wep, filter, dot1x, mlme, conformance, power, mode;
struct obj_buffer psm_buffer = {
.size = PSM_BUFFER_SIZE,
.addr = priv->device_psm_buffer
};
- mgt_set(priv, DOT11_OID_CHANNEL, &init_channel);
- mgt_set(priv, DOT11_OID_AUTHENABLE, &init_authen);
- mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &init_wep);
-
+ channel = CARD_DEFAULT_CHANNEL;
+ authen = CARD_DEFAULT_AUTHEN;
+ wep = CARD_DEFAULT_WEP;
+ filter = CARD_DEFAULT_FILTER; /* (0) Do not filter un-encrypted data */
+ dot1x = CARD_DEFAULT_DOT1X;
+ mlme = CARD_DEFAULT_MLME_MODE;
+ conformance = CARD_DEFAULT_CONFORMANCE;
+ power = 127;
+ mode = CARD_DEFAULT_IW_MODE;
+
+ mgt_set(priv, DOT11_OID_CHANNEL, &channel);
+ mgt_set(priv, DOT11_OID_AUTHENABLE, &authen);
+ mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &wep);
mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer);
- mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &init_filter);
- mgt_set(priv, DOT11_OID_DOT1XENABLE, &init_dot1x);
- mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &init_mlme);
- mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &init_conformance);
-
- t = 127;
- mgt_set(priv, OID_INL_OUTPUTPOWER, &t);
-
- /* Important: we are setting a default wireless mode and we are
- * forcing a valid one, so prism54_mib_mode_helper should just set
- * mib values depending on what the wireless mode given is. No need
- * for it save old values */
- if (init_mode > IW_MODE_MONITOR || init_mode < IW_MODE_AUTO) {
- printk(KERN_DEBUG "%s(): You passed a non-valid init_mode. "
- "Using default mode\n", __FUNCTION__);
- init_mode = CARD_DEFAULT_IW_MODE;
- }
- /* This sets all of the mode-dependent values */
- prism54_mib_mode_helper(priv, init_mode);
-}
+ mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &filter);
+ mgt_set(priv, DOT11_OID_DOT1XENABLE, &dot1x);
+ mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlme);
+ mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &conformance);
+ mgt_set(priv, OID_INL_OUTPUTPOWER, &power);
-void
-prism54_mib_init_work(islpci_private *priv)
-{
- down_write(&priv->mib_sem);
- mgt_commit(priv);
- up_write(&priv->mib_sem);
+ /* This sets all of the mode-dependent values */
+ prism54_mib_mode_helper(priv, mode);
}
/* this will be executed outside of atomic context thanks to
if (down_interruptible(&priv->stats_sem))
return;
-/* missing stats are :
- * iwstatistics.qual.updated
- * iwstatistics.discard.nwid
- * iwstatistics.discard.fragment
- * iwstatistics.discard.misc
- * iwstatistics.miss.beacon */
-
/* Noise floor.
* I'm not sure if the unit is dBm.
- * Note : If we are not connected, this value seems to be irrevelant. */
+ * Note : If we are not connected, this value seems to be irrelevant. */
mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
priv->local_iwstatistics.qual.noise = r.u;
data = r.ptr;
/* copy this MAC to the bss */
- for (j = 0; j < 6; j++)
- bss.address[j] = data[j];
+ memcpy(bss.address, data, 6);
kfree(data);
/* now ask for the corresponding bss */
int rvalue;
rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r);
-
+ fwrq->i = r.u;
+ rvalue |= mgt_get_request(priv, DOT11_OID_FREQUENCY, 0, NULL, &r);
fwrq->m = r.u;
- fwrq->e = 0;
+ fwrq->e = 3;
return rvalue;
}
mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
- mgt_commit(priv);
+ if (mgt_commit(priv)) {
+ up_write(&priv->mib_sem);
+ return -EIO;
+ }
priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR)
? priv->monitor_type : ARPHRD_ETHER;
up_write(&priv->mib_sem);
/* by default the card sets this to 20. */
sens = vwrq->disabled ? 20 : vwrq->value;
- /* set the ed threshold. */
return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens);
}
{
struct iw_range *range = (struct iw_range *) extra;
islpci_private *priv = netdev_priv(ndev);
- char *data;
+ u8 *data;
int i, m, rvalue;
struct obj_frequencies *freq;
union oid_res_t r;
/* txpower is supported in dBm's */
range->txpower_capa = IW_TXPOW_DBM;
+ /* Event capability (kernel + driver) */
+ range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
+ IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
+ IW_EVENT_CAPA_MASK(SIOCGIWAP));
+ range->event_capa[1] = IW_EVENT_CAPA_K_1;
+ range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM);
+
if (islpci_get_state(priv) < PRV_STATE_INIT)
return 0;
/* Request the device for the supported frequencies
- * not really revelant since some devices will report the 5 GHz band
+ * not really relevant since some devices will report the 5 GHz band
* frequencies even if they don't support them.
*/
rvalue =
range->num_channels = freq->nr;
range->num_frequency = freq->nr;
- /* Frequencies are not listed in the right order. The reordering is probably
- * firmware dependant and thus should work for everyone.
- */
m = min(IW_MAX_FREQUENCIES, (int) freq->nr);
- for (i = 0; i < m - 12; i++) {
- range->freq[i].m = freq->mhz[12 + i];
+ for (i = 0; i < m; i++) {
+ range->freq[i].m = freq->mhz[i];
range->freq[i].e = 6;
- range->freq[i].i = i + 1;
+ range->freq[i].i = channel_of_freq(freq->mhz[i]);
}
- for (i = m - 12; i < m; i++) {
- range->freq[i].m = freq->mhz[i - m + 12];
- range->freq[i].e = 6;
- range->freq[i].i = i + 23;
- }
-
kfree(freq);
rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r);
i = 0;
while ((i < IW_MAX_BITRATES) && (*data != 0)) {
/* the result must be in bps. The card gives us 500Kbps */
- range->bitrate[i] = (__s32) (*data >> 1);
- range->bitrate[i] *= 1000000;
+ range->bitrate[i] = *data * 500000;
i++;
data++;
}
-
range->num_bitrates = i;
-
kfree(r.ptr);
return rvalue;
int rvalue;
rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r);
-
memcpy(awrq->sa_data, r.ptr, 6);
awrq->sa_family = ARPHRD_ETHER;
kfree(r.ptr);
* the "Aironet driver for 4500 and 4800 series cards" (GPL)
*/
-inline char *
+static char *
prism54_translate_bss(struct net_device *ndev, char *current_ev,
char *end_buf, struct obj_bss *bss, char noise)
{
kfree(buf);
}
}
-
return current_ev;
}
-int
+static int
prism54_get_scan(struct net_device *ndev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
noise = r.u;
- /* Ask the device for a list of known bss. We can report at most
- * IW_MAX_AP=64 to the range struct. But the device won't repport anything
- * if you change the value of MAXBSS=24. Anyway 24 AP It is probably enough.
- */
+ /* Ask the device for a list of known bss.
+ * The old API, using SIOCGIWAPLIST, had a hard limit of IW_MAX_AP=64.
+ * The new API, using SIOCGIWSCAN, is only limited by the buffer size.
+ * WE-14->WE-16, the buffer is limited to IW_SCAN_MAX_DATA bytes.
+ * Starting with WE-17, the buffer can be as big as needed.
+ * But the device won't repport anything if you change the value
+ * of IWMAX_BSS=24. */
+
rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
bsslist = r.ptr;
/* ok now, scan the list and translate its info */
- for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
+ for (i = 0; i < (int) bsslist->nr; i++) {
current_ev = prism54_translate_bss(ndev, current_ev,
- extra + IW_SCAN_MAX_DATA,
+ extra + dwrq->length,
&(bsslist->bsslist[i]),
noise);
+
+ /* Check if there is space for one more entry */
+ if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
+ /* Ask user space to try again with a bigger buffer */
+ rvalue = -E2BIG;
+ break;
+ }
+ }
+
kfree(bsslist);
dwrq->length = (current_ev - extra);
dwrq->flags = 0; /* todo */
memcpy(essid.octets, extra, dwrq->length);
} else
essid.length = 0;
-
+
if (priv->iw_mode != IW_MODE_MONITOR)
return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid);
if (essid->length) {
dwrq->flags = 1; /* set ESSID to ON for Wireless Extensions */
/* if it is to big, trunk it */
- dwrq->length = min(IW_ESSID_MAX_SIZE, essid->length + 1);
+ dwrq->length = min((u8)IW_ESSID_MAX_SIZE, essid->length);
} else {
dwrq->flags = 0;
dwrq->length = 0;
char *data;
int ret, i;
union oid_res_t r;
-
+
if (vwrq->value == -1) {
/* auto mode. No limit. */
profile = 1;
return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
}
-
- if ((ret =
- mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r)))
+
+ ret = mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r);
+ if (ret) {
+ kfree(r.ptr);
return ret;
-
+ }
+
rate = (u32) (vwrq->value / 500000);
data = r.ptr;
i = 0;
-
+
while (data[i]) {
if (rate && (data[i] == rate)) {
break;
data[i] |= 0x80;
i++;
}
-
+
if (!data[i]) {
+ kfree(r.ptr);
return -EINVAL;
}
-
+
data[i] |= 0x80;
data[i + 1] = 0;
-
+
/* Now, check if we want a fixed or auto value */
if (vwrq->fixed) {
data[0] = data[i];
i++;
}
printk("0\n");
-*/
+*/
profile = -1;
ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data);
ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data);
-
+
kfree(r.ptr);
-
+
return ret;
}
vwrq->value = r.u * 500000;
/* request the device for the enabled rates */
- if ((rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r)))
+ rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r);
+ if (rvalue) {
+ kfree(r.ptr);
return rvalue;
+ }
data = r.ptr;
vwrq->fixed = (data[0] != 0) && (data[1] == 0);
kfree(r.ptr);
-
+
return 0;
}
* small frame <=> smaller than the rts threshold
* This is not really the behavior expected by the wireless tool but it seems
* to be a common behavior in other drivers.
- *
- * It seems that playing with this tends to hang the card -> DISABLED
*/
static int
lifetime = vwrq->value / 1024;
/* now set what is requested */
-
- if (slimit != 0)
+ if (slimit)
rvalue =
mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit);
- if (llimit != 0)
+ if (llimit)
rvalue |=
mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit);
- if (lifetime != 0)
+ if (lifetime)
rvalue |=
mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0,
&lifetime);
-
return rvalue;
}
}
}
}
-
- /* now read the flags */
+ /* now read the flags */
if (dwrq->flags & IW_ENCODE_DISABLED) {
/* Encoding disabled,
* authen = DOT11_AUTH_OS;
static int
prism54_set_u32(struct net_device *ndev, struct iw_request_info *info,
- __u32 * uwrq, char *extra)
+ __u32 * uwrq, char *extra)
{
- /*
- u32 *i = (int *) extra;
- int param = *i;
- int u = *(i + 1);
- */
u32 oid = uwrq[0], u = uwrq[1];
return mgt_set_request((islpci_private *) ndev->priv, oid, 0, &u);
mlmeautolevel = DOT11_MLME_EXTENDED;
mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
/* restart the card with our new policy */
- mgt_commit(priv);
+ if (mgt_commit(priv)) {
+ up_write(&priv->mib_sem);
+ return -EIO;
+ }
up_write(&priv->mib_sem);
return 0;
/* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */
-static inline void
+static void
format_event(islpci_private *priv, char *dest, const char *str,
const struct obj_mlme *mlme, u16 *length, int error)
{
const struct obj_mlme *mlme, int error)
{
union iwreq_data wrqu;
+ char *memptr;
- wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
- if (!wrqu.data.pointer)
+ memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
+ if (!memptr)
return;
+ wrqu.data.pointer = memptr;
wrqu.data.length = 0;
- format_event(priv, wrqu.data.pointer, str, mlme, &wrqu.data.length,
+ format_event(priv, memptr, str, mlme, &wrqu.data.length,
error);
- wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer);
- kfree(wrqu.data.pointer);
+ wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr);
+ kfree(memptr);
}
static void
send_simple_event(islpci_private *priv, const char *str)
{
union iwreq_data wrqu;
+ char *memptr;
int n = strlen(str);
- wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
- if (!wrqu.data.pointer)
+ memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
+ if (!memptr)
return;
BUG_ON(n > IW_CUSTOM_MAX);
+ wrqu.data.pointer = memptr;
wrqu.data.length = n;
- strcpy(wrqu.data.pointer, str);
- wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer);
- kfree(wrqu.data.pointer);
+ strcpy(memptr, str);
+ wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr);
+ kfree(memptr);
}
static void
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
-void
+static void
prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
u8 *wpa_ie, size_t wpa_ie_len)
{
up(&priv->wpa_sem);
}
-size_t
+static size_t
prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
{
struct list_head *ptr;
}
}
-int
+static int
prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
char *data)
{
struct obj_mlme *mlme = (struct obj_mlme *) data;
- size_t len;
- u8 *payload, *pos = (u8 *) (mlme + 1);
-
- len = pos[0] | (pos[1] << 8); /* little endian data length */
- payload = pos + 2;
+ struct obj_mlmeex *mlmeex = (struct obj_mlmeex *) data;
+ struct obj_mlmeex *confirm;
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ int wpa_ie_len;
+ size_t len = 0; /* u16, better? */
+ u8 *payload = NULL, *pos = NULL;
+ int ret;
/* I think all trapable objects are listed here.
* Some oids have a EX version. The difference is that they are emitted
* suited. We use the more flexible custom event facility.
*/
+ if (oid >= DOT11_OID_BEACON) {
+ len = mlmeex->size;
+ payload = pos = mlmeex->data;
+ }
+
/* I fear prism54_process_bss_data won't work with big endian data */
if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE))
- prism54_process_bss_data(priv, oid, mlme->address,
+ prism54_process_bss_data(priv, oid, mlmeex->address,
payload, len);
mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme);
0);
break;
- /* Note : the following should never happen since we don't run the card in
- * extended mode.
- * Note : "mlme" is actually a "struct obj_mlmeex *" here, but this
+ /* Note : "mlme" is actually a "struct obj_mlmeex *" here, but this
* is backward compatible layout-wise with "struct obj_mlme".
*/
case DOT11_OID_AUTHENTICATEEX:
handle_request(priv, mlme, oid);
- send_formatted_event(priv, "Authenticate request", mlme, 1);
+ send_formatted_event(priv, "Authenticate request (ex)", mlme, 1);
+
+ if (priv->iw_mode != IW_MODE_MASTER
+ && mlmeex->state != DOT11_STATE_AUTHING)
+ break;
+
+ confirm = kmalloc(sizeof(struct obj_mlmeex) + 6, GFP_ATOMIC);
+
+ if (!confirm)
+ break;
+
+ memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
+ printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
+ mlmeex->address[0],
+ mlmeex->address[1],
+ mlmeex->address[2],
+ mlmeex->address[3],
+ mlmeex->address[4],
+ mlmeex->address[5]
+ );
+ confirm->id = -1; /* or mlmeex->id ? */
+ confirm->state = 0; /* not used */
+ confirm->code = 0;
+ confirm->size = 6;
+ confirm->data[0] = 0x00;
+ confirm->data[1] = 0x00;
+ confirm->data[2] = 0x02;
+ confirm->data[3] = 0x00;
+ confirm->data[4] = 0x00;
+ confirm->data[5] = 0x00;
+
+ ret = mgt_set_varlen(priv, DOT11_OID_ASSOCIATEEX, confirm, 6);
+
+ kfree(confirm);
+ if (ret)
+ return ret;
break;
case DOT11_OID_DISASSOCIATEEX:
- send_formatted_event(priv, "Disassociate request", mlme, 0);
+ send_formatted_event(priv, "Disassociate request (ex)", mlme, 0);
break;
case DOT11_OID_ASSOCIATEEX:
handle_request(priv, mlme, oid);
- send_formatted_event(priv, "Associate request", mlme, 1);
+ send_formatted_event(priv, "Associate request (ex)", mlme, 1);
+
+ if (priv->iw_mode != IW_MODE_MASTER
+ && mlmeex->state != DOT11_STATE_AUTHING)
+ break;
+
+ confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
+
+ if (!confirm)
+ break;
+
+ memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
+
+ confirm->id = ((struct obj_mlmeex *)mlme)->id;
+ confirm->state = 0; /* not used */
+ confirm->code = 0;
+
+ wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+
+ if (!wpa_ie_len) {
+ printk(KERN_DEBUG "No WPA IE found from "
+ "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
+ mlmeex->address[0],
+ mlmeex->address[1],
+ mlmeex->address[2],
+ mlmeex->address[3],
+ mlmeex->address[4],
+ mlmeex->address[5]
+ );
+ kfree(confirm);
+ break;
+ }
+
+ confirm->size = wpa_ie_len;
+ memcpy(&confirm->data, wpa_ie, wpa_ie_len);
+
+ mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
+
+ kfree(confirm);
+
break;
case DOT11_OID_REASSOCIATEEX:
handle_request(priv, mlme, oid);
- send_formatted_event(priv, "Reassociate request", mlme, 1);
+ send_formatted_event(priv, "Reassociate request (ex)", mlme, 1);
+
+ if (priv->iw_mode != IW_MODE_MASTER
+ && mlmeex->state != DOT11_STATE_ASSOCING)
+ break;
+
+ confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
+
+ if (!confirm)
+ break;
+
+ memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
+
+ confirm->id = mlmeex->id;
+ confirm->state = 0; /* not used */
+ confirm->code = 0;
+
+ wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+
+ if (!wpa_ie_len) {
+ printk(KERN_DEBUG "No WPA IE found from "
+ "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
+ mlmeex->address[0],
+ mlmeex->address[1],
+ mlmeex->address[2],
+ mlmeex->address[3],
+ mlmeex->address[4],
+ mlmeex->address[5]
+ );
+ kfree(confirm);
+ break;
+ }
+
+ confirm->size = wpa_ie_len;
+ memcpy(&confirm->data, wpa_ie, wpa_ie_len);
+
+ mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
+
+ kfree(confirm);
+
break;
default:
struct net_device *ndev = frame->ndev;
enum oid_num_t n = mgt_oidtonum(frame->header->oid);
- prism54_process_trap_helper(netdev_priv(ndev), n, frame->data);
+ if (n != OID_NUM_LAST)
+ prism54_process_trap_helper(netdev_priv(ndev), n, frame->data);
islpci_mgt_release(frame);
}
return ret;
}
-int
+/* Note: currently, use hostapd ioctl from the Host AP driver for WPA
+ * support. This is to be replaced with Linux wireless extensions once they
+ * get WPA support. */
+
+/* Note II: please leave all this together as it will be easier to remove later,
+ * once wireless extensions add WPA support -mcgrof */
+
+/* PRISM54_HOSTAPD ioctl() cmd: */
+enum {
+ PRISM2_SET_ENCRYPTION = 6,
+ PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
+ PRISM2_HOSTAPD_MLME = 13,
+ PRISM2_HOSTAPD_SCAN_REQ = 14,
+};
+
+#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12
+#define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25
+#define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26
+
+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
+#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
+((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+
+/* Maximum length for algorithm names (-1 for nul termination)
+ * used in ioctl() */
+#define HOSTAP_CRYPT_ALG_NAME_LEN 16
+
+struct prism2_hostapd_param {
+ u32 cmd;
+ u8 sta_addr[ETH_ALEN];
+ union {
+ struct {
+ u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
+ u32 flags;
+ u32 err;
+ u8 idx;
+ u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+ u16 key_len;
+ u8 key[0];
+ } crypt;
+ struct {
+ u8 len;
+ u8 data[0];
+ } generic_elem;
+ struct {
+#define MLME_STA_DEAUTH 0
+#define MLME_STA_DISASSOC 1
+ u16 cmd;
+ u16 reason_code;
+ } mlme;
+ struct {
+ u8 ssid_len;
+ u8 ssid[32];
+ } scan_req;
+ } u;
+};
+
+
+static int
+prism2_ioctl_set_encryption(struct net_device *dev,
+ struct prism2_hostapd_param *param,
+ int param_len)
+{
+ islpci_private *priv = netdev_priv(dev);
+ int rvalue = 0, force = 0;
+ int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
+ union oid_res_t r;
+
+ /* with the new API, it's impossible to get a NULL pointer.
+ * New version of iwconfig set the IW_ENCODE_NOKEY flag
+ * when no key is given, but older versions don't. */
+
+ if (param->u.crypt.key_len > 0) {
+ /* we have a key to set */
+ int index = param->u.crypt.idx;
+ int current_index;
+ struct obj_key key = { DOT11_PRIV_TKIP, 0, "" };
+
+ /* get the current key index */
+ rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+ current_index = r.u;
+ /* Verify that the key is not marked as invalid */
+ if (!(param->u.crypt.flags & IW_ENCODE_NOKEY)) {
+ key.length = param->u.crypt.key_len > sizeof (param->u.crypt.key) ?
+ sizeof (param->u.crypt.key) : param->u.crypt.key_len;
+ memcpy(key.key, param->u.crypt.key, key.length);
+ if (key.length == 32)
+ /* we want WPA-PSK */
+ key.type = DOT11_PRIV_TKIP;
+ if ((index < 0) || (index > 3))
+ /* no index provided use the current one */
+ index = current_index;
+
+ /* now send the key to the card */
+ rvalue |=
+ mgt_set_request(priv, DOT11_OID_DEFKEYX, index,
+ &key);
+ }
+ /*
+ * If a valid key is set, encryption should be enabled
+ * (user may turn it off later).
+ * This is also how "iwconfig ethX key on" works
+ */
+ if ((index == current_index) && (key.length > 0))
+ force = 1;
+ } else {
+ int index = (param->u.crypt.flags & IW_ENCODE_INDEX) - 1;
+ if ((index >= 0) && (index <= 3)) {
+ /* we want to set the key index */
+ rvalue |=
+ mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
+ &index);
+ } else {
+ if (!param->u.crypt.flags & IW_ENCODE_MODE) {
+ /* we cannot do anything. Complain. */
+ return -EINVAL;
+ }
+ }
+ }
+ /* now read the flags */
+ if (param->u.crypt.flags & IW_ENCODE_DISABLED) {
+ /* Encoding disabled,
+ * authen = DOT11_AUTH_OS;
+ * invoke = 0;
+ * exunencrypt = 0; */
+ }
+ if (param->u.crypt.flags & IW_ENCODE_OPEN)
+ /* Encode but accept non-encoded packets. No auth */
+ invoke = 1;
+ if ((param->u.crypt.flags & IW_ENCODE_RESTRICTED) || force) {
+ /* Refuse non-encoded packets. Auth */
+ authen = DOT11_AUTH_BOTH;
+ invoke = 1;
+ exunencrypt = 1;
+ }
+ /* do the change if requested */
+ if ((param->u.crypt.flags & IW_ENCODE_MODE) || force) {
+ rvalue |=
+ mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
+ rvalue |=
+ mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke);
+ rvalue |=
+ mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
+ &exunencrypt);
+ }
+ return rvalue;
+}
+
+static int
+prism2_ioctl_set_generic_element(struct net_device *ndev,
+ struct prism2_hostapd_param *param,
+ int param_len)
+{
+ islpci_private *priv = netdev_priv(ndev);
+ int max_len, len, alen, ret=0;
+ struct obj_attachment *attach;
+
+ len = param->u.generic_elem.len;
+ max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
+ if (max_len < 0 || max_len < len)
+ return -EINVAL;
+
+ alen = sizeof(*attach) + len;
+ attach = kmalloc(alen, GFP_KERNEL);
+ if (attach == NULL)
+ return -ENOMEM;
+
+ memset(attach, 0, alen);
+#define WLAN_FC_TYPE_MGMT 0
+#define WLAN_FC_STYPE_ASSOC_REQ 0
+#define WLAN_FC_STYPE_REASSOC_REQ 2
+
+ /* Note: endianness is covered by mgt_set_varlen */
+
+ attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_ASSOC_REQ << 4);
+ attach->id = -1;
+ attach->size = len;
+ memcpy(attach->data, param->u.generic_elem.data, len);
+
+ ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
+
+ if (ret == 0) {
+ attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_REASSOC_REQ << 4);
+
+ ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
+
+ if (ret == 0)
+ printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
+ ndev->name);
+ }
+
+ kfree(attach);
+ return ret;
+
+}
+
+static int
+prism2_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param)
+{
+ return -EOPNOTSUPP;
+}
+
+static int
+prism2_ioctl_scan_req(struct net_device *ndev,
+ struct prism2_hostapd_param *param)
+{
+ islpci_private *priv = netdev_priv(ndev);
+ int i, rvalue;
+ struct obj_bsslist *bsslist;
+ u32 noise = 0;
+ char *extra = "";
+ char *current_ev = "foo";
+ union oid_res_t r;
+
+ if (islpci_get_state(priv) < PRV_STATE_INIT) {
+ /* device is not ready, fail gently */
+ return 0;
+ }
+
+ /* first get the noise value. We will use it to report the link quality */
+ rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
+ noise = r.u;
+
+ /* Ask the device for a list of known bss. We can report at most
+ * IW_MAX_AP=64 to the range struct. But the device won't repport anything
+ * if you change the value of IWMAX_BSS=24.
+ */
+ rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
+ bsslist = r.ptr;
+
+ /* ok now, scan the list and translate its info */
+ for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
+ current_ev = prism54_translate_bss(ndev, current_ev,
+ extra + IW_SCAN_MAX_DATA,
+ &(bsslist->bsslist[i]),
+ noise);
+ kfree(bsslist);
+
+ return rvalue;
+}
+
+static int
+prism54_hostapd(struct net_device *ndev, struct iw_point *p)
+{
+ struct prism2_hostapd_param *param;
+ int ret = 0;
+ u32 uwrq;
+
+ printk(KERN_DEBUG "prism54_hostapd - len=%d\n", p->length);
+ if (p->length < sizeof(struct prism2_hostapd_param) ||
+ p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
+ return -EINVAL;
+
+ param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL);
+ if (param == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(param, p->pointer, p->length)) {
+ kfree(param);
+ return -EFAULT;
+ }
+
+ switch (param->cmd) {
+ case PRISM2_SET_ENCRYPTION:
+ printk(KERN_DEBUG "%s: Caught WPA supplicant set encryption request\n",
+ ndev->name);
+ ret = prism2_ioctl_set_encryption(ndev, param, p->length);
+ break;
+ case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT:
+ printk(KERN_DEBUG "%s: Caught WPA supplicant set WPA IE request\n",
+ ndev->name);
+ ret = prism2_ioctl_set_generic_element(ndev, param,
+ p->length);
+ break;
+ case PRISM2_HOSTAPD_MLME:
+ printk(KERN_DEBUG "%s: Caught WPA supplicant MLME request\n",
+ ndev->name);
+ ret = prism2_ioctl_mlme(ndev, param);
+ break;
+ case PRISM2_HOSTAPD_SCAN_REQ:
+ printk(KERN_DEBUG "%s: Caught WPA supplicant scan request\n",
+ ndev->name);
+ ret = prism2_ioctl_scan_req(ndev, param);
+ break;
+ case PRISM54_SET_WPA:
+ printk(KERN_DEBUG "%s: Caught WPA supplicant wpa init request\n",
+ ndev->name);
+ uwrq = 1;
+ ret = prism54_set_wpa(ndev, NULL, &uwrq, NULL);
+ break;
+ case PRISM54_DROP_UNENCRYPTED:
+ printk(KERN_DEBUG "%s: Caught WPA drop unencrypted request\n",
+ ndev->name);
+#if 0
+ uwrq = 0x01;
+ mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &uwrq);
+ down_write(&priv->mib_sem);
+ mgt_commit(priv);
+ up_write(&priv->mib_sem);
+#endif
+ /* Not necessary, as set_wpa does it, should we just do it here though? */
+ ret = 0;
+ break;
+ default:
+ printk(KERN_DEBUG "%s: Caught a WPA supplicant request that is not supported\n",
+ ndev->name);
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ if (ret == 0 && copy_to_user(p->pointer, param, p->length))
+ ret = -EFAULT;
+
+ kfree(param);
+
+ return ret;
+}
+
+static int
prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra)
{
islpci_private *priv = netdev_priv(ndev);
+ u32 mlme, authen, dot1x, filter, wep;
- down_write(&priv->mib_sem);
+ if (islpci_get_state(priv) < PRV_STATE_INIT)
+ return 0;
+
+ wep = 1; /* For privacy invoked */
+ filter = 1; /* Filter out all unencrypted frames */
+ dot1x = 0x01; /* To enable eap filter */
+ mlme = DOT11_MLME_EXTENDED;
+ authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
+ down_write(&priv->mib_sem);
priv->wpa = *uwrq;
- if (priv->wpa) {
- u32 l = DOT11_MLME_EXTENDED;
- mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &l);
+
+ switch (priv->wpa) {
+ default:
+ case 0: /* Clears/disables WPA and friends */
+ wep = 0;
+ filter = 0; /* Do not filter un-encrypted data */
+ dot1x = 0;
+ mlme = DOT11_MLME_AUTO;
+ printk("%s: Disabling WPA\n", ndev->name);
+ break;
+ case 2:
+ case 1: /* WPA */
+ printk("%s: Enabling WPA\n", ndev->name);
+ break;
}
- /* restart the card with new level. Needed ? */
- mgt_commit(priv);
up_write(&priv->mib_sem);
+ mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
+ mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &wep);
+ mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &filter);
+ mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
+ mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlme);
+
return 0;
}
-int
+static int
prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra)
{
return 0;
}
-int
+static int
prism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra)
{
return 0;
}
-int
+static int
prism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra)
{
return 0;
}
-int
-prism54_set_maxframeburst(struct net_device *ndev, struct iw_request_info *info,
- __u32 * uwrq, char *extra)
-{
- islpci_private *priv = netdev_priv(ndev);
- u32 max_burst;
-
- max_burst = (*uwrq) ? *uwrq : CARD_DEFAULT_MAXFRAMEBURST;
- mgt_set_request(priv, DOT11_OID_MAXFRAMEBURST, 0, &max_burst);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-int
-prism54_get_maxframeburst(struct net_device *ndev, struct iw_request_info *info,
- __u32 * uwrq, char *extra)
-{
- islpci_private *priv = netdev_priv(ndev);
- union oid_res_t r;
- int rvalue;
-
- rvalue = mgt_get_request(priv, DOT11_OID_MAXFRAMEBURST, 0, NULL, &r);
- *uwrq = r.u;
-
- return rvalue;
-}
-
-int
-prism54_set_profile(struct net_device *ndev, struct iw_request_info *info,
- __u32 * uwrq, char *extra)
-{
- islpci_private *priv = netdev_priv(ndev);
- u32 profile;
-
- profile = (*uwrq) ? *uwrq : CARD_DEFAULT_PROFILE;
- mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-int
-prism54_get_profile(struct net_device *ndev, struct iw_request_info *info,
- __u32 * uwrq, char *extra)
-{
- islpci_private *priv = netdev_priv(ndev);
- union oid_res_t r;
- int rvalue;
-
- rvalue = mgt_get_request(priv, DOT11_OID_PROFILES, 0, NULL, &r);
- *uwrq = r.u;
-
- return rvalue;
-}
-
-int
+static int
prism54_debug_oid(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra)
{
islpci_private *priv = netdev_priv(ndev);
-
+
priv->priv_oid = *uwrq;
printk("%s: oid 0x%08X\n", ndev->name, *uwrq);
return 0;
}
-int
+static int
prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info,
- struct iw_point *data, char *extra)
+ struct iw_point *data, char *extra)
{
islpci_private *priv = netdev_priv(ndev);
- struct islpci_mgmtframe *response = NULL;
- int ret = -EIO, response_op = PIMFOR_OP_ERROR;
-
+ struct islpci_mgmtframe *response;
+ int ret = -EIO;
+
printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid);
data->length = 0;
-
+
if (islpci_get_state(priv) >= PRV_STATE_INIT) {
ret =
islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
priv->priv_oid, extra, 256,
&response);
- response_op = response->header->operation;
printk("%s: ret: %i\n", ndev->name, ret);
- printk("%s: response_op: %i\n", ndev->name, response_op);
if (ret || !response
|| response->header->operation == PIMFOR_OP_ERROR) {
if (response) {
printk("%s: len: %i\n", ndev->name, data->length);
}
}
-
+
return ret;
}
-int
+static int
prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info,
- struct iw_point *data, char *extra)
+ struct iw_point *data, char *extra)
{
islpci_private *priv = netdev_priv(ndev);
- struct islpci_mgmtframe *response = NULL;
+ struct islpci_mgmtframe *response;
int ret = 0, response_op = PIMFOR_OP_ERROR;
-
+
printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid,
data->length);
-
+
if (islpci_get_state(priv) >= PRV_STATE_INIT) {
ret =
islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
priv->priv_oid, extra, data->length,
&response);
printk("%s: ret: %i\n", ndev->name, ret);
+ if (ret || !response
+ || response->header->operation == PIMFOR_OP_ERROR) {
+ if (response) {
+ islpci_mgt_release(response);
+ }
+ printk("%s: EIO\n", ndev->name);
+ ret = -EIO;
+ }
if (!ret) {
response_op = response->header->operation;
printk("%s: response_op: %i\n", ndev->name,
response_op);
islpci_mgt_release(response);
}
- if (ret || response_op == PIMFOR_OP_ERROR) {
- printk("%s: EIO\n", ndev->name);
- ret = -EIO;
- }
}
-
- return ret;
+
+ return (ret ? ret : -EINPROGRESS);
}
static int
#define PRISM54_DBG_GET_OID SIOCIWFIRSTPRIV+15
#define PRISM54_DBG_SET_OID SIOCIWFIRSTPRIV+16
-#define PRISM54_GET_OID SIOCIWFIRSTPRIV+17
+#define PRISM54_GET_OID SIOCIWFIRSTPRIV+17
#define PRISM54_SET_OID_U32 SIOCIWFIRSTPRIV+18
#define PRISM54_SET_OID_STR SIOCIWFIRSTPRIV+20
#define PRISM54_SET_OID_ADDR SIOCIWFIRSTPRIV+22
#define PRISM54_GET_PRISMHDR SIOCIWFIRSTPRIV+23
#define PRISM54_SET_PRISMHDR SIOCIWFIRSTPRIV+24
-#define IWPRIV_SET_U32(n,x) { n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_"x }
-#define IWPRIV_SET_SSID(n,x) { n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "set_"x }
-#define IWPRIV_SET_ADDR(n,x) { n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "set_"x }
-#define IWPRIV_GET(n,x) { n, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, "get_"x }
+#define IWPRIV_SET_U32(n,x) { n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
+#define IWPRIV_SET_SSID(n,x) { n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
+#define IWPRIV_SET_ADDR(n,x) { n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
+#define IWPRIV_GET(n,x) { n, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, "g_"x }
#define IWPRIV_U32(n,x) IWPRIV_SET_U32(n,x), IWPRIV_GET(n,x)
#define IWPRIV_SSID(n,x) IWPRIV_SET_SSID(n,x), IWPRIV_GET(n,x)
#define IWPRIV_ADDR(n,x) IWPRIV_SET_ADDR(n,x), IWPRIV_GET(n,x)
-/* Note : limited to 128 private ioctls */
+/* Note : limited to 128 private ioctls (wireless tools 26) */
static const struct iw_priv_args prism54_private_args[] = {
/*{ cmd, set_args, get_args, name } */
{PRISM54_DBG_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
"dbg_oid"},
{PRISM54_DBG_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "dbg_get_oid"},
- {PRISM54_DBG_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "dbg_get_oid"},
+ {PRISM54_DBG_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "dbg_set_oid"},
/* --- sub-ioctls handlers --- */
{PRISM54_GET_OID,
0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, ""},
IWPRIV_U32(DOT11_OID_AUTHENABLE, "authenable"),
IWPRIV_U32(DOT11_OID_PRIVACYINVOKED, "privinvok"),
IWPRIV_U32(DOT11_OID_EXUNENCRYPTED, "exunencrypt"),
-
+
IWPRIV_U32(DOT11_OID_REKEYTHRESHOLD, "rekeythresh"),
IWPRIV_U32(DOT11_OID_MAXTXLIFETIME, "maxtxlife"),
.standard = (iw_handler *) prism54_handler,
.private = (iw_handler *) prism54_private_handler,
.private_args = (struct iw_priv_args *) prism54_private_args,
- .spy_offset = offsetof(islpci_private, spy_data),
+ .get_wireless_stats = prism54_get_wireless_stats,
};
-/* For ioctls that don't work with the new API */
+/* For wpa_supplicant */
int
prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
{
+ struct iwreq *wrq = (struct iwreq *) rq;
+ int ret = -1;
+ switch (cmd) {
+ case PRISM54_HOSTAPD:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ ret = prism54_hostapd(ndev, &wrq->u.data);
+ return ret;
+ }
return -EOPNOTSUPP;
}