Merge branch 'upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6 into upstream

This commit is contained in:
Jeff Garzik 2006-07-29 00:33:35 -04:00
Родитель a47e920948 8f0f850e24
Коммит 7d2d8259a2
15 изменённых файлов: 777 добавлений и 128 удалений

Просмотреть файл

@ -2594,6 +2594,18 @@ P: Nicolas Pitre
M: nico@cam.org M: nico@cam.org
S: Maintained S: Maintained
SOFTMAC LAYER (IEEE 802.11)
P: Johannes Berg
M: johannes@sipsolutions.net
P: Joe Jezak
M: josejx@gentoo.org
P: Daniel Drake
M: dsd@gentoo.org
W: http://softmac.sipsolutions.net/
L: softmac-dev@sipsolutions.net
L: netdev@vger.kernel.org
S: Maintained
SOFTWARE RAID (Multiple Disks) SUPPORT SOFTWARE RAID (Multiple Disks) SUPPORT
P: Ingo Molnar P: Ingo Molnar
M: mingo@redhat.com M: mingo@redhat.com
@ -3302,6 +3314,15 @@ W: http://www.qsl.net/dl1bke/
L: linux-hams@vger.kernel.org L: linux-hams@vger.kernel.org
S: Maintained S: Maintained
ZD1211RW WIRELESS DRIVER
P: Daniel Drake
M: dsd@gentoo.org
P: Ulrich Kunitz
M: kune@deine-taler.de
W: http://zd1211.ath.cx/wiki/DriverRewrite
L: zd1211-devs@lists.sourceforge.net (subscribers-only)
S: Maintained
ZF MACHZ WATCHDOG ZF MACHZ WATCHDOG
P: Fernando Fuganti P: Fernando Fuganti
M: fuganti@netbank.com.br M: fuganti@netbank.com.br

Просмотреть файл

@ -3950,13 +3950,11 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
pRsp->rsp0 = IN4500(ai, RESP0); pRsp->rsp0 = IN4500(ai, RESP0);
pRsp->rsp1 = IN4500(ai, RESP1); pRsp->rsp1 = IN4500(ai, RESP1);
pRsp->rsp2 = IN4500(ai, RESP2); pRsp->rsp2 = IN4500(ai, RESP2);
if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) { if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET)
airo_print_err(ai->dev->name, "cmd= %x\n", pCmd->cmd); airo_print_err(ai->dev->name,
airo_print_err(ai->dev->name, "status= %x\n", pRsp->status); "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x",
airo_print_err(ai->dev->name, "Rsp0= %x\n", pRsp->rsp0); pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1,
airo_print_err(ai->dev->name, "Rsp1= %x\n", pRsp->rsp1); pRsp->rsp2);
airo_print_err(ai->dev->name, "Rsp2= %x\n", pRsp->rsp2);
}
// clear stuck command busy if necessary // clear stuck command busy if necessary
if (IN4500(ai, COMMAND) & COMMAND_BUSY) { if (IN4500(ai, COMMAND) & COMMAND_BUSY) {

Просмотреть файл

@ -2667,7 +2667,7 @@ static void ipw_fw_dma_abort(struct ipw_priv *priv)
IPW_DEBUG_FW(">> :\n"); IPW_DEBUG_FW(">> :\n");
//set the Stop and Abort bit /* set the Stop and Abort bit */
control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT; control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT;
ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control); ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
priv->sram_desc.last_cb_index = 0; priv->sram_desc.last_cb_index = 0;
@ -3002,8 +3002,6 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
if (rc < 0) if (rc < 0)
return rc; return rc;
// spin_lock_irqsave(&priv->lock, flags);
for (addr = IPW_SHARED_LOWER_BOUND; for (addr = IPW_SHARED_LOWER_BOUND;
addr < IPW_REGISTER_DOMAIN1_END; addr += 4) { addr < IPW_REGISTER_DOMAIN1_END; addr += 4) {
ipw_write32(priv, addr, 0); ipw_write32(priv, addr, 0);
@ -3097,8 +3095,6 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
firmware have problem getting alive resp. */ firmware have problem getting alive resp. */
ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0); ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
// spin_unlock_irqrestore(&priv->lock, flags);
return rc; return rc;
} }
@ -6387,13 +6383,6 @@ static int ipw_wx_set_genie(struct net_device *dev,
(wrqu->data.length && extra == NULL)) (wrqu->data.length && extra == NULL))
return -EINVAL; return -EINVAL;
//mutex_lock(&priv->mutex);
//if (!ieee->wpa_enabled) {
// err = -EOPNOTSUPP;
// goto out;
//}
if (wrqu->data.length) { if (wrqu->data.length) {
buf = kmalloc(wrqu->data.length, GFP_KERNEL); buf = kmalloc(wrqu->data.length, GFP_KERNEL);
if (buf == NULL) { if (buf == NULL) {
@ -6413,7 +6402,6 @@ static int ipw_wx_set_genie(struct net_device *dev,
ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
out: out:
//mutex_unlock(&priv->mutex);
return err; return err;
} }
@ -6426,13 +6414,6 @@ static int ipw_wx_get_genie(struct net_device *dev,
struct ieee80211_device *ieee = priv->ieee; struct ieee80211_device *ieee = priv->ieee;
int err = 0; int err = 0;
//mutex_lock(&priv->mutex);
//if (!ieee->wpa_enabled) {
// err = -EOPNOTSUPP;
// goto out;
//}
if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
wrqu->data.length = 0; wrqu->data.length = 0;
goto out; goto out;
@ -6447,7 +6428,6 @@ static int ipw_wx_get_genie(struct net_device *dev,
memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
out: out:
//mutex_unlock(&priv->mutex);
return err; return err;
} }
@ -6558,7 +6538,6 @@ static int ipw_wx_set_auth(struct net_device *dev,
ieee->ieee802_1x = param->value; ieee->ieee802_1x = param->value;
break; break;
//case IW_AUTH_ROAMING_CONTROL:
case IW_AUTH_PRIVACY_INVOKED: case IW_AUTH_PRIVACY_INVOKED:
ieee->privacy_invoked = param->value; ieee->privacy_invoked = param->value;
break; break;
@ -6680,7 +6659,7 @@ static int ipw_wx_set_mlme(struct net_device *dev,
switch (mlme->cmd) { switch (mlme->cmd) {
case IW_MLME_DEAUTH: case IW_MLME_DEAUTH:
// silently ignore /* silently ignore */
break; break;
case IW_MLME_DISASSOC: case IW_MLME_DISASSOC:
@ -9766,7 +9745,7 @@ static int ipw_wx_set_monitor(struct net_device *dev,
return 0; return 0;
} }
#endif // CONFIG_IPW2200_MONITOR #endif /* CONFIG_IPW2200_MONITOR */
static int ipw_wx_reset(struct net_device *dev, static int ipw_wx_reset(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
@ -10009,7 +9988,7 @@ static void init_sys_config(struct ipw_sys_config *sys_config)
sys_config->dot11g_auto_detection = 0; sys_config->dot11g_auto_detection = 0;
sys_config->enable_cts_to_self = 0; sys_config->enable_cts_to_self = 0;
sys_config->bt_coexist_collision_thr = 0; sys_config->bt_coexist_collision_thr = 0;
sys_config->pass_noise_stats_to_host = 1; //1 -- fix for 256 sys_config->pass_noise_stats_to_host = 1; /* 1 -- fix for 256 */
sys_config->silence_threshold = 0x1e; sys_config->silence_threshold = 0x1e;
} }

Просмотреть файл

@ -35,10 +35,14 @@
#include <net/iw_handler.h> /* New driver API */ #include <net/iw_handler.h> /* New driver API */
#define KEY_SIZE_WEP104 13 /* 104/128-bit WEP keys */
#define KEY_SIZE_WEP40 5 /* 40/64-bit WEP keys */
/* KEY_SIZE_TKIP should match isl_oid.h, struct obj_key.key[] size */
#define KEY_SIZE_TKIP 32 /* TKIP keys */
static void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, static void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
u8 *wpa_ie, size_t wpa_ie_len); u8 *wpa_ie, size_t wpa_ie_len);
static size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie); static size_t prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
static int prism54_set_wpa(struct net_device *, struct iw_request_info *, static int prism54_set_wpa(struct net_device *, struct iw_request_info *,
__u32 *, char *); __u32 *, char *);
@ -468,6 +472,9 @@ prism54_get_range(struct net_device *ndev, struct iw_request_info *info,
range->event_capa[1] = IW_EVENT_CAPA_K_1; range->event_capa[1] = IW_EVENT_CAPA_K_1;
range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM); range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM);
range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
IW_ENC_CAPA_CIPHER_TKIP;
if (islpci_get_state(priv) < PRV_STATE_INIT) if (islpci_get_state(priv) < PRV_STATE_INIT)
return 0; return 0;
@ -567,6 +574,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
struct iw_event iwe; /* Temporary buffer */ struct iw_event iwe; /* Temporary buffer */
short cap; short cap;
islpci_private *priv = netdev_priv(ndev); islpci_private *priv = netdev_priv(ndev);
u8 wpa_ie[MAX_WPA_IE_LEN];
size_t wpa_ie_len;
/* The first entry must be the MAC address */ /* The first entry must be the MAC address */
memcpy(iwe.u.ap_addr.sa_data, bss->address, 6); memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
@ -627,27 +636,13 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
current_ev = current_ev =
iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
if (priv->wpa) { /* Add WPA/RSN Information Element, if any */
u8 wpa_ie[MAX_WPA_IE_LEN]; wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
char *buf, *p; if (wpa_ie_len > 0) {
size_t wpa_ie_len; iwe.cmd = IWEVGENIE;
int i; iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN);
wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie);
if (wpa_ie_len > 0 &&
(buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) {
p = buf;
p += sprintf(p, "wpa_ie=");
for (i = 0; i < wpa_ie_len; i++) {
p += sprintf(p, "%02x", wpa_ie[i]);
}
memset(&iwe, 0, sizeof (iwe));
iwe.cmd = IWEVCUSTOM;
iwe.u.data.length = strlen(buf);
current_ev = iwe_stream_add_point(current_ev, end_buf, current_ev = iwe_stream_add_point(current_ev, end_buf,
&iwe, buf); &iwe, wpa_ie);
kfree(buf);
}
} }
return current_ev; return current_ev;
} }
@ -1051,12 +1046,24 @@ prism54_set_encode(struct net_device *ndev, struct iw_request_info *info,
current_index = r.u; current_index = r.u;
/* Verify that the key is not marked as invalid */ /* Verify that the key is not marked as invalid */
if (!(dwrq->flags & IW_ENCODE_NOKEY)) { if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
key.length = dwrq->length > sizeof (key.key) ? if (dwrq->length > KEY_SIZE_TKIP) {
sizeof (key.key) : dwrq->length; /* User-provided key data too big */
memcpy(key.key, extra, key.length); return -EINVAL;
if (key.length == 32) }
/* we want WPA-PSK */ if (dwrq->length > KEY_SIZE_WEP104) {
/* WPA-PSK TKIP */
key.type = DOT11_PRIV_TKIP; key.type = DOT11_PRIV_TKIP;
key.length = KEY_SIZE_TKIP;
} else if (dwrq->length > KEY_SIZE_WEP40) {
/* WEP 104/128 */
key.length = KEY_SIZE_WEP104;
} else {
/* WEP 40/64 */
key.length = KEY_SIZE_WEP40;
}
memset(key.key, 0, sizeof (key.key));
memcpy(key.key, extra, dwrq->length);
if ((index < 0) || (index > 3)) if ((index < 0) || (index > 3))
/* no index provided use the current one */ /* no index provided use the current one */
index = current_index; index = current_index;
@ -1210,6 +1217,489 @@ prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info,
} }
} }
static int prism54_set_genie(struct net_device *ndev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
{
islpci_private *priv = netdev_priv(ndev);
int alen, ret = 0;
struct obj_attachment *attach;
if (data->length > MAX_WPA_IE_LEN ||
(data->length && extra == NULL))
return -EINVAL;
memcpy(priv->wpa_ie, extra, data->length);
priv->wpa_ie_len = data->length;
alen = sizeof(*attach) + priv->wpa_ie_len;
attach = kzalloc(alen, GFP_KERNEL);
if (attach == NULL)
return -ENOMEM;
#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 = priv->wpa_ie_len;
memcpy(attach->data, extra, priv->wpa_ie_len);
ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
priv->wpa_ie_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,
priv->wpa_ie_len);
if (ret == 0)
printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
ndev->name);
}
kfree(attach);
return ret;
}
static int prism54_get_genie(struct net_device *ndev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
{
islpci_private *priv = netdev_priv(ndev);
int len = priv->wpa_ie_len;
if (len <= 0) {
data->length = 0;
return 0;
}
if (data->length < len)
return -E2BIG;
data->length = len;
memcpy(extra, priv->wpa_ie, len);
return 0;
}
static int prism54_set_auth(struct net_device *ndev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
islpci_private *priv = netdev_priv(ndev);
struct iw_param *param = &wrqu->param;
u32 mlmelevel = 0, authen = 0, dot1x = 0;
u32 exunencrypt = 0, privinvoked = 0, wpa = 0;
u32 old_wpa;
int ret = 0;
union oid_res_t r;
if (islpci_get_state(priv) < PRV_STATE_INIT)
return 0;
/* first get the flags */
down_write(&priv->mib_sem);
wpa = old_wpa = priv->wpa;
up_write(&priv->mib_sem);
ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
authen = r.u;
ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
privinvoked = r.u;
ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
exunencrypt = r.u;
ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
dot1x = r.u;
ret = mgt_get_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, NULL, &r);
mlmelevel = r.u;
if (ret < 0)
goto out;
switch (param->flags & IW_AUTH_INDEX) {
case IW_AUTH_CIPHER_PAIRWISE:
case IW_AUTH_CIPHER_GROUP:
case IW_AUTH_KEY_MGMT:
break;
case IW_AUTH_WPA_ENABLED:
/* Do the same thing as IW_AUTH_WPA_VERSION */
if (param->value) {
wpa = 1;
privinvoked = 1; /* For privacy invoked */
exunencrypt = 1; /* Filter out all unencrypted frames */
dot1x = 0x01; /* To enable eap filter */
mlmelevel = DOT11_MLME_EXTENDED;
authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
} else {
wpa = 0;
privinvoked = 0;
exunencrypt = 0; /* Do not filter un-encrypted data */
dot1x = 0;
mlmelevel = DOT11_MLME_AUTO;
}
break;
case IW_AUTH_WPA_VERSION:
if (param->value & IW_AUTH_WPA_VERSION_DISABLED) {
wpa = 0;
privinvoked = 0;
exunencrypt = 0; /* Do not filter un-encrypted data */
dot1x = 0;
mlmelevel = DOT11_MLME_AUTO;
} else {
if (param->value & IW_AUTH_WPA_VERSION_WPA)
wpa = 1;
else if (param->value & IW_AUTH_WPA_VERSION_WPA2)
wpa = 2;
privinvoked = 1; /* For privacy invoked */
exunencrypt = 1; /* Filter out all unencrypted frames */
dot1x = 0x01; /* To enable eap filter */
mlmelevel = DOT11_MLME_EXTENDED;
authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
}
break;
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
dot1x = param->value ? 1 : 0;
break;
case IW_AUTH_PRIVACY_INVOKED:
privinvoked = param->value ? 1 : 0;
case IW_AUTH_DROP_UNENCRYPTED:
exunencrypt = param->value ? 1 : 0;
break;
case IW_AUTH_80211_AUTH_ALG:
if (param->value & IW_AUTH_ALG_SHARED_KEY) {
/* Only WEP uses _SK and _BOTH */
if (wpa > 0) {
ret = -EINVAL;
goto out;
}
authen = DOT11_AUTH_SK;
} else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
authen = DOT11_AUTH_OS;
} else {
ret = -EINVAL;
goto out;
}
break;
default:
return -EOPNOTSUPP;
}
/* Set all the values */
down_write(&priv->mib_sem);
priv->wpa = wpa;
up_write(&priv->mib_sem);
mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &privinvoked);
mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &exunencrypt);
mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlmelevel);
out:
return ret;
}
static int prism54_get_auth(struct net_device *ndev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
islpci_private *priv = netdev_priv(ndev);
struct iw_param *param = &wrqu->param;
u32 wpa = 0;
int ret = 0;
union oid_res_t r;
if (islpci_get_state(priv) < PRV_STATE_INIT)
return 0;
/* first get the flags */
down_write(&priv->mib_sem);
wpa = priv->wpa;
up_write(&priv->mib_sem);
switch (param->flags & IW_AUTH_INDEX) {
case IW_AUTH_CIPHER_PAIRWISE:
case IW_AUTH_CIPHER_GROUP:
case IW_AUTH_KEY_MGMT:
/*
* wpa_supplicant will control these internally
*/
ret = -EOPNOTSUPP;
break;
case IW_AUTH_WPA_VERSION:
switch (wpa) {
case 1:
param->value = IW_AUTH_WPA_VERSION_WPA;
break;
case 2:
param->value = IW_AUTH_WPA_VERSION_WPA2;
break;
case 0:
default:
param->value = IW_AUTH_WPA_VERSION_DISABLED;
break;
}
break;
case IW_AUTH_DROP_UNENCRYPTED:
ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
if (ret >= 0)
param->value = r.u > 0 ? 1 : 0;
break;
case IW_AUTH_80211_AUTH_ALG:
ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
if (ret >= 0) {
switch (r.u) {
case DOT11_AUTH_OS:
param->value = IW_AUTH_ALG_OPEN_SYSTEM;
break;
case DOT11_AUTH_BOTH:
case DOT11_AUTH_SK:
param->value = IW_AUTH_ALG_SHARED_KEY;
case DOT11_AUTH_NONE:
default:
param->value = 0;
break;
}
}
break;
case IW_AUTH_WPA_ENABLED:
param->value = wpa > 0 ? 1 : 0;
break;
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
if (ret >= 0)
param->value = r.u > 0 ? 1 : 0;
break;
case IW_AUTH_PRIVACY_INVOKED:
ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
if (ret >= 0)
param->value = r.u > 0 ? 1 : 0;
break;
default:
return -EOPNOTSUPP;
}
return ret;
}
static int prism54_set_encodeext(struct net_device *ndev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
islpci_private *priv = netdev_priv(ndev);
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int idx, alg = ext->alg, set_key = 1;
union oid_res_t r;
int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
int ret = 0;
if (islpci_get_state(priv) < PRV_STATE_INIT)
return 0;
/* Determine and validate the key index */
idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
if (idx) {
if (idx < 0 || idx > 3)
return -EINVAL;
} else {
ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
if (ret < 0)
goto out;
idx = r.u;
}
if (encoding->flags & IW_ENCODE_DISABLED)
alg = IW_ENCODE_ALG_NONE;
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
/* Only set transmit key index here, actual
* key is set below if needed.
*/
ret = mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &idx);
set_key = ext->key_len > 0 ? 1 : 0;
}
if (set_key) {
struct obj_key key = { DOT11_PRIV_WEP, 0, "" };
switch (alg) {
case IW_ENCODE_ALG_NONE:
break;
case IW_ENCODE_ALG_WEP:
if (ext->key_len > KEY_SIZE_WEP104) {
ret = -EINVAL;
goto out;
}
if (ext->key_len > KEY_SIZE_WEP40)
key.length = KEY_SIZE_WEP104;
else
key.length = KEY_SIZE_WEP40;
break;
case IW_ENCODE_ALG_TKIP:
if (ext->key_len > KEY_SIZE_TKIP) {
ret = -EINVAL;
goto out;
}
key.type = DOT11_PRIV_TKIP;
key.length = KEY_SIZE_TKIP;
default:
return -EINVAL;
}
if (key.length) {
memset(key.key, 0, sizeof(key.key));
memcpy(key.key, ext->key, ext->key_len);
ret = mgt_set_request(priv, DOT11_OID_DEFKEYX, idx,
&key);
if (ret < 0)
goto out;
}
}
/* Read the flags */
if (encoding->flags & IW_ENCODE_DISABLED) {
/* Encoding disabled,
* authen = DOT11_AUTH_OS;
* invoke = 0;
* exunencrypt = 0; */
}
if (encoding->flags & IW_ENCODE_OPEN) {
/* Encode but accept non-encoded packets. No auth */
invoke = 1;
}
if (encoding->flags & IW_ENCODE_RESTRICTED) {
/* Refuse non-encoded packets. Auth */
authen = DOT11_AUTH_BOTH;
invoke = 1;
exunencrypt = 1;
}
/* do the change if requested */
if (encoding->flags & IW_ENCODE_MODE) {
ret = mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0,
&authen);
ret = mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0,
&invoke);
ret = mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
&exunencrypt);
}
out:
return ret;
}
static int prism54_get_encodeext(struct net_device *ndev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
islpci_private *priv = netdev_priv(ndev);
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int idx, max_key_len;
union oid_res_t r;
int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0;
int ret = 0;
if (islpci_get_state(priv) < PRV_STATE_INIT)
return 0;
/* first get the flags */
ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
authen = r.u;
ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
invoke = r.u;
ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
exunencrypt = r.u;
if (ret < 0)
goto out;
max_key_len = encoding->length - sizeof(*ext);
if (max_key_len < 0)
return -EINVAL;
idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
if (idx) {
if (idx < 0 || idx > 3)
return -EINVAL;
} else {
ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
if (ret < 0)
goto out;
idx = r.u;
}
encoding->flags = idx + 1;
memset(ext, 0, sizeof(*ext));
switch (authen) {
case DOT11_AUTH_BOTH:
case DOT11_AUTH_SK:
wrqu->encoding.flags |= IW_ENCODE_RESTRICTED;
case DOT11_AUTH_OS:
default:
wrqu->encoding.flags |= IW_ENCODE_OPEN;
break;
}
down_write(&priv->mib_sem);
wpa = priv->wpa;
up_write(&priv->mib_sem);
if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) {
/* No encryption */
ext->alg = IW_ENCODE_ALG_NONE;
ext->key_len = 0;
wrqu->encoding.flags |= IW_ENCODE_DISABLED;
} else {
struct obj_key *key;
ret = mgt_get_request(priv, DOT11_OID_DEFKEYX, idx, NULL, &r);
if (ret < 0)
goto out;
key = r.ptr;
if (max_key_len < key->length) {
ret = -E2BIG;
goto out;
}
memcpy(ext->key, key->key, key->length);
ext->key_len = key->length;
switch (key->type) {
case DOT11_PRIV_TKIP:
ext->alg = IW_ENCODE_ALG_TKIP;
break;
default:
case DOT11_PRIV_WEP:
ext->alg = IW_ENCODE_ALG_WEP;
break;
}
wrqu->encoding.flags |= IW_ENCODE_ENABLED;
}
out:
return ret;
}
static int static int
prism54_reset(struct net_device *ndev, struct iw_request_info *info, prism54_reset(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra) __u32 * uwrq, char *extra)
@ -1591,7 +2081,7 @@ static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
static void static void
prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
u8 *wpa_ie, size_t wpa_ie_len) u8 *wpa_ie, size_t wpa_ie_len)
{ {
struct list_head *ptr; struct list_head *ptr;
@ -1658,7 +2148,7 @@ prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
} }
static size_t static size_t
prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
{ {
struct list_head *ptr; struct list_head *ptr;
struct islpci_bss_wpa_ie *bss = NULL; struct islpci_bss_wpa_ie *bss = NULL;
@ -1683,14 +2173,14 @@ prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
} }
void void
prism54_wpa_ie_init(islpci_private *priv) prism54_wpa_bss_ie_init(islpci_private *priv)
{ {
INIT_LIST_HEAD(&priv->bss_wpa_list); INIT_LIST_HEAD(&priv->bss_wpa_list);
sema_init(&priv->wpa_sem, 1); sema_init(&priv->wpa_sem, 1);
} }
void void
prism54_wpa_ie_clean(islpci_private *priv) prism54_wpa_bss_ie_clean(islpci_private *priv)
{ {
struct list_head *ptr, *n; struct list_head *ptr, *n;
@ -1722,7 +2212,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
} }
if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
memcmp(pos + 2, wpa_oid, 4) == 0) { memcmp(pos + 2, wpa_oid, 4) == 0) {
prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2); prism54_wpa_bss_ie_add(priv, addr, pos, pos[1] + 2);
return; return;
} }
pos += 2 + pos[1]; pos += 2 + pos[1];
@ -1879,7 +2369,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
send_formatted_event(priv, "Associate request (ex)", mlme, 1); send_formatted_event(priv, "Associate request (ex)", mlme, 1);
if (priv->iw_mode != IW_MODE_MASTER if (priv->iw_mode != IW_MODE_MASTER
&& mlmeex->state != DOT11_STATE_AUTHING) && mlmeex->state != DOT11_STATE_ASSOCING)
break; break;
confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
@ -1893,7 +2383,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
confirm->state = 0; /* not used */ confirm->state = 0; /* not used */
confirm->code = 0; confirm->code = 0;
wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie); wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
if (!wpa_ie_len) { if (!wpa_ie_len) {
printk(KERN_DEBUG "No WPA IE found from " printk(KERN_DEBUG "No WPA IE found from "
@ -1937,7 +2427,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
confirm->state = 0; /* not used */ confirm->state = 0; /* not used */
confirm->code = 0; confirm->code = 0;
wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie); wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
if (!wpa_ie_len) { if (!wpa_ie_len) {
printk(KERN_DEBUG "No WPA IE found from " printk(KERN_DEBUG "No WPA IE found from "
@ -2553,6 +3043,15 @@ static const iw_handler prism54_handler[] = {
(iw_handler) prism54_get_encode, /* SIOCGIWENCODE */ (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */
(iw_handler) NULL, /* SIOCSIWPOWER */ (iw_handler) NULL, /* SIOCSIWPOWER */
(iw_handler) NULL, /* SIOCGIWPOWER */ (iw_handler) NULL, /* SIOCGIWPOWER */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
(iw_handler) prism54_set_genie, /* SIOCSIWGENIE */
(iw_handler) prism54_get_genie, /* SIOCGIWGENIE */
(iw_handler) prism54_set_auth, /* SIOCSIWAUTH */
(iw_handler) prism54_get_auth, /* SIOCGIWAUTH */
(iw_handler) prism54_set_encodeext, /* SIOCSIWENCODEEXT */
(iw_handler) prism54_get_encodeext, /* SIOCGIWENCODEEXT */
NULL, /* SIOCSIWPMKSA */
}; };
/* The low order bit identify a SET (0) or a GET (1) ioctl. */ /* The low order bit identify a SET (0) or a GET (1) ioctl. */

Просмотреть файл

@ -27,7 +27,7 @@
#include <net/iw_handler.h> /* New driver API */ #include <net/iw_handler.h> /* New driver API */
#define SUPPORTED_WIRELESS_EXT 16 #define SUPPORTED_WIRELESS_EXT 19
void prism54_mib_init(islpci_private *); void prism54_mib_init(islpci_private *);
@ -39,8 +39,8 @@ void prism54_acl_clean(struct islpci_acl *);
void prism54_process_trap(void *); void prism54_process_trap(void *);
void prism54_wpa_ie_init(islpci_private *priv); void prism54_wpa_bss_ie_init(islpci_private *priv);
void prism54_wpa_ie_clean(islpci_private *priv); void prism54_wpa_bss_ie_clean(islpci_private *priv);
int prism54_set_mac_address(struct net_device *, void *); int prism54_set_mac_address(struct net_device *, void *);

Просмотреть файл

@ -715,7 +715,7 @@ islpci_alloc_memory(islpci_private *priv)
} }
prism54_acl_init(&priv->acl); prism54_acl_init(&priv->acl);
prism54_wpa_ie_init(priv); prism54_wpa_bss_ie_init(priv);
if (mgt_init(priv)) if (mgt_init(priv))
goto out_free; goto out_free;
@ -774,7 +774,7 @@ islpci_free_memory(islpci_private *priv)
/* Free the acces control list and the WPA list */ /* Free the acces control list and the WPA list */
prism54_acl_clean(&priv->acl); prism54_acl_clean(&priv->acl);
prism54_wpa_ie_clean(priv); prism54_wpa_bss_ie_clean(priv);
mgt_clean(priv); mgt_clean(priv);
return 0; return 0;

Просмотреть файл

@ -179,6 +179,8 @@ typedef struct {
struct list_head bss_wpa_list; struct list_head bss_wpa_list;
int num_bss_wpa; int num_bss_wpa;
struct semaphore wpa_sem; struct semaphore wpa_sem;
u8 wpa_ie[MAX_WPA_IE_LEN];
size_t wpa_ie_len;
struct work_struct reset_task; struct work_struct reset_task;
int reset_task_pending; int reset_task_pending;

Просмотреть файл

@ -72,10 +72,18 @@ static int iw_get_name(struct net_device *netdev,
struct iw_request_info *info, struct iw_request_info *info,
union iwreq_data *req, char *extra) union iwreq_data *req, char *extra)
{ {
/* FIXME: check whether 802.11a will also supported, add also /* FIXME: check whether 802.11a will also supported */
* zd1211B, if we support it. strlcpy(req->name, "IEEE 802.11b/g", IFNAMSIZ);
*/ return 0;
strlcpy(req->name, "802.11g zd1211", IFNAMSIZ); }
static int iw_get_nick(struct net_device *netdev,
struct iw_request_info *info,
union iwreq_data *req, char *extra)
{
strcpy(extra, "zd1211");
req->data.length = strlen(extra) + 1;
req->data.flags = 1;
return 0; return 0;
} }
@ -181,6 +189,7 @@ static int iw_get_encodeext(struct net_device *netdev,
static const iw_handler zd_standard_iw_handlers[] = { static const iw_handler zd_standard_iw_handlers[] = {
WX(SIOCGIWNAME) = iw_get_name, WX(SIOCGIWNAME) = iw_get_name,
WX(SIOCGIWNICKN) = iw_get_nick,
WX(SIOCSIWFREQ) = iw_set_freq, WX(SIOCSIWFREQ) = iw_set_freq,
WX(SIOCGIWFREQ) = iw_get_freq, WX(SIOCGIWFREQ) = iw_get_freq,
WX(SIOCSIWMODE) = iw_set_mode, WX(SIOCSIWMODE) = iw_set_mode,

Просмотреть файл

@ -240,6 +240,11 @@ struct ieee80211_snap_hdr {
#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10) #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
#define WLAN_CAPABILITY_DSSS_OFDM (1<<13) #define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
/* 802.11g ERP information element */
#define WLAN_ERP_NON_ERP_PRESENT (1<<0)
#define WLAN_ERP_USE_PROTECTION (1<<1)
#define WLAN_ERP_BARKER_PREAMBLE (1<<2)
/* Status codes */ /* Status codes */
enum ieee80211_statuscode { enum ieee80211_statuscode {
WLAN_STATUS_SUCCESS = 0, WLAN_STATUS_SUCCESS = 0,
@ -747,6 +752,8 @@ struct ieee80211_txb {
#define NETWORK_HAS_IBSS_DFS (1<<8) #define NETWORK_HAS_IBSS_DFS (1<<8)
#define NETWORK_HAS_TPC_REPORT (1<<9) #define NETWORK_HAS_TPC_REPORT (1<<9)
#define NETWORK_HAS_ERP_VALUE (1<<10)
#define QOS_QUEUE_NUM 4 #define QOS_QUEUE_NUM 4
#define QOS_OUI_LEN 3 #define QOS_OUI_LEN 3
#define QOS_OUI_TYPE 2 #define QOS_OUI_TYPE 2
@ -1252,6 +1259,8 @@ extern int ieee80211_tx_frame(struct ieee80211_device *ieee,
int total_len, int encrypt_mpdu); int total_len, int encrypt_mpdu);
/* ieee80211_rx.c */ /* ieee80211_rx.c */
extern void ieee80211_rx_any(struct ieee80211_device *ieee,
struct sk_buff *skb, struct ieee80211_rx_stats *stats);
extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
struct ieee80211_rx_stats *rx_stats); struct ieee80211_rx_stats *rx_stats);
/* make sure to set stats->len */ /* make sure to set stats->len */

Просмотреть файл

@ -87,9 +87,6 @@ struct ieee80211softmac_assoc_info {
/* BSSID we're trying to associate to */ /* BSSID we're trying to associate to */
char bssid[ETH_ALEN]; char bssid[ETH_ALEN];
/* Rates supported by the network */
struct ieee80211softmac_ratesinfo supported_rates;
/* some flags. /* some flags.
* static_essid is valid if the essid is constant, * static_essid is valid if the essid is constant,
* this is for use by the wx handlers only. * this is for use by the wx handlers only.
@ -103,6 +100,7 @@ struct ieee80211softmac_assoc_info {
* bssfixed is used for SIOCSIWAP. * bssfixed is used for SIOCSIWAP.
*/ */
u8 static_essid:1, u8 static_essid:1,
short_preamble_available:1,
associating:1, associating:1,
assoc_wait:1, assoc_wait:1,
bssvalid:1, bssvalid:1,
@ -115,6 +113,19 @@ struct ieee80211softmac_assoc_info {
struct work_struct timeout; struct work_struct timeout;
}; };
struct ieee80211softmac_bss_info {
/* Rates supported by the network */
struct ieee80211softmac_ratesinfo supported_rates;
/* This indicates whether frames can currently be transmitted with
* short preamble (only use this variable during TX at CCK rates) */
u8 short_preamble:1;
/* This indicates whether protection (e.g. self-CTS) should be used
* when transmitting with OFDM modulation */
u8 use_protection:1;
};
enum { enum {
IEEE80211SOFTMAC_AUTH_OPEN_REQUEST = 1, IEEE80211SOFTMAC_AUTH_OPEN_REQUEST = 1,
IEEE80211SOFTMAC_AUTH_OPEN_RESPONSE = 2, IEEE80211SOFTMAC_AUTH_OPEN_RESPONSE = 2,
@ -157,6 +168,10 @@ struct ieee80211softmac_txrates {
#define IEEE80211SOFTMAC_TXRATECHG_MCAST (1 << 2) /* mcast_rate */ #define IEEE80211SOFTMAC_TXRATECHG_MCAST (1 << 2) /* mcast_rate */
#define IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST (1 << 3) /* mgt_mcast_rate */ #define IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST (1 << 3) /* mgt_mcast_rate */
#define IEEE80211SOFTMAC_BSSINFOCHG_RATES (1 << 0) /* supported_rates */
#define IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE (1 << 1) /* short_preamble */
#define IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION (1 << 2) /* use_protection */
struct ieee80211softmac_device { struct ieee80211softmac_device {
/* 802.11 structure for data stuff */ /* 802.11 structure for data stuff */
struct ieee80211_device *ieee; struct ieee80211_device *ieee;
@ -200,10 +215,16 @@ struct ieee80211softmac_device {
* The driver just needs to read them. * The driver just needs to read them.
*/ */
struct ieee80211softmac_txrates txrates; struct ieee80211softmac_txrates txrates;
/* If the driver needs to do stuff on TX rate changes, assign this callback. */
/* If the driver needs to do stuff on TX rate changes, assign this
* callback. See IEEE80211SOFTMAC_TXRATECHG for change flags. */
void (*txrates_change)(struct net_device *dev, void (*txrates_change)(struct net_device *dev,
u32 changes, /* see IEEE80211SOFTMAC_TXRATECHG flags */ u32 changes);
const struct ieee80211softmac_txrates *rates_before_change);
/* If the driver needs to do stuff when BSS properties change, assign
* this callback. see IEEE80211SOFTMAC_BSSINFOCHG for change flags. */
void (*bssinfo_change)(struct net_device *dev,
u32 changes);
/* private stuff follows */ /* private stuff follows */
/* this lock protects this structure */ /* this lock protects this structure */
@ -216,6 +237,7 @@ struct ieee80211softmac_device {
struct ieee80211softmac_scaninfo *scaninfo; struct ieee80211softmac_scaninfo *scaninfo;
struct ieee80211softmac_assoc_info associnfo; struct ieee80211softmac_assoc_info associnfo;
struct ieee80211softmac_bss_info bssinfo;
struct list_head auth_queue; struct list_head auth_queue;
struct list_head events; struct list_head events;
@ -257,6 +279,14 @@ extern void ieee80211softmac_fragment_lost(struct net_device *dev,
* Note that the rates need to be sorted. */ * Note that the rates need to be sorted. */
extern void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates); extern void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates);
/* Finds the highest rate which is:
* 1. Present in ri (optionally a basic rate)
* 2. Supported by the device
* 3. Less than or equal to the user-defined rate
*/
extern u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
struct ieee80211softmac_ratesinfo *ri, int basic_only);
/* Helper function which advises you the rate at which a frame should be /* Helper function which advises you the rate at which a frame should be
* transmitted at. */ * transmitted at. */
static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device *mac, static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device *mac,
@ -279,6 +309,24 @@ static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device
return txrates->mcast_rate; return txrates->mcast_rate;
} }
/* Helper function which advises you when it is safe to transmit with short
* preamble.
* You should only call this function when transmitting at CCK rates. */
static inline int ieee80211softmac_short_preamble_ok(struct ieee80211softmac_device *mac,
int is_multicast,
int is_mgt)
{
return (is_multicast && is_mgt) ? 0 : mac->bssinfo.short_preamble;
}
/* Helper function which advises you whether protection (e.g. self-CTS) is
* needed. 1 = protection needed, 0 = no protection needed
* Only use this function when transmitting with OFDM modulation. */
static inline int ieee80211softmac_protection_needed(struct ieee80211softmac_device *mac)
{
return mac->bssinfo.use_protection;
}
/* Start the SoftMAC. Call this after you initialized the device /* Start the SoftMAC. Call this after you initialized the device
* and it is ready to run. * and it is ready to run.
*/ */

Просмотреть файл

@ -779,33 +779,44 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
return 0; return 0;
} }
/* Filter out unrelated packets, call ieee80211_rx[_mgt] */ /* Filter out unrelated packets, call ieee80211_rx[_mgt]
int ieee80211_rx_any(struct ieee80211_device *ieee, * This function takes over the skb, it should not be used again after calling
* this function. */
void ieee80211_rx_any(struct ieee80211_device *ieee,
struct sk_buff *skb, struct ieee80211_rx_stats *stats) struct sk_buff *skb, struct ieee80211_rx_stats *stats)
{ {
struct ieee80211_hdr_4addr *hdr; struct ieee80211_hdr_4addr *hdr;
int is_packet_for_us; int is_packet_for_us;
u16 fc; u16 fc;
if (ieee->iw_mode == IW_MODE_MONITOR) if (ieee->iw_mode == IW_MODE_MONITOR) {
return ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL; if (!ieee80211_rx(ieee, skb, stats))
dev_kfree_skb_irq(skb);
return;
}
if (skb->len < sizeof(struct ieee80211_hdr))
goto drop_free;
hdr = (struct ieee80211_hdr_4addr *)skb->data; hdr = (struct ieee80211_hdr_4addr *)skb->data;
fc = le16_to_cpu(hdr->frame_ctl); fc = le16_to_cpu(hdr->frame_ctl);
if ((fc & IEEE80211_FCTL_VERS) != 0) if ((fc & IEEE80211_FCTL_VERS) != 0)
return -EINVAL; goto drop_free;
switch (fc & IEEE80211_FCTL_FTYPE) { switch (fc & IEEE80211_FCTL_FTYPE) {
case IEEE80211_FTYPE_MGMT: case IEEE80211_FTYPE_MGMT:
if (skb->len < sizeof(struct ieee80211_hdr_3addr))
goto drop_free;
ieee80211_rx_mgt(ieee, hdr, stats); ieee80211_rx_mgt(ieee, hdr, stats);
return 0; dev_kfree_skb_irq(skb);
return;
case IEEE80211_FTYPE_DATA: case IEEE80211_FTYPE_DATA:
break; break;
case IEEE80211_FTYPE_CTL: case IEEE80211_FTYPE_CTL:
return 0; return;
default: default:
return -EINVAL; return;
} }
is_packet_for_us = 0; is_packet_for_us = 0;
@ -849,8 +860,14 @@ int ieee80211_rx_any(struct ieee80211_device *ieee,
} }
if (is_packet_for_us) if (is_packet_for_us)
return (ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL); if (!ieee80211_rx(ieee, skb, stats))
return 0; dev_kfree_skb_irq(skb);
return;
drop_free:
dev_kfree_skb_irq(skb);
ieee->stats.rx_dropped++;
return;
} }
#define MGMT_FRAME_FIXED_PART_LENGTH 0x24 #define MGMT_FRAME_FIXED_PART_LENGTH 0x24
@ -1166,6 +1183,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
case MFIE_TYPE_ERP_INFO: case MFIE_TYPE_ERP_INFO:
network->erp_value = info_element->data[0]; network->erp_value = info_element->data[0];
network->flags |= NETWORK_HAS_ERP_VALUE;
IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n", IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
network->erp_value); network->erp_value);
break; break;
@ -1729,5 +1747,6 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
} }
} }
EXPORT_SYMBOL_GPL(ieee80211_rx_any);
EXPORT_SYMBOL(ieee80211_rx_mgt); EXPORT_SYMBOL(ieee80211_rx_mgt);
EXPORT_SYMBOL(ieee80211_rx); EXPORT_SYMBOL(ieee80211_rx);

Просмотреть файл

@ -96,7 +96,7 @@ ieee80211softmac_disassoc(struct ieee80211softmac_device *mac)
mac->associated = 0; mac->associated = 0;
mac->associnfo.bssvalid = 0; mac->associnfo.bssvalid = 0;
mac->associnfo.associating = 0; mac->associnfo.associating = 0;
ieee80211softmac_init_txrates(mac); ieee80211softmac_init_bss(mac);
ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL); ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
spin_unlock_irqrestore(&mac->lock, flags); spin_unlock_irqrestore(&mac->lock, flags);
} }
@ -334,11 +334,19 @@ ieee80211softmac_associated(struct ieee80211softmac_device *mac,
struct ieee80211_assoc_response * resp, struct ieee80211_assoc_response * resp,
struct ieee80211softmac_network *net) struct ieee80211softmac_network *net)
{ {
u16 cap = le16_to_cpu(resp->capability);
u8 erp_value = net->erp_value;
mac->associnfo.associating = 0; mac->associnfo.associating = 0;
mac->associnfo.supported_rates = net->supported_rates; mac->bssinfo.supported_rates = net->supported_rates;
ieee80211softmac_recalc_txrates(mac); ieee80211softmac_recalc_txrates(mac);
mac->associated = 1; mac->associated = 1;
mac->associnfo.short_preamble_available =
(cap & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0;
ieee80211softmac_process_erp(mac, erp_value);
if (mac->set_bssid_filter) if (mac->set_bssid_filter)
mac->set_bssid_filter(mac->dev, net->bssid); mac->set_bssid_filter(mac->dev, net->bssid);
memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN); memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
@ -351,9 +359,9 @@ ieee80211softmac_associated(struct ieee80211softmac_device *mac,
int int
ieee80211softmac_handle_assoc_response(struct net_device * dev, ieee80211softmac_handle_assoc_response(struct net_device * dev,
struct ieee80211_assoc_response * resp, struct ieee80211_assoc_response * resp,
struct ieee80211_network * _ieee80211_network_do_not_use) struct ieee80211_network * _ieee80211_network)
{ {
/* NOTE: the network parameter has to be ignored by /* NOTE: the network parameter has to be mostly ignored by
* this code because it is the ieee80211's pointer * this code because it is the ieee80211's pointer
* to the struct, not ours (we made a copy) * to the struct, not ours (we made a copy)
*/ */
@ -385,6 +393,11 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev,
/* now that we know it was for us, we can cancel the timeout */ /* now that we know it was for us, we can cancel the timeout */
cancel_delayed_work(&mac->associnfo.timeout); cancel_delayed_work(&mac->associnfo.timeout);
/* if the association response included an ERP IE, update our saved
* copy */
if (_ieee80211_network->flags & NETWORK_HAS_ERP_VALUE)
network->erp_value = _ieee80211_network->erp_value;
switch (status) { switch (status) {
case 0: case 0:
dprintk(KERN_INFO PFX "associated!\n"); dprintk(KERN_INFO PFX "associated!\n");

Просмотреть файл

@ -467,3 +467,17 @@ ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
kfree(pkt); kfree(pkt);
return 0; return 0;
} }
/* Beacon handling */
int ieee80211softmac_handle_beacon(struct net_device *dev,
struct ieee80211_beacon *beacon,
struct ieee80211_network *network)
{
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
if (mac->associated && memcmp(network->bssid, mac->associnfo.bssid, ETH_ALEN) == 0)
ieee80211softmac_process_erp(mac, network->erp_value);
return 0;
}

Просмотреть файл

@ -44,6 +44,7 @@ struct net_device *alloc_ieee80211softmac(int sizeof_priv)
softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response; softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req; softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc; softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
softmac->ieee->handle_beacon = ieee80211softmac_handle_beacon;
softmac->scaninfo = NULL; softmac->scaninfo = NULL;
softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT; softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
@ -178,21 +179,14 @@ int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo
return 0; return 0;
} }
/* Finds the highest rate which is: u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
* 1. Present in ri (optionally a basic rate)
* 2. Supported by the device
* 3. Less than or equal to the user-defined rate
*/
static u8 highest_supported_rate(struct ieee80211softmac_device *mac,
struct ieee80211softmac_ratesinfo *ri, int basic_only) struct ieee80211softmac_ratesinfo *ri, int basic_only)
{ {
u8 user_rate = mac->txrates.user_rate; u8 user_rate = mac->txrates.user_rate;
int i; int i;
if (ri->count == 0) { if (ri->count == 0)
dprintk(KERN_ERR PFX "empty ratesinfo?\n");
return IEEE80211_CCK_RATE_1MB; return IEEE80211_CCK_RATE_1MB;
}
for (i = ri->count - 1; i >= 0; i--) { for (i = ri->count - 1; i >= 0; i--) {
u8 rate = ri->rates[i]; u8 rate = ri->rates[i];
@ -208,36 +202,61 @@ static u8 highest_supported_rate(struct ieee80211softmac_device *mac,
/* If we haven't found a suitable rate by now, just trust the user */ /* If we haven't found a suitable rate by now, just trust the user */
return user_rate; return user_rate;
} }
EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate);
void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
u8 erp_value)
{
int use_protection;
int short_preamble;
u32 changes = 0;
/* Barker preamble mode */
short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0
&& mac->associnfo.short_preamble_available) ? 1 : 0;
/* Protection needed? */
use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
if (mac->bssinfo.short_preamble != short_preamble) {
changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
mac->bssinfo.short_preamble = short_preamble;
}
if (mac->bssinfo.use_protection != use_protection) {
changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
mac->bssinfo.use_protection = use_protection;
}
if (mac->bssinfo_change && changes)
mac->bssinfo_change(mac->dev, changes);
}
void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac) void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
{ {
struct ieee80211softmac_txrates *txrates = &mac->txrates; struct ieee80211softmac_txrates *txrates = &mac->txrates;
struct ieee80211softmac_txrates oldrates;
u32 change = 0; u32 change = 0;
if (mac->txrates_change)
oldrates = mac->txrates;
change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
txrates->default_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 0); txrates->default_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0);
change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
txrates->default_fallback = lower_rate(mac, txrates->default_rate); txrates->default_fallback = lower_rate(mac, txrates->default_rate);
change |= IEEE80211SOFTMAC_TXRATECHG_MCAST; change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
txrates->mcast_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 1); txrates->mcast_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1);
if (mac->txrates_change) if (mac->txrates_change)
mac->txrates_change(mac->dev, change, &oldrates); mac->txrates_change(mac->dev, change);
} }
void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac) void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac)
{ {
struct ieee80211_device *ieee = mac->ieee; struct ieee80211_device *ieee = mac->ieee;
u32 change = 0; u32 change = 0;
struct ieee80211softmac_txrates *txrates = &mac->txrates; struct ieee80211softmac_txrates *txrates = &mac->txrates;
struct ieee80211softmac_txrates oldrates; struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo;
/* TODO: We need some kind of state machine to lower the default rates /* TODO: We need some kind of state machine to lower the default rates
* if we loose too many packets. * if we loose too many packets.
@ -245,8 +264,6 @@ void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac)
/* Change the default txrate to the highest possible value. /* Change the default txrate to the highest possible value.
* The txrate machine will lower it, if it is too high. * The txrate machine will lower it, if it is too high.
*/ */
if (mac->txrates_change)
oldrates = mac->txrates;
/* FIXME: We don't correctly handle backing down to lower /* FIXME: We don't correctly handle backing down to lower
rates, so 801.11g devices start off at 11M for now. People rates, so 801.11g devices start off at 11M for now. People
can manually change it if they really need to, but 11M is can manually change it if they really need to, but 11M is
@ -272,7 +289,23 @@ void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac)
change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST; change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
if (mac->txrates_change) if (mac->txrates_change)
mac->txrates_change(mac->dev, change, &oldrates); mac->txrates_change(mac->dev, change);
change = 0;
bssinfo->supported_rates.count = 0;
memset(bssinfo->supported_rates.rates, 0,
sizeof(bssinfo->supported_rates.rates));
change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES;
bssinfo->short_preamble = 0;
change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
bssinfo->use_protection = 0;
change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
if (mac->bssinfo_change)
mac->bssinfo_change(mac->dev, change);
mac->running = 1; mac->running = 1;
} }
@ -282,7 +315,7 @@ void ieee80211softmac_start(struct net_device *dev)
struct ieee80211softmac_device *mac = ieee80211_priv(dev); struct ieee80211softmac_device *mac = ieee80211_priv(dev);
ieee80211softmac_start_check_rates(mac); ieee80211softmac_start_check_rates(mac);
ieee80211softmac_init_txrates(mac); ieee80211softmac_init_bss(mac);
} }
EXPORT_SYMBOL_GPL(ieee80211softmac_start); EXPORT_SYMBOL_GPL(ieee80211softmac_start);
@ -335,7 +368,6 @@ u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rat
static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac, static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
int amount) int amount)
{ {
struct ieee80211softmac_txrates oldrates;
u8 default_rate = mac->txrates.default_rate; u8 default_rate = mac->txrates.default_rate;
u8 default_fallback = mac->txrates.default_fallback; u8 default_fallback = mac->txrates.default_fallback;
u32 changes = 0; u32 changes = 0;
@ -348,8 +380,6 @@ printk("badness %d\n", mac->txrate_badness);
mac->txrate_badness += amount; mac->txrate_badness += amount;
if (mac->txrate_badness <= -1000) { if (mac->txrate_badness <= -1000) {
/* Very small badness. Try a faster bitrate. */ /* Very small badness. Try a faster bitrate. */
if (mac->txrates_change)
memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
default_rate = raise_rate(mac, default_rate); default_rate = raise_rate(mac, default_rate);
changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
default_fallback = get_fallback_rate(mac, default_rate); default_fallback = get_fallback_rate(mac, default_rate);
@ -358,8 +388,6 @@ printk("badness %d\n", mac->txrate_badness);
printk("Bitrate raised to %u\n", default_rate); printk("Bitrate raised to %u\n", default_rate);
} else if (mac->txrate_badness >= 10000) { } else if (mac->txrate_badness >= 10000) {
/* Very high badness. Try a slower bitrate. */ /* Very high badness. Try a slower bitrate. */
if (mac->txrates_change)
memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
default_rate = lower_rate(mac, default_rate); default_rate = lower_rate(mac, default_rate);
changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
default_fallback = get_fallback_rate(mac, default_rate); default_fallback = get_fallback_rate(mac, default_rate);
@ -372,7 +400,7 @@ printk("Bitrate lowered to %u\n", default_rate);
mac->txrates.default_fallback = default_fallback; mac->txrates.default_fallback = default_fallback;
if (changes && mac->txrates_change) if (changes && mac->txrates_change)
mac->txrates_change(mac->dev, changes, &oldrates); mac->txrates_change(mac->dev, changes);
} }
void ieee80211softmac_fragment_lost(struct net_device *dev, void ieee80211softmac_fragment_lost(struct net_device *dev,
@ -417,6 +445,10 @@ ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
softnet->supported_rates.count += net->rates_ex_len; softnet->supported_rates.count += net->rates_ex_len;
sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL); sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
/* we save the ERP value because it is needed at association time, and
* many AP's do not include an ERP IE in the association response. */
softnet->erp_value = net->erp_value;
softnet->capabilities = net->capability; softnet->capabilities = net->capability;
return softnet; return softnet;
} }

Просмотреть файл

@ -116,9 +116,11 @@ ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
struct ieee80211softmac_essid *essid); struct ieee80211softmac_essid *essid);
/* Rates related */ /* Rates related */
void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
u8 erp_value);
int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate); int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate);
u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta); u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac); void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac);
void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac); void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac);
static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) { static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
return ieee80211softmac_lower_rate_delta(mac, rate, 1); return ieee80211softmac_lower_rate_delta(mac, rate, 1);
@ -133,6 +135,9 @@ static inline u8 get_fallback_rate(struct ieee80211softmac_device *mac, u8 rate)
/*** prototypes from _io.c */ /*** prototypes from _io.c */
int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac, int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
void* ptrarg, u32 type, u32 arg); void* ptrarg, u32 type, u32 arg);
int ieee80211softmac_handle_beacon(struct net_device *dev,
struct ieee80211_beacon *beacon,
struct ieee80211_network *network);
/*** prototypes from _auth.c */ /*** prototypes from _auth.c */
/* do these have to go into the public header? */ /* do these have to go into the public header? */
@ -189,6 +194,7 @@ struct ieee80211softmac_network {
authenticated:1, authenticated:1,
auth_desynced_once:1; auth_desynced_once:1;
u8 erp_value; /* Saved ERP value */
u16 capabilities; /* Capabilities bitfield */ u16 capabilities; /* Capabilities bitfield */
u8 challenge_len; /* Auth Challenge length */ u8 challenge_len; /* Auth Challenge length */
char *challenge; /* Challenge Text */ char *challenge; /* Challenge Text */