Commit 4b743325 authored by Jeff Garzik's avatar Jeff Garzik

Merge pobox.com:/garz/repo/netdev-2.6/prism54

into pobox.com:/garz/repo/net-drivers-2.6
parents 1fc12ca8 991ae550
......@@ -133,8 +133,8 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
readl(device_base + ISL38XX_CTRL_STAT_REG));
udelay(ISL38XX_WRITEIO_DELAY);
if (reg = readl(device_base + ISL38XX_INT_IDENT_REG),
reg == 0xabadface) {
reg = readl(device_base + ISL38XX_INT_IDENT_REG);
if (reg == 0xabadface) {
#if VERBOSE > SHOW_ERROR_MESSAGES
do_gettimeofday(&current_time);
DEBUG(SHOW_TRACING,
......@@ -192,10 +192,8 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
void
isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address)
{
u32 reg;
#if VERBOSE > SHOW_ERROR_MESSAGES
DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset \n");
DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n");
#endif
/* load the address of the control block in the device */
......@@ -203,8 +201,7 @@ isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address)
udelay(ISL38XX_WRITEIO_DELAY);
/* set the reset bit in the Device Interrupt Register */
isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET,
ISL38XX_DEV_INT_REG);
isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, ISL38XX_DEV_INT_REG);
udelay(ISL38XX_WRITEIO_DELAY);
/* enable the interrupt for detecting initialization */
......@@ -212,9 +209,7 @@ isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address)
/* Note: Do not enable other interrupts here. We want the
* device to have come up first 100% before allowing any other
* interrupts. */
reg = ISL38XX_INT_IDENT_INIT;
isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG);
isl38xx_w32_flush(device_base, ISL38XX_INT_IDENT_INIT, ISL38XX_INT_EN_REG);
udelay(ISL38XX_WRITEIO_DELAY); /* allow complete full reset */
}
......
......@@ -95,6 +95,10 @@ isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset)
#define ISL38XX_INT_SOURCES 0x001E
/* Control/Status register bits */
/* Looks like there are other meaningful bits
0x20004400 seen in normal operation,
0x200044db at 'timeout waiting for mgmt response'
*/
#define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200
#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000
#define ISL38XX_CTRL_STAT_RESET 0x10000000
......
......@@ -36,38 +36,6 @@
#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");
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
* @mib: the &struct islpci_mib object to modify
......@@ -141,36 +109,34 @@ prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode)
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;
}
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);
/* This sets all of the mode-dependent values */
prism54_mib_mode_helper(priv, init_mode);
prism54_mib_mode_helper(priv, mode);
}
/* this will be executed outside of atomic context thanks to
......@@ -374,7 +340,10 @@ prism54_set_mode(struct net_device *ndev, struct iw_request_info *info,
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);
......@@ -485,6 +454,15 @@ prism54_get_range(struct net_device *ndev, struct iw_request_info *info,
/* txpower is supported in dBm's */
range->txpower_capa = IW_TXPOW_DBM;
#if WIRELESS_EXT > 16
/* 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);
#endif /* WIRELESS_EXT > 16 */
if (islpci_get_state(priv) < PRV_STATE_INIT)
return 0;
......@@ -629,8 +607,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL);
/* Add frequency. (short) bss->channel is the frequency in MHz */
iwe.u.freq.m = channel_of_freq(bss->channel);
iwe.u.freq.e = 0;
iwe.u.freq.m = bss->channel;
iwe.u.freq.e = 6;
iwe.cmd = SIOCGIWFREQ;
current_ev =
iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
......@@ -690,19 +668,33 @@ prism54_get_scan(struct net_device *ndev, struct iw_request_info *info,
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.
*/
/* 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);
#if WIRELESS_EXT > 16
/* 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;
}
#endif /* WIRELESS_EXT > 16 */
}
kfree(bsslist);
dwrq->length = (current_ev - extra);
dwrq->flags = 0; /* todo */
......@@ -1412,7 +1404,10 @@ prism54_set_policy(struct net_device *ndev, struct iw_request_info *info,
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;
......@@ -1746,11 +1741,13 @@ 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 = 0, *pos = 0;
int ret;
/* I think all trapable objects are listed here.
* Some oids have a EX version. The difference is that they are emitted
......@@ -1760,9 +1757,14 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
* 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);
......@@ -1822,21 +1824,134 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
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:
......@@ -1879,23 +1994,367 @@ prism54_set_mac_address(struct net_device *ndev, void *addr)
return ret;
}
/* 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;
}
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;
}
......@@ -1947,7 +2406,7 @@ prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info,
struct iw_point *data, char *extra)
{
islpci_private *priv = netdev_priv(ndev);
struct islpci_mgmtframe *response = NULL;
struct islpci_mgmtframe *response;
int ret = -EIO;
printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid);
......@@ -1983,7 +2442,7 @@ prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info,
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,
......@@ -2256,14 +2715,24 @@ const struct iw_handler_def prism54_handler_def = {
.standard = (iw_handler *) prism54_handler,
.private = (iw_handler *) prism54_private_handler,
.private_args = (struct iw_priv_args *) prism54_private_args,
#if WIRELESS_EXT == 16
.spy_offset = offsetof(islpci_private, spy_data),
#endif /* WIRELESS_EXT == 16 */
};
/* 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;
}
......@@ -48,6 +48,8 @@ size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
int prism54_set_mac_address(struct net_device *, void *);
int prism54_ioctl(struct net_device *, struct ifreq *, int);
int prism54_set_wpa(struct net_device *, struct iw_request_info *,
__u32 *, char *);
extern const struct iw_handler_def prism54_handler_def;
......
......@@ -91,6 +91,14 @@ struct obj_frequencies {
u16 mhz[0];
} __attribute__ ((packed));
struct obj_attachment {
char type;
char reserved;
short id;
short size;
char data[0];
} __attribute__((packed));
/*
* in case everything's ok, the inlined function below will be
* optimized away by the compiler...
......@@ -472,6 +480,7 @@ enum oid_num_t {
#define OID_TYPE_MLMEEX 0x09
#define OID_TYPE_ADDR 0x0A
#define OID_TYPE_RAW 0x0B
#define OID_TYPE_ATTACH 0x0C
/* OID_TYPE_MLMEEX is special because of a variable size field when sending.
* Not yet implemented (not used in driver anyway).
......
......@@ -105,7 +105,7 @@ isl_upload_firmware(islpci_private *priv)
"%s: firmware '%s' size is not multiple of 32bit, aborting!\n",
"prism54", priv->firmware);
release_firmware(fw_entry);
return EILSEQ; /* Illegal byte sequence */;
return -EILSEQ; /* Illegal byte sequence */;
}
while (fw_len > 0) {
......@@ -142,6 +142,10 @@ isl_upload_firmware(islpci_private *priv)
BUG_ON(fw_len != 0);
/* Firmware version is at offset 40 (also for "newmac") */
printk(KERN_DEBUG "%s: firmware version: %.8s\n",
priv->ndev->name, fw_entry->data + 40);
release_firmware(fw_entry);
}
......@@ -375,8 +379,6 @@ islpci_open(struct net_device *ndev)
u32 rc;
islpci_private *priv = netdev_priv(ndev);
printk(KERN_DEBUG "%s: islpci_open()\n", ndev->name);
/* reset data structures, upload firmware and reset device */
rc = islpci_reset(priv,1);
if (rc) {
......@@ -462,8 +464,7 @@ islpci_upload_fw(islpci_private *priv)
return rc;
}
printk(KERN_DEBUG
"%s: firmware uploaded done, now triggering reset...\n",
printk(KERN_DEBUG "%s: firmware upload complete\n",
priv->ndev->name);
islpci_set_state(priv, PRV_STATE_POSTBOOT);
......@@ -489,6 +490,7 @@ islpci_reset_if(islpci_private *priv)
/* The software reset acknowledge needs about 220 msec here.
* Be conservative and wait for up to one second. */
set_current_state(TASK_UNINTERRUPTIBLE);
remaining = schedule_timeout(HZ);
if(remaining > 0) {
......@@ -499,15 +501,16 @@ islpci_reset_if(islpci_private *priv)
/* If we're here it's because our IRQ hasn't yet gone through.
* Retry a bit more...
*/
printk(KERN_ERR "%s: device soft reset timed out\n",
printk(KERN_ERR "%s: no 'reset complete' IRQ seen - retrying\n",
priv->ndev->name);
}
finish_wait(&priv->reset_done, &wait);
if(result)
if (result) {
printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name);
return result;
}
islpci_set_state(priv, PRV_STATE_INIT);
......@@ -519,11 +522,17 @@ islpci_reset_if(islpci_private *priv)
isl38xx_enable_common_interrupts(priv->device_base);
down_write(&priv->mib_sem);
mgt_commit(priv);
result = mgt_commit(priv);
if (result) {
printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name);
up_write(&priv->mib_sem);
return result;
}
up_write(&priv->mib_sem);
islpci_set_state(priv, PRV_STATE_READY);
printk(KERN_DEBUG "%s: interface reset complete\n", priv->ndev->name);
return 0;
}
......@@ -584,18 +593,18 @@ islpci_reset(islpci_private *priv, int reload_firmware)
/* now that the data structures are cleaned up, upload
* firmware and reset interface */
rc = islpci_upload_fw(priv);
if (rc)
if (rc) {
printk(KERN_ERR "%s: islpci_reset: failure\n",
priv->ndev->name);
return rc;
}
}
/* finally reset interface */
rc = islpci_reset_if(priv);
if (!rc) /* If successful */
return rc;
printk(KERN_DEBUG "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n");
if (rc)
printk(KERN_ERR "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n");
return rc;
}
struct net_device_stats *
......@@ -604,7 +613,7 @@ islpci_statistics(struct net_device *ndev)
islpci_private *priv = netdev_priv(ndev);
#if VERBOSE > SHOW_ERROR_MESSAGES
DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics \n");
DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics\n");
#endif
return &priv->statistics;
......@@ -830,6 +839,12 @@ islpci_setup(struct pci_dev *pdev)
priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ?
priv->monitor_type : ARPHRD_ETHER;
#if WIRELESS_EXT > 16
/* Add pointers to enable iwspy support. */
priv->wireless_data.spy_data = &priv->spy_data;
ndev->wireless_data = &priv->wireless_data;
#endif /* WIRELESS_EXT > 16 */
/* save the start and end address of the PCI memory area */
ndev->mem_start = (unsigned long) priv->device_base;
ndev->mem_end = ndev->mem_start + ISL38XX_PCI_MEM_SIZE;
......
......@@ -100,6 +100,10 @@ typedef struct {
struct iw_spy_data spy_data; /* iwspy support */
#if WIRELESS_EXT > 16
struct iw_public_data wireless_data;
#endif /* WIRELESS_EXT > 16 */
int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */
struct islpci_acl acl;
......
......@@ -508,11 +508,12 @@ islpci_eth_tx_timeout(struct net_device *ndev)
/* increment the transmit error counter */
statistics->tx_errors++;
printk(KERN_WARNING "%s: tx_timeout", ndev->name);
if (!priv->reset_task_pending) {
priv->reset_task_pending = 1;
printk(", scheduling a reset");
netif_stop_queue(ndev);
schedule_work(&priv->reset_task);
}
return;
printk("\n");
}
......@@ -107,9 +107,6 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id)
islpci_private *priv;
int rvalue;
/* TRACE(DRV_NAME); */
/* Enable the pci device */
if (pci_enable_device(pdev)) {
printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME);
......
......@@ -473,6 +473,7 @@ islpci_mgt_transaction(struct net_device *ndev,
int timeleft;
struct islpci_mgmtframe *frame;
set_current_state(TASK_UNINTERRUPTIBLE);
timeleft = schedule_timeout(wait_cycle_jiffies);
frame = xchg(&priv->mgmt_received, NULL);
if (frame) {
......
......@@ -31,8 +31,6 @@
#define K_DEBUG(f, m, args...) do { if(f & m) printk(KERN_DEBUG args); } while(0)
#define DEBUG(f, args...) K_DEBUG(f, pc_debug, args)
#define TRACE(devname) K_DEBUG(SHOW_TRACING, VERBOSE, "%s: -> " __FUNCTION__ "()\n", devname)
extern int pc_debug;
#define init_wds 0 /* help compiler optimize away dead code */
......
......@@ -201,7 +201,8 @@ struct oid_t isl_oid[] = {
OID_U32(DOT11_OID_STATIMEOUT, 0x19000000),
OID_U32_C(DOT11_OID_MLMEAUTOLEVEL, 0x19000001),
OID_U32(DOT11_OID_BSSTIMEOUT, 0x19000002),
OID_UNKNOWN(DOT11_OID_ATTACHMENT, 0x19000003),
[DOT11_OID_ATTACHMENT] = {0x19000003, 0,
sizeof(struct obj_attachment), OID_TYPE_ATTACH},
OID_STRUCT_C(DOT11_OID_PSMBUFFER, 0x19000004, struct obj_buffer,
OID_TYPE_BUFFER),
......@@ -329,6 +330,12 @@ mgt_le_to_cpu(int type, void *data)
mlme->size = le16_to_cpu(mlme->size);
break;
}
case OID_TYPE_ATTACH:{
struct obj_attachment *attach = data;
attach->id = le16_to_cpu(attach->id);
attach->size = le16_to_cpu(attach->size);;
break;
}
case OID_TYPE_SSID:
case OID_TYPE_KEY:
case OID_TYPE_ADDR:
......@@ -392,6 +399,12 @@ mgt_cpu_to_le(int type, void *data)
mlme->size = cpu_to_le16(mlme->size);
break;
}
case OID_TYPE_ATTACH:{
struct obj_attachment *attach = data;
attach->id = cpu_to_le16(attach->id);
attach->size = cpu_to_le16(attach->size);;
break;
}
case OID_TYPE_SSID:
case OID_TYPE_KEY:
case OID_TYPE_ADDR:
......@@ -465,6 +478,42 @@ mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data)
return ret;
}
/* None of these are cached */
int
mgt_set_varlen(islpci_private *priv, enum oid_num_t n, void *data, int extra_len)
{
int ret = 0;
struct islpci_mgmtframe *response;
int response_op = PIMFOR_OP_ERROR;
int dlen;
u32 oid;
BUG_ON(OID_NUM_LAST <= n);
dlen = isl_oid[n].size;
oid = isl_oid[n].oid;
mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, data);
if (islpci_get_state(priv) >= PRV_STATE_READY) {
ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid,
data, dlen + extra_len, &response);
if (!ret) {
response_op = response->header->operation;
islpci_mgt_release(response);
}
if (ret || response_op == PIMFOR_OP_ERROR)
ret = -EIO;
} else
ret = -EIO;
/* re-set given data to what it was */
if (data)
mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, data);
return ret;
}
int
mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data,
union oid_res_t *res)
......@@ -555,15 +604,18 @@ mgt_commit_list(islpci_private *priv, enum oid_num_t *l, int n)
u32 oid = t->oid;
BUG_ON(data == NULL);
while (j <= t->range) {
response = NULL;
ret |= islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
int r = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
oid, data, t->size,
&response);
if (response) {
ret |= (response->header->operation ==
PIMFOR_OP_ERROR);
r |= (response->header->operation == PIMFOR_OP_ERROR);
islpci_mgt_release(response);
}
if (r)
printk(KERN_ERR "%s: mgt_commit_list: failure. "
"oid=%08x err=%d\n",
priv->ndev->name, oid, r);
ret |= r;
j++;
oid++;
data += t->size;
......@@ -624,7 +676,7 @@ static enum oid_num_t commit_part2[] = {
static int
mgt_update_addr(islpci_private *priv)
{
struct islpci_mgmtframe *res = NULL;
struct islpci_mgmtframe *res;
int ret;
ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
......@@ -638,26 +690,26 @@ mgt_update_addr(islpci_private *priv)
if (res)
islpci_mgt_release(res);
if (ret)
printk(KERN_ERR "%s: mgt_update_addr: failure\n", priv->ndev->name);
return ret;
}
void
#define VEC_SIZE(a) (sizeof(a)/sizeof(a[0]))
int
mgt_commit(islpci_private *priv)
{
int rvalue;
u32 u;
if (islpci_get_state(priv) < PRV_STATE_INIT)
return;
return 0;
rvalue = mgt_commit_list(priv, commit_part1,
sizeof (commit_part1) /
sizeof (commit_part1[0]));
rvalue = mgt_commit_list(priv, commit_part1, VEC_SIZE(commit_part1));
if (priv->iw_mode != IW_MODE_MONITOR)
rvalue |= mgt_commit_list(priv, commit_part2,
sizeof (commit_part2) /
sizeof (commit_part2[0]));
rvalue |= mgt_commit_list(priv, commit_part2, VEC_SIZE(commit_part2));
u = OID_INL_MODE;
rvalue |= mgt_commit_list(priv, &u, 1);
......@@ -666,9 +718,43 @@ mgt_commit(islpci_private *priv)
if (rvalue) {
/* some request have failed. The device might be in an
incoherent state. We should reset it ! */
printk(KERN_DEBUG "%s: mgt_commit has failed. Restart the "
"device \n", priv->ndev->name);
printk(KERN_DEBUG "%s: mgt_commit: failure\n", priv->ndev->name);
}
return rvalue;
}
/* The following OIDs need to be "unlatched":
*
* MEDIUMLIMIT,BEACONPERIOD,DTIMPERIOD,ATIMWINDOW,LISTENINTERVAL
* FREQUENCY,EXTENDEDRATES.
*
* The way to do this is to set ESSID. Note though that they may get
* unlatch before though by setting another OID. */
void
mgt_unlatch_all(islpci_private *priv)
{
u32 u;
int rvalue = 0;
if (islpci_get_state(priv) < PRV_STATE_INIT)
return;
u = DOT11_OID_SSID;
rvalue = mgt_commit_list(priv, &u, 1);
/* Necessary if in MANUAL RUN mode? */
#if 0
u = OID_INL_MODE;
rvalue |= mgt_commit_list(priv, &u, 1);
u = DOT11_OID_MLMEAUTOLEVEL;
rvalue |= mgt_commit_list(priv, &u, 1);
u = OID_INL_MODE;
rvalue |= mgt_commit_list(priv, &u, 1);
#endif
if (rvalue)
printk(KERN_DEBUG "%s: Unlatching OIDs failed\n", priv->ndev->name);
}
/* This will tell you if you are allowed to answer a mlme(ex) request .*/
......@@ -771,6 +857,14 @@ mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str)
mlme->state, mlme->code, mlme->size);
}
break;
case OID_TYPE_ATTACH:{
struct obj_attachment *attach = r->ptr;
return snprintf(str, PRIV_STR_SIZE,
"id=%d\nsize=%d\n",
attach->id,
attach->size);
}
break;
case OID_TYPE_SSID:{
struct obj_ssid *ssid = r->ptr;
return snprintf(str, PRIV_STR_SIZE,
......
......@@ -36,6 +36,8 @@ int channel_of_freq(int);
void mgt_le_to_cpu(int, void *);
int mgt_set_request(islpci_private *, enum oid_num_t, int, void *);
int mgt_set_varlen(islpci_private *, enum oid_num_t, void *, int);
int mgt_get_request(islpci_private *, enum oid_num_t, int, void *,
union oid_res_t *);
......@@ -46,7 +48,8 @@ void mgt_set(islpci_private *, enum oid_num_t, void *);
void mgt_get(islpci_private *, enum oid_num_t, void *);
void mgt_commit(islpci_private *);
int mgt_commit(islpci_private *);
void mgt_unlatch_all(islpci_private *);
int mgt_mlme_answer(islpci_private *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment