* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.1.2.3 2002/02/07 15:12:37 ambrisko Exp $
- * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.10 2006/04/02 03:33:59 sephe Exp $
+ * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.18.2.9 2006/03/07 17:50:23 sam Exp $
+ * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.11 2006/05/18 13:51:45 sephe Exp $
*/
/*-
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
+#include <net/if_media.h>
#include <net/route.h>
+
#include <netproto/802_11/ieee80211.h>
#include <netproto/802_11/ieee80211_crypto.h>
#include <netproto/802_11/ieee80211_ioctl.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <stdarg.h>
#include "ifconfig.h"
u_int8_t *buf, int *lenp);
static void print_string(const u_int8_t *buf, int len);
+static int
+isanyarg(const char *arg)
+{
+ return (strcmp(arg, "-") == 0 ||
+ strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0);
+}
+
static void
-set80211ssid(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
{
int ssid;
int len;
- u_int8_t data[33];
+ u_int8_t data[IEEE80211_NWID_LEN];
ssid = 0;
len = strlen(val);
bzero(data, sizeof(data));
len = sizeof(data);
- get_string(val, NULL, data, &len);
+ if (get_string(val, NULL, data, &len) == NULL)
+ exit(1);
set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
}
static void
-set80211stationname(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
{
int len;
u_int8_t data[33];
set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
}
+/*
+ * Convert IEEE channel number to MHz frequency.
+ */
+static u_int
+ieee80211_ieee2mhz(u_int chan)
+{
+ if (chan == 14)
+ return 2484;
+ if (chan < 14) /* 0-13 */
+ return 2407 + chan*5;
+ if (chan < 27) /* 15-26 */
+ return 2512 + ((chan-15)*20);
+ return 5000 + (chan*5);
+}
+
+/*
+ * Convert MHz frequency to IEEE channel number.
+ */
+static u_int
+ieee80211_mhz2ieee(u_int freq)
+{
+ if (freq == 2484)
+ return 14;
+ if (freq < 2484)
+ return (freq - 2407) / 5;
+ if (freq < 5000)
+ return 15 + ((freq - 2512) / 20);
+ return (freq - 5000) / 5;
+}
+
static void
-set80211channel(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
{
- if (strcmp(val, "-") == 0)
+ if (!isanyarg(val)) {
+ int v = atoi(val);
+ if (v > 255) /* treat as frequency */
+ v = ieee80211_mhz2ieee(v);
+ set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL);
+ } else
set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
- else
- set80211(s, IEEE80211_IOC_CHANNEL, atoi(val), 0, NULL);
}
static void
-set80211authmode(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
{
int mode;
mode = IEEE80211_AUTH_OPEN;
} else if (strcasecmp(val, "shared") == 0) {
mode = IEEE80211_AUTH_SHARED;
+ } else if (strcasecmp(val, "8021x") == 0) {
+ mode = IEEE80211_AUTH_8021X;
+ } else if (strcasecmp(val, "wpa") == 0) {
+ mode = IEEE80211_AUTH_WPA;
} else {
- err(1, "unknown authmode");
+ errx(1, "unknown authmode");
}
set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
}
static void
-set80211powersavemode(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
{
int mode;
} else if (strcasecmp(val, "psp-cam") == 0) {
mode = IEEE80211_POWERSAVE_PSP_CAM;
} else {
- err(1, "unknown powersavemode");
+ errx(1, "unknown powersavemode");
}
set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
}
static void
-set80211powersave(const char *val __unused, int d, int s,
- const struct afswtch *rafp __unused)
+set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
{
if (d == 0)
set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
}
static void
-set80211powersavesleep(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
{
set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
}
static void
-set80211wepmode(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
{
int mode;
} else if (strcasecmp(val, "mixed") == 0) {
mode = IEEE80211_WEP_MIXED;
} else {
- err(1, "unknown wep mode");
+ errx(1, "unknown wep mode");
}
set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
}
static void
-set80211wep(const char *val __unused, int d, int s,
- const struct afswtch *rafp __unused)
+set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
{
set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
}
+static int
+isundefarg(const char *arg)
+{
+ return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0);
+}
+
static void
-set80211weptxkey(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
{
- set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
+ if (isundefarg(val))
+ set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL);
+ else
+ set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
}
static void
-set80211wepkey(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
{
int key = 0;
int len;
}
/*
- * This function is purly a NetBSD compatability interface. The NetBSD
- * iterface is too inflexable, but it's there so we'll support it since
+ * This function is purely a NetBSD compatability interface. The NetBSD
+ * interface is too inflexible, but it's there so we'll support it since
* it's not all that hard.
*/
static void
-set80211nwkey(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
{
int txkey;
int i, len;
bzero(data, sizeof(data));
len = sizeof(data);
val = get_string(val, ",", data, &len);
+ if (val == NULL)
+ exit(1);
set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
}
}
static void
-set80211rtsthreshold(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
{
- set80211(s, IEEE80211_IOC_RTSTHRESHOLD, atoi(val), 0, NULL);
+ set80211(s, IEEE80211_IOC_RTSTHRESHOLD,
+ isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL);
}
static void
-set80211protmode(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
{
int mode;
} else if (strcasecmp(val, "rtscts") == 0) {
mode = IEEE80211_PROTMODE_RTSCTS;
} else {
- err(1, "unknown protection mode");
+ errx(1, "unknown protection mode");
}
set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
}
static void
-set80211txpower(const char *val, int d __unused, int s,
- const struct afswtch *rafp __unused)
+set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
{
set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
}
+#define IEEE80211_ROAMING_DEVICE 0
+#define IEEE80211_ROAMING_AUTO 1
+#define IEEE80211_ROAMING_MANUAL 2
+
static void
-ieee80211_status (int s)
+set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
{
- int i;
- int num;
- struct ieee80211req ireq;
- u_int8_t data[32];
- char spacer;
+ int mode;
+
+ if (strcasecmp(val, "device") == 0) {
+ mode = IEEE80211_ROAMING_DEVICE;
+ } else if (strcasecmp(val, "auto") == 0) {
+ mode = IEEE80211_ROAMING_AUTO;
+ } else if (strcasecmp(val, "manual") == 0) {
+ mode = IEEE80211_ROAMING_MANUAL;
+ } else {
+ errx(1, "unknown roaming mode");
+ }
+ set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
+}
- memset(&ireq, 0, sizeof(ireq));
- strncpy(ireq.i_name, name, sizeof(ireq.i_name));
- ireq.i_data = &data;
+static void
+set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
+}
- ireq.i_type = IEEE80211_IOC_SSID;
- ireq.i_val = -1;
- if (ioctl(s, SIOCG80211, &ireq) < 0) {
- /* If we can't get the SSID, the this isn't an 802.11 device. */
- return;
- }
- printf("\tssid ");
- print_string(data, ireq.i_len);
- num = 0;
- ireq.i_type = IEEE80211_IOC_NUMSSIDS;
- if (ioctl(s, SIOCG80211, &ireq) >= 0) {
- num = ireq.i_val;
- }
- ireq.i_type = IEEE80211_IOC_SSID;
- for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
- if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
- printf(" %d:", ireq.i_val + 1);
- print_string(data, ireq.i_len);
+static void
+set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
+}
+
+static void
+set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
+}
+
+static void
+set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ struct ieee80211req_chanlist chanlist;
+#define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY)
+ char *temp, *cp, *tp;
+
+ temp = malloc(strlen(val) + 1);
+ if (temp == NULL)
+ errx(1, "malloc failed");
+ strcpy(temp, val);
+ memset(&chanlist, 0, sizeof(chanlist));
+ cp = temp;
+ for (;;) {
+ int first, last, f;
+
+ tp = strchr(cp, ',');
+ if (tp != NULL)
+ *tp++ = '\0';
+ switch (sscanf(cp, "%u-%u", &first, &last)) {
+ case 1:
+ if (first > MAXCHAN)
+ errx(-1, "channel %u out of range, max %zu",
+ first, MAXCHAN);
+ setbit(chanlist.ic_channels, first);
+ break;
+ case 2:
+ if (first > MAXCHAN)
+ errx(-1, "channel %u out of range, max %zu",
+ first, MAXCHAN);
+ if (last > MAXCHAN)
+ errx(-1, "channel %u out of range, max %zu",
+ last, MAXCHAN);
+ if (first > last)
+ errx(-1, "void channel range, %u > %u",
+ first, last);
+ for (f = first; f <= last; f++)
+ setbit(chanlist.ic_channels, f);
+ break;
}
+ if (tp == NULL)
+ break;
+ while (isspace(*tp))
+ tp++;
+ if (!isdigit(*tp))
+ break;
+ cp = tp;
}
- printf("\n");
+ set80211(s, IEEE80211_IOC_CHANLIST, 0,
+ sizeof(chanlist), (uint8_t *) &chanlist);
+#undef MAXCHAN
+}
- ireq.i_type = IEEE80211_IOC_STATIONNAME;
- if (ioctl(s, SIOCG80211, &ireq) != -1) {
- printf("\tstationname ");
- print_string(data, ireq.i_len);
- printf("\n");
+static void
+set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
+{
+
+ if (!isanyarg(val)) {
+ char *temp;
+ struct sockaddr_dl sdl;
+
+ temp = malloc(strlen(val) + 2); /* ':' and '\0' */
+ if (temp == NULL)
+ errx(1, "malloc failed");
+ temp[0] = ':';
+ strcpy(temp + 1, val);
+ sdl.sdl_len = sizeof(sdl);
+ link_addr(temp, &sdl);
+ free(temp);
+ if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
+ errx(1, "malformed link-level address");
+ set80211(s, IEEE80211_IOC_BSSID, 0,
+ IEEE80211_ADDR_LEN, LLADDR(&sdl));
+ } else {
+ uint8_t zerobssid[IEEE80211_ADDR_LEN];
+ memset(zerobssid, 0, sizeof(zerobssid));
+ set80211(s, IEEE80211_IOC_BSSID, 0,
+ IEEE80211_ADDR_LEN, zerobssid);
}
+}
- ireq.i_type = IEEE80211_IOC_CHANNEL;
- if (ioctl(s, SIOCG80211, &ireq) < 0) {
- goto end;
+static int
+getac(const char *ac)
+{
+ if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0)
+ return WME_AC_BE;
+ if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0)
+ return WME_AC_BK;
+ if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0)
+ return WME_AC_VI;
+ if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0)
+ return WME_AC_VO;
+ errx(1, "unknown wme access class %s", ac);
+}
+
+static
+DECL_CMD_FUNC2(set80211cwmin, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211cwmax, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211aifs, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211txoplimit, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211acm, ac, d)
+{
+ set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
+}
+static
+DECL_CMD_FUNC(set80211noacm, ac, d)
+{
+ set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211ackpolicy, ac, d)
+{
+ set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
+}
+static
+DECL_CMD_FUNC(set80211noackpolicy, ac, d)
+{
+ set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
+ getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
+ getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bssaifs, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
+ getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
+ getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211dtimperiod, val, d)
+{
+ set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211bintval, val, d)
+{
+ set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
+}
+
+static void
+set80211macmac(int s, int op, const char *val)
+{
+ char *temp;
+ struct sockaddr_dl sdl;
+
+ temp = malloc(strlen(val) + 2); /* ':' and '\0' */
+ if (temp == NULL)
+ errx(1, "malloc failed");
+ temp[0] = ':';
+ strcpy(temp + 1, val);
+ sdl.sdl_len = sizeof(sdl);
+ link_addr(temp, &sdl);
+ free(temp);
+ if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
+ errx(1, "malformed link-level address");
+ set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
+}
+
+static
+DECL_CMD_FUNC(set80211addmac, val, d)
+{
+ set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
+}
+
+static
+DECL_CMD_FUNC(set80211delmac, val, d)
+{
+ set80211macmac(s, IEEE80211_IOC_DELMAC, val);
+}
+
+static
+DECL_CMD_FUNC(set80211kickmac, val, d)
+{
+ char *temp;
+ struct sockaddr_dl sdl;
+ struct ieee80211req_mlme mlme;
+
+ temp = malloc(strlen(val) + 2); /* ':' and '\0' */
+ if (temp == NULL)
+ errx(1, "malloc failed");
+ temp[0] = ':';
+ strcpy(temp + 1, val);
+ sdl.sdl_len = sizeof(sdl);
+ link_addr(temp, &sdl);
+ free(temp);
+ if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
+ errx(1, "malformed link-level address");
+ memset(&mlme, 0, sizeof(mlme));
+ mlme.im_op = IEEE80211_MLME_DEAUTH;
+ mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
+ memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
+ set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme);
+}
+
+static
+DECL_CMD_FUNC(set80211maccmd, val, d)
+{
+ set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
+}
+
+static void
+set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
+}
+
+static void
+set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211mcastrate, val, d)
+{
+ set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211fragthreshold, val, d)
+{
+ set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
+ isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
+}
+
+static int
+getmaxrate(uint8_t rates[15], uint8_t nrates)
+{
+ int i, maxrate = -1;
+
+ for (i = 0; i < nrates; i++) {
+ int rate = rates[i] & IEEE80211_RATE_VAL;
+ if (rate > maxrate)
+ maxrate = rate;
}
- printf("\tchannel %d", ireq.i_val);
+ return maxrate / 2;
+}
- ireq.i_type = IEEE80211_IOC_AUTHMODE;
- if (ioctl(s, SIOCG80211, &ireq) != -1) {
- printf(" authmode");
- switch (ireq.i_val) {
- case IEEE80211_AUTH_NONE:
- printf(" NONE");
- break;
- case IEEE80211_AUTH_OPEN:
- printf(" OPEN");
- break;
- case IEEE80211_AUTH_SHARED:
- printf(" SHARED");
- break;
- default:
- printf(" UNKNOWN");
+static const char *
+getcaps(int capinfo)
+{
+ static char capstring[32];
+ char *cp = capstring;
+
+ if (capinfo & IEEE80211_CAPINFO_ESS)
+ *cp++ = 'E';
+ if (capinfo & IEEE80211_CAPINFO_IBSS)
+ *cp++ = 'I';
+ if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
+ *cp++ = 'c';
+ if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
+ *cp++ = 'C';
+ if (capinfo & IEEE80211_CAPINFO_PRIVACY)
+ *cp++ = 'P';
+ if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
+ *cp++ = 'S';
+ if (capinfo & IEEE80211_CAPINFO_PBCC)
+ *cp++ = 'B';
+ if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
+ *cp++ = 'A';
+ if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
+ *cp++ = 's';
+ if (capinfo & IEEE80211_CAPINFO_RSN)
+ *cp++ = 'R';
+ if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
+ *cp++ = 'D';
+ *cp = '\0';
+ return capstring;
+}
+
+static void
+printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
+{
+ printf("%s", tag);
+ if (verbose) {
+ maxlen -= strlen(tag)+2;
+ if (2*ielen > maxlen)
+ maxlen--;
+ printf("<");
+ for (; ielen > 0; ie++, ielen--) {
+ if (maxlen-- <= 0)
break;
+ printf("%02x", *ie);
}
+ if (ielen != 0)
+ printf("-");
+ printf(">");
}
+}
- ireq.i_type = IEEE80211_IOC_POWERSAVE;
- if (ioctl(s, SIOCG80211, &ireq) != -1 &&
- ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
- printf(" powersavemode");
- switch (ireq.i_val) {
- case IEEE80211_POWERSAVE_OFF:
- printf(" OFF");
- break;
- case IEEE80211_POWERSAVE_CAM:
- printf(" CAM");
- break;
- case IEEE80211_POWERSAVE_PSP:
- printf(" PSP");
+/*
+ * Copy the ssid string contents into buf, truncating to fit. If the
+ * ssid is entirely printable then just copy intact. Otherwise convert
+ * to hexadecimal. If the result is truncated then replace the last
+ * three characters with "...".
+ */
+static int
+copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
+{
+ const u_int8_t *p;
+ size_t maxlen;
+ int i;
+
+ if (essid_len > bufsize)
+ maxlen = bufsize;
+ else
+ maxlen = essid_len;
+ /* determine printable or not */
+ for (i = 0, p = essid; i < maxlen; i++, p++) {
+ if (*p < ' ' || *p > 0x7e)
+ break;
+ }
+ if (i != maxlen) { /* not printable, print as hex */
+ if (bufsize < 3)
+ return 0;
+ strlcpy(buf, "0x", bufsize);
+ bufsize -= 2;
+ p = essid;
+ for (i = 0; i < maxlen && bufsize >= 2; i++) {
+ sprintf(&buf[2+2*i], "%02x", p[i]);
+ bufsize -= 2;
+ }
+ if (i != essid_len)
+ memcpy(&buf[2+2*i-3], "...", 3);
+ } else { /* printable, truncate as needed */
+ memcpy(buf, essid, maxlen);
+ if (maxlen != essid_len)
+ memcpy(&buf[maxlen-3], "...", 3);
+ }
+ return maxlen;
+}
+
+/* unaligned little endian access */
+#define LE_READ_4(p) \
+ ((u_int32_t) \
+ ((((const u_int8_t *)(p))[0] ) | \
+ (((const u_int8_t *)(p))[1] << 8) | \
+ (((const u_int8_t *)(p))[2] << 16) | \
+ (((const u_int8_t *)(p))[3] << 24)))
+
+static int __inline
+iswpaoui(const u_int8_t *frm)
+{
+ return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
+}
+
+static int __inline
+iswmeoui(const u_int8_t *frm)
+{
+ return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
+}
+
+static int __inline
+isatherosoui(const u_int8_t *frm)
+{
+ return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
+}
+
+static void
+printies(const u_int8_t *vp, int ielen, int maxcols)
+{
+ while (ielen > 0) {
+ switch (vp[0]) {
+ case IEEE80211_ELEMID_VENDOR:
+ if (iswpaoui(vp))
+ printie(" WPA", vp, 2+vp[1], maxcols);
+ else if (iswmeoui(vp))
+ printie(" WME", vp, 2+vp[1], maxcols);
+ else if (isatherosoui(vp))
+ printie(" ATH", vp, 2+vp[1], maxcols);
+ else
+ printie(" VEN", vp, 2+vp[1], maxcols);
+ break;
+ case IEEE80211_ELEMID_RSN:
+ printie(" RSN", vp, 2+vp[1], maxcols);
+ break;
+ default:
+ printie(" ???", vp, 2+vp[1], maxcols);
+ break;
+ }
+ ielen -= 2+vp[1];
+ vp += 2+vp[1];
+ }
+}
+
+static void
+list_scan(int s)
+{
+ uint8_t buf[24*1024];
+ struct ieee80211req ireq;
+ char ssid[IEEE80211_NWID_LEN+1];
+ uint8_t *cp;
+ int len, ssidmax;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
+ ireq.i_data = buf;
+ ireq.i_len = sizeof(buf);
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get scan results");
+ len = ireq.i_len;
+ if (len < sizeof(struct ieee80211req_scan_result))
+ return;
+
+ ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
+ printf("%-*.*s %-17.17s %4s %4s %-5s %3s %4s\n"
+ , ssidmax, ssidmax, "SSID"
+ , "BSSID"
+ , "CHAN"
+ , "RATE"
+ , "S:N"
+ , "INT"
+ , "CAPS"
+ );
+ cp = buf;
+ do {
+ struct ieee80211req_scan_result *sr;
+ uint8_t *vp;
+
+ sr = (struct ieee80211req_scan_result *) cp;
+ vp = (u_int8_t *)(sr+1);
+ printf("%-*.*s %s %3d %3dM %2d:%-2d %3d %-4.4s"
+ , ssidmax
+ , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
+ , ssid
+ , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
+ , ieee80211_mhz2ieee(sr->isr_freq)
+ , getmaxrate(sr->isr_rates, sr->isr_nrates)
+ , sr->isr_rssi, sr->isr_noise
+ , sr->isr_intval
+ , getcaps(sr->isr_capinfo)
+ );
+ printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);;
+ printf("\n");
+ cp += sr->isr_len, len -= sr->isr_len;
+ } while (len >= sizeof(struct ieee80211req_scan_result));
+}
+
+#include <netproto/802_11/ieee80211_dragonfly.h>
+
+static void
+scan_and_wait(int s)
+{
+ struct ieee80211req ireq;
+ int sroute;
+
+ sroute = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (sroute < 0) {
+ perror("socket(PF_ROUTE,SOCK_RAW)");
+ return;
+ }
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_SCAN_REQ;
+ /* NB: only root can trigger a scan so ignore errors */
+ if (ioctl(s, SIOCS80211, &ireq) >= 0) {
+ char buf[2048];
+ struct if_announcemsghdr *ifan;
+ struct rt_msghdr *rtm;
+
+ do {
+ if (read(sroute, buf, sizeof(buf)) < 0) {
+ perror("read(PF_ROUTE)");
break;
- case IEEE80211_POWERSAVE_PSP_CAM:
- printf(" PSP-CAM");
+ }
+ rtm = (struct rt_msghdr *) buf;
+ if (rtm->rtm_version != RTM_VERSION)
break;
+ ifan = (struct if_announcemsghdr *) rtm;
+ } while (rtm->rtm_type != RTM_IEEE80211 ||
+ ifan->ifan_what != RTM_IEEE80211_SCAN);
+ }
+ close(sroute);
+}
+
+static
+DECL_CMD_FUNC(set80211scan, val, d)
+{
+ scan_and_wait(s);
+ list_scan(s);
+}
+
+static void
+list_stations(int s)
+{
+ uint8_t buf[24*1024];
+ struct ieee80211req ireq;
+ uint8_t *cp;
+ int len;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_STA_INFO;
+ ireq.i_data = buf;
+ ireq.i_len = sizeof(buf);
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get station information");
+ len = ireq.i_len;
+ if (len < sizeof(struct ieee80211req_sta_info))
+ return;
+
+ printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n"
+ , "ADDR"
+ , "AID"
+ , "CHAN"
+ , "RATE"
+ , "RSSI"
+ , "IDLE"
+ , "TXSEQ"
+ , "RXSEQ"
+ , "CAPS"
+ , "ERP"
+ );
+ cp = buf;
+ do {
+ struct ieee80211req_sta_info *si;
+ uint8_t *vp;
+
+ si = (struct ieee80211req_sta_info *) cp;
+ vp = (u_int8_t *)(si+1);
+ printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x"
+ , ether_ntoa((const struct ether_addr*) si->isi_macaddr)
+ , IEEE80211_AID(si->isi_associd)
+ , ieee80211_mhz2ieee(si->isi_freq)
+ , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
+ , si->isi_rssi
+ , si->isi_inact
+ , si->isi_txseqs[0]
+ , si->isi_rxseqs[0]
+ , getcaps(si->isi_capinfo)
+ , si->isi_erp
+ );
+ printies(vp, si->isi_ie_len, 24);
+ printf("\n");
+ cp += si->isi_len, len -= si->isi_len;
+ } while (len >= sizeof(struct ieee80211req_sta_info));
+}
+
+static void
+print_chaninfo(const struct ieee80211_channel *c)
+{
+#define IEEE80211_IS_CHAN_PASSIVE(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
+ char buf[14];
+
+ buf[0] = '\0';
+ if (IEEE80211_IS_CHAN_FHSS(c))
+ strlcat(buf, " FHSS", sizeof(buf));
+ if (IEEE80211_IS_CHAN_A(c))
+ strlcat(buf, " 11a", sizeof(buf));
+ /* XXX 11g schizophrenia */
+ if (IEEE80211_IS_CHAN_G(c) ||
+ IEEE80211_IS_CHAN_PUREG(c))
+ strlcat(buf, " 11g", sizeof(buf));
+ else if (IEEE80211_IS_CHAN_B(c))
+ strlcat(buf, " 11b", sizeof(buf));
+ if (IEEE80211_IS_CHAN_T(c))
+ strlcat(buf, " Turbo", sizeof(buf));
+ printf("Channel %3u : %u%c Mhz%-14.14s",
+ ieee80211_mhz2ieee(c->ic_freq), c->ic_freq,
+ IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
+#undef IEEE80211_IS_CHAN_PASSIVE
+}
+
+static void
+list_channels(int s, int allchans)
+{
+ struct ieee80211req ireq;
+ struct ieee80211req_chaninfo chans;
+ struct ieee80211req_chaninfo achans;
+ const struct ieee80211_channel *c;
+ int i, half;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_CHANINFO;
+ ireq.i_data = &chans;
+ ireq.i_len = sizeof(chans);
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get channel information");
+ if (!allchans) {
+ struct ieee80211req_chanlist active;
+
+ ireq.i_type = IEEE80211_IOC_CHANLIST;
+ ireq.i_data = &active;
+ ireq.i_len = sizeof(active);
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get active channel list");
+ memset(&achans, 0, sizeof(achans));
+ for (i = 0; i < chans.ic_nchans; i++) {
+ c = &chans.ic_chans[i];
+ if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans)
+ achans.ic_chans[achans.ic_nchans++] = *c;
}
+ } else
+ achans = chans;
+ half = achans.ic_nchans / 2;
+ if (achans.ic_nchans % 2)
+ half++;
+ for (i = 0; i < achans.ic_nchans / 2; i++) {
+ print_chaninfo(&achans.ic_chans[i]);
+ print_chaninfo(&achans.ic_chans[half+i]);
+ printf("\n");
+ }
+ if (achans.ic_nchans % 2) {
+ print_chaninfo(&achans.ic_chans[i]);
+ printf("\n");
+ }
+}
+
+static void
+list_keys(int s)
+{
+}
+
+#define IEEE80211_C_BITS \
+"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
+"\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
+"\31WPA2\32BURST\33WME"
- ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
+static void
+list_capabilities(int s)
+{
+ struct ieee80211req ireq;
+ u_int32_t caps;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get driver capabilities");
+ caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len);
+ printb(name, caps, IEEE80211_C_BITS);
+ putchar('\n');
+}
+
+static void
+list_wme(int s)
+{
+ static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
+ struct ieee80211req ireq;
+ int ac;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_len = 0;
+ for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
+again:
+ if (ireq.i_len & IEEE80211_WMEPARAM_BSS)
+ printf("\t%s", " ");
+ else
+ printf("\t%s", acnames[ac]);
+
+ ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac;
+
+ /* show WME BSS parameters */
+ ireq.i_type = IEEE80211_IOC_WME_CWMIN;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ printf(" cwmin %2u", ireq.i_val);
+ ireq.i_type = IEEE80211_IOC_WME_CWMAX;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ printf(" cwmax %2u", ireq.i_val);
+ ireq.i_type = IEEE80211_IOC_WME_AIFS;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ printf(" aifs %2u", ireq.i_val);
+ ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ printf(" txopLimit %3u", ireq.i_val);
+ ireq.i_type = IEEE80211_IOC_WME_ACM;
if (ioctl(s, SIOCG80211, &ireq) != -1) {
if (ireq.i_val)
- printf(" powersavesleep %d", ireq.i_val);
+ printf(" acm");
+ else if (verbose)
+ printf(" -acm");
+ }
+ /* !BSS only */
+ if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
+ ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (!ireq.i_val)
+ printf(" -ack");
+ else if (verbose)
+ printf(" ack");
+ }
}
+ printf("\n");
+ if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
+ ireq.i_len |= IEEE80211_WMEPARAM_BSS;
+ goto again;
+ } else
+ ireq.i_len &= ~IEEE80211_WMEPARAM_BSS;
}
+}
- printf("\n");
+static void
+list_mac(int s)
+{
+ struct ieee80211req ireq;
+ struct ieee80211req_maclist *acllist;
+ int i, nacls, policy;
+ char c;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */
+ ireq.i_type = IEEE80211_IOC_MACCMD;
+ ireq.i_val = IEEE80211_MACCMD_POLICY;
+ if (ioctl(s, SIOCG80211, &ireq) < 0) {
+ if (errno == EINVAL) {
+ printf("No acl policy loaded\n");
+ return;
+ }
+ err(1, "unable to get mac policy");
+ }
+ policy = ireq.i_val;
- spacer = '\t';
- ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
+ ireq.i_val = IEEE80211_MACCMD_LIST;
+ ireq.i_len = 0;
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ err(1, "unable to get mac acl list size");
+ if (ireq.i_len == 0) /* NB: no acls */
+ return;
+
+ ireq.i_data = malloc(ireq.i_len);
+ if (ireq.i_data == NULL)
+ err(1, "out of memory for acl list");
+
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ err(1, "unable to get mac acl list");
+ if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
+ if (verbose)
+ printf("policy: open\n");
+ c = '*';
+ } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
+ if (verbose)
+ printf("policy: allow\n");
+ c = '+';
+ } else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
+ if (verbose)
+ printf("policy: deny\n");
+ c = '-';
+ } else {
+ printf("policy: unknown (%u)\n", policy);
+ c = '?';
+ }
+ nacls = ireq.i_len / sizeof(*acllist);
+ acllist = (struct ieee80211req_maclist *) ireq.i_data;
+ for (i = 0; i < nacls; i++)
+ printf("%c%s\n", c, ether_ntoa(
+ (const struct ether_addr *) acllist[i].ml_macaddr));
+}
+
+static
+DECL_CMD_FUNC(set80211list, arg, d)
+{
+#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0)
+
+ if (iseq(arg, "sta"))
+ list_stations(s);
+ else if (iseq(arg, "scan") || iseq(arg, "ap"))
+ list_scan(s);
+ else if (iseq(arg, "chan") || iseq(arg, "freq"))
+ list_channels(s, 1);
+ else if (iseq(arg, "active"))
+ list_channels(s, 0);
+ else if (iseq(arg, "keys"))
+ list_keys(s);
+ else if (iseq(arg, "caps"))
+ list_capabilities(s);
+ else if (iseq(arg, "wme"))
+ list_wme(s);
+ else if (iseq(arg, "mac"))
+ list_mac(s);
+ else
+ errx(1, "Don't know how to list %s for %s", arg, name);
+#undef iseq
+}
+
+static enum ieee80211_opmode
+get80211opmode(int s)
+{
+ struct ifmediareq ifmr;
+
+ (void) memset(&ifmr, 0, sizeof(ifmr));
+ (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
+ if (ifmr.ifm_current & IFM_IEEE80211_ADHOC)
+ return IEEE80211_M_IBSS; /* XXX ahdemo */
+ if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
+ return IEEE80211_M_HOSTAP;
+ if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
+ return IEEE80211_M_MONITOR;
+ }
+ return IEEE80211_M_STA;
+}
+
+static const struct ieee80211_channel *
+getchaninfo(int s, int chan)
+{
+ struct ieee80211req ireq;
+ static struct ieee80211req_chaninfo chans;
+ static struct ieee80211_channel undef;
+ const struct ieee80211_channel *c;
+ int i, freq;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_CHANINFO;
+ ireq.i_data = &chans;
+ ireq.i_len = sizeof(chans);
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get channel information");
+ freq = ieee80211_ieee2mhz(chan);
+ for (i = 0; i < chans.ic_nchans; i++) {
+ c = &chans.ic_chans[i];
+ if (c->ic_freq == freq)
+ return c;
+ }
+ return &undef;
+}
+
+#if 0
+static void
+printcipher(int s, struct ieee80211req *ireq, int keylenop)
+{
+ switch (ireq->i_val) {
+ case IEEE80211_CIPHER_WEP:
+ ireq->i_type = keylenop;
+ if (ioctl(s, SIOCG80211, ireq) != -1)
+ printf("WEP-%s",
+ ireq->i_len <= 5 ? "40" :
+ ireq->i_len <= 13 ? "104" : "128");
+ else
+ printf("WEP");
+ break;
+ case IEEE80211_CIPHER_TKIP:
+ printf("TKIP");
+ break;
+ case IEEE80211_CIPHER_AES_OCB:
+ printf("AES-OCB");
+ break;
+ case IEEE80211_CIPHER_AES_CCM:
+ printf("AES-CCM");
+ break;
+ case IEEE80211_CIPHER_CKIP:
+ printf("CKIP");
+ break;
+ case IEEE80211_CIPHER_NONE:
+ printf("NONE");
+ break;
+ default:
+ printf("UNKNOWN (0x%x)", ireq->i_val);
+ break;
+ }
+}
+#endif
+
+#define MAXCOL 78
+static int col;
+static char spacer;
+
+static void
+LINE_BREAK(void)
+{
+ if (spacer != '\t') {
+ printf("\n");
+ spacer = '\t';
+ }
+ col = 8; /* 8-col tab */
+}
+
+static void
+LINE_CHECK(const char *fmt, ...)
+{
+ char buf[80];
+ va_list ap;
+ int n;
+
+ va_start(ap, fmt);
+ n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
+ va_end(ap);
+ col += 1+n;
+ if (col > MAXCOL) {
+ LINE_BREAK();
+ col += n;
+ }
+ buf[0] = spacer;
+ printf("%s", buf);
+ spacer = ' ';
+}
+
+static void
+printkey(const struct ieee80211req_key *ik)
+{
+ static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
+ int keylen = ik->ik_keylen;
+ int printcontents;
+
+ printcontents = printkeys &&
+ (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
+ if (printcontents)
+ LINE_BREAK();
+ switch (ik->ik_type) {
+ case IEEE80211_CIPHER_WEP:
+ /* compatibility */
+ LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1,
+ keylen <= 5 ? "40-bit" :
+ keylen <= 13 ? "104-bit" : "128-bit");
+ break;
+ case IEEE80211_CIPHER_TKIP:
+ if (keylen > 128/8)
+ keylen -= 128/8; /* ignore MIC for now */
+ LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
+ break;
+ case IEEE80211_CIPHER_AES_OCB:
+ LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen);
+ break;
+ case IEEE80211_CIPHER_AES_CCM:
+ LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen);
+ break;
+ case IEEE80211_CIPHER_CKIP:
+ LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
+ break;
+ case IEEE80211_CIPHER_NONE:
+ LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen);
+ break;
+ default:
+ LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit",
+ ik->ik_type, ik->ik_keyix+1, 8*keylen);
+ break;
+ }
+ if (printcontents) {
+ int i;
+
+ printf(" <");
+ for (i = 0; i < keylen; i++)
+ printf("%02x", ik->ik_keydata[i]);
+ printf(">");
+ if (ik->ik_type != IEEE80211_CIPHER_WEP &&
+ (ik->ik_keyrsc != 0 || verbose))
+ printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc);
+ if (ik->ik_type != IEEE80211_CIPHER_WEP &&
+ (ik->ik_keytsc != 0 || verbose))
+ printf(" tsc %ju", (uintmax_t)ik->ik_keytsc);
+ if (ik->ik_flags != 0 && verbose) {
+ const char *sep = " ";
+
+ if (ik->ik_flags & IEEE80211_KEY_XMIT)
+ printf("%stx", sep), sep = "+";
+ if (ik->ik_flags & IEEE80211_KEY_RECV)
+ printf("%srx", sep), sep = "+";
+ if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
+ printf("%sdef", sep), sep = "+";
+ }
+ LINE_BREAK();
+ }
+}
+
+static void
+ieee80211_status(int s)
+{
+ static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
+ enum ieee80211_opmode opmode = get80211opmode(s);
+ int i, num, wpa, wme;
+ struct ieee80211req ireq;
+ u_int8_t data[32];
+ const struct ieee80211_channel *c;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_data = &data;
+
+ wpa = 0; /* unknown/not set */
+
+ ireq.i_type = IEEE80211_IOC_SSID;
+ ireq.i_val = -1;
+ if (ioctl(s, SIOCG80211, &ireq) < 0) {
+ /* If we can't get the SSID, this isn't an 802.11 device. */
+ return;
+ }
+ num = 0;
+ ireq.i_type = IEEE80211_IOC_NUMSSIDS;
+ if (ioctl(s, SIOCG80211, &ireq) >= 0)
+ num = ireq.i_val;
+ printf("\tssid ");
+ if (num > 1) {
+ ireq.i_type = IEEE80211_IOC_SSID;
+ for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
+ if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
+ printf(" %d:", ireq.i_val + 1);
+ print_string(data, ireq.i_len);
+ }
+ }
+ } else
+ print_string(data, ireq.i_len);
+
+ ireq.i_type = IEEE80211_IOC_CHANNEL;
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ goto end;
+ c = getchaninfo(s, ireq.i_val);
+ if (ireq.i_val != -1) {
+ printf(" channel %d", ireq.i_val);
+ if (verbose)
+ printf(" (%u)", c->ic_freq);
+ } else if (verbose)
+ printf(" channel UNDEF");
+
+ ireq.i_type = IEEE80211_IOC_BSSID;
+ ireq.i_len = IEEE80211_ADDR_LEN;
+ if (ioctl(s, SIOCG80211, &ireq) >= 0 &&
+ (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
+ printf(" bssid %s", ether_ntoa(ireq.i_data));
+
+ ireq.i_type = IEEE80211_IOC_STATIONNAME;
if (ioctl(s, SIOCG80211, &ireq) != -1) {
- printf("%crtsthreshold %d", spacer, ireq.i_val);
- spacer = ' ';
+ printf("\n\tstationname ");
+ print_string(data, ireq.i_len);
}
- ireq.i_type = IEEE80211_IOC_PROTMODE;
+ spacer = ' '; /* force first break */
+ LINE_BREAK();
+
+ ireq.i_type = IEEE80211_IOC_AUTHMODE;
if (ioctl(s, SIOCG80211, &ireq) != -1) {
- printf("%cprotmode", spacer);
switch (ireq.i_val) {
- case IEEE80211_PROTMODE_OFF:
- printf(" OFF");
+ case IEEE80211_AUTH_NONE:
+ LINE_CHECK("authmode NONE");
+ break;
+ case IEEE80211_AUTH_OPEN:
+ LINE_CHECK("authmode OPEN");
+ break;
+ case IEEE80211_AUTH_SHARED:
+ LINE_CHECK("authmode SHARED");
break;
- case IEEE80211_PROTMODE_CTS:
- printf(" CTS");
+ case IEEE80211_AUTH_8021X:
+ LINE_CHECK("authmode 802.1x");
break;
- case IEEE80211_PROTMODE_RTSCTS:
- printf(" RTSCTS");
+ case IEEE80211_AUTH_WPA:
+ ireq.i_type = IEEE80211_IOC_WPA;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ wpa = ireq.i_val;
+ if (!wpa)
+ wpa = 1; /* default to WPA1 */
+ switch (wpa) {
+ case 2:
+ LINE_CHECK("authmode WPA2/802.11i");
+ break;
+ case 3:
+ LINE_CHECK("authmode WPA1+WPA2/802.11i");
+ break;
+ default:
+ LINE_CHECK("authmode WPA");
+ break;
+ }
+ break;
+ case IEEE80211_AUTH_AUTO:
+ LINE_CHECK("authmode AUTO");
break;
default:
- printf(" UNKNOWN");
+ LINE_CHECK("authmode UNKNOWN (0x%x)",
+ ireq.i_val);
break;
}
- spacer = ' ';
- }
-
- ireq.i_type = IEEE80211_IOC_TXPOWER;
- if (ioctl(s, SIOCG80211, &ireq) != -1) {
- printf("%ctxpower %d", spacer, ireq.i_val);
- spacer = ' ';
}
- if (spacer != '\t')
- printf("\n");
-
ireq.i_type = IEEE80211_IOC_WEP;
if (ioctl(s, SIOCG80211, &ireq) != -1 &&
ireq.i_val != IEEE80211_WEP_NOSUP) {
- printf("\twepmode");
- switch (ireq.i_val) {
+ int firstkey, wepmode;
+
+ wepmode = ireq.i_val;
+ switch (wepmode) {
case IEEE80211_WEP_OFF:
- printf(" OFF");
+ LINE_CHECK("privacy OFF");
break;
case IEEE80211_WEP_ON:
- printf(" ON");
+ LINE_CHECK("privacy ON");
break;
case IEEE80211_WEP_MIXED:
- printf(" MIXED");
+ LINE_CHECK("privacy MIXED");
break;
default:
- printf(" UNKNOWN");
+ LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
break;
}
warn("WEP support, but no tx key!");
goto end;
}
- printf(" weptxkey %d", ireq.i_val+1);
+ if (ireq.i_val != -1)
+ LINE_CHECK("deftxkey %d", ireq.i_val+1);
+ else if (wepmode != IEEE80211_WEP_OFF || verbose)
+ LINE_CHECK("deftxkey UNDEF");
ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
if (ioctl(s, SIOCG80211, &ireq) < 0) {
}
num = ireq.i_val;
- printf("\n");
-
- ireq.i_type = IEEE80211_IOC_WEPKEY;
- spacer = '\t';
+ firstkey = 1;
for (i = 0; i < num; i++) {
- ireq.i_val = i;
+ struct ieee80211req_key ik;
+
+ memset(&ik, 0, sizeof(ik));
+ ik.ik_keyix = i;
+ ireq.i_type = IEEE80211_IOC_WPAKEY;
+ ireq.i_data = &ik;
+ ireq.i_len = sizeof(ik);
if (ioctl(s, SIOCG80211, &ireq) < 0) {
warn("WEP support, but can get keys!");
goto end;
}
- if (ireq.i_len == 0 ||
- ireq.i_len > IEEE80211_KEYBUF_SIZE)
- continue;
- printf("%cwepkey %d:%s", spacer, i+1,
- ireq.i_len <= 5 ? "40-bit" :
- ireq.i_len <= 13 ? "104-bit" : "128-bit");
- if (spacer == '\t')
+ if (ik.ik_keylen != 0) {
+ if (verbose)
+ LINE_BREAK();
+ printkey(&ik);
+ firstkey = 0;
+ }
+ }
+ }
+
+ ireq.i_type = IEEE80211_IOC_POWERSAVE;
+ if (ioctl(s, SIOCG80211, &ireq) != -1 &&
+ ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
+ if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) {
+ switch (ireq.i_val) {
+ case IEEE80211_POWERSAVE_OFF:
+ LINE_CHECK("powersavemode OFF");
+ break;
+ case IEEE80211_POWERSAVE_CAM:
+ LINE_CHECK("powersavemode CAM");
+ break;
+ case IEEE80211_POWERSAVE_PSP:
+ LINE_CHECK("powersavemode PSP");
+ break;
+ case IEEE80211_POWERSAVE_PSP_CAM:
+ LINE_CHECK("powersavemode PSP-CAM");
+ break;
+ }
+ ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("powersavesleep %d", ireq.i_val);
+ }
+ }
+
+ ireq.i_type = IEEE80211_IOC_TXPOWMAX;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("txpowmax %d", ireq.i_val);
+
+ if (verbose) {
+ ireq.i_type = IEEE80211_IOC_TXPOWER;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("txpower %d", ireq.i_val);
+ }
+
+ ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
+ LINE_CHECK("rtsthreshold %d", ireq.i_val);
+ }
+
+ ireq.i_type = IEEE80211_IOC_MCAST_RATE;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val != 2*1 || verbose) {
+ if (ireq.i_val == 11)
+ LINE_CHECK("mcastrate 5.5");
+ else
+ LINE_CHECK("mcastrate %d", ireq.i_val/2);
+ }
+ }
+
+ ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
+ LINE_CHECK("fragthreshold %d", ireq.i_val);
+ }
+
+ if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) {
+ ireq.i_type = IEEE80211_IOC_PUREG;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ LINE_CHECK("pureg");
+ else if (verbose)
+ LINE_CHECK("-pureg");
+ }
+ ireq.i_type = IEEE80211_IOC_PROTMODE;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ switch (ireq.i_val) {
+ case IEEE80211_PROTMODE_OFF:
+ LINE_CHECK("protmode OFF");
+ break;
+ case IEEE80211_PROTMODE_CTS:
+ LINE_CHECK("protmode CTS");
+ break;
+ case IEEE80211_PROTMODE_RTSCTS:
+ LINE_CHECK("protmode RTSCTS");
+ break;
+ default:
+ LINE_CHECK("protmode UNKNOWN (0x%x)",
+ ireq.i_val);
+ break;
+ }
+ }
+ }
+
+ ireq.i_type = IEEE80211_IOC_WME;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ wme = ireq.i_val;
+ if (wme)
+ LINE_CHECK("wme");
+ else if (verbose)
+ LINE_CHECK("-wme");
+ } else
+ wme = 0;
+
+ ireq.i_type = IEEE80211_IOC_BURST;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ LINE_CHECK("burst");
+ else if (verbose)
+ LINE_CHECK("-burst");
+ }
+
+ if (opmode == IEEE80211_M_HOSTAP) {
+ ireq.i_type = IEEE80211_IOC_HIDESSID;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ LINE_CHECK("ssid HIDE");
+ else if (verbose)
+ LINE_CHECK("ssid SHOW");
+ }
+
+ ireq.i_type = IEEE80211_IOC_APBRIDGE;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (!ireq.i_val)
+ LINE_CHECK("-apbridge");
+ else if (verbose)
+ LINE_CHECK("apbridge");
+ }
+
+ ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("dtimperiod %u", ireq.i_val);
+ } else {
+ ireq.i_type = IEEE80211_IOC_ROAMING;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) {
+ switch (ireq.i_val) {
+ case IEEE80211_ROAMING_DEVICE:
+ LINE_CHECK("roaming DEVICE");
+ break;
+ case IEEE80211_ROAMING_AUTO:
+ LINE_CHECK("roaming AUTO");
+ break;
+ case IEEE80211_ROAMING_MANUAL:
+ LINE_CHECK("roaming MANUAL");
+ break;
+ default:
+ LINE_CHECK("roaming UNKNOWN (0x%x)",
+ ireq.i_val);
+ break;
+ }
+ }
+ }
+ }
+ ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ LINE_CHECK("bintval %u", ireq.i_val);
+ else if (verbose)
+ LINE_CHECK("bintval %u", ireq.i_val);
+ }
+
+ if (wme && verbose) {
+ LINE_BREAK();
+ list_wme(s);
+ }
+
+ if (wpa) {
+ ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ LINE_CHECK("countermeasures");
+ else if (verbose)
+ LINE_CHECK("-countermeasures");
+ }
+#if 0
+ /* XXX not interesting with WPA done in user space */
+ ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ }
+
+ ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ LINE_CHECK("mcastcipher ");
+ printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
+ spacer = ' ';
+ }
+
+ ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ LINE_CHECK("ucastcipher ");
+ printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
+ }
+
+ if (wpa & 2) {
+ ireq.i_type = IEEE80211_IOC_RSNCAPS;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ LINE_CHECK("RSN caps 0x%x", ireq.i_val);
spacer = ' ';
+ }
+ }
+
+ ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
}
- if (spacer == ' ')
- printf("\n");
+#endif
+ LINE_BREAK();
}
+ LINE_BREAK();
end:
return;
{
struct ieee80211req ireq;
- memset(&ireq, 0, sizeof(ireq));
- strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
ireq.i_type = type;
ireq.i_val = val;
ireq.i_len = len;
DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold),
DEF_CMD_ARG("protmode", set80211protmode),
DEF_CMD_ARG("txpower", set80211txpower),
+ DEF_CMD_ARG("roaming", set80211roaming),
+ DEF_CMD("wme", 1, set80211wme),
+ DEF_CMD("-wme", 0, set80211wme),
+ DEF_CMD("hidessid", 1, set80211hidessid),
+ DEF_CMD("-hidessid", 0, set80211hidessid),
+ DEF_CMD("apbridge", 1, set80211apbridge),
+ DEF_CMD("-apbridge", 0, set80211apbridge),
+ DEF_CMD_ARG("chanlist", set80211chanlist),
+ DEF_CMD_ARG("bssid", set80211bssid),
+ DEF_CMD_ARG("ap", set80211bssid),
+ DEF_CMD("scan", 0, set80211scan),
+ DEF_CMD_ARG("list", set80211list),
+ DEF_CMD_ARG2("cwmin", set80211cwmin),
+ DEF_CMD_ARG2("cwmax", set80211cwmax),
+ DEF_CMD_ARG2("aifs", set80211aifs),
+ DEF_CMD_ARG2("txoplimit", set80211txoplimit),
+ DEF_CMD_ARG("acm", set80211acm),
+ DEF_CMD_ARG("-acm", set80211noacm),
+ DEF_CMD_ARG("ack", set80211ackpolicy),
+ DEF_CMD_ARG("-ack", set80211noackpolicy),
+ DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin),
+ DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax),
+ DEF_CMD_ARG2("bss:aifs", set80211bssaifs),
+ DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit),
+ DEF_CMD_ARG("dtimperiod", set80211dtimperiod),
+ DEF_CMD_ARG("bintval", set80211bintval),
+ DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd),
+ DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd),
+ DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd),
+ DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd),
+ DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd),
+ DEF_CMD_ARG("mac:add", set80211addmac),
+ DEF_CMD_ARG("mac:del", set80211delmac),
+ DEF_CMD_ARG("mac:kick", set80211kickmac),
+ DEF_CMD("pureg", 1, set80211pureg),
+ DEF_CMD("-pureg", 0, set80211pureg),
+ DEF_CMD_ARG("mcastrate", set80211mcastrate),
+ DEF_CMD_ARG("fragthreshold", set80211fragthreshold),
+ DEF_CMD("burst", 1, set80211burst),
+ DEF_CMD("-burst", 0, set80211burst),
};
-
static struct afswtch af_ieee80211 = {
.af_name = "af_ieee80211",
.af_af = AF_UNSPEC,
*
*
* $Id: if_ipw.c,v 1.7.2.1 2005/01/13 20:01:03 damien Exp $
- * $DragonFly: src/sys/dev/netif/ipw/Attic/if_ipw.c,v 1.13 2005/12/31 14:07:59 sephe Exp $
+ * $FreeBSD: src/sys/dev/ipw/if_ipw.c,v 1.7.2.4 2006/01/29 15:13:01 damien Exp $
+ * $DragonFly: src/sys/dev/netif/ipw/Attic/if_ipw.c,v 1.14 2006/05/18 13:51:45 sephe Exp $
*/
/*-
#include <bus/pci/pcireg.h>
#include <bus/pci/pcivar.h>
+#include <bus/pci/pcidevs.h>
#include <net/bpf.h>
#include <net/if.h>
#include <netproto/802_11/ieee80211_radiotap.h>
#include <netproto/802_11/if_wavelan_ieee.h>
-#include "if_ipwreg.h"
-#include "if_ipwvar.h"
+#include <dev/netif/ipw/if_ipwreg.h>
+#include <dev/netif/ipw/if_ipwvar.h>
#ifdef IPW_DEBUG
#define DPRINTF(x) if (ipw_debug > 0) printf x
};
static const struct ipw_ident ipw_ident_table[] = {
- { 0x8086, 0x1043, "Intel(R) PRO/Wireless 2100 MiniPCI" },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_PRO_WL_2100,
+ "Intel(R) PRO/Wireless 2100 MiniPCI" },
{ 0, 0, NULL }
};
struct ifnet *ifp = &ic->ic_if;
struct sysctl_oid *sysctl_tree;
u_int16_t val;
- int error, rid, i;
+ int error, i;
if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
device_printf(dev, "chip is in D%d power mode "
pci_enable_busmaster(dev);
/* map the register window */
- rid = IPW_PCI_BAR0;
- sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ sc->mem_rid = IPW_PCI_BAR0;
+ sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
+ RF_ACTIVE);
if (sc->mem == NULL) {
device_printf(dev, "could not allocate memory resource\n");
goto fail;
sc->sc_st = rman_get_bustag(sc->mem);
sc->sc_sh = rman_get_bushandle(sc->mem);
- rid = 0;
- sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE |
- RF_SHAREABLE);
+ sc->irq_rid = 0;
+ sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
+ RF_ACTIVE | RF_SHAREABLE);
if (sc->irq == NULL) {
device_printf(dev, "could not allocate interrupt resource\n");
goto fail;
if (!(ipw_read_prom_word(sc, IPW_EEPROM_RADIO) & 8))
sc->flags |= IPW_FLAG_HAS_RADIO_SWITCH;
- /* default to authmode OPEN */
- sc->authmode = IEEE80211_AUTH_OPEN;
-
/* IBSS channel undefined for now */
ic->ic_ibss_chan = &ic->ic_channels[0];
ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
ifq_set_ready(&ifp->if_snd);
- ieee80211_ifattach(ifp);
+ ieee80211_ifattach(ic);
/* override state transition machine */
sc->sc_newstate = ic->ic_newstate;
ic->ic_newstate = ipw_newstate;
- ieee80211_media_init(ifp, ipw_media_change, ipw_media_status);
+ ieee80211_media_init(ic, ipw_media_change, ipw_media_status);
bpfattach_dlt(ifp, DLT_IEEE802_11_RADIO,
sizeof (struct ieee80211_frame) + 64, &sc->sc_drvbpf);
sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
sc->sc_txtap.wt_ihdr.it_present = htole32(IPW_TX_RADIOTAP_PRESENT);
+ sc->dwelltime = 100;
+
SYSCTL_ADD_PROC(&sc->sysctl_ctx,
SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "radio",
CTLTYPE_INT | CTLFLAG_RD, sc, 0, ipw_sysctl_radio, "I",
CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, ipw_sysctl_stats, "S",
"Statistics");
+ SYSCTL_ADD_INT(&sc->sysctl_ctx,
+ SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "dwell",
+ CTLFLAG_RW, &sc->dwelltime, 0,
+ "Channel dwell time (ms) for AP/station scanning");
+
/*
* Hook our interrupt after all initialization is complete
*/
if (error != 0) {
device_printf(dev, "could not set up interrupt\n");
bpfdetach(ifp);
- ieee80211_ifdetach(ifp);
+ ieee80211_ifdetach(ic);
goto fail;
}
+ if (bootverbose)
+ ieee80211_announce(ic);
+
return 0;
fail:
lwkt_serialize_exit(ifp->if_serializer);
bpfdetach(ifp);
- ieee80211_ifdetach(ifp);
+ ieee80211_ifdetach(&sc->sc_ic);
}
ipw_release(sc);
if (sc->irq != NULL)
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
+ bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
- if (sc->mem != NULL) {
- bus_release_resource(dev, SYS_RES_MEMORY, IPW_PCI_BAR0,
- sc->mem);
- }
+ if (sc->mem != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
sysctl_ctx_free(&sc->sysctl_ctx);
static int
ipw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg __unused)
{
- struct ipw_softc *sc = ic->ic_softc;
- struct ieee80211_node *ni = ic->ic_bss;
- u_int32_t len;
- u_int8_t val;
+ struct ipw_softc *sc = ic->ic_if.if_softc;
+ struct ieee80211_node *ni;
+ uint8_t macaddr[IEEE80211_ADDR_LEN];
+ uint32_t len;
switch (nstate) {
case IEEE80211_S_RUN:
- len = IEEE80211_NWID_LEN;
- ipw_read_table2(sc, IPW_INFO_CURRENT_SSID, ni->ni_essid, &len);
- ni->ni_esslen = len;
+ DELAY(200); /* firmware needs a short delay here */
- val = ipw_read_table1(sc, IPW_INFO_CURRENT_CHANNEL);
- ni->ni_chan = &ic->ic_channels[val];
+ len = IEEE80211_ADDR_LEN;
+ ipw_read_table2(sc, IPW_INFO_CURRENT_BSSID, macaddr, &len);
+ ni = ieee80211_find_node(&ic->ic_scan, macaddr);
+ if (ni == NULL)
+ break;
- DELAY(100); /* firmware needs a short delay here */
+ ieee80211_ref_node(ni);
+ ieee80211_sta_join(ic, ni);
+ ieee80211_node_authorize(ni);
- len = IEEE80211_ADDR_LEN;
- ipw_read_table2(sc, IPW_INFO_CURRENT_BSSID, ni->ni_bssid, &len);
- IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid);
+ if (ic->ic_opmode == IEEE80211_M_STA)
+ ieee80211_notify_node_join(ic, ni, 1);
break;
case IEEE80211_S_INIT:
return le16toh(val);
}
-static void
-ipw_scan_result(struct ipw_softc *sc)
-{
- struct ieee80211com *ic = &sc->sc_ic;
- struct ieee80211_node *ni;
- u_int32_t i, cnt, off;
- struct ipw_node ap;
-
- /* flush previously seen access points */
- ieee80211_free_allnodes(ic);
-
- cnt = ipw_read_table1(sc, IPW_INFO_APS_CNT);
- off = ipw_read_table1(sc, IPW_INFO_APS_BASE);
-
- DPRINTF(("Found %u APs\n", cnt));
-
- for (i = 0; i < cnt; i++) {
- ipw_read_mem_1(sc, off, (u_int8_t *)&ap, sizeof ap);
- off += sizeof ap;
-
-#ifdef IPW_DEBUG
- if (ipw_debug >= 2) {
- u_char *p = (u_char *)≈
- int j;
-
- printf("AP%u\n", i);
- for (j = 0; j < sizeof ap; j++)
- printf("%02x", *p++);
- printf("\n");
- }
-#endif
-
- ni = ieee80211_lookup_node(ic, ap.bssid,
- &ic->ic_channels[ap.chan]);
- if (ni != NULL)
- continue;
-
- ni = ieee80211_alloc_node(ic, ap.bssid);
- if (ni == NULL)
- return;
-
- IEEE80211_ADDR_COPY(ni->ni_bssid, ap.bssid);
- ni->ni_rssi = ap.rssi;
- ni->ni_intval = le16toh(ap.intval);
- ni->ni_capinfo = le16toh(ap.capinfo);
- ni->ni_chan = &ic->ic_channels[ap.chan];
- ni->ni_esslen = ap.esslen;
- bcopy(ap.essid, ni->ni_essid, IEEE80211_NWID_LEN);
- }
-}
-
static void
ipw_command_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
{
struct ipw_cmd *cmd;
+ bus_dmamap_sync(sc->rxbuf_dmat, sbuf->map, BUS_DMASYNC_POSTREAD);
+
cmd = mtod(sbuf->m, struct ipw_cmd *);
DPRINTFN(2, ("RX!CMD!%u!%u!%u!%u!%u\n",
struct ieee80211com *ic = &sc->sc_ic;
u_int32_t state;
+ bus_dmamap_sync(sc->rxbuf_dmat, sbuf->map, BUS_DMASYNC_POSTREAD);
+
state = le32toh(*mtod(sbuf->m, u_int32_t *));
DPRINTFN(2, ("RX!NEWSTATE!%u\n", state));
/* don't leave run state on background scan */
if (ic->ic_state != IEEE80211_S_RUN)
ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+
+ ic->ic_flags |= IEEE80211_F_SCAN;
break;
case IPW_STATE_SCAN_COMPLETE:
- ipw_scan_result(sc);
+ ieee80211_notify_scan_done(ic);
+ ic->ic_flags &= ~IEEE80211_F_SCAN;
break;
case IPW_STATE_ASSOCIATION_LOST:
break;
case IPW_STATE_RADIO_DISABLED:
- sc->sc_ic.ic_if.if_flags &= ~IFF_UP;
+ ic->ic_if.if_flags &= ~IFF_UP;
ipw_stop(sc);
break;
}
}
+/*
+ * XXX: Hack to set the current channel to the value advertised in beacons or
+ * probe responses. Only used during AP detection.
+ */
+static void
+ipw_fix_channel(struct ieee80211com *ic, struct mbuf *m)
+{
+ struct ieee80211_frame *wh;
+ uint8_t subtype;
+ uint8_t *frm, *efrm;
+
+ wh = mtod(m, struct ieee80211_frame *);
+
+ if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT)
+ return;
+
+ subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
+
+ if (subtype != IEEE80211_FC0_SUBTYPE_BEACON &&
+ subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP)
+ return;
+
+ frm = (uint8_t *)(wh + 1);
+ efrm = mtod(m, uint8_t *) + m->m_len;
+
+ frm += 12; /* skip tstamp, bintval and capinfo fields */
+ while (frm < efrm) {
+ if (*frm == IEEE80211_ELEMID_DSPARMS)
+#if IEEE80211_CHAN_MAX < 255
+ if (frm[2] <= IEEE80211_CHAN_MAX)
+#endif
+ ic->ic_curchan = &ic->ic_channels[frm[2]];
+
+ frm += frm[1] + 2;
+ }
+}
+
static void
ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
struct ipw_soft_bd *sbd, struct ipw_soft_buf *sbuf)
{
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &ic->ic_if;
- struct mbuf *m;
+ struct mbuf *mnew, *m;
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
bus_addr_t physaddr;
return;
}
+ /*
+ * Try to allocate a new mbuf for this ring element and load it before
+ * processing the current mbuf. If the ring element cannot be loaded,
+ * drop the received packet and reuse the old mbuf. In the unlikely
+ * case that the old mbuf can't be reloaded either, explicitly panic.
+ */
+ mnew = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (mnew == NULL) {
+ ifp->if_ierrors++;
+ return;
+ }
+
+ bus_dmamap_sync(sc->rxbuf_dmat, sbuf->map, BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(sc->rxbuf_dmat, sbuf->map);
- /* Finalize mbuf */
+ error = bus_dmamap_load(sc->rxbuf_dmat, sbuf->map, mtod(mnew, void *),
+ MCLBYTES, ipw_dma_map_addr, &physaddr, 0);
+ if (error != 0) {
+ m_freem(mnew);
+
+ /* try to reload the old mbuf */
+ error = bus_dmamap_load(sc->rxbuf_dmat, sbuf->map,
+ mtod(sbuf->m, void *), MCLBYTES, ipw_dma_map_addr,
+ &physaddr, 0);
+ if (error != 0) /* XXX very unlikely that it will fail... */
+ panic("%s: could not load old rx mbuf", ifp->if_xname);
+ ifp->if_ierrors++;
+ return;
+ }
+
+ /*
+ * New mbuf successfully loaded, update Rx ring and continue
+ * processing.
+ */
m = sbuf->m;
+ sbuf->m = mnew;
+ sbd->bd->physaddr = htole32(physaddr);
+
+ /* finalize mbuf */
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = m->m_len = le32toh(status->len);
tap->wr_flags = 0;
tap->wr_antsignal = status->rssi;
- tap->wr_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
- tap->wr_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
+ tap->wr_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
+ tap->wr_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
bpf_ptap(sc->sc_drvbpf, m, tap, sc->sc_rxtap_len);
}
- wh = mtod(m, struct ieee80211_frame *);
-
- if (ic->ic_opmode != IEEE80211_M_STA) {
- ni = ieee80211_find_node(ic, wh->i_addr2);
- if (ni == NULL)
- ni = ieee80211_ref_node(ic->ic_bss);
- } else
- ni = ieee80211_ref_node(ic->ic_bss);
+ if (ic->ic_state == IEEE80211_S_SCAN)
+ ipw_fix_channel(ic, m);
- /* Send the frame to the upper layer */
- ieee80211_input(ifp, m, ni, status->rssi, 0);
-
- if (ni == ic->ic_bss)
- ieee80211_unref_node(&ni);
- else
- ieee80211_free_node(ic, ni);
+ wh = mtod(m, struct ieee80211_frame *);
+ ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
- m = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
- if (m == NULL) {
- if_printf(ifp, "could not allocate rx mbuf\n");
- sbuf->m = NULL;
- return;
- }
+ /* send the frame to the 802.11 layer */
+ ieee80211_input(ic, m, ni, status->rssi, 0);
- error = bus_dmamap_load(sc->rxbuf_dmat, sbuf->map, mtod(m, void *),
- MCLBYTES, ipw_dma_map_addr, &physaddr, 0);
- if (error != 0) {
- if_printf(ifp, "could not map rx DMA memory\n");
- m_freem(m);
- sbuf->m = NULL;
- return;
- }
+ /* node is no longer needed */
+ ieee80211_free_node(ni);
- sbuf->m = m;
- sbd->bd->physaddr = htole32(physaddr);
+ bus_dmamap_sync(sc->rbd_dmat, sc->rbd_map, BUS_DMASYNC_PREWRITE);
}
static void
sbd = &sc->srbd_list[i];
sbuf = sbd->priv;
- bus_dmamap_sync(sc->rxbuf_dmat, sbuf->map,
- BUS_DMASYNC_POSTREAD);
-
switch (le16toh(status->code) & 0xf) {
case IPW_STATUS_CODE_COMMAND:
ipw_command_intr(sc, sbuf);
static void
ipw_release_sbd(struct ipw_softc *sc, struct ipw_soft_bd *sbd)
{
- struct ieee80211com *ic = &sc->sc_ic;
struct ipw_soft_hdr *shdr;
struct ipw_soft_buf *sbuf;
SLIST_INSERT_HEAD(&sc->free_sbuf, sbuf, next);
m_freem(sbuf->m);
-
- if (sbuf->ni != NULL && sbuf->ni != ic->ic_bss)
- ieee80211_free_node(ic, sbuf->ni);
+ ieee80211_free_node(sbuf->ni);
/* kill watchdog timer */
sc->sc_tx_timer = 0;
r = CSR_READ_4(sc, IPW_CSR_TX_READ_INDEX);
for (i = (sc->txold + 1) % IPW_NTBD; i != r; i = (i + 1) % IPW_NTBD) {
- ipw_release_sbd(sc, &sc->stbd_list[i]);
+ struct ipw_soft_bd *sbd;
+
+ sbd = &sc->stbd_list[i];
+ if (sbd->type == IPW_SBD_TYPE_DATA)
+ ifp->if_opackets++;
+
+ ipw_release_sbd(sc, sbd);
sc->txfree++;
}
bus_dmamap_sync(sc->cmd_dmat, sc->cmd_map, BUS_DMASYNC_PREWRITE);
bus_dmamap_sync(sc->tbd_dmat, sc->tbd_map, BUS_DMASYNC_PREWRITE);
+ /* kick firmware */
sc->txcur = (sc->txcur + 1) % IPW_NTBD;
sc->txfree--;
+ CSR_WRITE_4(sc, IPW_CSR_TX_WRITE_INDEX, sc->txcur);
/*
* This is kinda messy. Since we may be MP, a combination of
bus_addr_t physaddr;
int error, i;
- if (ic->ic_flags & IEEE80211_F_WEPON) {
- m0 = ieee80211_wep_crypt(ifp, m0, 1);
- if (m0 == NULL)
+ wh = mtod(m0, struct ieee80211_frame *);
+ if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ if (ieee80211_crypto_encap(ic, ni, m0) == NULL) {
+ m_freem(m0);
return ENOBUFS;
- }
+ }
+
+ /* packet header may have moved, reset our local pointer */
+ wh = mtod(m0, struct ieee80211_frame *);
+ }
if (sc->sc_drvbpf != NULL) {
struct ipw_tx_radiotap_header *tap = &sc->sc_txtap;
tap->wt_flags = 0;
- tap->wt_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
- tap->wt_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
+ tap->wt_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
+ tap->wt_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
bpf_ptap(sc->sc_drvbpf, m0, tap, sc->sc_txtap_len);
}
- wh = mtod(m0, struct ieee80211_frame *);
-
shdr = SLIST_FIRST(&sc->free_shdr);
sbuf = SLIST_FIRST(&sc->free_sbuf);
KASSERT(shdr != NULL && sbuf != NULL, ("empty sw hdr/buf pool"));
}
for (;;) {
+ struct ether_header *eh;
+
m0 = ifq_poll(&ifp->if_snd);
if (m0 == NULL)
break;
}
ifq_dequeue(&ifp->if_snd, m0);
+ if (m0->m_len < sizeof (struct ether_header) &&
+ (m0 = m_pullup(m0, sizeof (struct ether_header))) == NULL)
+ continue;
+
+ eh = mtod(m0, struct ether_header *);
+ ni = ieee80211_find_txnode(ic, eh->ether_dhost);
+ if (ni == NULL) {
+ m_freem(m0);
+ continue;
+ }
+
BPF_MTAP(ifp, m0);
- m0 = ieee80211_encap(ifp, m0, &ni);
- if (m0 == NULL)
+ m0 = ieee80211_encap(ic, m0, ni);
+ if (m0 == NULL) {
+ ieee80211_free_node(ni);
continue;
+ }
if (ic->ic_rawbpf != NULL)
bpf_mtap(ic->ic_rawbpf, m0);
if (ipw_tx_start(ifp, m0, ni) != 0) {
- if (ni != NULL && ni != ic->ic_bss)
- ieee80211_free_node(ic, ni);
+ ieee80211_free_node(ni);
+ ifp->if_oerrors++;
break;
}
if (sc->sc_tx_timer > 0) {
if (--sc->sc_tx_timer == 0) {
if_printf(ifp, "device timeout\n");
+ ifp->if_oerrors++;
ifp->if_flags &= ~IFF_UP;
ipw_stop(sc);
return;
ifp->if_timer = 1;
}
- ieee80211_watchdog(ifp);
+ ieee80211_watchdog(&sc->sc_ic);
}
static int
struct ipw_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
struct ifreq *ifr;
- struct ieee80211req *ireq;
int error = 0;
switch (cmd) {
ipw_free_firmware(sc);
break;
- case SIOCG80211:
- ireq = (struct ieee80211req *)data;
- switch (ireq->i_type) {
- case IEEE80211_IOC_AUTHMODE:
- ireq->i_val = sc->authmode;
- break;
-
- case IEEE80211_IOC_TXPOWER:
- ireq->i_val = (CSR_READ_4(sc, IPW_CSR_IO) &
- IPW_IO_RADIO_DISABLED) ? 0 : ic->ic_txpower;
- break;
-
- default:
- error = ieee80211_ioctl(ifp, cmd, data, cr);
- }
- break;
-
- case SIOCS80211:
- /* only super-user can do that! */
- if ((error = suser(curthread)) != 0)
- break;
-
- ireq = (struct ieee80211req *)data;
- switch (ireq->i_type) {
- case IEEE80211_IOC_AUTHMODE:
- sc->authmode = ireq->i_val;
- break;
-
- default:
- error = ieee80211_ioctl(ifp, cmd, data, cr);
- }
- break;
-
default:
- error = ieee80211_ioctl(ifp, cmd, data, cr);
+ error = ieee80211_ioctl(ic, cmd, data, cr);
}
if (error == ENETRESET) {
CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, 0);
CSR_WRITE_4(sc, IPW_CSR_RST, IPW_RST_STOP_MASTER);
- for (ntries = 0; ntries < 5; ntries++) {
+ for (ntries = 0; ntries < 50; ntries++) {
if (CSR_READ_4(sc, IPW_CSR_RST) & IPW_RST_MASTER_DISABLED)
break;
DELAY(10);
}
- if (ntries == 5)
+ if (ntries == 50)
if_printf(&sc->sc_ic.ic_if, "timeout waiting for master\n");
CSR_WRITE_4(sc, IPW_CSR_RST, CSR_READ_4(sc, IPW_CSR_RST) |
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &ic->ic_if;
struct ipw_security security;
- struct ieee80211_wepkey *k;
+ struct ieee80211_key *k;
struct ipw_wep_key wepkey;
struct ipw_scan_options options;
struct ipw_configuration config;
}
bzero(&security, sizeof security);
- security.authmode = (sc->authmode == IEEE80211_AUTH_SHARED) ?
+ security.authmode = (ic->ic_bss->ni_authmode == IEEE80211_AUTH_SHARED) ?
IPW_AUTH_SHARED : IPW_AUTH_OPEN;
security.ciphers = htole32(IPW_CIPHER_NONE);
DPRINTF(("Setting authmode to %u\n", security.authmode));
if (error != 0)
return error;
- if (ic->ic_flags & IEEE80211_F_WEPON) {
- k = ic->ic_nw_keys;
+ if (ic->ic_flags & IEEE80211_F_PRIVACY) {
+ k = ic->ic_crypto.cs_nw_keys;
for (i = 0; i < IEEE80211_WEP_NKID; i++, k++) {
- if (k->wk_len == 0)
+ if (k->wk_keylen == 0)
continue;
wepkey.idx = i;
- wepkey.len = k->wk_len;
+ wepkey.len = k->wk_keylen;
bzero(wepkey.key, sizeof wepkey.key);
- bcopy(k->wk_key, wepkey.key, k->wk_len);
+ bcopy(k->wk_key, wepkey.key, k->wk_keylen);
DPRINTF(("Setting wep key index %u len %u\n",
wepkey.idx, wepkey.len));
error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY, &wepkey,
return error;
}
- data = htole32(ic->ic_wep_txkey);
+ data = htole32(ic->ic_crypto.cs_def_txkey);
DPRINTF(("Setting wep tx key index to %u\n", le32toh(data)));
error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY_INDEX, &data,
sizeof data);
return error;
}
- data = htole32((ic->ic_flags & IEEE80211_F_WEPON) ? IPW_WEPON : 0);
+ data = htole32((ic->ic_flags & IEEE80211_F_PRIVACY) ? IPW_WEPON : 0);
DPRINTF(("Setting wep flags to 0x%x\n", le32toh(data)));
error = ipw_cmd(sc, IPW_CMD_SET_WEP_FLAGS, &data, sizeof data);
if (error != 0)
return error;
+#if 0
+ struct ipw_wpa_ie ie;
+
+ memset(&ie, 0, sizeof ie);
+ ie.len = htole32(sizeof (struct ieee80211_ie_wpa));
+ DPRINTF(("Setting wpa ie\n"));
+ error = ipw_cmd(sc, IPW_CMD_SET_WPA_IE, &ie, sizeof ie);
+ if (error != 0)
+ return error;
+#endif
+
if (ic->ic_opmode == IEEE80211_M_IBSS ||
ic->ic_opmode == IEEE80211_M_HOSTAP) {
- data = htole32(ic->ic_lintval);
+ data = htole32(ic->ic_bintval);
DPRINTF(("Setting beacon interval to %u\n", le32toh(data)));
error = ipw_cmd(sc, IPW_CMD_SET_BEACON_INTERVAL, &data,
sizeof data);
/* exit immediately if firmware has not been ioctl'd */
if (!(sc->flags & IPW_FLAG_FW_CACHED)) {
+ if (!(sc->flags & IPW_FLAG_FW_WARNED))
+ if_printf(ifp, "Please load firmware\n");
+ sc->flags |= IPW_FLAG_FW_WARNED;
ifp->if_flags &= ~IFF_UP;
return;
}
for (i = 0; i < IPW_NTBD; i++)
ipw_release_sbd(sc, &sc->stbd_list[i]);
+ sc->sc_tx_timer = 0;
ifp->if_timer = 0;
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
ipw_sysctl_stats(SYSCTL_HANDLER_ARGS)
{
struct ipw_softc *sc = arg1;
+ struct ifnet *ifp = &sc->sc_ic.ic_if;
u_int32_t i, size, buf[256];
(void)arg2; /* silence WARNS == 6 */
(void)oidp; /* silence WARNS == 6 */
+ lwkt_serialize_enter(ifp->if_serializer);
+
if (!(sc->flags & IPW_FLAG_FW_INITED)) {
bzero(buf, sizeof buf);
- return SYSCTL_OUT(req, buf, sizeof buf);
+ goto back;
}
CSR_WRITE_4(sc, IPW_CSR_AUTOINC_ADDR, sc->table1_base);
size = min(CSR_READ_4(sc, IPW_CSR_AUTOINC_DATA), 256);
for (i = 1; i < size; i++)
buf[i] = MEM_READ_4(sc, CSR_READ_4(sc, IPW_CSR_AUTOINC_DATA));
-
+back:
+ lwkt_serialize_exit(ifp->if_serializer);
return SYSCTL_OUT(req, buf, sizeof buf);
}
ipw_sysctl_radio(SYSCTL_HANDLER_ARGS)
{
struct ipw_softc *sc = arg1;
+ struct ifnet *ifp = &sc->sc_ic.ic_if;
int val;
(void)arg2; /* silence WARNS == 6 */
(void)oidp; /* silence WARNS == 6 */
+ lwkt_serialize_enter(ifp->if_serializer);
val = !((sc->flags & IPW_FLAG_HAS_RADIO_SWITCH) &&
(CSR_READ_4(sc, IPW_CSR_IO) & IPW_IO_RADIO_DISABLED));
+ lwkt_serialize_exit(ifp->if_serializer);
return SYSCTL_OUT(req, &val, sizeof val);
}
/*
- * Copyright (c) 2004, 2005
+ * Copyright (c) 2004-2006
* Damien Bergamini <damien.bergamini@free.fr>.
* Copyright (c) 2004, 2005
* Andrew Atrens <atrens@nortelnetworks.com>.
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $DragonFly: src/sys/dev/netif/iwi/if_iwi.c,v 1.10 2005/12/31 14:07:59 sephe Exp $
+ * $FreeBSD: src/sys/dev/iwi/if_iwi.c,v 1.8.2.6 2006/02/23 02:06:46 sam Exp $
+ * $DragonFly: src/sys/dev/netif/iwi/if_iwi.c,v 1.11 2006/05/18 13:51:45 sephe Exp $
*/
-#include "opt_inet.h"
-
-#include <sys/cdefs.h>
-
/*-
- * Intel(R) PRO/Wireless 2200BG/2915ABG driver
+ * Intel(R) PRO/Wireless 2200BG/2225BG/2915ABG driver
* http://www.intel.com/network/connectivity/products/wireless/prowireless_mobile.htm
*/
#include <sys/endian.h>
#include <sys/proc.h>
#include <sys/ucred.h>
-#include <sys/thread2.h>
+#include <sys/serialize.h>
#include <machine/bus.h>
#include <machine/resource.h>
-#include <machine/clock.h>
#include <sys/rman.h>
#include <bus/pci/pcireg.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_arp.h>
-#include <net/ifq_var.h>
#include <net/ethernet.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
#include <net/ifq_var.h>
+#include <netproto/802_11/ieee80211_var.h>
+#include <netproto/802_11/ieee80211_radiotap.h>
+
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
-#ifdef IPX
-#include <netproto/ipx/ipx.h>
-#include <netproto/ipx/ipx_if.h>
-#endif
-
-#include <netproto/802_11/ieee80211_var.h>
-#include <netproto/802_11/ieee80211_ioctl.h>
-#include <netproto/802_11/ieee80211_radiotap.h>
-#include <netproto/802_11/if_wavelan_ieee.h>
-
-#include "if_iwireg.h"
-#include "if_iwivar.h"
+#include <dev/netif/iwi/if_iwireg.h>
+#include <dev/netif/iwi/if_iwivar.h>
#ifdef IWI_DEBUG
-#define DPRINTF(x) if (sc->debug_level > 0) printf x
-#define DPRINTFN(n, x) if (sc->debug_level >= (n)) printf x
-
+#define DPRINTF(x) do { if (iwi_debug > 0) printf x; } while (0)
+#define DPRINTFN(n, x) do { if (iwi_debug >= (n)) printf x; } while (0)
+int iwi_debug = 0;
+SYSCTL_INT(_debug, OID_AUTO, iwi, CTLFLAG_RW, &iwi_debug, 0, "iwi debug level");
#else
#define DPRINTF(x)
#define DPRINTFN(n, x)
#endif
-MODULE_DEPEND(iwi, pci, 1, 1, 1);
-MODULE_DEPEND(iwi, wlan, 1, 1, 1);
-
-struct iwi_dump_buffer {
- u_int32_t buf[128];
-};
-
struct iwi_ident {
- u_int16_t vendor;
- u_int16_t device;
+ uint16_t vendor;
+ uint16_t device;
const char *name;
};
static const struct iwi_ident iwi_ident_table[] = {
- { 0x8086, 0x4220, "Intel(R) PRO/Wireless 2200BG MiniPCI" },
- { 0x8086, 0x4223, "Intel(R) PRO/Wireless 2915ABG MiniPCI" },
- { 0x8086, 0x4224, "Intel(R) PRO/Wireless 2915ABG MiniPCI" },
+ { 0x8086, 0x4220, "Intel(R) PRO/Wireless 2200BG" },
+ { 0x8086, 0x4221, "Intel(R) PRO/Wireless 2225BG" },
+ { 0x8086, 0x4223, "Intel(R) PRO/Wireless 2915ABG" },
+ { 0x8086, 0x4224, "Intel(R) PRO/Wireless 2915ABG" },
{ 0, 0, NULL }
};
-static const struct ieee80211_rateset iwi_rateset_11a =
- { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } };
-
-static const struct ieee80211_rateset iwi_rateset_11b =
- { 4, { 2, 4, 11, 22 } };
-
-static const struct ieee80211_rateset iwi_rateset_11g =
- { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
-
-static int iwi_dma_alloc(struct iwi_softc *);
-static void iwi_release(struct iwi_softc *);
-static int iwi_media_change(struct ifnet *);
-static void iwi_media_status(struct ifnet *, struct ifmediareq *);
-static u_int16_t iwi_read_prom_word(struct iwi_softc *, u_int8_t);
-static int iwi_newstate(struct ieee80211com *,
- enum ieee80211_state, int);
-static void iwi_fix_channel(struct iwi_softc *, struct mbuf *);
-static void iwi_frame_intr(struct iwi_softc *,
- struct iwi_rx_buf *, int, struct iwi_frame *);
-static void iwi_notification_intr(struct iwi_softc *,
- struct iwi_notif *);
-static void iwi_rx_intr(struct iwi_softc *);
-static void iwi_tx_intr(struct iwi_softc *);
-static void iwi_intr(void *);
-static void iwi_dma_map_buf(void *, bus_dma_segment_t *, int,
- bus_size_t, int);
-static void iwi_dma_map_addr(void *, bus_dma_segment_t *, int, int);
-static int iwi_cmd(struct iwi_softc *, u_int8_t, void *, u_int8_t,
- int);
-static int iwi_tx_start(struct ifnet *, struct mbuf *,
- struct ieee80211_node *);
-static void iwi_start(struct ifnet *);
-static void iwi_watchdog(struct ifnet *);
-static int iwi_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *cr);
-static void iwi_stop_master(struct iwi_softc *);
-static int iwi_reset(struct iwi_softc *);
-static int iwi_load_ucode(struct iwi_softc *, void *, int);
-static int iwi_load_firmware(struct iwi_softc *, void *, int);
-static int iwi_cache_firmware(struct iwi_softc *, void *, int);
-static void iwi_free_firmware(struct iwi_softc *);
-static int iwi_config(struct iwi_softc *);
-static int iwi_scan(struct iwi_softc *);
-static int iwi_auth_and_assoc(struct iwi_softc *);
-static void iwi_init(void *);
-static void iwi_stop(void *);
-static void iwi_dump_fw_event_log(struct iwi_softc *sc);
-static void iwi_dump_fw_error_log(struct iwi_softc *sc);
-static u_int8_t iwi_find_station(struct iwi_softc *sc, u_int8_t *mac);
-static int8_t iwi_cache_station(struct iwi_softc *sc, u_int8_t *mac);
-static int iwi_adapter_config(struct iwi_softc *sc, int is_a, int cmd_wait);
-
-static int iwi_sysctl_bt_coexist(SYSCTL_HANDLER_ARGS);
-static int iwi_sysctl_bg_autodetect(SYSCTL_HANDLER_ARGS);
-static int iwi_sysctl_cts_to_self(SYSCTL_HANDLER_ARGS);
-static int iwi_sysctl_antenna_diversity(SYSCTL_HANDLER_ARGS);
-static int iwi_sysctl_radio(SYSCTL_HANDLER_ARGS);
-static int iwi_sysctl_stats(SYSCTL_HANDLER_ARGS);
-static int iwi_sysctl_dump_logs(SYSCTL_HANDLER_ARGS);
-static int iwi_sysctl_neg_best_rates_first(SYSCTL_HANDLER_ARGS);
-static int iwi_sysctl_disable_unicast_decryption(SYSCTL_HANDLER_ARGS);
-static int iwi_sysctl_disable_multicast_decryption(SYSCTL_HANDLER_ARGS);
-
-static __inline u_int8_t MEM_READ_1(struct iwi_softc *sc, u_int32_t addr)
-{
- CSR_WRITE_4(sc, IWI_CSR_INDIRECT_ADDR, addr);
- return CSR_READ_1(sc, IWI_CSR_INDIRECT_DATA);
-}
-
-static __inline u_int32_t MEM_READ_4(struct iwi_softc *sc, u_int32_t addr)
-{
- CSR_WRITE_4(sc, IWI_CSR_INDIRECT_ADDR, addr);
- return CSR_READ_4(sc, IWI_CSR_INDIRECT_DATA);
-}
-
-static int iwi_probe(device_t);
-static int iwi_attach(device_t);
-static int iwi_detach(device_t);
-static int iwi_shutdown(device_t);
-static int iwi_suspend(device_t);
-static int iwi_resume(device_t);
+static void iwi_dma_map_addr(void *, bus_dma_segment_t *, int, int);
+static void iwi_dma_map_mbuf(void *, bus_dma_segment_t *, int, bus_size_t,
+ int);
+static int iwi_alloc_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *,
+ int);
+static void iwi_reset_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *);
+static void iwi_free_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *);
+static int iwi_alloc_tx_ring(struct iwi_softc *, struct iwi_tx_ring *,
+ int, bus_addr_t, bus_addr_t);
+static void iwi_reset_tx_ring(struct iwi_softc *, struct iwi_tx_ring *);
+static void iwi_free_tx_ring(struct iwi_softc *, struct iwi_tx_ring *);
+static int iwi_alloc_rx_ring(struct iwi_softc *, struct iwi_rx_ring *,
+ int);
+static void iwi_reset_rx_ring(struct iwi_softc *, struct iwi_rx_ring *);
+static void iwi_free_rx_ring(struct iwi_softc *, struct iwi_rx_ring *);
+static struct ieee80211_node *iwi_node_alloc(struct ieee80211_node_table *);
+static void iwi_node_free(struct ieee80211_node *);
+static int iwi_media_change(struct ifnet *);
+static void iwi_media_status(struct ifnet *, struct ifmediareq *);
+static int iwi_newstate(struct ieee80211com *, enum ieee80211_state, int);
+static int iwi_wme_update(struct ieee80211com *);
+static uint16_t iwi_read_prom_word(struct iwi_softc *, uint8_t);
+static void iwi_fix_channel(struct ieee80211com *, struct mbuf *);
+static void iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *, int,
+ struct iwi_frame *);
+static void iwi_notification_intr(struct iwi_softc *, struct iwi_notif *);
+static void iwi_rx_intr(struct iwi_softc *);
+static void iwi_tx_intr(struct iwi_softc *, struct iwi_tx_ring *);
+static void iwi_intr(void *);
+static int iwi_cmd(struct iwi_softc *, uint8_t, void *, uint8_t, int);
+static void iwi_write_ibssnode(struct iwi_softc *, const struct iwi_node *);
+static int iwi_tx_start(struct ifnet *, struct mbuf *,
+ struct ieee80211_node *, int);
+static void iwi_start(struct ifnet *);
+static void iwi_watchdog(struct ifnet *);
+static int iwi_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
+static void iwi_stop_master(struct iwi_softc *);
+static int iwi_reset(struct iwi_softc *);
+static int iwi_load_ucode(struct iwi_softc *, void *, int);
+static int iwi_load_firmware(struct iwi_softc *, void *, int);
+static int iwi_cache_firmware(struct iwi_softc *, void *);
+static void iwi_free_firmware(struct iwi_softc *);
+static int iwi_config(struct iwi_softc *);
+static int iwi_set_chan(struct iwi_softc *, struct ieee80211_channel *);
+static int iwi_scan(struct iwi_softc *);
+static int iwi_auth_and_assoc(struct iwi_softc *);
+static void iwi_init(void *);
+static void iwi_stop(void *);
+static int iwi_sysctl_stats(SYSCTL_HANDLER_ARGS);
+static int iwi_sysctl_radio(SYSCTL_HANDLER_ARGS);
+
+static int iwi_probe(device_t);
+static int iwi_attach(device_t);
+static int iwi_detach(device_t);
+static int iwi_shutdown(device_t);
+static int iwi_suspend(device_t);
+static int iwi_resume(device_t);
+
+static int iwi_alloc_ibss_node(struct iwi_softc *);
+static void iwi_free_ibss_node(struct iwi_softc *, int);
static device_method_t iwi_methods[] = {
/* Device interface */
static driver_t iwi_driver = {
"iwi",
iwi_methods,
- sizeof (struct iwi_softc),
- 0, /* baseclasses */
- 0, /* refs */
- 0 /* ops */
+ sizeof (struct iwi_softc)
};
static devclass_t iwi_devclass;
DRIVER_MODULE(iwi, pci, iwi_driver, iwi_devclass, 0, 0);
+MODULE_DEPEND(iwi, pci, 1, 1, 1);
+MODULE_DEPEND(iwi, wlan, 1, 1, 1);
+
+/*
+ * Supported rates for 802.11a/b/g modes (in 500Kbps unit).
+ */
+static const struct ieee80211_rateset iwi_rateset_11a =
+ { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } };
+
+static const struct ieee80211_rateset iwi_rateset_11b =
+ { 4, { 2, 4, 11, 22 } };
+
+static const struct ieee80211_rateset iwi_rateset_11g =
+ { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
+
static int
iwi_probe(device_t dev)
{
const struct iwi_ident *ident;
+ uint16_t vid, did;
+ vid = pci_get_vendor(dev);
+ did = pci_get_device(dev);
for (ident = iwi_ident_table; ident->name != NULL; ident++) {
- if (pci_get_vendor(dev) == ident->vendor &&
- pci_get_device(dev) == ident->device) {
+ if (vid == ident->vendor && did == ident->device) {
device_set_desc(dev, ident->name);
return 0;
}
return ENXIO;
}
-static void
-iwi_fw_monitor(void *arg)
-{
- struct iwi_softc *sc = (struct iwi_softc *)arg;
- struct ifnet *ifp = &sc->sc_ic.ic_if;
- int error, boff;
-
- for ( ;; ) {
- crit_enter();
- tsleep_interlock(IWI_FW_WAKE_MONITOR(sc));
- error = tsleep(IWI_FW_WAKE_MONITOR(sc), 0, "iwifwm", 0 );
- crit_exit();
-
- if ( error == 0 ) {
- if ( sc->flags & IWI_FLAG_EXIT ) {
- sc->flags &= ~( IWI_FLAG_EXIT );
- break;
- } else if ( sc->flags & IWI_FLAG_RESET ) {
- device_printf(sc->sc_dev, "firmware reset\n");
- for ( boff = 1; sc->flags & IWI_FLAG_RESET ; boff++ ) {
- if ( sc->debug_level > 0 )
- iwi_dump_fw_error_log(sc);
- lwkt_serialize_enter(ifp->if_serializer);
- iwi_init(sc);
- lwkt_serialize_exit(ifp->if_serializer);
- if ((sc->flags & IWI_FLAG_FW_INITED))
- sc->flags &= ~( IWI_FLAG_RESET );
- crit_enter();
- tsleep_interlock(IWI_FW_CMD_ACKED(sc));
- error = tsleep(IWI_FW_CMD_ACKED(sc), 0,
- "iwirun", boff * hz );
- crit_exit();
- }
- }
- }
- }
- wakeup(IWI_FW_MON_EXIT(sc));
- kthread_exit();
-}
-
-static int
-iwi_start_fw_monitor_thread( struct iwi_softc *sc )
-{
- if (kthread_create(iwi_fw_monitor, sc, &sc->event_thread,
- "%s%d:fw-monitor", device_get_name(sc->sc_dev),
- device_get_unit(sc->sc_dev))) {
- device_printf (sc->sc_dev,
- "unable to create firmware monitor thread.\n");
- return -1;
- }
- return 0;
-}
-
/* Base Address Register */
#define IWI_PCI_BAR0 0x10
struct iwi_softc *sc = device_get_softc(dev);
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &ic->ic_if;
- u_int16_t val;
- int error, rid, i;
+ uint16_t val;
+ int error, i;
sc->sc_dev = dev;
+ if_initname(ifp, device_get_name(dev), device_get_unit(dev));
if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
device_printf(dev, "chip is in D%d power mode "
/* enable bus-mastering */
pci_enable_busmaster(dev);
- sc->num_stations = 0;
-
- /* map the register window */
- rid = IWI_PCI_BAR0;
- sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ sc->mem_rid = IWI_PCI_BAR0;
+ sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
+ RF_ACTIVE);
if (sc->mem == NULL) {
device_printf(dev, "could not allocate memory resource\n");
- error = ENXIO;
- goto fail;
+ return ENXIO;
}
-
sc->sc_st = rman_get_bustag(sc->mem);
sc->sc_sh = rman_get_bushandle(sc->mem);
- rid = 0;
- sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE |
- RF_SHAREABLE);
+ sc->irq_rid = 0;
+ sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
+ RF_ACTIVE | RF_SHAREABLE);
if (sc->irq == NULL) {
device_printf(dev, "could not allocate interrupt resource\n");
- error = ENXIO;
goto fail;
}
- error = iwi_reset(sc);
- if (error != 0) {
+ if (iwi_reset(sc) != 0) {
device_printf(dev, "could not reset adapter\n");
goto fail;
}
- if (iwi_start_fw_monitor_thread(sc)) {
- device_printf(dev, "could not start f/w reset thread\n");
- error = ENXIO;
+ /*
+ * Allocate rings.
+ */
+ error = iwi_alloc_cmd_ring(sc, &sc->cmdq, IWI_CMD_RING_COUNT);
+ if (error != 0) {
+ device_printf(dev, "could not allocate Cmd ring\n");
+ goto fail;
+ }
+
+ error = iwi_alloc_tx_ring(sc, &sc->txq[0], IWI_TX_RING_COUNT,
+ IWI_CSR_TX1_RIDX, IWI_CSR_TX1_WIDX);
+ if (error != 0) {
+ device_printf(dev, "could not allocate Tx ring 1\n");
+ goto fail;
+ }
+
+ error = iwi_alloc_tx_ring(sc, &sc->txq[1], IWI_TX_RING_COUNT,
+ IWI_CSR_TX2_RIDX, IWI_CSR_TX2_WIDX);
+ if (error != 0) {
+ device_printf(dev, "could not allocate Tx ring 2\n");
goto fail;
}
- error = iwi_dma_alloc(sc);
+ error = iwi_alloc_tx_ring(sc, &sc->txq[2], IWI_TX_RING_COUNT,
+ IWI_CSR_TX3_RIDX, IWI_CSR_TX3_WIDX);
if (error != 0) {
- device_printf(dev, "could not allocate DMA resources\n");
+ device_printf(dev, "could not allocate Tx ring 3\n");
goto fail;
}
- ic->ic_phytype = IEEE80211_T_OFDM;
- ic->ic_opmode = IEEE80211_M_STA;
- ic->ic_state = IEEE80211_S_INIT;
+ error = iwi_alloc_tx_ring(sc, &sc->txq[3], IWI_TX_RING_COUNT,
+ IWI_CSR_TX4_RIDX, IWI_CSR_TX4_WIDX);
+ if (error != 0) {
+ device_printf(dev, "could not allocate Tx ring 4\n");
+ goto fail;
+ }
+
+ error = iwi_alloc_rx_ring(sc, &sc->rxq, IWI_RX_RING_COUNT);
+ if (error != 0) {
+ device_printf(dev, "could not allocate Rx ring\n");
+ goto fail;
+ }
+
+ sysctl_ctx_init(&sc->sysctl_ctx);
+ sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
+ SYSCTL_STATIC_CHILDREN(_hw),
+ OID_AUTO,
+ device_get_nameunit(dev),
+ CTLFLAG_RD,
+ 0, "");
+ if (sc->sysctl_tree == NULL) {
+ device_printf(dev, "sysctl add node failed\n");
+ error = EIO;
+ goto fail;
+ }
+
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_init = iwi_init;
+ ifp->if_ioctl = iwi_ioctl;
+ ifp->if_start = iwi_start;
+ ifp->if_watchdog = iwi_watchdog;
+ ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
+ ifq_set_ready(&ifp->if_snd);
+
+ ic->ic_wme.wme_update = iwi_wme_update;
+ ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
+ ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
+ ic->ic_state = IEEE80211_S_INIT;
/* set device capabilities */
- ic->ic_caps = IEEE80211_C_IBSS | IEEE80211_C_PMGT | IEEE80211_C_WEP |
- IEEE80211_C_TXPMGT | IEEE80211_C_SHPREAMBLE;
+ ic->ic_caps =
+ IEEE80211_C_IBSS | /* IBSS mode supported */
+ IEEE80211_C_MONITOR | /* monitor mode supported */
+ IEEE80211_C_TXPMGT | /* tx power management */
+ IEEE80211_C_SHPREAMBLE | /* short preamble supported */
+ IEEE80211_C_WEP | /* WEP */
+ IEEE80211_C_WPA | /* 802.11i */
+ IEEE80211_C_WME; /* 802.11e */
/* read MAC address from EEPROM */
val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 0);
- ic->ic_myaddr[0] = val >> 8;
- ic->ic_myaddr[1] = val & 0xff;
+ ic->ic_myaddr[0] = val & 0xff;
+ ic->ic_myaddr[1] = val >> 8;
val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 1);
- ic->ic_myaddr[2] = val >> 8;
- ic->ic_myaddr[3] = val & 0xff;
+ ic->ic_myaddr[2] = val & 0xff;
+ ic->ic_myaddr[3] = val >> 8;
val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 2);
- ic->ic_myaddr[4] = val >> 8;
- ic->ic_myaddr[5] = val & 0xff;
+ ic->ic_myaddr[4] = val & 0xff;
+ ic->ic_myaddr[5] = val >> 8;
- if (pci_get_device(dev) != 0x4220) {
- /* set supported .11a rates */
+ if (pci_get_device(dev) >= 0x4223) {
+ /* set supported .11a rates (2915ABG only) */
ic->ic_sup_rates[IEEE80211_MODE_11A] = iwi_rateset_11a;
/* set supported .11a channels */
IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
}
- /* default to authmode OPEN */
- sc->authmode = IEEE80211_AUTH_OPEN;
-
- /* IBSS channel undefined for now */
- ic->ic_ibss_chan = &ic->ic_channels[0];
-
- ifp->if_softc = sc;
- if_initname(ifp, device_get_name(dev), device_get_unit(dev));
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_init = iwi_init;
- ifp->if_ioctl = iwi_ioctl;
- ifp->if_start = iwi_start;
- ifp->if_watchdog = iwi_watchdog;
- ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
- ifq_set_ready(&ifp->if_snd);
-
- ieee80211_ifattach(ifp);
+ ieee80211_ifattach(ic);
+ /* override default methods */
+ ic->ic_node_alloc = iwi_node_alloc;
+ sc->sc_node_free = ic->ic_node_free;
+ ic->ic_node_free = iwi_node_free;
/* override state transition machine */
sc->sc_newstate = ic->ic_newstate;
ic->ic_newstate = iwi_newstate;
- ieee80211_media_init(ifp, iwi_media_change, iwi_media_status);
+ ieee80211_media_init(ic, iwi_media_change, iwi_media_status);
bpfattach_dlt(ifp, DLT_IEEE802_11_RADIO,
sizeof (struct ieee80211_frame) + 64, &sc->sc_drvbpf);
sc->sc_txtap.wt_ihdr.it_present = htole32(IWI_TX_RADIOTAP_PRESENT);
/*
- * Add sysctl knobs
- *
- * use -1 to indicate 'default / not set'
+ * Add a few sysctl knobs.
*/
-
- sc->enable_bg_autodetect = -1;
- sc->enable_bt_coexist = -1;
- sc->enable_cts_to_self = -1;
- sc->antenna_diversity = -1;
- sc->enable_neg_best_first = -1;
- sc->disable_unicast_decryption = -1;
- sc->disable_multicast_decryption = -1;
-
- sysctl_ctx_init(&sc->sysctl_ctx);
- sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
- SYSCTL_STATIC_CHILDREN(_hw),
- OID_AUTO,
- device_get_nameunit(dev),
- CTLFLAG_RD,
- 0, "");
-
- if (sc->sysctl_tree == NULL) {
- device_printf(dev, "sysctl add node failed\n");
- error = EIO;
- goto fail2;
- }
-
- SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
- OID_AUTO, "debug", CTLFLAG_RW, &sc->debug_level, 0,
- "Set driver debug level (0 = off)");
-
- SYSCTL_ADD_PROC(&sc->sysctl_ctx,
- SYSCTL_CHILDREN(sc->sysctl_tree),
- OID_AUTO, "cts_to_self", CTLTYPE_INT|CTLFLAG_RW,
- (void *)sc, 0, iwi_sysctl_cts_to_self, "I",
- "Enable cts to self [0 = Off] [1 = On] [-1 = Auto]" );
-
- SYSCTL_ADD_PROC(&sc->sysctl_ctx,
- SYSCTL_CHILDREN(sc->sysctl_tree),
- OID_AUTO, "antenna_diversity", CTLTYPE_INT|CTLFLAG_RW,
- (void *)sc, 0, iwi_sysctl_antenna_diversity,
- "I", "Set antenna diversity [0 = Both] "
- "[1 = Antenna A] [3 = Antenna B] [-1 = Auto]" );
+ sc->dwelltime = 100;
+ sc->bluetooth = 1;
+ sc->antenna = 0;
SYSCTL_ADD_PROC(&sc->sysctl_ctx,
- SYSCTL_CHILDREN(sc->sysctl_tree),
- OID_AUTO, "bluetooth_coexist", CTLTYPE_INT|CTLFLAG_RW,
- (void *)sc, 0, iwi_sysctl_bt_coexist,
- "I", "Enable bluetooth coexistence heuristics "
- "[0 = Off] [1 = On] [-1 = Auto]" );
+ SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "radio",
+ CTLTYPE_INT | CTLFLAG_RD, sc, 0, iwi_sysctl_radio, "I",
+ "radio transmitter switch state (0=off, 1=on)");
SYSCTL_ADD_PROC(&sc->sysctl_ctx,
- SYSCTL_CHILDREN(sc->sysctl_tree),
- OID_AUTO, "bg_autodetect", CTLTYPE_INT|CTLFLAG_RW,
- (void *)sc, 0, iwi_sysctl_bg_autodetect,
- "I", "Set b/g autodetect [0 = Off] [1 = On] [-1 = Auto]" );
+ SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "stats",
+ CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, iwi_sysctl_stats, "S",
+ "statistics");
+ SYSCTL_ADD_INT(&sc->sysctl_ctx,
+ SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "dwell",
+ CTLFLAG_RW, &sc->dwelltime, 0,
+ "channel dwell time (ms) for AP/station scanning");
- SYSCTL_ADD_PROC(&sc->sysctl_ctx,
- SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "radio",
- CTLTYPE_INT | CTLFLAG_RD, sc, 0, iwi_sysctl_radio, "I",
- "Radio transmitter switch");
+ SYSCTL_ADD_INT(&sc->sysctl_ctx,
+ SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "bluetooth",
+ CTLFLAG_RW, &sc->bluetooth, 0, "bluetooth coexistence");
- SYSCTL_ADD_PROC(&sc->sysctl_ctx,
- SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "stats",
- CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, iwi_sysctl_stats,
- "S,iwi_dump_buffer", "statistics");
-
- SYSCTL_ADD_PROC(&sc->sysctl_ctx,
- SYSCTL_CHILDREN(sc->sysctl_tree),
- OID_AUTO, "firmware_logs", CTLTYPE_INT|CTLFLAG_RW,
- (void *)sc, 0, iwi_sysctl_dump_logs, "I", "Dump firmware logs");
-
- SYSCTL_ADD_PROC(&sc->sysctl_ctx,
- SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
- "neg_best_rates_first",
- CTLTYPE_INT | CTLFLAG_RW, sc, 0,
- iwi_sysctl_neg_best_rates_first, "I",
- "Negotiate highest rates first.");
-
- SYSCTL_ADD_PROC(&sc->sysctl_ctx,
- SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
- "disable_unicast_decrypt",
- CTLTYPE_INT | CTLFLAG_RW, sc, 0,
- iwi_sysctl_disable_unicast_decryption, "I",
- "Disable unicast decryption.");
-
- SYSCTL_ADD_PROC(&sc->sysctl_ctx,
- SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
- "disable_multicast_decrypt",
- CTLTYPE_INT | CTLFLAG_RW, sc, 0,
- iwi_sysctl_disable_multicast_decryption, "I",
- "Disable multicast decryption.");
+ SYSCTL_ADD_INT(&sc->sysctl_ctx,
+ SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "antenna",
+ CTLFLAG_RW, &sc->antenna, 0, "antenna (0=auto)");
/*
- * Hook our interrupt after all initialization is complete
+ * Hook our interrupt after all initialization is complete.
*/
- error = bus_setup_intr(dev, sc->irq, INTR_MPSAFE,
- iwi_intr, sc, &sc->sc_ih, ifp->if_serializer);
+ error = bus_setup_intr(dev, sc->irq, INTR_MPSAFE, iwi_intr, sc,
+ &sc->sc_ih, ifp->if_serializer);
if (error != 0) {
device_printf(dev, "could not set up interrupt\n");
- goto fail2;
+
+ bpfdetach(ifp);
+ ieee80211_ifdetach(ic);
+ goto fail;
}
- return 0;
+ if (bootverbose)
+ ieee80211_announce(ic);
-fail2:
- bpfdetach(ifp);
- ieee80211_ifdetach(ifp);
+ return 0;
fail:
iwi_detach(dev);
- return error;
+ return ENXIO;
}
static int
iwi_detach(device_t dev)
{
struct iwi_softc *sc = device_get_softc(dev);
- struct ifnet *ifp = &sc->sc_ic.ic_if;
-
- sc->flags |= IWI_FLAG_EXIT;
- wakeup(IWI_FW_WAKE_MONITOR(sc)); /* Stop firmware monitor. */
-
- tsleep(IWI_FW_MON_EXIT(sc), 0, "iwiexi", 10 * hz);
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = ic->ic_ifp;
if (device_is_attached(dev)) {
lwkt_serialize_enter(ifp->if_serializer);
+
iwi_stop(sc);
- iwi_free_firmware(sc);
bus_teardown_intr(dev, sc->irq, sc->sc_ih);
+ iwi_free_firmware(sc);
+
lwkt_serialize_exit(ifp->if_serializer);
bpfdetach(ifp);
- ieee80211_ifdetach(ifp);
+ ieee80211_ifdetach(ic);
}
- if (sc->sysctl_tree) {
- sysctl_ctx_free(&sc->sysctl_ctx);
- sc->sysctl_tree = 0;
- }
+ iwi_free_cmd_ring(sc, &sc->cmdq);
+ iwi_free_tx_ring(sc, &sc->txq[0]);
+ iwi_free_tx_ring(sc, &sc->txq[1]);
+ iwi_free_tx_ring(sc, &sc->txq[2]);
+ iwi_free_tx_ring(sc, &sc->txq[3]);
+ iwi_free_rx_ring(sc, &sc->rxq);
if (sc->irq != NULL)
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
+ bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
- if (sc->mem != NULL) {
- bus_release_resource(dev, SYS_RES_MEMORY, IWI_PCI_BAR0,
- sc->mem);
- }
+ if (sc->mem != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
- iwi_release(sc);
+ if (sc->sysctl_tree != NULL)
+ sysctl_ctx_free(&sc->sysctl_ctx);
return 0;
}
+static void
+iwi_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ if (error != 0)
+ return;
+
+ KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
+
+ *(bus_addr_t *)arg = segs[0].ds_addr;
+}
+
static int
-iwi_dma_alloc(struct iwi_softc *sc)
+iwi_alloc_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring, int count)
{
- int i, error;
+ int error;
- error = bus_dma_tag_create(NULL, /* parent */
- 1, 0,
- BUS_SPACE_MAXADDR_32BIT,
- BUS_SPACE_MAXADDR,
- NULL, NULL,
- MAXBSIZE, 128,
- BUS_SPACE_MAXSIZE_32BIT,
- BUS_DMA_ALLOCNOW,
- &sc->iwi_parent_tag );
+ ring->count = count;
+ ring->queued = 0;
+ ring->cur = ring->next = 0;
+
+ error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR, NULL, NULL, count * IWI_CMD_DESC_SIZE, 1,
+ count * IWI_CMD_DESC_SIZE, 0, &ring->desc_dmat);
if (error != 0) {
- device_printf(sc->sc_dev, "could not create parent tag\n");
+ device_printf(sc->sc_dev, "could not create desc DMA tag\n");
goto fail;
}
- /*
- * Allocate and map Tx ring
- */
- error = bus_dma_tag_create(sc->iwi_parent_tag, 4, 0, BUS_SPACE_MAXADDR_32BIT,
- BUS_SPACE_MAXADDR, NULL, NULL,
- sizeof (struct iwi_tx_desc) * IWI_TX_RING_SIZE, 1,
- sizeof (struct iwi_tx_desc) * IWI_TX_RING_SIZE,
- BUS_DMA_ALLOCNOW, &sc->tx_ring_dmat);
+
+ error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc,
+ BUS_DMA_WAITOK | BUS_DMA_ZERO, &ring->desc_map);
if (error != 0) {
- device_printf(sc->sc_dev, "could not create tx ring DMA tag\n");
+ device_printf(sc->sc_dev, "could not allocate DMA memory\n");
goto fail;
}
- error = bus_dmamem_alloc(sc->tx_ring_dmat,(void **) &sc->tx_desc,
- BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->tx_ring_map);
+ error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc,
+ count * IWI_CMD_DESC_SIZE, iwi_dma_map_addr, &ring->physaddr, 0);
if (error != 0) {
- device_printf(sc->sc_dev,
- "could not allocate tx ring DMA memory\n");
- goto fail;
+ device_printf(sc->sc_dev, "could not load desc DMA map\n");
+ bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map);
+ ring->desc = NULL;
+ return error;
}
- error = bus_dmamap_load(sc->tx_ring_dmat, sc->tx_ring_map,
- sc->tx_desc, sizeof (struct iwi_tx_desc) * IWI_TX_RING_SIZE,
- iwi_dma_map_addr, &sc->tx_ring_pa, 0);
- if (error != 0) {
- device_printf(sc->sc_dev, "could not load tx ring DMA map\n");
- goto fail;
+ return 0;
+
+fail: iwi_free_cmd_ring(sc, ring);
+ return error;
+}
+
+static void
+iwi_reset_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring)
+{
+ ring->queued = 0;
+ ring->cur = ring->next = 0;
+}
+
+static void
+iwi_free_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring)
+{
+ if (ring->desc != NULL) {
+ bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(ring->desc_dmat, ring->desc_map);
+ bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map);
+ ring->desc = NULL;
}
- /*
- * Allocate and map command ring
- */
- error = bus_dma_tag_create(sc->iwi_parent_tag, 4, 0, BUS_SPACE_MAXADDR_32BIT,
- BUS_SPACE_MAXADDR, NULL, NULL,
- sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE, 1,
- sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE,
- BUS_DMA_ALLOCNOW,
- &sc->cmd_ring_dmat);
+ if (ring->desc_dmat != NULL) {
+ bus_dma_tag_destroy(ring->desc_dmat);
+ ring->desc_dmat = NULL;
+ }
+}
+
+static int
+iwi_alloc_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring, int count,
+ bus_addr_t csr_ridx, bus_addr_t csr_widx)
+{
+ int i, error;
+
+ ring->count = count;
+ ring->queued = 0;
+ ring->cur = ring->next = 0;
+ ring->csr_ridx = csr_ridx;
+ ring->csr_widx = csr_widx;
+
+ error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR, NULL, NULL, count * IWI_TX_DESC_SIZE, 1,
+ count * IWI_TX_DESC_SIZE, 0, &ring->desc_dmat);
if (error != 0) {
- device_printf(sc->sc_dev,
- "could not create command ring DMA tag\n");
+ device_printf(sc->sc_dev, "could not create desc DMA tag\n");
goto fail;
}
- error = bus_dmamem_alloc(sc->cmd_ring_dmat, (void **)&sc->cmd_desc,
- BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->cmd_ring_map);
+ error = bus_dmamem_alloc(ring->desc_dmat, (void **)&ring->desc,
+ BUS_DMA_WAITOK | BUS_DMA_ZERO, &ring->desc_map);
if (error != 0) {
- device_printf(sc->sc_dev,
- "could not allocate command ring DMA memory\n");
+ device_printf(sc->sc_dev, "could not allocate DMA memory\n");
goto fail;
}
- error = bus_dmamap_load(sc->cmd_ring_dmat, sc->cmd_ring_map,
- sc->cmd_desc, sizeof (struct iwi_cmd_desc) * IWI_CMD_RING_SIZE,
- iwi_dma_map_addr, &sc->cmd_ring_pa, 0);
+ error = bus_dmamap_load(ring->desc_dmat, ring->desc_map, ring->desc,
+ count * IWI_TX_DESC_SIZE, iwi_dma_map_addr, &ring->physaddr, 0);
if (error != 0) {
- device_printf(sc->sc_dev,
- "could not load command ring DMA map\n");
+ device_printf(sc->sc_dev, "could not load desc DMA map\n");
+
+ bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map);
+ ring->desc = NULL;
goto fail;
}
- /*
- * Allocate Tx buffers DMA maps
- */
- error = bus_dma_tag_create(sc->iwi_parent_tag, 1, 0, BUS_SPACE_MAXADDR_32BIT,
- BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, IWI_MAX_NSEG, MCLBYTES,
- BUS_DMA_ALLOCNOW, &sc->tx_buf_dmat);
+ ring->data = malloc(count * sizeof (struct iwi_tx_data), M_DEVBUF,
+ M_WAITOK | M_ZERO);
+
+ error = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, IWI_MAX_NSEG - 2,
+ MCLBYTES, 0, &ring->data_dmat);
if (error != 0) {
- device_printf(sc->sc_dev, "could not create tx buf DMA tag\n");
+ device_printf(sc->sc_dev, "could not create data DMA tag\n");
goto fail;
}
- for (i = 0; i < IWI_TX_RING_SIZE; i++) {
- error = bus_dmamap_create(sc->tx_buf_dmat, 0,
- &sc->tx_buf[i].map);
+ for (i = 0; i < count; i++) {
+ error = bus_dmamap_create(ring->data_dmat, 0,
+ &ring->data[i].map);
if (error != 0) {
- device_printf(sc->sc_dev,
- "could not create tx buf DMA map");
+ device_printf(sc->sc_dev, "could not create DMA map\n");
goto fail;
}
}
- /*
- * Allocate and map Rx buffers
- */
- error = bus_dma_tag_create(sc->iwi_parent_tag, 1, 0, BUS_SPACE_MAXADDR_32BIT,
- BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES,
- BUS_DMA_ALLOCNOW, &sc->rx_buf_dmat);
+ return 0;
+
+fail: iwi_free_tx_ring(sc, ring);
+ return error;
+}
+
+static void
+iwi_reset_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring)
+{
+ struct iwi_tx_data *data;
+ int i;
+
+ for (i = 0; i < ring->count; i++) {
+ data = &ring->data[i];
+
+ if (data->m != NULL) {
+ bus_dmamap_sync(ring->data_dmat, data->map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(ring->data_dmat, data->map);
+ m_freem(data->m);
+ data->m = NULL;
+ }
+
+ if (data->ni != NULL) {
+ ieee80211_free_node(data->ni);
+ data->ni = NULL;
+ }
+ }
+
+ ring->queued = 0;
+ ring->cur = ring->next = 0;
+}
+
+static void
+iwi_free_tx_ring(struct iwi_softc *sc, struct iwi_tx_ring *ring)
+{
+ struct iwi_tx_data *data;
+ int i;
+
+ if (ring->desc != NULL) {
+ bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(ring->desc_dmat, ring->desc_map);
+ bus_dmamem_free(ring->desc_dmat, ring->desc, ring->desc_map);
+ ring->desc = NULL;
+ }
+
+ if (ring->desc_dmat != NULL) {
+ bus_dma_tag_destroy(ring->desc_dmat);
+ ring->desc_dmat = NULL;
+ }
+
+ if (ring->data != NULL) {
+ for (i = 0; i < ring->count; i++) {
+ data = &ring->data[i];
+
+ if (data->m != NULL) {
+ bus_dmamap_sync(ring->data_dmat, data->map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(ring->data_dmat, data->map);
+ m_freem(data->m);
+ data->m = NULL;
+ }
+
+ if (data->ni != NULL) {
+ ieee80211_free_node(data->ni);
+ data->ni = NULL;
+ }
+
+ if (data->map != NULL) {
+ bus_dmamap_destroy(ring->data_dmat, data->map);
+ data->map = NULL;
+ }
+ }
+
+ free(ring->data, M_DEVBUF);
+ ring->data = NULL;
+ }
+
+ if (ring->data_dmat != NULL) {
+ bus_dma_tag_destroy(ring->data_dmat);
+ ring->data_dmat = NULL;
+ }
+}
+
+static int
+iwi_alloc_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring, int count)
+{
+ struct iwi_rx_data *data;
+ int i, error;
+
+ ring->count = count;
+ ring->cur = 0;
+
+ ring->data = malloc(count * sizeof (struct iwi_rx_data), M_DEVBUF,
+ M_WAITOK | M_ZERO);
+
+ error = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES, 0,
+ &ring->data_dmat);
if (error != 0) {
- device_printf(sc->sc_dev, "could not create rx buf DMA tag\n");
+ device_printf(sc->sc_dev, "could not create data DMA tag\n");
goto fail;
}
- for (i = 0; i < IWI_RX_RING_SIZE; i++) {
+ for (i = 0; i < count; i++) {
+ data = &ring->data[i];
- error = bus_dmamap_create(sc->rx_buf_dmat, 0,
- &sc->rx_buf[i].map);
+ error = bus_dmamap_create(ring->data_dmat, 0, &data->map);
if (error != 0) {
- device_printf(sc->sc_dev,
- "could not create rx buf DMA map");
+ device_printf(sc->sc_dev, "could not create DMA map\n");
goto fail;
}
- sc->rx_buf[i].m = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
- if (sc->rx_buf[i].m == NULL) {
+ data->m = m_getcl(MB_WAIT, MT_DATA, M_PKTHDR);
+ if (data->m == NULL) {
device_printf(sc->sc_dev,
"could not allocate rx mbuf\n");
error = ENOMEM;
goto fail;
}
- error = bus_dmamap_load(sc->rx_buf_dmat, sc->rx_buf[i].map,
- mtod(sc->rx_buf[i].m, void *), MCLBYTES, iwi_dma_map_addr,
- &sc->rx_buf[i].physaddr, 0);
+ error = bus_dmamap_load(ring->data_dmat, data->map,
+ mtod(data->m, void *), MCLBYTES, iwi_dma_map_addr,
+ &data->physaddr, 0);
if (error != 0) {
device_printf(sc->sc_dev,
"could not load rx buf DMA map");
+
+ m_freem(data->m);
+ data->m = NULL;
goto fail;
}
+
+ data->reg = IWI_CSR_RX_BASE + i * 4;
}
return 0;
-fail: iwi_release(sc);
+fail: iwi_free_rx_ring(sc, ring);
return error;
}
static void
-iwi_release(struct iwi_softc *sc)
+iwi_reset_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring)
{
- int i;
+ ring->cur = 0;
+}
- if (sc->tx_ring_dmat != NULL) {
- if (sc->tx_desc != NULL) {
- bus_dmamap_sync(sc->tx_ring_dmat, sc->tx_ring_map,
- BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->tx_ring_dmat, sc->tx_ring_map);
- bus_dmamem_free(sc->tx_ring_dmat, sc->tx_desc,
- sc->tx_ring_map);
- }
- bus_dma_tag_destroy(sc->tx_ring_dmat);
- }
+static void
+iwi_free_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring)
+{
+ struct iwi_rx_data *data;
+ int i;
- if (sc->cmd_ring_dmat != NULL) {
- if (sc->cmd_desc != NULL) {
- bus_dmamap_sync(sc->cmd_ring_dmat, sc->cmd_ring_map,
- BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->cmd_ring_dmat, sc->cmd_ring_map);
- bus_dmamem_free(sc->cmd_ring_dmat, sc->cmd_desc,
- sc->cmd_ring_map);
- }
- bus_dma_tag_destroy(sc->cmd_ring_dmat);
- }
+ if (ring->data != NULL) {
+ for (i = 0; i < ring->count; i++) {
+ data = &ring->data[i];
- if (sc->tx_buf_dmat != NULL) {
- for (i = 0; i < IWI_TX_RING_SIZE; i++) {
- if (sc->tx_buf[i].m != NULL) {
- bus_dmamap_sync(sc->tx_buf_dmat,
- sc->tx_buf[i].map, BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->tx_buf_dmat,
- sc->tx_buf[i].map);
- m_freem(sc->tx_buf[i].m);
+ if (data->m != NULL) {
+ bus_dmamap_sync(ring->data_dmat, data->map,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(ring->data_dmat, data->map);
+ m_freem(data->m);
+ data->m = NULL;
}
- bus_dmamap_destroy(sc->tx_buf_dmat, sc->tx_buf[i].map);
- }
- bus_dma_tag_destroy(sc->tx_buf_dmat);
- }
- if (sc->rx_buf_dmat != NULL) {
- for (i = 0; i < IWI_RX_RING_SIZE; i++) {
- if (sc->rx_buf[i].m != NULL) {
- bus_dmamap_sync(sc->rx_buf_dmat,
- sc->rx_buf[i].map, BUS_DMASYNC_POSTREAD);
- bus_dmamap_unload(sc->rx_buf_dmat,
- sc->rx_buf[i].map);
- m_freem(sc->rx_buf[i].m);
+ if (data->map != NULL) {
+ bus_dmamap_destroy(ring->data_dmat, data->map);
+ data->map = NULL;
}
- bus_dmamap_destroy(sc->rx_buf_dmat, sc->rx_buf[i].map);
}
- bus_dma_tag_destroy(sc->rx_buf_dmat);
+
+ free(ring->data, M_DEVBUF);
+ ring->data = NULL;
}
- if ( sc->iwi_parent_tag != NULL ) {
- bus_dma_tag_destroy(sc->iwi_parent_tag);
+
+ if (ring->data_dmat != NULL) {
+ bus_dma_tag_destroy(ring->data_dmat);
+ ring->data_dmat = NULL;
}
}
iwi_resume(device_t dev)
{
struct iwi_softc *sc = device_get_softc(dev);
- struct ifnet *ifp = &sc->sc_ic.ic_if;
+ struct ifnet *ifp = sc->sc_ic.ic_ifp;
lwkt_serialize_enter(ifp->if_serializer);
+
pci_write_config(dev, 0x41, 0, 1);
if (ifp->if_flags & IFF_UP) {
if (ifp->if_flags & IFF_RUNNING)
ifp->if_start(ifp);
}
+
lwkt_serialize_exit(ifp->if_serializer);
+
return 0;
}
+static struct ieee80211_node *
+iwi_node_alloc(struct ieee80211_node_table *nt)
+{
+ struct iwi_node *in;
+
+ in = malloc(sizeof (struct iwi_node), M_80211_NODE, M_NOWAIT | M_ZERO);
+ if (in == NULL)
+ return NULL;
+
+ in->in_station = -1;
+
+ return &in->in_node;
+}
+
+static void
+iwi_node_free(struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct iwi_softc *sc = ic->ic_ifp->if_softc;
+ struct iwi_node *in = (struct iwi_node *)ni;
+
+ if (in->in_station != -1)
+ iwi_free_ibss_node(sc, in->in_station);
+
+ sc->sc_node_free(ni);
+}
+
static int
iwi_media_change(struct ifnet *ifp)
{
struct iwi_softc *sc = ifp->if_softc;
- int error = 0;
+ int error;
+
+ ASSERT_SERIALIZED(ifp->if_serializer);
error = ieee80211_media_change(ifp);
- if (error != ENETRESET) {
+ if (error != ENETRESET)
return error;
- }
- error = 0; /* clear ENETRESET */
- if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)){
+ if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
iwi_init(sc);
- error = tsleep( IWI_FW_CMD_ACKED(sc), 0, "iwirun", hz );
- }
- return error;
+ return 0;
}
+/*
+ * The firmware automatically adapts the transmit speed. We report its current
+ * value here.
+ */
static void
iwi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
{
struct ieee80211com *ic = &sc->sc_ic;
#define N(a) (sizeof (a) / sizeof (a[0]))
static const struct {
- u_int32_t val;
+ uint32_t val;
int rate;
} rates[] = {
{ IWI_RATE_DS1, 2 },
{ IWI_RATE_OFDM48, 96 },
{ IWI_RATE_OFDM54, 108 },
};
- u_int32_t val, i;
- int rate;
+ uint32_t val;
+ int rate, i;
imr->ifm_status = IFM_AVALID;
imr->ifm_active = IFM_IEEE80211;
val = CSR_READ_4(sc, IWI_CSR_CURRENT_TX_RATE);
/* convert rate to 802.11 rate */
- for (i = 0; i < N(rates) && rates[i].val != val ; i++);
+ for (i = 0; i < N(rates) && rates[i].val != val; i++);
rate = (i < N(rates)) ? rates[i].rate : 0;
imr->ifm_active |= ieee80211_rate2media(ic, rate, ic->ic_curmode);
}
static int
-iwi_disassociate( struct iwi_softc *sc )
-{
- sc->assoc.type = 2; /* DISASSOCIATE */
- return iwi_cmd(sc, IWI_CMD_ASSOCIATE, &sc->assoc, sizeof sc->assoc, 0);
-}
-
-
-static int
-iwi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg __unused)
+iwi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
{
- struct iwi_softc *sc = ic->ic_softc;
- struct ifnet *ifp = &ic->ic_if;
+ struct ifnet *ifp = ic->ic_ifp;
+ struct iwi_softc *sc = ifp->if_softc;
+ enum ieee80211_state ostate;
+ uint32_t tmp;
- ASSERT_SERIALIZED(ifp->if_serializer);
+ ostate = ic->ic_state;
switch (nstate) {
case IEEE80211_S_SCAN:
- if (sc->flags & IWI_FLAG_ASSOCIATED) {
- sc->flags &= ~( IWI_FLAG_ASSOCIATED );
- iwi_disassociate(sc);
-
- crit_enter();
- tsleep_interlock(IWI_FW_DEASSOCIATED(sc));
- lwkt_serialize_exit(ifp->if_serializer);
- tsleep(IWI_FW_DEASSOCIATED(sc), 0, "iwisca", hz );
- crit_exit();
- lwkt_serialize_enter(ifp->if_serializer);
- }
- if ( !(sc->flags & IWI_FLAG_SCANNING) &&
- !(sc->flags & IWI_FLAG_RF_DISABLED) ) {
- iwi_scan(sc);
- }
+ if (sc->flags & IWI_FLAG_SCANNING)
+ break;
+
+ ieee80211_node_table_reset(&ic->ic_scan);
+ ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN;
+ sc->flags |= IWI_FLAG_SCANNING;
+ iwi_scan(sc);
break;
case IEEE80211_S_AUTH:
- if ( sc->flags & IWI_FLAG_ASSOCIATED ) {
- sc->flags &= ~( IWI_FLAG_ASSOCIATED );
- iwi_disassociate(sc);
-
- crit_enter();
- tsleep_interlock(IWI_FW_DEASSOCIATED(sc));
- lwkt_serialize_exit(ifp->if_serializer);
- tsleep(IWI_FW_DEASSOCIATED(sc), 0, "iwiaut", hz );
- crit_exit();
- lwkt_serialize_enter(ifp->if_serializer);
- }
- if ( iwi_auth_and_assoc(sc) != 0 )
- ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+ iwi_auth_and_assoc(sc);
break;
case IEEE80211_S_RUN:
- if (sc->flags & IWI_FLAG_SCAN_COMPLETE) {
- sc->flags &= ~(IWI_FLAG_SCAN_COMPLETE);
- if (ic->ic_opmode == IEEE80211_M_IBSS ||
- ic->ic_opmode == IEEE80211_M_MONITOR ) {
- /*
- * In IBSS mode, following an end_scan
- * the ieee80211 stack state machine transitions
- * straight to 'run' state. This is out of
- * step with the firmware which requires
- * an association first. Flip our state from
- * RUN back to AUTH to allow us to tell the
- * firmware to associate.
- */
- ieee80211_new_state(ic, IEEE80211_S_AUTH, -1);
- }
- }
- break;
+ if (ic->ic_opmode == IEEE80211_M_IBSS)
+ iwi_auth_and_assoc(sc);
+ else if (ic->ic_opmode == IEEE80211_M_MONITOR)
+ iwi_set_chan(sc, ic->ic_ibss_chan);
+
+ /* assoc led on */
+ tmp = MEM_READ_4(sc, IWI_MEM_EVENT_CTL) & IWI_LED_MASK;
+ MEM_WRITE_4(sc, IWI_MEM_EVENT_CTL, tmp | IWI_LED_ASSOC);
+
+ return sc->sc_newstate(ic, nstate,
+ IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
case IEEE80211_S_ASSOC:
break;
+
case IEEE80211_S_INIT:
- sc->flags &= ~( IWI_FLAG_SCANNING | IWI_FLAG_ASSOCIATED );
+ sc->flags &= ~IWI_FLAG_SCANNING;
+
+ if (ostate != IEEE80211_S_RUN)
+ break;
+
+ /* assoc led off */
+ tmp = MEM_READ_4(sc, IWI_MEM_EVENT_CTL) & IWI_LED_MASK;
+ MEM_WRITE_4(sc, IWI_MEM_EVENT_CTL, tmp & ~IWI_LED_ASSOC);
break;
}
ic->ic_state = nstate;
+
return 0;
}
+/*
+ * WME parameters coming from IEEE 802.11e specification. These values are
+ * already declared in ieee80211_proto.c, but they are static so they can't
+ * be reused here.
+ */
+static const struct wmeParams iwi_wme_cck_params[WME_NUM_AC] = {
+ { 0, 3, 5, 7, 0 }, /* WME_AC_BE */
+ { 0, 3, 5, 10, 0 }, /* WME_AC_BK */
+ { 0, 2, 4, 5, 188 }, /* WME_AC_VI */
+ { 0, 2, 3, 4, 102 } /* WME_AC_VO */
+};
+
+static const struct wmeParams iwi_wme_ofdm_params[WME_NUM_AC] = {
+ { 0, 3, 4, 6, 0 }, /* WME_AC_BE */
+ { 0, 3, 4, 10, 0 }, /* WME_AC_BK */
+ { 0, 2, 3, 4, 94 }, /* WME_AC_VI */
+ { 0, 2, 2, 3, 47 } /* WME_AC_VO */
+};
+
+static int
+iwi_wme_update(struct ieee80211com *ic)
+{
+#define IWI_EXP2(v) htole16((1 << (v)) - 1)
+#define IWI_USEC(v) htole16(IEEE80211_TXOP_TO_US(v))
+ struct iwi_softc *sc = ic->ic_ifp->if_softc;
+ struct iwi_wme_params wme[3];
+ const struct wmeParams *wmep;
+ int ac;
+
+ /*
+ * We shall not override firmware default WME values if WME is not
+ * actually enabled.
+ */
+ if (!(ic->ic_flags & IEEE80211_F_WME))
+ return 0;
+
+ for (ac = 0; ac < WME_NUM_AC; ac++) {
+ /* set WME values for current operating mode */
+ wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac];
+ wme[0].aifsn[ac] = wmep->wmep_aifsn;
+ wme[0].cwmin[ac] = IWI_EXP2(wmep->wmep_logcwmin);
+ wme[0].cwmax[ac] = IWI_EXP2(wmep->wmep_logcwmax);
+ wme[0].burst[ac] = IWI_USEC(wmep->wmep_txopLimit);
+ wme[0].acm[ac] = wmep->wmep_acm;
+
+ /* set WME values for CCK modulation */
+ wmep = &iwi_wme_cck_params[ac];
+ wme[1].aifsn[ac] = wmep->wmep_aifsn;
+ wme[1].cwmin[ac] = IWI_EXP2(wmep->wmep_logcwmin);
+ wme[1].cwmax[ac] = IWI_EXP2(wmep->wmep_logcwmax);
+ wme[1].burst[ac] = IWI_USEC(wmep->wmep_txopLimit);
+ wme[1].acm[ac] = wmep->wmep_acm;
+
+ /* set WME values for OFDM modulation */
+ wmep = &iwi_wme_ofdm_params[ac];
+ wme[2].aifsn[ac] = wmep->wmep_aifsn;
+ wme[2].cwmin[ac] = IWI_EXP2(wmep->wmep_logcwmin);
+ wme[2].cwmax[ac] = IWI_EXP2(wmep->wmep_logcwmax);
+ wme[2].burst[ac] = IWI_USEC(wmep->wmep_txopLimit);
+ wme[2].acm[ac] = wmep->wmep_acm;
+ }
+
+ DPRINTF(("Setting WME parameters\n"));
+ return iwi_cmd(sc, IWI_CMD_SET_WME_PARAMS, wme, sizeof wme, 1);
+#undef IWI_USEC
+#undef IWI_EXP2
+}
+
/*
* Read 16 bits at address 'addr' from the serial EEPROM.
- * DON'T PLAY WITH THIS CODE UNLESS YOU KNOW *EXACTLY* WHAT YOU'RE DOING!
*/
-static u_int16_t
-iwi_read_prom_word(struct iwi_softc *sc, u_int8_t addr)
+static uint16_t
+iwi_read_prom_word(struct iwi_softc *sc, uint8_t addr)
{
- u_int32_t tmp;
- u_int16_t val;
+ uint32_t tmp;
+ uint16_t val;
int n;
/* Clock C once before the first command */
IWI_EEPROM_CTL(sc, 0);
IWI_EEPROM_CTL(sc, IWI_EEPROM_C);
- return be16toh(val);
+ return val;
}
/*
* probe responses. Only used during AP detection.
*/
static void
-iwi_fix_channel(struct iwi_softc *sc, struct mbuf *m)
+iwi_fix_channel(struct ieee80211com *ic, struct mbuf *m)
{
- struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_frame *wh;
- u_int8_t subtype;
- u_int8_t *frm, *efrm;
+ uint8_t subtype;
+ uint8_t *frm, *efrm;
wh = mtod(m, struct ieee80211_frame *);
subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
if (subtype != IEEE80211_FC0_SUBTYPE_BEACON &&
- subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP)
- return;
-
- /*
- * Cache station entries from beacons and probes.
- */
- if ( iwi_find_station(sc, wh->i_addr2) == 0xff )
- iwi_cache_station(sc, wh->i_addr2);
+ subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP)
+ return;
- frm = (u_int8_t *)(wh + 1);
- efrm = mtod(m, u_int8_t *) + m->m_len;
+ frm = (uint8_t *)(wh + 1);
+ efrm = mtod(m, uint8_t *) + m->m_len;
frm += 12; /* skip tstamp, bintval and capinfo fields */
-#if 0
- { /* XXX - debugging code */
- u_int8_t *ptr;
- u_int32_t cnt;
- printf("Frame -->");
- for ( ptr = frm, cnt = 0 ; ptr < efrm ; ptr++, cnt++ ) {
- if ( cnt % 8 == 0 )
- printf("\n");
- printf("0x%-2.2x ", *ptr);
- }
- printf("<-- End Frame\n");
- }
-#endif
-
while (frm < efrm) {
if (*frm == IEEE80211_ELEMID_DSPARMS)
#if IEEE80211_CHAN_MAX < 255
if (frm[2] <= IEEE80211_CHAN_MAX)
#endif
- ic->ic_bss->ni_chan = &ic->ic_channels[frm[2]];
+ ic->ic_curchan = &ic->ic_channels[frm[2]];
- frm += frm[1] + 2; /* advance to the next tag */
+ frm += frm[1] + 2;
}
}
static void
-iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_buf *buf, int i,
+iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, int i,
struct iwi_frame *frame)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
- struct mbuf *m;
+ struct ifnet *ifp = ic->ic_ifp;
+ struct mbuf *mnew, *m;
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
int error;
- DPRINTFN(5, ("RX!DATA!%u!%u!%u\n", le16toh(frame->len), frame->chan,
- frame->rssi_dbm));
+ DPRINTFN(5, ("received frame len=%u chan=%u rssi=%u\n",
+ le16toh(frame->len), frame->chan, frame->rssi_dbm));
+
+ if (le16toh(frame->len) < sizeof (struct ieee80211_frame))
+ return;
+
+ /*
+ * Try to allocate a new mbuf for this ring element and load it before
+ * processing the current mbuf. If the ring element cannot be loaded,
+ * drop the received packet and reuse the old mbuf. In the unlikely
+ * case that the old mbuf can't be reloaded either, explicitly panic.
+ */
+ mnew = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (mnew == NULL) {
+ ifp->if_ierrors++;
+ return;
+ }
+
+ bus_dmamap_unload(sc->rxq.data_dmat, data->map);
- if (le16toh(frame->len) < sizeof (struct ieee80211_frame_min) ||
- le16toh(frame->len) > MCLBYTES) {
- device_printf(sc->sc_dev, "bad frame length\n");
+ error = bus_dmamap_load(sc->rxq.data_dmat, data->map,
+ mtod(mnew, void *), MCLBYTES, iwi_dma_map_addr, &data->physaddr,
+ 0);
+ if (error != 0) {
+ m_freem(mnew);
+
+ /* try to reload the old mbuf */
+ error = bus_dmamap_load(sc->rxq.data_dmat, data->map,
+ mtod(data->m, void *), MCLBYTES, iwi_dma_map_addr,
+ &data->physaddr, 0);
+ if (error != 0) {
+ /* very unlikely that it will fail... */
+ panic("%s: could not load old rx mbuf",
+ device_get_name(sc->sc_dev));
+ }
+ ifp->if_ierrors++;
return;
}
- bus_dmamap_unload(sc->rx_buf_dmat, buf->map);
+ /*
+ * New mbuf successfully loaded, update Rx ring and continue
+ * processing.
+ */
+ m = data->m;
+ data->m = mnew;
+ CSR_WRITE_4(sc, data->reg, data->physaddr);
/* Finalize mbuf */
- m = buf->m;
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = m->m_len = sizeof (struct iwi_hdr) +
sizeof (struct iwi_frame) + le16toh(frame->len);
m_adj(m, sizeof (struct iwi_hdr) + sizeof (struct iwi_frame));
- wh = mtod(m, struct ieee80211_frame *);
- if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
- /*
- * Hardware decrypts the frame itself but leaves the WEP bit
- * set in the 802.11 header and don't remove the iv and crc
- * fields
- */
- wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
- bcopy(wh, (char *)wh + IEEE80211_WEP_IVLEN +
- IEEE80211_WEP_KIDLEN, sizeof (struct ieee80211_frame));
- m_adj(m, IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN);
- m_adj(m, -IEEE80211_WEP_CRCLEN);
- wh = mtod(m, struct ieee80211_frame *);
- }
+ if (ic->ic_state == IEEE80211_S_SCAN)
+ iwi_fix_channel(ic, m);
if (sc->sc_drvbpf != NULL) {
struct iwi_rx_radiotap_header *tap = &sc->sc_rxtap;
tap->wr_chan_flags =
htole16(ic->ic_channels[frame->chan].ic_flags);
tap->wr_antsignal = frame->signal;
- tap->wr_antnoise = frame->noise;
tap->wr_antenna = frame->antenna;
bpf_ptap(sc->sc_drvbpf, m, tap, sc->sc_rxtap_len);
}
- if (ic->ic_state == IEEE80211_S_SCAN)
- iwi_fix_channel(sc, m);
-
- if (ic->ic_opmode != IEEE80211_M_STA) {
- ni = ieee80211_find_node(ic, wh->i_addr2);
- if (ni == NULL)
- ni = ieee80211_ref_node(ic->ic_bss);
- } else
- ni = ieee80211_ref_node(ic->ic_bss);
-
- /* Send the frame to the upper layer */
- ieee80211_input(ifp, m, ni, IWI_RSSIDBM2RAW(frame->rssi_dbm), 0);
-
- if (ni == ic->ic_bss)
- ieee80211_unref_node(&ni);
- else
- ieee80211_free_node(ic, ni);
-
- buf->m = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR);
- if (buf->m == NULL) {
- device_printf(sc->sc_dev, "could not allocate rx mbuf\n");
- return;
- }
+ wh = mtod(m, struct ieee80211_frame *);
+ ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
- error = bus_dmamap_load(sc->rx_buf_dmat, buf->map, mtod(buf->m, void *),
- MCLBYTES, iwi_dma_map_addr, &buf->physaddr, 0);
- if (error != 0) {
- device_printf(sc->sc_dev, "could not load rx buf DMA map\n");
- m_freem(buf->m);
- buf->m = NULL;
- return;
- }
+ /* send the frame to the 802.11 layer */
+ ieee80211_input(ic, m, ni, frame->rssi_dbm, 0);
- CSR_WRITE_4(sc, IWI_CSR_RX_BASE + i * 4, buf->physaddr);
+ /* node is no longer needed */
+ ieee80211_free_node(ni);
}
static void
iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
struct iwi_notif_scan_channel *chan;
struct iwi_notif_scan_complete *scan;
struct iwi_notif_authentication *auth;
case IWI_NOTIF_TYPE_SCAN_CHANNEL:
chan = (struct iwi_notif_scan_channel *)(notif + 1);
- DPRINTFN(2, ("Scan channel (%u)\n", chan->nchan));
+ DPRINTFN(2, ("Scanning channel (%u)\n", chan->nchan));
break;
case IWI_NOTIF_TYPE_SCAN_COMPLETE:
DPRINTFN(2, ("Scan completed (%u, %u)\n", scan->nchan,
scan->status));
- sc->flags &= ~(IWI_FLAG_SCANNING);
- sc->flags |= IWI_FLAG_SCAN_COMPLETE;
-
- if ( sc->flags & IWI_FLAG_SCAN_ABORT )
- sc->flags &= ~(IWI_FLAG_SCAN_ABORT);
- else
- ieee80211_end_scan(ifp);
- wakeup(IWI_FW_SCAN_COMPLETED(sc));
+ /* monitor mode uses scan to set the channel ... */
+ if (ic->ic_opmode != IEEE80211_M_MONITOR) {
+ sc->flags &= ~IWI_FLAG_SCANNING;
+ ieee80211_end_scan(ic);
+ } else
+ iwi_set_chan(sc, ic->ic_ibss_chan);
break;
case IWI_NOTIF_TYPE_AUTHENTICATION:
switch (auth->state) {
case IWI_AUTHENTICATED:
+ ieee80211_node_authorize(ic->ic_bss);
ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1);
break;
case IWI_DEAUTHENTICATED:
- ieee80211_begin_scan(ifp);/* not necessary */
break;
default:
assoc->status));
switch (assoc->state) {
+ case IWI_AUTHENTICATED:
+ /* re-association, do nothing */
+ break;
+
case IWI_ASSOCIATED:
- sc->flags |= IWI_FLAG_ASSOCIATED;
ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
break;
case IWI_DEASSOCIATED:
- sc->flags &= ~(IWI_FLAG_ASSOCIATED);
- wakeup(IWI_FW_DEASSOCIATED(sc));
- ieee80211_begin_scan(ifp);/* probably not necessary */
+ ieee80211_begin_scan(ic, 1);
break;
default:
}
break;
- case IWI_NOTIF_TYPE_CALIBRATION:
- DPRINTFN(5, ("Notification calib (%u)\n", notif->type));
- break;
- case IWI_NOTIF_TYPE_BEACON:
- DPRINTFN(5, ("Notification beacon (%u)\n", notif->type));
- break;
- case IWI_NOTIF_TYPE_NOISE:
- DPRINTFN(5, ("Notification noise (%u)\n", notif->type));
- break;
-
default:
- device_printf(sc->sc_dev, "unknown notification type %u\n",
- notif->type);
+ DPRINTFN(5, ("Notification (%u)\n", notif->type));
}
}
static void
iwi_rx_intr(struct iwi_softc *sc)
{
- struct iwi_rx_buf *buf;
+ struct iwi_rx_data *data;
struct iwi_hdr *hdr;
- u_int32_t r, i;
-
- r = CSR_READ_4(sc, IWI_CSR_RX_READ_INDEX);
+ uint32_t hw;
- for (i = (sc->rx_cur + 1) % IWI_RX_RING_SIZE; i != r;
- i = (i + 1) % IWI_RX_RING_SIZE) {
+ hw = CSR_READ_4(sc, IWI_CSR_RX_RIDX);
- buf = &sc->rx_buf[i];
+ for (; sc->rxq.cur != hw;) {
+ data = &sc->rxq.data[sc->rxq.cur];
- bus_dmamap_sync(sc->rx_buf_dmat, buf->map,
+ bus_dmamap_sync(sc->rxq.data_dmat, data->map,
BUS_DMASYNC_POSTREAD);
- hdr = mtod(buf->m, struct iwi_hdr *);
+ hdr = mtod(data->m, struct iwi_hdr *);
switch (hdr->type) {
case IWI_HDR_TYPE_FRAME:
- iwi_frame_intr(sc, buf, i,
+ iwi_frame_intr(sc, data, sc->rxq.cur,
(struct iwi_frame *)(hdr + 1));
break;
device_printf(sc->sc_dev, "unknown hdr type %u\n",
hdr->type);
}
+
+ DPRINTFN(15, ("rx done idx=%u\n", sc->rxq.cur));
+
+ sc->rxq.cur = (sc->rxq.cur + 1) % IWI_RX_RING_COUNT;
}
/* Tell the firmware what we have processed */
- sc->rx_cur = (r == 0) ? IWI_RX_RING_SIZE - 1 : r - 1;
- CSR_WRITE_4(sc, IWI_CSR_RX_WRITE_INDEX, sc->rx_cur);
+ hw = (hw == 0) ? IWI_RX_RING_COUNT - 1 : hw - 1;
+ CSR_WRITE_4(sc, IWI_CSR_RX_WIDX, hw);
}
static void
-iwi_tx_intr(struct iwi_softc *sc)
+iwi_tx_intr(struct iwi_softc *sc, struct iwi_tx_ring *txq)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
- struct iwi_tx_buf *buf;
- u_int32_t r, i;
-
- r = CSR_READ_4(sc, IWI_CSR_TX1_READ_INDEX);
-#if notyet
- bus_dmamap_sync(sc->tx_ring_dmat, sc->tx_ring_map, BUS_DMASYNC_POSTWRITE);
-#endif
+ struct ifnet *ifp = ic->ic_ifp;
+ struct iwi_tx_data *data;
+ uint32_t hw;
- for (i = (sc->tx_old + 1) % IWI_TX_RING_SIZE; i != r;
- i = (i + 1) % IWI_TX_RING_SIZE) {
+ hw = CSR_READ_4(sc, txq->csr_ridx);
- buf = &sc->tx_buf[i];
+ for (; txq->next != hw;) {
+ data = &txq->data[txq->next];
- bus_dmamap_sync(sc->tx_buf_dmat, buf->map,
+ bus_dmamap_sync(txq->data_dmat, data->map,
BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->tx_buf_dmat, buf->map);
- m_freem(buf->m);
- buf->m = NULL;
- if (buf->ni != ic->ic_bss)
- ieee80211_free_node(ic, buf->ni);
- buf->ni = NULL;
+ bus_dmamap_unload(txq->data_dmat, data->map);
+ m_freem(data->m);
+ data->m = NULL;
+ ieee80211_free_node(data->ni);
+ data->ni = NULL;
- sc->tx_queued--;
+ DPRINTFN(15, ("tx done idx=%u\n", txq->next));
- /* kill watchdog timer */
- sc->sc_tx_timer = 0;
- }
+ ifp->if_opackets++;
- /* Remember what the firmware has processed */
- sc->tx_old = (r == 0) ? IWI_TX_RING_SIZE - 1 : r - 1;
+ txq->queued--;
+ txq->next = (txq->next + 1) % IWI_TX_RING_COUNT;
+ }
- /* Call start() since some buffer descriptors have been released */
+ sc->sc_tx_timer = 0;
ifp->if_flags &= ~IFF_OACTIVE;
- (*ifp->if_start)(ifp);
+ iwi_start(ifp);
}
static void
iwi_intr(void *arg)
{
struct iwi_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
- u_int32_t r;
+ uint32_t r;
- if ((r = CSR_READ_4(sc, IWI_CSR_INTR)) == 0 || r == 0xffffffff)
+ r = CSR_READ_4(sc, IWI_CSR_INTR);
+ if (r == 0 || r == 0xffffffff)
return;
- /* Disable interrupts */
+ /* disable interrupts */
CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, 0);
- DPRINTFN(8, ("INTR!0x%08x\n", r));
-
- sc->flags &= ~(IWI_FLAG_RF_DISABLED);
-
- if (r & IWI_INTR_FATAL_ERROR) {
- if (!(sc->flags & (IWI_FLAG_RESET | IWI_FLAG_EXIT))) {
- sc->flags |= IWI_FLAG_RESET;
- wakeup(IWI_FW_WAKE_MONITOR(sc));
- }
- }
-
- if (r & IWI_INTR_PARITY_ERROR) {
+ if (r & (IWI_INTR_FATAL_ERROR | IWI_INTR_PARITY_ERROR)) {
device_printf(sc->sc_dev, "fatal error\n");
- sc->sc_ic.ic_if.if_flags &= ~IFF_UP;
+ sc->sc_ic.ic_ifp->if_flags &= ~IFF_UP;
iwi_stop(sc);
}
}
if (r & IWI_INTR_RADIO_OFF) {
- DPRINTF(("radio transmitter off\n"));
- sc->sc_ic.ic_if.if_flags &= ~IFF_UP;
+ DPRINTF(("radio transmitter turned off\n"));
+ sc->sc_ic.ic_ifp->if_flags &= ~IFF_UP;
iwi_stop(sc);
- sc->flags |= IWI_FLAG_RF_DISABLED;
}
- if (r & IWI_INTR_RX_TRANSFER)
- iwi_rx_intr(sc);
-
- if (r & IWI_INTR_CMD_TRANSFER)
+ if (r & IWI_INTR_CMD_DONE)
wakeup(IWI_FW_CMD_ACKED(sc));
- if (r & IWI_INTR_TX1_TRANSFER)
- iwi_tx_intr(sc);
-
- if (r & ~(IWI_HANDLED_INTR_MASK)) {
- device_printf(sc->sc_dev,
- "unhandled interrupt(s) INTR!0x%08x\n",
- r & ~(IWI_HANDLED_INTR_MASK));
- }
-
- /* Acknowledge interrupts */
- CSR_WRITE_4(sc, IWI_CSR_INTR, r);
-
- /* Re-enable interrupts */
- CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, IWI_INTR_MASK);
-
- if ((ifp->if_flags & IFF_RUNNING) && !ifq_is_empty(&ifp->if_snd))
- iwi_start(ifp);
-}
-
-struct iwi_dma_mapping {
- bus_dma_segment_t segs[IWI_MAX_NSEG];
- int nseg;
- bus_size_t mapsize;
-};
-
-static void
-iwi_dma_map_buf(void *arg, bus_dma_segment_t *segs, int nseg,
- bus_size_t mapsize, int error)
-{
- struct iwi_dma_mapping *map = arg;
+ if (r & IWI_INTR_TX1_DONE)
+ iwi_tx_intr(sc, &sc->txq[0]);
- if (error != 0)
- return;
+ if (r & IWI_INTR_TX2_DONE)
+ iwi_tx_intr(sc, &sc->txq[1]);
- KASSERT(nseg <= IWI_MAX_NSEG, ("too many DMA segments %d", nseg));
+ if (r & IWI_INTR_TX3_DONE)
+ iwi_tx_intr(sc, &sc->txq[2]);
- bcopy(segs, map->segs, nseg * sizeof (bus_dma_segment_t));
- map->nseg = nseg;
- map->mapsize = mapsize;
-}
+ if (r & IWI_INTR_TX4_DONE)
+ iwi_tx_intr(sc, &sc->txq[3]);
-static void
-iwi_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg __unused, int error)
-{
- if (error != 0) {
- printf("iwi: fatal DMA mapping error !!!\n");
- return;
- }
+ if (r & IWI_INTR_RX_DONE)
+ iwi_rx_intr(sc);
- KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
+ /* acknowledge interrupts */
+ CSR_WRITE_4(sc, IWI_CSR_INTR, r);
- *(bus_addr_t *)arg = segs[0].ds_addr;
+ /* re-enable interrupts */
+ CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, IWI_INTR_MASK);
}
static int
-iwi_cmd(struct iwi_softc *sc, u_int8_t type, void *data, u_int8_t len,
- int async)
+iwi_cmd(struct iwi_softc *sc, uint8_t type, void *data, uint8_t len, int async)
{
struct iwi_cmd_desc *desc;
+ struct ifnet *ifp = &sc->sc_ic.ic_if;
int ret;
- DPRINTFN(2, ("TX!CMD!%u!%u\n", type, len));
+ desc = &sc->cmdq.desc[sc->cmdq.cur];
- desc = &sc->cmd_desc[sc->cmd_cur];
desc->hdr.type = IWI_HDR_TYPE_COMMAND;
desc->hdr.flags = IWI_HDR_FLAG_IRQ;
desc->type = type;
desc->len = len;
- bcopy(data, desc->data, len);
+ memcpy(desc->data, data, len);
- bus_dmamap_sync(sc->cmd_ring_dmat, sc->cmd_ring_map,
+ bus_dmamap_sync(sc->cmdq.desc_dmat, sc->cmdq.desc_map,
BUS_DMASYNC_PREWRITE);
- sc->cmd_cur = (sc->cmd_cur + 1) % IWI_CMD_RING_SIZE;
+ DPRINTFN(2, ("sending command idx=%u type=%u len=%u\n", sc->cmdq.cur,
+ type, len));
+
+ sc->cmdq.cur = (sc->cmdq.cur + 1) % IWI_CMD_RING_COUNT;
+ CSR_WRITE_4(sc, IWI_CSR_CMD_WIDX, sc->cmdq.cur);
+
if (!async) {
- struct ifnet *ifp = &sc->sc_ic.ic_if;
+ ASSERT_SERIALIZED(ifp->if_serializer);
crit_enter();
- CSR_WRITE_4(sc, IWI_CSR_CMD_WRITE_INDEX, sc->cmd_cur);
tsleep_interlock(IWI_FW_CMD_ACKED(sc));
lwkt_serialize_exit(ifp->if_serializer);
ret = tsleep(IWI_FW_CMD_ACKED(sc), 0, "iwicmd", hz);
crit_exit();
lwkt_serialize_enter(ifp->if_serializer);
} else {
- CSR_WRITE_4(sc, IWI_CSR_CMD_WRITE_INDEX, sc->cmd_cur);
ret = 0;
}
- return ret;
+ return ret;
+}
+
+static void
+iwi_write_ibssnode(struct iwi_softc *sc, const struct iwi_node *in)
+{
+ struct iwi_ibssnode node;
+
+ /* write node information into NIC memory */
+ memset(&node, 0, sizeof node);
+ IEEE80211_ADDR_COPY(node.bssid, in->in_node.ni_macaddr);
+
+ CSR_WRITE_REGION_1(sc,
+ IWI_CSR_NODE_BASE + in->in_station * sizeof node,
+ (uint8_t *)&node, sizeof node);
+}
+
+struct iwi_dma_mapping {
+ bus_dma_segment_t segs[IWI_MAX_NSEG];
+ int nseg;
+ bus_size_t mapsize;
+};
+
+static void
+iwi_dma_map_mbuf(void *arg, bus_dma_segment_t *segs, int nseg,
+ bus_size_t mapsize, int error)
+{
+ struct iwi_dma_mapping *map = arg;
+
+ if (error != 0)
+ return;
+
+ KASSERT(nseg <= IWI_MAX_NSEG, ("too many DMA segments %d", nseg));
+
+ bcopy(segs, map->segs, nseg * sizeof(bus_dma_segment_t));
+ map->nseg = nseg;
+ map->mapsize = mapsize;
}
static int
-iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni)
+iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni,
+ int ac)
{
struct iwi_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
+ struct iwi_node *in = (struct iwi_node *)ni;
struct ieee80211_frame *wh;
- struct iwi_tx_buf *buf;
+ struct ieee80211_key *k;
+ const struct chanAccParams *cap;
+ struct iwi_tx_ring *txq = &sc->txq[ac];
+ struct iwi_tx_data *data;
struct iwi_tx_desc *desc;
- struct iwi_dma_mapping map;
struct mbuf *mnew;
- u_int32_t id = 0;
- int error, i;
+ struct iwi_dma_mapping map;
+ int error, hdrlen, i, noack = 0;
+
+ wh = mtod(m0, struct ieee80211_frame *);
+
+ if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) {
+ hdrlen = sizeof (struct ieee80211_qosframe);
+ cap = &ic->ic_wme.wme_chanParams;
+ noack = cap->cap_wmeParams[ac].wmep_noackPolicy;
+ } else
+ hdrlen = sizeof (struct ieee80211_frame);
+
+ /*
+ * This is only used in IBSS mode where the firmware expect an index
+ * in a h/w table instead of a destination address.
+ */
+ if (ic->ic_opmode == IEEE80211_M_IBSS && in->in_station == -1) {
+ in->in_station = iwi_alloc_ibss_node(sc);
+ if (in->in_station == -1) { /* h/w table is full */
+ m_freem(m0);
+ ieee80211_free_node(ni);
+ ifp->if_oerrors++;
+ if_printf(ifp, "ibss table is full\n");
+ return 0;
+ }
+ iwi_write_ibssnode(sc, in);
+ }
+
+ if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ k = ieee80211_crypto_encap(ic, ni, m0);
+ if (k == NULL) {
+ m_freem(m0);
+ return ENOBUFS;
+ }
+
+ /* packet header may have moved, reset our local pointer */
+ wh = mtod(m0, struct ieee80211_frame *);
+ }
if (sc->sc_drvbpf != NULL) {
struct iwi_tx_radiotap_header *tap = &sc->sc_txtap;
tap->wt_flags = 0;
- tap->wt_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
- tap->wt_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
+ tap->wt_chan_freq = htole16(ic->ic_ibss_chan->ic_freq);
+ tap->wt_chan_flags = htole16(ic->ic_ibss_chan->ic_flags);
bpf_ptap(sc->sc_drvbpf, m0, tap, sc->sc_txtap_len);
}
- buf = &sc->tx_buf[sc->tx_cur];
- desc = &sc->tx_desc[sc->tx_cur];
-
- wh = mtod(m0, struct ieee80211_frame *);
-
- if ( (id = iwi_find_station( sc, wh->i_addr1 ) ) == 0xff )
- id = iwi_cache_station( sc, wh->i_addr1 );
-
- bzero( desc, sizeof (struct iwi_tx_desc) );
- desc->station_number = id;
+ data = &txq->data[txq->cur];
+ desc = &txq->desc[txq->cur];
- /* trim IEEE802.11 header */
- m_adj(m0, sizeof (struct ieee80211_frame));
+ /* save and trim IEEE802.11 header */
+ m_copydata(m0, 0, hdrlen, (caddr_t)&desc->wh);
+ m_adj(m0, hdrlen);
- error = bus_dmamap_load_mbuf(sc->tx_buf_dmat, buf->map, m0,
- iwi_dma_map_buf, &map, BUS_DMA_NOWAIT);
+ error = bus_dmamap_load_mbuf(txq->data_dmat, data->map, m0,
+ iwi_dma_map_mbuf, &map, BUS_DMA_NOWAIT);
if (error != 0 && error != EFBIG) {
device_printf(sc->sc_dev, "could not map mbuf (error %d)\n",
error);
}
m0 = mnew;
- error = bus_dmamap_load_mbuf(sc->tx_buf_dmat, buf->map, m0,
- iwi_dma_map_buf, &map, BUS_DMA_NOWAIT);
+ error = bus_dmamap_load_mbuf(txq->data_dmat, data->map, m0,
+ iwi_dma_map_mbuf, &map,
+ BUS_DMA_NOWAIT);
if (error != 0) {
device_printf(sc->sc_dev,
"could not map mbuf (error %d)\n", error);
}
}
- buf->m = m0;
- buf->ni = ni;
+ data->m = m0;
+ data->ni = ni;
desc->hdr.type = IWI_HDR_TYPE_DATA;
desc->hdr.flags = IWI_HDR_FLAG_IRQ;
+ desc->station =
+ (ic->ic_opmode == IEEE80211_M_IBSS) ? in->in_station : 0;
desc->cmd = IWI_DATA_CMD_TX;
desc->len = htole16(m0->m_pkthdr.len);
desc->flags = 0;
- if (ic->ic_opmode == IEEE80211_M_IBSS) {
- if (!IEEE80211_IS_MULTICAST(wh->i_addr1))
- desc->flags |= IWI_DATA_FLAG_NEED_ACK;
- } else if (!IEEE80211_IS_MULTICAST(wh->i_addr3))
+ desc->xflags = 0;
+
+ if (!noack && !IEEE80211_IS_MULTICAST(desc->wh.i_addr1))
desc->flags |= IWI_DATA_FLAG_NEED_ACK;
- if (ic->ic_flags & IEEE80211_F_WEPON) {
- wh->i_fc[1] |= IEEE80211_FC1_WEP;
- desc->wep_txkey = ic->ic_wep_txkey;
+#if 0
+ if (ic->ic_flags & IEEE80211_F_PRIVACY) {
+ desc->wh.i_fc[1] |= IEEE80211_FC1_WEP;
+ desc->weptxkey = ic->ic_crypto.cs_def_txkey;
} else
+#endif
desc->flags |= IWI_DATA_FLAG_NO_WEP;
if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
desc->flags |= IWI_DATA_FLAG_SHPREAMBLE;
- bcopy(wh, &desc->wh, sizeof (struct ieee80211_frame));
+ if (desc->wh.i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS)
+ desc->xflags |= IWI_DATA_XFLAG_QOS;
+
desc->nseg = htole32(map.nseg);
for (i = 0; i < map.nseg; i++) {
desc->seg_addr[i] = htole32(map.segs[i].ds_addr);
- desc->seg_len[i] = htole32(map.segs[i].ds_len);
+ desc->seg_len[i] = htole16(map.segs[i].ds_len);
}
- bus_dmamap_sync(sc->tx_buf_dmat, buf->map, BUS_DMASYNC_PREWRITE);
- bus_dmamap_sync(sc->tx_ring_dmat, sc->tx_ring_map,
- BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(txq->data_dmat, data->map, BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(txq->desc_dmat, txq->desc_map, BUS_DMASYNC_PREWRITE);
- DPRINTFN(5, ("TX!DATA!%u!%u\n", desc->len, desc->nseg));
+ DPRINTFN(5, ("sending data frame txq=%u idx=%u len=%u nseg=%u\n",
+ ac, txq->cur, le16toh(desc->len), nsegs));
- /* Inform firmware about this new packet */
- sc->tx_queued++;
- sc->tx_cur = (sc->tx_cur + 1) % IWI_TX_RING_SIZE;
- CSR_WRITE_4(sc, IWI_CSR_TX1_WRITE_INDEX, sc->tx_cur);
+ txq->queued++;
+ txq->cur = (txq->cur + 1) % IWI_TX_RING_COUNT;
+ CSR_WRITE_4(sc, txq->csr_widx, txq->cur);
return 0;
}
struct iwi_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
struct mbuf *m0;
+ struct ether_header *eh;
struct ieee80211_node *ni;
+ int ac;
- if (ic->ic_state != IEEE80211_S_RUN) {
+ if (ic->ic_state != IEEE80211_S_RUN)
return;
- }
for (;;) {
- m0 = ifq_poll(&ifp->if_snd);
+ m0 = ifq_dequeue(&ifp->if_snd, NULL);
if (m0 == NULL)
break;
- if (sc->tx_queued >= IWI_TX_RING_SIZE - 4) {
+ if (m0->m_len < sizeof (struct ether_header) &&
+ (m0 = m_pullup(m0, sizeof (struct ether_header))) == NULL) {
+ ifp->if_oerrors++;
+ continue;
+ }
+ eh = mtod(m0, struct ether_header *);
+ ni = ieee80211_find_txnode(ic, eh->ether_dhost);
+ if (ni == NULL) {
+ m_freem(m0);
+ ifp->if_oerrors++;
+ continue;
+ }
+
+ /* classify mbuf so we can find which tx ring to use */
+ if (ieee80211_classify(ic, m0, ni) != 0) {
+ m_freem(m0);
+ ieee80211_free_node(ni);
+ ifp->if_oerrors++;
+ continue;
+ }
+
+ /* no QoS encapsulation for EAPOL frames */
+ ac = (eh->ether_type != htons(ETHERTYPE_PAE)) ?
+ M_WME_GETAC(m0) : WME_AC_BE;
+
+ if (sc->txq[ac].queued > IWI_TX_RING_COUNT - 8) {
+ /* there is no place left in this ring */
+ m_freem(m0);
+ ieee80211_free_node(ni);
ifp->if_flags |= IFF_OACTIVE;
break;
}
-
- ifq_dequeue(&ifp->if_snd, m0);
BPF_MTAP(ifp, m0);
- m0 = ieee80211_encap(ifp, m0, &ni);
- if (m0 == NULL)
+ m0 = ieee80211_encap(ic, m0, ni);
+ if (m0 == NULL) {
+ ieee80211_free_node(ni);
+ ifp->if_oerrors++;
continue;
+ }
if (ic->ic_rawbpf != NULL)
bpf_mtap(ic->ic_rawbpf, m0);
- if (iwi_tx_start(ifp, m0, ni) != 0) {
- if (ni != NULL && ni != ic->ic_bss)
- ieee80211_free_node(ic, ni);
+ if (iwi_tx_start(ifp, m0, ni, ac) != 0) {
+ ieee80211_free_node(ni);
+ ifp->if_oerrors++;
break;
}
- /* start watchdog timer */
sc->sc_tx_timer = 5;
ifp->if_timer = 1;
}
-
}
static void
iwi_watchdog(struct ifnet *ifp)
{
struct iwi_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
ifp->if_timer = 0;
if (sc->sc_tx_timer > 0) {
if (--sc->sc_tx_timer == 0) {
if_printf(ifp, "device timeout\n");
- wakeup(IWI_FW_WAKE_MONITOR(sc));
+ ifp->if_oerrors++;
+ ifp->if_flags &= ~IFF_UP;
+ iwi_stop(sc);
return;
}
ifp->if_timer = 1;
}
- ieee80211_watchdog(ifp);
-}
-
-
-static int
-iwi_wi_ioctl_get(struct ifnet *ifp, caddr_t data)
-{
- struct wi_req wreq;
- struct ifreq *ifr;
- struct iwi_softc *sc;
- int error;
-
- sc = ifp->if_softc;
- ifr = (struct ifreq *)data;
- error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
- if (error)
- return (error);
-
- switch (wreq.wi_type) {
- case WI_RID_READ_APS:
- ieee80211_begin_scan(ifp);
-
- crit_enter();
- tsleep_interlock(IWI_FW_SCAN_COMPLETED(sc));
- lwkt_serialize_exit(ifp->if_serializer);
- tsleep(IWI_FW_SCAN_COMPLETED(sc), PCATCH, "ssidscan", hz * 2);
- crit_exit();
- lwkt_serialize_enter(ifp->if_serializer);
-
- ieee80211_end_scan(ifp);
- break;
- default:
- error = ENOTTY;
- break;
- }
- return (error);
+ ieee80211_watchdog(ic);
}
-
-
-
static int
iwi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
{
struct iwi_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
struct ifreq *ifr;
- struct ieee80211req *ireq;
- struct ifaddr *ifa;
int error = 0;
switch (cmd) {
- case SIOCSIFADDR:
- /*
- * Handle this here instead of in net80211_ioctl.c
- * so that we can lock the call to iwi_init().
- */
- ifa = (struct ifaddr *) data;
- switch (ifa->ifa_addr->sa_family) {
-#ifdef INET
- case AF_INET:
- if ((ifp->if_flags & IFF_UP) == 0) {
- ifp->if_flags |= IFF_UP;
- ifp->if_init(ifp->if_softc);
- }
- arp_ifinit(ifp, ifa);
- break;
-#endif
-#ifdef IPX
-#warning "IPX support has not been tested"
- /*
- * XXX - This code is probably wrong,
- * but has been copied many times.
- */
- case AF_IPX: {
- struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
- struct arpcom *ac = (struct arpcom *)ifp;
-
- if (ipx_nullhost(*ina))
- ina->x_host = *(union ipx_host *) ac->ac_enaddr;
- else
- bcopy((caddr_t) ina->x_host.c_host,
- (caddr_t) ac->ac_enaddr,
- sizeof(ac->ac_enaddr));
- /* fall thru... */
- }
-#endif
- default:
- if ((ifp->if_flags & IFF_UP) == 0) {
- ifp->if_flags |= IFF_UP;
- ifp->if_init(ifp->if_softc);
- }
- break;
- }
- break;
-
case SIOCSIFFLAGS:
if (ifp->if_flags & IFF_UP) {
- if (!(ifp->if_flags & IFF_RUNNING)) {
+ if (!(ifp->if_flags & IFF_RUNNING))
iwi_init(sc);
- error = tsleep(IWI_FW_CMD_ACKED(sc), 0,
- "iwirun", hz);
- }
} else {
- if (ifp->if_flags & IFF_RUNNING) {
+ if (ifp->if_flags & IFF_RUNNING)
iwi_stop(sc);
- }
}
break;
case SIOCSLOADFW:
- case SIOCSLOADIBSSFW:
/* only super-user can do that! */
- if ((error = suser(curthread)) != 0)
+ error = suser_cred(cr, NULL_CRED_OKAY);
+ if (error != 0)
break;
ifr = (struct ifreq *)data;
- error = iwi_cache_firmware(sc, ifr->ifr_data,
- (cmd == SIOCSLOADIBSSFW) ? 1 : 0);
+ error = iwi_cache_firmware(sc, ifr->ifr_data);
break;
case SIOCSKILLFW:
/* only super-user can do that! */
- if ((error = suser(curthread)) != 0)
+ error = suser_cred(cr, NULL_CRED_OKAY);
+ if (error != 0)
break;
ifp->if_flags &= ~IFF_UP;
iwi_free_firmware(sc);
break;
- case SIOCG80211:
- ireq = (struct ieee80211req *)data;
- switch (ireq->i_type) {
- case IEEE80211_IOC_AUTHMODE:
- ireq->i_val = sc->authmode;
- break;
-
- default:
- error = ieee80211_ioctl(ifp, cmd, data, cr);
- }
- break;
-
- case SIOCS80211:
- /* only super-user can do that! */
- if ((error = suser(curthread)) != 0)
- break;
-
- ireq = (struct ieee80211req *)data;
- switch (ireq->i_type) {
- case IEEE80211_IOC_AUTHMODE:
- sc->authmode = ireq->i_val;
- break;
-
- default:
- error = ieee80211_ioctl(ifp, cmd, data, cr);
- }
- break;
- case SIOCGIFGENERIC:
- if (sc->flags & IWI_FLAG_FW_INITED) {
- error = iwi_wi_ioctl_get(ifp, data);
- if (! error)
- error = ieee80211_ioctl(ifp, cmd, data, cr);
- } else
- error = ENOTTY;
- if (error != ENOTTY)
- break;
-
default:
- error = ieee80211_ioctl(ifp, cmd, data, cr);
+ error = ieee80211_ioctl(ic, cmd, data, cr);
}
if (error == ENETRESET) {
- error = 0;
if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
- (IFF_UP | IFF_RUNNING)) {
+ (IFF_UP | IFF_RUNNING) &&
+ (ic->ic_roaming != IEEE80211_ROAMING_MANUAL))
iwi_init(sc);
- error = tsleep(IWI_FW_CMD_ACKED(sc), 0, "iwirun", hz);
- }
+ error = 0;
}
- return error;
-}
-static int
-iwi_abort_scan( struct iwi_softc *sc )
-{
- sc->flags |= IWI_FLAG_SCAN_ABORT;
- return iwi_cmd(sc, IWI_CMD_SCAN_ABORT, NULL, 0, 1);
+ return error;
}
static void
iwi_stop_master(struct iwi_softc *sc)
{
+ uint32_t tmp;
int ntries;
- /*
- * If the master is busy scanning, we will occasionally
- * timeout waiting for it (the master) to stop. Make the
- * 'stopping' process more robust by ceasing all scans
- * prior to asking for the stop.
- */
- if ( ( sc->flags & IWI_FLAG_SCANNING ) &&
- !( sc->flags & IWI_FLAG_RF_DISABLED ) ) {
- struct ifnet *ifp = &sc->sc_ic.ic_if;
-
- ASSERT_SERIALIZED(ifp->if_serializer);
-
- iwi_abort_scan(sc);
- if (( sc->flags & IWI_FLAG_SCAN_ABORT ) &&
- !( sc->flags & IWI_FLAG_RF_DISABLED )) {
- crit_enter();
- tsleep_interlock(IWI_FW_SCAN_COMPLETED(sc));
- lwkt_serialize_exit(ifp->if_serializer);
- tsleep(IWI_FW_SCAN_COMPLETED(sc), 0, "iwiabr", hz);
- crit_exit();
- lwkt_serialize_enter(ifp->if_serializer);
- }
- }
- /* Disable interrupts */
-
+ /* disable interrupts */
CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, 0);
CSR_WRITE_4(sc, IWI_CSR_RST, IWI_RST_STOP_MASTER);
break;
DELAY(10);
}
- if (ntries == 5 && sc->debug_level > 0)
- device_printf(sc->sc_dev, "timeout waiting for master\n");
+ if (ntries == 5)
+ if_printf(&sc->sc_ic.ic_if, "timeout waiting for master\n");
- CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) |
- IWI_RST_PRINCETON_RESET);
+ tmp = CSR_READ_4(sc, IWI_CSR_RST);
+ CSR_WRITE_4(sc, IWI_CSR_RST, tmp | IWI_RST_PRINCETON_RESET);
sc->flags &= ~IWI_FLAG_FW_INITED;
}
static int
iwi_reset(struct iwi_softc *sc)
{
+ uint32_t tmp;
int i, ntries;
iwi_stop_master(sc);
- /* Move adapter to D0 state */
- CSR_WRITE_4(sc, IWI_CSR_CTL, CSR_READ_4(sc, IWI_CSR_CTL) |
- IWI_CTL_INIT);
+ tmp = CSR_READ_4(sc, IWI_CSR_CTL);
+ CSR_WRITE_4(sc, IWI_CSR_CTL, tmp | IWI_CTL_INIT);
- /* Initialize Phase-Locked Level (PLL) */
CSR_WRITE_4(sc, IWI_CSR_READ_INT, IWI_READ_INT_INIT_HOST);
/* Wait for clock stabilization */
DELAY(200);
}
if (ntries == 1000) {
+ if_printf(&sc->sc_ic.ic_if,
+ "timeout waiting for clock stabilization\n");
return EIO;
}
- CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) |
- IWI_RST_SW_RESET);
+ tmp = CSR_READ_4(sc, IWI_CSR_RST);
+ CSR_WRITE_4(sc, IWI_CSR_RST, tmp | IWI_RST_SOFT_RESET);
DELAY(10);
- CSR_WRITE_4(sc, IWI_CSR_CTL, CSR_READ_4(sc, IWI_CSR_CTL) |
- IWI_CTL_INIT);
-
+ tmp = CSR_READ_4(sc, IWI_CSR_CTL);
+ CSR_WRITE_4(sc, IWI_CSR_CTL, tmp | IWI_CTL_INIT);
/* Clear NIC memory */
CSR_WRITE_4(sc, IWI_CSR_AUTOINC_ADDR, 0);
-
- for (i = 0; i < 0xc000; i++) {
+ for (i = 0; i < 0xc000; i++)
CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, 0);
- }
- sc->num_stations = 0;
return 0;
}
static int
iwi_load_ucode(struct iwi_softc *sc, void *uc, int size)
{
- u_int16_t *w;
+ uint32_t tmp;
+ uint16_t *w;
int ntries, i;
CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) |
MEM_WRITE_4(sc, 0x3000e0, 0x80000000);
DELAY(5000);
- CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) &
- ~IWI_RST_PRINCETON_RESET);
+
+ tmp = CSR_READ_4(sc, IWI_CSR_RST);
+ tmp &= ~IWI_RST_PRINCETON_RESET;
+ CSR_WRITE_4(sc, IWI_CSR_RST, tmp);
+
DELAY(5000);
MEM_WRITE_4(sc, 0x3000e0, 0);
DELAY(1000);
- MEM_WRITE_4(sc, 0x300004, 1);
+ MEM_WRITE_4(sc, IWI_MEM_EVENT_CTL, 1);
DELAY(1000);
- MEM_WRITE_4(sc, 0x300004, 0);
+ MEM_WRITE_4(sc, IWI_MEM_EVENT_CTL, 0);
DELAY(1000);
MEM_WRITE_1(sc, 0x200000, 0x00);
MEM_WRITE_1(sc, 0x200000, 0x40);
DELAY(1000);
- /* Adapter is buggy, we must set the address for each word */
+ /* write microcode into adapter memory */
for (w = uc; size > 0; w++, size -= 2)
- MEM_WRITE_2(sc, 0x200010, *w);
+ MEM_WRITE_2(sc, 0x200010, htole16(*w));
MEM_WRITE_1(sc, 0x200000, 0x00);
MEM_WRITE_1(sc, 0x200000, 0x80);
- /* Wait until we get a response in the uc queue */
+ /* wait until we get an answer */
for (ntries = 0; ntries < 100; ntries++) {
if (MEM_READ_1(sc, 0x200000) & 1)
break;
return EIO;
}
- /* Empty the uc queue or the firmware will not initialize properly */
+ /* read the answer or the firmware will not initialize properly */
for (i = 0; i < 7; i++)
MEM_READ_4(sc, 0x200004);
/* macro to handle unaligned little endian data in firmware image */
#define GETLE32(p) ((p)[0] | (p)[1] << 8 | (p)[2] << 16 | (p)[3] << 24)
+
static int
iwi_load_firmware(struct iwi_softc *sc, void *fw, int size)
{
bus_addr_t physaddr;
void *virtaddr;
u_char *p, *end;
- u_int32_t sentinel, ctl, src, dst, sum, len, mlen;
+ uint32_t sentinel, ctl, src, dst, sum, len, mlen, tmp;
int ntries, error = 0;
struct ifnet *ifp = &sc->sc_ic.ic_if;
- sc->flags &= ~(IWI_FLAG_FW_INITED);
+ ASSERT_SERIALIZED(ifp->if_serializer);
- /* Allocate DMA memory for storing firmware image */
- error = bus_dma_tag_create(sc->iwi_parent_tag, 1, 0, BUS_SPACE_MAXADDR_32BIT,
- BUS_SPACE_MAXADDR, NULL, NULL, size, 1, size, BUS_DMA_ALLOCNOW, &dmat);
+ /* Allocate DMA memory for mapping firmware image */
+ error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR, NULL, NULL, size, 1, size, 0, &dmat);
if (error != 0) {
device_printf(sc->sc_dev,
"could not create firmware DMA tag\n");
goto fail1;
}
-
- /*
- * We cannot map fw directly because of some hardware constraints on
- * the mapping address.
- */
+
error = bus_dmamem_alloc(dmat, &virtaddr, BUS_DMA_WAITOK, &map);
if (error != 0) {
device_printf(sc->sc_dev,
}
/* Copy firmware image to DMA memory */
- bcopy(fw, virtaddr, size);
+ memcpy(virtaddr, fw, size);
/* Make sure the adapter will get up-to-date values */
bus_dmamap_sync(dmat, map, BUS_DMASYNC_PREWRITE);
sentinel = CSR_READ_4(sc, IWI_CSR_AUTOINC_ADDR);
CSR_WRITE_4(sc, IWI_CSR_AUTOINC_DATA, 0);
- CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) &
- ~(IWI_RST_MASTER_DISABLED | IWI_RST_STOP_MASTER));
+ tmp = CSR_READ_4(sc, IWI_CSR_RST);
+ tmp &= ~(IWI_RST_MASTER_DISABLED | IWI_RST_STOP_MASTER);
+ CSR_WRITE_4(sc, IWI_CSR_RST, tmp);
/* Tell the adapter to start processing command blocks */
MEM_WRITE_4(sc, 0x3000a4, 0x540100);
- /* Wait until the adapter has processed all command blocks */
+ /* Wait until the adapter reaches the sentinel */
for (ntries = 0; ntries < 400; ntries++) {
if (MEM_READ_4(sc, 0x3000d0) >= sentinel)
break;
goto fail4;
}
-
/* We're done with command blocks processing */
MEM_WRITE_4(sc, 0x3000a4, 0x540c00);
- /* Allow interrupts so we know when the firmware is inited */
+ /* Allow interrupts so we know when the firmware is ready */
CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, IWI_INTR_MASK);
/* Tell the adapter to initialize the firmware */
- crit_enter();
CSR_WRITE_4(sc, IWI_CSR_RST, 0);
- CSR_WRITE_4(sc, IWI_CSR_CTL,
- CSR_READ_4(sc, IWI_CSR_CTL) | IWI_CTL_ALLOW_STANDBY);
+ tmp = CSR_READ_4(sc, IWI_CSR_CTL);
+ CSR_WRITE_4(sc, IWI_CSR_CTL, tmp | IWI_CTL_ALLOW_STANDBY);
+
+ /* wait at most one second for firmware initialization to complete */
+ crit_enter();
tsleep_interlock(IWI_FW_INITIALIZED(sc));
lwkt_serialize_exit(ifp->if_serializer);
- error = tsleep(IWI_FW_INITIALIZED(sc), 0, "iwiini", hz);
+ error = tsleep(IWI_FW_INITIALIZED(sc), 0, "iwiinit", hz);
crit_exit();
lwkt_serialize_enter(ifp->if_serializer);
if (error != 0) {
goto fail4;
}
-fail4: bus_dmamap_sync(dmat, map, BUS_DMASYNC_POSTWRITE);
+fail4: bus_dmamap_sync(dmat, map, BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(dmat, map);
fail3: bus_dmamem_free(dmat, virtaddr, map);
fail2: bus_dma_tag_destroy(dmat);
* e.g when the adapter wakes up from suspend mode.
*/
static int
-iwi_cache_firmware(struct iwi_softc *sc, void *data, int is_ibss)
+iwi_cache_firmware(struct iwi_softc *sc, void *data)
{
struct iwi_firmware *kfw = &sc->fw;
struct iwi_firmware ufw;
iwi_free_firmware(sc);
- /*
- * mutex(9): no mutexes should be held across functions which access
- * memory in userspace, such as copyin(9) [...]
- */
-
if ((error = copyin(data, &ufw, sizeof ufw)) != 0)
- goto fail1;
+ return error;
kfw->boot_size = ufw.boot_size;
kfw->ucode_size = ufw.ucode_size;
kfw->main_size = ufw.main_size;
kfw->boot = malloc(kfw->boot_size, M_DEVBUF, M_WAITOK);
- if (kfw->boot == NULL) {
- error = ENOMEM;
- goto fail1;
- }
-
kfw->ucode = malloc(kfw->ucode_size, M_DEVBUF, M_WAITOK);
- if (kfw->ucode == NULL) {
- error = ENOMEM;
- goto fail2;
- }
-
kfw->main = malloc(kfw->main_size, M_DEVBUF, M_WAITOK);
- if (kfw->main == NULL) {
- error = ENOMEM;
- goto fail3;
- }
if ((error = copyin(ufw.boot, kfw->boot, kfw->boot_size)) != 0)
- goto fail4;
+ goto fail;
if ((error = copyin(ufw.ucode, kfw->ucode, kfw->ucode_size)) != 0)
- goto fail4;
+ goto fail;
if ((error = copyin(ufw.main, kfw->main, kfw->main_size)) != 0)
- goto fail4;
+ goto fail;
DPRINTF(("Firmware cached: boot %u, ucode %u, main %u\n",
kfw->boot_size, kfw->ucode_size, kfw->main_size));
-
sc->flags |= IWI_FLAG_FW_CACHED;
- sc->flags |= is_ibss ? IWI_FLAG_FW_IBSS : 0;
+
return 0;
-fail4: free(kfw->boot, M_DEVBUF);
-fail3: free(kfw->ucode, M_DEVBUF);
-fail2: free(kfw->main, M_DEVBUF);
-fail1:
+fail:
+ free(kfw->boot, M_DEVBUF);
+ free(kfw->ucode, M_DEVBUF);
+ free(kfw->main, M_DEVBUF);
return error;
}
free(sc->fw.ucode, M_DEVBUF);
free(sc->fw.main, M_DEVBUF);
- sc->flags &= ~( IWI_FLAG_FW_CACHED | IWI_FLAG_FW_IBSS );
-}
-
-static int
-iwi_adapter_config(struct iwi_softc *sc, int is_a, int cmd_wait)
-{
- struct iwi_configuration config;
-
- bzero(&config, sizeof config);
- config.enable_multicast = 1;
- config.noise_reported = 1;
-
- config.bg_autodetect =
- ( !(is_a) &&
- ( sc->enable_bg_autodetect != 0 ) ) ? 1 : 0; /* default: on */
-
- config.bluetooth_coexistence =
- ( sc->enable_bt_coexist != 0 ) ? 1 : 0; /* default: on */
-
- config.enable_cts_to_self =
- ( sc->enable_cts_to_self > 0 ) ? 1 : 0; /* default: off */
-
- if (sc->antenna_diversity > 0 ) { /* default: BOTH */
- switch( sc->antenna_diversity ) {
- case 1: case 3:
- config.antenna_diversity = sc->antenna_diversity;
- }
- }
-
- config.disable_unicast_decryption =
- ( sc->disable_unicast_decryption != 0 ) ? 1 : 0; /* default: on */
-
- config.disable_multicast_decryption =
- ( sc->disable_multicast_decryption != 0 ) ? 1 : 0;/* default: on */
-
-
- if ( sc->debug_level > 0 ) {
- printf("config.bluetooth_coexistence = %d\n",
- config.bluetooth_coexistence );
- printf("config.bg_autodetect = %d\n",
- config.bg_autodetect );
- printf("config.enable_cts_to_self = %d\n",
- config.enable_cts_to_self );
- printf("config.antenna_diversity = %d\n",
- config.antenna_diversity );
- printf("config.disable_unicast_decryption = %d\n",
- config.disable_unicast_decryption );
- printf("config.disable_multicast_decryption = %d\n",
- config.disable_multicast_decryption );
- printf("config.neg_best_rates_first = %d\n",
- sc->enable_neg_best_first );
- }
-
- return iwi_cmd(sc, IWI_CMD_SET_CONFIGURATION, &config,
- sizeof config, cmd_wait );
+ sc->flags &= ~IWI_FLAG_FW_CACHED;
}
static int
iwi_config(struct iwi_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
+ struct ifnet *ifp = ic->ic_ifp;
+ struct iwi_configuration config;
struct iwi_rateset rs;
struct iwi_txpower power;
- struct ieee80211_wepkey *k;
+ struct ieee80211_key *wk;
struct iwi_wep_key wepkey;
- u_int32_t data;
+ uint32_t data;
int error, i;
IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
if (error != 0)
return error;
+ memset(&config, 0, sizeof config);
+ config.bluetooth_coexistence = sc->bluetooth;
+ config.antenna = sc->antenna;
+ config.multicast_enabled = 1;
+ config.answer_pbreq = (ic->ic_opmode == IEEE80211_M_IBSS) ? 1 : 0;
+ config.disable_unicast_decryption = 1;
+ config.disable_multicast_decryption = 1;
DPRINTF(("Configuring adapter\n"));
- if ((error = iwi_adapter_config(sc, 1, 0)) != 0)
+ error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config, 0);
+ if (error != 0)
return error;
data = htole32(IWI_POWER_MODE_CAM);
if (error != 0)
return error;
+ data = htole32(ic->ic_fragthreshold);
+ DPRINTF(("Setting fragmentation threshold to %u\n", le32toh(data)));
+ error = iwi_cmd(sc, IWI_CMD_SET_FRAG_THRESHOLD, &data, sizeof data, 0);
+ if (error != 0)
+ return error;
+
if (ic->ic_opmode == IEEE80211_M_IBSS) {
power.mode = IWI_MODE_11B;
power.nchan = 11;
rs.mode = IWI_MODE_11G;
rs.type = IWI_RATESET_TYPE_SUPPORTED;
rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates;
- bcopy(ic->ic_sup_rates[IEEE80211_MODE_11G].rs_rates, rs.rates,
+ memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11G].rs_rates,
rs.nrates);
DPRINTF(("Setting .11bg supported rates (%u)\n", rs.nrates));
error = iwi_cmd(sc, IWI_CMD_SET_RATES, &rs, sizeof rs, 0);
rs.mode = IWI_MODE_11A;
rs.type = IWI_RATESET_TYPE_SUPPORTED;
rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates;
- bcopy(ic->ic_sup_rates[IEEE80211_MODE_11A].rs_rates, rs.rates,
+ memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11A].rs_rates,
rs.nrates);
DPRINTF(("Setting .11a supported rates (%u)\n", rs.nrates));
error = iwi_cmd(sc, IWI_CMD_SET_RATES, &rs, sizeof rs, 0);
if (error != 0)
return error;
+ /* if we have a desired ESSID, set it now */
+ if (ic->ic_des_esslen != 0) {
+#ifdef IWI_DEBUG
+ if (iwi_debug > 0) {
+ printf("Setting desired ESSID to ");
+ ieee80211_print_essid(ic->ic_des_essid,
+ ic->ic_des_esslen);
+ printf("\n");
+ }
+#endif
+ error = iwi_cmd(sc, IWI_CMD_SET_ESSID, ic->ic_des_essid,
+ ic->ic_des_esslen, 0);
+ if (error != 0)
+ return error;
+ }
+
data = htole32(arc4random());
DPRINTF(("Setting initialization vector to %u\n", le32toh(data)));
error = iwi_cmd(sc, IWI_CMD_SET_IV, &data, sizeof data, 0);
if (error != 0)
return error;
- if (ic->ic_flags & IEEE80211_F_WEPON) {
- k = ic->ic_nw_keys;
- for (i = 0; i < IEEE80211_WEP_NKID; i++, k++) {
- wepkey.cmd = IWI_WEP_KEY_CMD_SETKEY;
- wepkey.idx = i;
- wepkey.len = k->wk_len;
- bzero(wepkey.key, sizeof wepkey.key);
- bcopy(k->wk_key, wepkey.key, k->wk_len);
- DPRINTF(("Setting wep key index %u len %u\n",
- wepkey.idx, wepkey.len));
- error = iwi_cmd(sc, IWI_CMD_SET_WEP_KEY, &wepkey,
- sizeof wepkey, 0);
- if (error != 0)
- return error;
- }
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ wk = &ic->ic_crypto.cs_nw_keys[i];
+
+ wepkey.cmd = IWI_WEP_KEY_CMD_SETKEY;
+ wepkey.idx = i;
+ wepkey.len = wk->wk_keylen;
+ memset(wepkey.key, 0, sizeof wepkey.key);
+ memcpy(wepkey.key, wk->wk_key, wk->wk_keylen);
+ DPRINTF(("Setting wep key index %u len %u\n", wepkey.idx,
+ wepkey.len));
+ error = iwi_cmd(sc, IWI_CMD_SET_WEP_KEY, &wepkey,
+ sizeof wepkey, 0);
+ if (error != 0)
+ return error;
}
/* Enable adapter */
}
static int
-iwi_scan(struct iwi_softc *sc)
+iwi_set_chan(struct iwi_softc *sc, struct ieee80211_channel *chan)
{
struct ieee80211com *ic = &sc->sc_ic;
struct iwi_scan scan;
- u_int8_t *p;
- int i, count;
- int do_5ghz_scan = 0;
- sc->scan_counter++; /* track the number of scans started */
+ memset(&scan, 0, sizeof scan);
+ memset(scan.type, IWI_SCAN_TYPE_PASSIVE, sizeof scan.type);
+ scan.passive = htole16(2000);
+ scan.channels[0] = 1 |
+ (IEEE80211_IS_CHAN_5GHZ(chan) ? IWI_CHAN_5GHZ : IWI_CHAN_2GHZ);
+ scan.channels[1] = ieee80211_chan2ieee(ic, chan);
+
+ DPRINTF(("Setting channel to %u\n", ieee80211_chan2ieee(ic, chan)));
+ return iwi_cmd(sc, IWI_CMD_SCAN, &scan, sizeof scan, 1);
+}
- sc->flags |= IWI_FLAG_SCANNING;
+static int
+iwi_scan(struct iwi_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct iwi_scan scan;
+ uint8_t *p;
+ int i, count;
- bzero(&scan, sizeof scan);
+ memset(&scan, 0, sizeof scan);
- /*
- * Alternate two broadcast scans with
- * two broadcast/direct scans.
- */
- if ( sc->scan_counter & 2 ) {
- scan.type = IWI_SCAN_TYPE_BROADCAST_AND_DIRECT;
- scan.intval = htole16(100);
+ if (ic->ic_des_esslen != 0) {
+ scan.bdirected = htole16(sc->dwelltime);
+ memset(scan.type, IWI_SCAN_TYPE_BDIRECTED, sizeof scan.type);
} else {
- scan.type = IWI_SCAN_TYPE_BROADCAST;
- scan.intval = htole16(40);
+ scan.broadcast = htole16(sc->dwelltime);
+ memset(scan.type, IWI_SCAN_TYPE_BROADCAST, sizeof scan.type);
}
p = scan.channels;
-
- /*
- * If we have .11a capable adapter, and
- * - we are in .11a mode, or
- * - we are in auto mode and this is an odd numbered scan
- * then do a 5GHz scan, otherwise do a 2GHz scan.
- */
- if ( ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates > 0 ) {
- if (( ic->ic_curmode == IEEE80211_MODE_11A ) ||
- (( ic->ic_curmode == IEEE80211_MODE_AUTO ) &&
- ( sc->scan_counter & 1)))
- do_5ghz_scan = 1;
- }
count = 0;
- if ( do_5ghz_scan ) {
- DPRINTF(("Scanning 5GHz band\n"));
- for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
- if (IEEE80211_IS_CHAN_5GHZ(&ic->ic_channels[i]) &&
- isset(ic->ic_chan_active, i)) {
- *++p = i;
- count++;
- }
+ for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
+ if (IEEE80211_IS_CHAN_5GHZ(&ic->ic_channels[i]) &&
+ isset(ic->ic_chan_active, i)) {
+ *++p = i;
+ count++;
}
- *(p - count) = IWI_CHAN_5GHZ | count;
- } else {
- DPRINTF(("Scanning 2GHz band\n"));
- for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
- if (IEEE80211_IS_CHAN_2GHZ(&ic->ic_channels[i]) &&
- isset(ic->ic_chan_active, i)) {
- *++p = i;
- count++;
- }
+ }
+ *(p - count) = IWI_CHAN_5GHZ | count;
+
+ p = (count > 0) ? p + 1 : scan.channels;
+ count = 0;
+ for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
+ if (IEEE80211_IS_CHAN_2GHZ(&ic->ic_channels[i]) &&
+ isset(ic->ic_chan_active, i)) {
+ *++p = i;
+ count++;
}
- *(p - count) = IWI_CHAN_2GHZ | count;
}
+ *(p - count) = IWI_CHAN_2GHZ | count;
+
+ DPRINTF(("Start scanning\n"));
return iwi_cmd(sc, IWI_CMD_SCAN, &scan, sizeof scan, 1);
}
iwi_auth_and_assoc(struct iwi_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
+ struct ifnet *ifp = ic->ic_ifp;
struct ieee80211_node *ni = ic->ic_bss;
+ struct ieee80211_wme_info wme;
+ struct iwi_configuration config;
+ struct iwi_associate assoc;
struct iwi_rateset rs;
- u_int32_t data;
- int error, x;
-
- if ( ( sc->flags & IWI_FLAG_FW_IBSS ) &&
- !( ni->ni_capinfo & IEEE80211_CAPINFO_IBSS ) ) {
- return -1; /* IBSS F/W requires network ibss capability */
- }
+ uint16_t capinfo;
+ uint32_t data;
+ int error;
- DPRINTF(("Configuring adapter\n"));
- if ((error = iwi_adapter_config(sc,
- IEEE80211_IS_CHAN_5GHZ(ni->ni_chan), 1)) != 0)
+ if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) {
+ memset(&config, 0, sizeof config);
+ config.bluetooth_coexistence = sc->bluetooth;
+ config.antenna = sc->antenna;
+ config.multicast_enabled = 1;
+ config.use_protection = 1;
+ config.answer_pbreq =
+ (ic->ic_opmode == IEEE80211_M_IBSS) ? 1 : 0;
+ config.disable_unicast_decryption = 1;
+ config.disable_multicast_decryption = 1;
+ DPRINTF(("Configuring adapter\n"));
+ error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config,
+ 1);
+ if (error != 0)
return error;
+ }
#ifdef IWI_DEBUG
- if (sc->debug_level > 0) {
+ if (iwi_debug > 0) {
printf("Setting ESSID to ");
ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
printf("\n");
IWI_MODE_11G;
rs.type = IWI_RATESET_TYPE_NEGOTIATED;
rs.nrates = ni->ni_rates.rs_nrates;
- if ( sc->enable_neg_best_first != 1 ) {
- bcopy(ni->ni_rates.rs_rates, rs.rates, rs.nrates);
- } else {
- for ( x = 0 ; x < rs.nrates; x++ ) {
- /*
- * Present the firmware with the most favourable
- * of the negotiated rates first.
- */
- rs.rates[rs.nrates-x-1] = ni->ni_rates.rs_rates[x];
- }
- }
-
- if ( sc->debug_level > 0 ) {
- printf("Setting negotiated rates (%u) : ", rs.nrates);
- for ( x = 0 ; x < rs.nrates; x++ ) {
- printf("%d ", rs.rates[x]);
- }
- printf("\n");
- }
-
+ memcpy(rs.rates, ni->ni_rates.rs_rates, rs.nrates);
+ DPRINTF(("Setting negociated rates (%u)\n", rs.nrates));
error = iwi_cmd(sc, IWI_CMD_SET_RATES, &rs, sizeof rs, 1);
if (error != 0)
return error;
+ if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_wme_ie != NULL) {
+ wme.wme_id = IEEE80211_ELEMID_VENDOR;
+ wme.wme_len = sizeof (struct ieee80211_wme_info) - 2;
+ wme.wme_oui[0] = 0x00;
+ wme.wme_oui[1] = 0x50;
+ wme.wme_oui[2] = 0xf2;
+ wme.wme_type = WME_OUI_TYPE;
+ wme.wme_subtype = WME_INFO_OUI_SUBTYPE;
+ wme.wme_version = WME_VERSION;
+ wme.wme_info = 0;
+
+ DPRINTF(("Setting WME IE (len=%u)\n", wme.wme_len));
+ error = iwi_cmd(sc, IWI_CMD_SET_WMEIE, &wme, sizeof wme, 1);
+ if (error != 0)
+ return error;
+ }
+
+ if (ic->ic_opt_ie != NULL) {
+ DPRINTF(("Setting optional IE (len=%u)\n", ic->ic_opt_ie_len));
+ error = iwi_cmd(sc, IWI_CMD_SET_OPTIE, ic->ic_opt_ie,
+ ic->ic_opt_ie_len, 1);
+ if (error != 0)
+ return error;
+ }
+
data = htole32(ni->ni_rssi);
DPRINTF(("Setting sensitivity to %d\n", (int8_t)ni->ni_rssi));
error = iwi_cmd(sc, IWI_CMD_SET_SENSITIVITY, &data, sizeof data, 1);
if (error != 0)
return error;
- bzero(&sc->assoc, sizeof sc->assoc);
- sc->assoc.mode = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? IWI_MODE_11A :
+ memset(&assoc, 0, sizeof assoc);
+ assoc.mode = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? IWI_MODE_11A :
IWI_MODE_11G;
- sc->assoc.chan = ieee80211_chan2ieee(ic, ni->ni_chan);
- if (sc->authmode == IEEE80211_AUTH_SHARED)
- sc->assoc.auth = (ic->ic_wep_txkey << 4) | IWI_AUTH_SHARED;
- bcopy(ni->ni_tstamp, sc->assoc.tstamp, 8);
- sc->assoc.capinfo = htole16(ni->ni_capinfo);
- sc->assoc.lintval = htole16(ic->ic_lintval);
- sc->assoc.intval = htole16(ni->ni_intval);
- IEEE80211_ADDR_COPY(sc->assoc.bssid, ni->ni_bssid);
- if ( ic->ic_opmode == IEEE80211_M_IBSS )
- IEEE80211_ADDR_COPY(sc->assoc.dst, ifp->if_broadcastaddr);
+ assoc.chan = ieee80211_chan2ieee(ic, ni->ni_chan);
+ if (ni->ni_authmode == IEEE80211_AUTH_SHARED)
+ assoc.auth = ic->ic_crypto.cs_def_txkey << 4 | IWI_AUTH_SHARED;
+ if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_wme_ie != NULL)
+ assoc.policy |= htole16(IWI_POLICY_WME);
+ if (ic->ic_flags & IEEE80211_F_WPA)
+ assoc.policy |= htole16(IWI_POLICY_WPA);
+ memcpy(assoc.tstamp, ni->ni_tstamp.data, 8);
+
+ if (ic->ic_opmode == IEEE80211_M_IBSS)
+ capinfo = IEEE80211_CAPINFO_IBSS;
+ else
+ capinfo = IEEE80211_CAPINFO_ESS;
+ if (ic->ic_flags & IEEE80211_F_PRIVACY)
+ capinfo |= IEEE80211_CAPINFO_PRIVACY;
+ if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
+ IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
+ capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
+ if (ic->ic_flags & IEEE80211_F_SHSLOT)
+ capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
+ assoc.capinfo = htole16(capinfo);
+
+ assoc.lintval = htole16(ic->ic_lintval);
+ assoc.intval = htole16(ni->ni_intval);
+ IEEE80211_ADDR_COPY(assoc.bssid, ni->ni_bssid);
+ if (ic->ic_opmode == IEEE80211_M_IBSS)
+ IEEE80211_ADDR_COPY(assoc.dst, ifp->if_broadcastaddr);
else
- IEEE80211_ADDR_COPY(sc->assoc.dst, ni->ni_bssid);
+ IEEE80211_ADDR_COPY(assoc.dst, ni->ni_bssid);
DPRINTF(("Trying to associate to %6D channel %u auth %u\n",
- sc->assoc.bssid, ":", sc->assoc.chan, sc->assoc.auth));
- return iwi_cmd(sc, IWI_CMD_ASSOCIATE, &sc->assoc, sizeof sc->assoc, 1);
+ assoc.bssid, ":", assoc.chan, assoc.auth));
+ return iwi_cmd(sc, IWI_CMD_ASSOCIATE, &assoc, sizeof assoc, 1);
}
static void
{
struct iwi_softc *sc = priv;
struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
+ struct ifnet *ifp = ic->ic_ifp;
struct iwi_firmware *fw = &sc->fw;
+ struct iwi_rx_data *data;
int i;
/* exit immediately if firmware has not been ioctl'd */
if (!(sc->flags & IWI_FLAG_FW_CACHED)) {
+ if (!(sc->flags & IWI_FLAG_FW_WARNED))
+ device_printf(sc->sc_dev, "Please load firmware\n");
+ sc->flags |= I