Skip site navigation (1)Skip section navigation (2)
Date:      Tue,  6 Mar 2001 17:50:09 -0800 (PST)
From:      brooks@one-eyed-alien.net
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   conf/25577: [PATCH] ifconfig support for wireless network cards
Message-ID:  <20010307015009.4624E24D22@minya.sea.one-eyed-alien.net>

next in thread | raw e-mail | index | archive | help

>Number:         25577
>Category:       conf
>Synopsis:       [PATCH] ifconfig support for wireless network cards
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue Mar 06 17:50:01 PST 2001
>Closed-Date:
>Last-Modified:
>Originator:     Brooks Davis
>Release:        FreeBSD 5.0-CURRENT i386
>Organization:
The Aerospace Corporation
>Environment:
System: FreeBSD minya.sea.one-eyed-alien.net 5.0-CURRENT FreeBSD 5.0-CURRENT #7: Mon Mar 5 15:04:33 PST 2001 root@minya.sea.one-eyed-alien.net:/usr/obj/usr/src/sys/MINYA i386


	
>Description:

Currently, each wireless networking driver has it's own control program
despite the fact that most people want to set exactly the same settings
regardless of which card they have.  It has been repeatidly suggested
that this configuration should be done via ifconfig.  This patch
implements the required functionality in ifconfig and add support to the
wi and an drivers.  It also provides partial, untested support for the
awi driver.

>How-To-Repeat:
	
>Fix:

The current version of the patch is included below.  Needed updates will
be posted on the web at:

http://www.one-eyed-alien.net/~brooks/FreeBSD/ifconfig.diff

The patch contained in ifconfig.diff makes the following changes:

sbin/ifconfig/Makefile
	- Compile in support for IEEE 802.11 devices by default.
sbin/ifconfig/ifconfig.8
	- Document new IEEE 802.11 ifconfig commands.
sbin/ifconfig/ifconfig.c
	- Add new IEEE 802.11 commands.
	- Add support for IEEE 802.11 status printing.
src/sbin/ifconfig/ifconfig.h
	- Declare new support functions (defined in ifieee80211.c).
src/sbin/ifconfig/ifmedia.c
	- Add support for new if_media types for IEEE 802.11
	- Fix a long standing bug which caused media specific mediaopts
	  to not be printed.
sbin/ifconfig/ifieee80211.c *NEW*
	- Define new command and status functions for IEEE 802.11
	  devices.
sys/dev/an/if_aironet_ieee.h
	- Make some more defines visible to the kernel so they can be
	  used for the IEEE 802.11 ioctls.
sys/dev/an/if_an.c
	- Add if_media support.
	- Change default mode to infrastructure.
	- Add support for IEEE 802.11 ioctls.
sys/dev/an/if_an_isa.c
	- Small change for if_media support.
sys/dev/an/if_an_pccard.c
	- Small change for if_media support.
sys/dev/an/if_an_pci.c
	- Small change for if_media support.
sys/dev/an/if_anreg.h
	- Add if_media struct to softc.
sys/dev/awi/awi.c
	- Add untested support for IEEE 802.11 ioctls.
sys/dev/wi/if_wavelan_ieee.h
	- Make some more defines visible to the kernel so they can be
	  used for the IEEE 802.11 ioctls.
sys/dev/wi/if_wi.c
	- Add if_media support.
	- Change default mode to infrastructure.
	- Add support for IEEE 802.11 ioctls.
sys/net/if_ieee80211.h
	- Add definitions for new ioctls.
sys/net/if_media.c
	- Add support for IEEE 802.11 media types.
sys/net/if_media.h
	- Add IEEE 802.11 media types.
share/man/man4/Makefile
	- Link in new ieee80211.4 man page.
share/man/man4/ieee80211.4 *NEW*
	- Document the new IEEE 802.11 ioctls in net/if_ieee80211.h.

Index: sbin/ifconfig//Makefile
===================================================================
RCS file: /home/ncvs/src/sbin/ifconfig/Makefile,v
retrieving revision 1.15
diff -u -u -r1.15 Makefile
--- sbin/ifconfig//Makefile	2000/11/30 21:35:09	1.15
+++ sbin/ifconfig//Makefile	2001/01/16 01:22:39
@@ -15,6 +15,10 @@
 CFLAGS+=-DUSE_VLANS
 .endif
 
+#comment out to exclude SIOC[GS]IEEE80211 support
+SRCS+=	ifieee80211.c
+CFLAGS+=-DUSE_IEEE80211
+
 MAN8=	ifconfig.8
 DPADD=	${LIBIPX}
 LDADD=	-lipx
Index: sbin/ifconfig//ifconfig.8
===================================================================
RCS file: /home/ncvs/src/sbin/ifconfig/ifconfig.8,v
retrieving revision 1.35
diff -u -u -r1.35 ifconfig.8
--- sbin/ifconfig//ifconfig.8	2001/02/01 16:32:06	1.35
+++ sbin/ifconfig//ifconfig.8	2001/03/02 02:40:24
@@ -403,6 +403,111 @@
 It happens automatically when setting the first address on an interface.
 If the interface was reset when previously marked down,
 the hardware will be re-initialized.
+.It Cm ssid Ar ssid
+For IEEE 802.11 wireless interfaces, set the desired Service Set
+Identifier (aka network name.)  The SSID is a string up to 32 characters
+in length and may be specified as either a normal string or in
+hexadecimal when proceeded by
+.Sq 0x .
+Additionally, the SSID may be cleared by setting it to
+.Sq - .
+.It Cm nwid Ar ssid
+Another name for the 
+.Dq ssid
+parameter.  Included for NetBSD compatibility.
+.It Cm stationname Ar name
+For IEEE 802.11 wireless interfaces, set the name of this station.
+It appears that the station name is not really part of the IEEE 802.11
+protocol though all interfaces seem to support it.  As such it only
+seems to be meaningful to identical or virtually identical equipment.
+Setting the station name is identical in syntax to setting the SSID.
+.It Cm station Ar name
+Another name for the 
+.Dq stationname
+parameter.  Included for BSD/OS compatibility.
+.It Cm channel Ar number
+For IEEE 802.11 wireless interfaces, set the desired channel.
+Channels range from 1 to 14, but the exact selection available
+depends on the region your adaptor was manufactured for.  Setting
+the channel to 0 will give you the default for your adaptor.  Many
+adaptors ignore this setting unless you are in ad-hoc mode.
+.It Cm authmode Ar mode
+For IEEE 802.11 wireless interfaces, set the desired authentication mode
+in infrastructure mode.  Not all adaptors support all modes.  The set of
+valid modes is
+.Dq none ,
+.Dq open ,
+and
+.Dq shared .
+Modes are case insensitive.
+.It Cm powersave
+For IEEE 802.11 wireless interfaces, enable powersave mode.
+.It Cm -powersave
+For IEEE 802.11 wireless interfaces, disable powersave mode.
+.It Cm powersavesleep Ar sleep
+For IEEE 802.11 wireless interfaces, set the desired max powersave sleep
+time in milliseconds.
+.It Cm wepmode Ar mode
+For IEEE 802.11 wireless interfaces, set the desired WEP mode.  Not all
+adaptors support all modes.  The set of valid modes is
+.Dq off ,
+.Dq on ,
+and
+.Dq mixed .
+.Dq Mixed
+mode explicitly tells the adaptor to allow association with access
+points which allow both encrypted and unencrypted traffic.  On these
+adaptors,
+.Dq on
+means that the access point must only allow encrypted connections.  On
+other adaptors,
+.Dq on
+is generally another name for
+.Dq mixed .
+Modes are case insensitive.
+.It Cm weptxkey Ar index
+For IEEE 802.11 wireless interfaces, set the WEP key to be used for
+transmission.
+.It Cm wepkey Ar key|index:key
+For IEEE 802.11 wireless interfaces, set the selected WEP key.  If
+an
+.Ar index
+is not given, key 1 is set.  A WEP key will be either 5 or 13
+characters (40 or 104 bits) depending of the local network and the
+capabilities of the adaptor.  It may be specified either as a plain
+string or as a string of hexadecimal digits proceeded by
+.Sq 0x .
+A key may be cleared by setting it to
+.Sq - .
+If WEP is supported then there are at least four keys.  Some adaptors
+support more then four keys.  If that is the case, then the first four keys
+(1-4) will be the standard temporary keys and any others will be adaptor
+specific keys such as permanent keys stored in NVRAM.
+.It Cm wep
+Another way of saying 
+.Dq wepmode on .
+Included for BSD/OS compatibility.
+.It Cm -wep
+Another way of saying
+.Dq wepmode off .
+Included for BSD/OS compatibility.
+.It Cm nwkey key
+Another way of saying:
+.Pp
+``wepmode on weptxkey 1 wepkey 1:key wepkey 2:- wepkey 3:- wepkey 4:-''.
+.Pp
+Included for NetBSD compatibility.
+.It Cm nwkey n:k1,k2,k3,k4
+Another way of saying
+.Pp
+``wepmode on weptxkey n wepkey 1:k1 wepkey 2:k2 wepkey 3:k3 wepkey 4:k4''.
+.Pp
+Included for NetBSD compatibility.
+.It Cm -nwkey
+Another way of saying
+.Dq wepmode off .
+.Pp
+Included for NetBSD compatibility.
 .El
 .Pp
 .Nm Ifconfig
Index: sbin/ifconfig//ifconfig.c
===================================================================
RCS file: /home/ncvs/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.59
diff -u -u -r1.59 ifconfig.c
--- sbin/ifconfig//ifconfig.c	2001/02/21 18:15:18	1.59
+++ sbin/ifconfig//ifconfig.c	2001/02/23 23:58:11
@@ -223,6 +223,25 @@
 	{ "vlandev",	NEXTARG,	setvlandev },
 	{ "-vlandev",	NEXTARG,	unsetvlandev },
 #endif
+#ifdef USE_IEEE80211
+	{ "ssid",	NEXTARG,	set80211ssid },
+	{ "nwid",	NEXTARG,	set80211ssid },
+	{ "stationname", NEXTARG,	set80211stationname },
+	{ "station",	NEXTARG,	set80211stationname },	/* BSD/OS */
+	{ "channel",	NEXTARG,	set80211channel },
+	{ "authmode",	NEXTARG,	set80211authmode },
+	{ "powersavemode", NEXTARG,	set80211powersavemode },
+	{ "powersave",	1,		set80211powersave },
+	{ "-powersave",	0,		set80211powersave },
+	{ "powersavesleep", NEXTARG,	set80211powersavesleep },
+	{ "wepmode",	NEXTARG,	set80211wepmode },
+	{ "wep",	1,		set80211wep },
+	{ "-wep",	0,		set80211wep },
+	{ "weptxkey",	NEXTARG,	set80211weptxkey },
+	{ "wepkey",	NEXTARG,	set80211wepkey },
+	{ "nwkey",	NEXTARG,	set80211nwkey },	/* NetBSD */
+	{ "-nwkey",	0,		set80211wep },		/* NetBSD */
+#endif
 	{ "normal",	-IFF_LINK0,	setifflags },
 	{ "compress",	IFF_LINK0,	setifflags },
 	{ "noicmp",	IFF_LINK1,	setifflags },
@@ -291,6 +310,9 @@
 #ifdef USE_VLANS
 	{ "vlan", AF_UNSPEC, vlan_status, NULL, NULL, },  /* XXX not real!! */
 #endif
+#ifdef USE_IEEE80211
+	{ "ieee80211", AF_UNSPEC, ieee80211_status, NULL, NULL, },  /* XXX not real!! */
+#endif
 #endif
 	{ 0,	0,	    0,		0 }
 };
@@ -969,6 +991,10 @@
 #ifdef USE_VLANS
 	if (allfamilies || afp->af_status == vlan_status)
 		vlan_status(s, NULL);
+#endif
+#ifdef USE_IEEE80211
+	if (allfamilies || afp->af_status == ieee80211_status)
+		ieee80211_status(s, NULL);
 #endif
 	strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
 	if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) 
Index: sbin/ifconfig//ifconfig.h
===================================================================
RCS file: /home/ncvs/src/sbin/ifconfig/ifconfig.h,v
retrieving revision 1.5
diff -u -u -r1.5 ifconfig.h
--- sbin/ifconfig//ifconfig.h	1999/08/28 00:13:08	1.5
+++ sbin/ifconfig//ifconfig.h	2001/01/24 21:54:44
@@ -49,3 +49,17 @@
 extern void setvlandev(const char *, int, int, const struct afswtch *rafp);
 extern void unsetvlandev(const char *, int, int, const struct afswtch *rafp);
 extern void vlan_status(int s, struct rt_addrinfo *);
+
+extern void set80211ssid(const char *, int, int, const struct afswtch *rafp);
+extern void set80211stationname(const char *, int, int, const struct afswtch *rafp);
+extern void set80211channel(const char *, int, int, const struct afswtch *rafp);
+extern void set80211authmode(const char *, int, int, const struct afswtch *rafp);
+extern void set80211powersave(const char *, int, int, const struct afswtch *rafp);
+extern void set80211powersavemode(const char *, int, int, const struct afswtch *rafp);
+extern void set80211powersavesleep(const char *, int, int, const struct afswtch *rafp);
+extern void set80211wepmode(const char *, int, int, const struct afswtch *rafp);
+extern void set80211wep(const char *, int, int, const struct afswtch *rafp);
+extern void set80211weptxkey(const char *, int, int, const struct afswtch *rafp);
+extern void set80211wepkey(const char *, int, int, const struct afswtch *rafp);
+extern void set80211nwkey(const char *, int, int, const struct afswtch *rafp);
+extern void ieee80211_status(int s, struct rt_addrinfo *);
Index: sbin/ifconfig//ifmedia.c
===================================================================
RCS file: /home/ncvs/src/sbin/ifconfig/ifmedia.c,v
retrieving revision 1.6
diff -u -u -r1.6 ifmedia.c
--- sbin/ifconfig//ifmedia.c	1999/08/28 00:13:08	1.6
+++ sbin/ifconfig//ifmedia.c	2001/03/01 00:07:13
@@ -152,6 +152,13 @@
 			else
 				printf("no ring");
 			break;
+		case IFM_IEEE80211:
+			/* XXX: Different value for adhoc? */
+			if (ifmr.ifm_status & IFM_ACTIVE)
+				printf("associated");
+			else
+				printf("no carrier");
+			break;
 		}
 	}
 
@@ -318,6 +325,15 @@
 static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
     IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
 
+static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
+    IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
+    IFM_SUBTYPE_IEEE80211_ALIASES;
+
+static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
+    IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
+
 static struct ifmedia_description ifm_subtype_shared_descriptions[] =
     IFM_SUBTYPE_SHARED_DESCRIPTIONS;
 
@@ -350,7 +366,7 @@
 		},
 		{
 			{ &ifm_shared_option_descriptions[0], 0 },
-			{ &ifm_subtype_ethernet_option_descriptions[0], 1 },
+			{ &ifm_subtype_ethernet_option_descriptions[0], 0 },
 			{ NULL, 0 },
 		},
 	},
@@ -364,7 +380,7 @@
 		},
 		{
 			{ &ifm_shared_option_descriptions[0], 0 },
-			{ &ifm_subtype_tokenring_option_descriptions[0], 1 },
+			{ &ifm_subtype_tokenring_option_descriptions[0], 0 },
 			{ NULL, 0 },
 		},
 	},
@@ -377,8 +393,22 @@
 			{ NULL, 0 },
 		},
 		{
+			{ &ifm_shared_option_descriptions[0], 0 },
+			{ &ifm_subtype_fddi_option_descriptions[0], 0 },
+			{ NULL, 0 },
+		},
+	},
+	{
+		{
+			{ &ifm_subtype_shared_descriptions[0], 0 },
+			{ &ifm_subtype_shared_aliases[0], 1 },
+			{ &ifm_subtype_ieee80211_descriptions[0], 0 },
+			{ &ifm_subtype_ieee80211_aliases[0], 1 },
+			{ NULL, 0 },
+		},
+		{
 			{ &ifm_shared_option_descriptions[0], 0 },
-			{ &ifm_subtype_fddi_option_descriptions[0], 1 },
+			{ &ifm_subtype_ieee80211_option_descriptions[0], 0 },
 			{ NULL, 0 },
 		},
 	},
--- sbin/ifconfig/ifieee80211.c.orig	Mon Jan 15 16:45:24 2001
+++ sbin/ifconfig/ifieee80211.c	Thu Mar  1 18:33:06 2001
@@ -0,0 +1,518 @@
+/*
+ * Copyright 2001 The Aerospace Corporation.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <net/if_ieee80211.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+
+static void set80211(int s, int type, int val, int len, u_int8_t *data);
+static const char *get_string(const char *val, const char *sep,
+    u_int8_t *buf, int *lenp);
+static void print_string(const u_int8_t *buf, int len);
+
+void
+set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int		ssid;
+	int		len;
+	u_int8_t	data[33];
+
+	ssid = 0;
+
+	bzero(data, sizeof(data));
+	len = sizeof(data);
+	get_string(val, NULL, data, &len);
+
+	set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
+}
+
+void
+set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int			len;
+	u_int8_t		data[33];
+
+	bzero(data, sizeof(data));
+	len = sizeof(data);
+	get_string(val, NULL, data, &len);
+
+	set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
+}
+
+void
+set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_CHANNEL, atoi(val), 0, NULL);
+}
+
+void
+set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int	mode;
+
+	if(strcasecmp(val, "none") == 0) {
+		mode = IEEE80211_AUTH_NONE;
+	} else if(strcasecmp(val, "open") == 0) {
+		mode = IEEE80211_AUTH_OPEN;
+	} else if(strcasecmp(val, "shared") == 0) {
+		mode = IEEE80211_AUTH_SHARED;
+	} else {
+		err(1, "unknown authmode");
+	}
+
+	set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
+}
+
+void
+set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int	mode;
+
+	if(strcasecmp(val, "off") == 0) {
+		mode = IEEE80211_POWERSAVE_OFF;
+	} else if(strcasecmp(val, "on") == 0) {
+		mode = IEEE80211_POWERSAVE_ON;
+	} else if(strcasecmp(val, "cam") == 0) {
+		mode = IEEE80211_POWERSAVE_CAM;
+	} else if(strcasecmp(val, "psp") == 0) {
+		mode = IEEE80211_POWERSAVE_PSP;
+	} else if(strcasecmp(val, "psp-cam") == 0) {
+		mode = IEEE80211_POWERSAVE_PSP_CAM;
+	} else {
+		err(1, "unknown powersavemode");
+	}
+
+	set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
+}
+
+void
+set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	if (d == 0)
+		set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
+		    0, NULL);
+	else
+		set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
+		    0, NULL);
+}
+
+void
+set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
+}
+
+void
+set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int	mode;
+
+	if(strcasecmp(val, "off") == 0) {
+		mode = IEEE80211_WEP_OFF;
+	} else if(strcasecmp(val, "on") == 0) {
+		mode = IEEE80211_WEP_ON;
+	} else if(strcasecmp(val, "mixed") == 0) {
+		mode = IEEE80211_WEP_MIXED;
+	} else {
+		err(1, "unknown wep mode");
+	}
+
+	set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
+}
+
+void
+set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
+}
+
+void
+set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
+}
+
+void
+set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int		key = 0;
+	int		len;
+	u_int8_t	data[14];
+
+	if(isdigit(val[0]) && val[1] == ':') {
+		key = atoi(val)-1;
+		val += 2;
+	}
+
+	bzero(data, sizeof(data));
+	len = sizeof(data);
+	get_string(val, NULL, data, &len);
+
+	set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
+}
+
+/*
+ * This function is purly a NetBSD compatability interface.  The NetBSD
+ * iterface is too inflexable, but it's there so we'll support it since
+ * it's not all that hard.
+ */
+void
+set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int		txkey;
+	int		i, len;
+	u_int8_t	data[14];
+
+	set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
+
+	if(isdigit(val[0]) && val[1] == ':') {
+		txkey = val[0]-'0'-1;
+		val += 2;
+
+		for(i = 0; i < 4; i++) {
+			bzero(data, sizeof(data));
+			len = sizeof(data);
+			val = get_string(val, ",", data, &len);
+
+			set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
+		}
+	} else {
+		bzero(data, sizeof(data));
+		len = sizeof(data);
+		get_string(val, NULL, data, &len);
+		txkey = 0;
+
+		set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
+
+		bzero(data, sizeof(data));
+		for(i = 1; i < 4; i++)
+			set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
+	}
+
+	set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
+}
+
+void
+ieee80211_status (s, info)
+	int s;
+	struct rt_addrinfo *info __unused;
+{
+	int			i;
+	int			num;
+	struct ieee80211req	ireq;
+	u_int8_t		data[32];
+	char			spacer;
+
+	(void) memset(&ireq, 0, sizeof(ireq));
+	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+	ireq.i_data = &data;
+
+	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);
+	printf("\n");
+
+	ireq.i_type = IEEE80211_IOC_STATIONNAME;
+	if (ioctl(s, SIOCG80211, &ireq) != -1) {
+		printf("\tstationname ");
+		print_string(data, ireq.i_len);
+		printf("\n");
+	}
+
+	ireq.i_type = IEEE80211_IOC_CHANNEL;
+	if (ioctl(s, SIOCG80211, &ireq) < 0) {
+		goto end;
+	}
+	printf("\tchannel %d", ireq.i_val);
+
+	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");
+				break;
+		}
+	}
+
+	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");
+				break;
+			case IEEE80211_POWERSAVE_PSP_CAM:
+				printf(" PSP-CAM");
+				break;
+		}
+
+		ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
+		if (ioctl(s, SIOCG80211, &ireq) != -1) {
+			if(ireq.i_val)
+				printf(" powersavesleep %d", ireq.i_val);
+		}
+	}
+
+	printf("\n");
+
+	ireq.i_type = IEEE80211_IOC_WEP;
+	if (ioctl(s, SIOCG80211, &ireq) < 0 ||
+	    ireq.i_val == IEEE80211_WEP_NOSUP)
+		goto nowep;
+	else {
+		printf("\twepmode");
+		switch (ireq.i_val) {
+			case IEEE80211_WEP_OFF:
+				printf(" OFF");
+				break;
+			case IEEE80211_WEP_ON:
+				printf(" ON");
+				break;
+			case IEEE80211_WEP_MIXED:
+				printf(" MIXED");
+				break;
+			default:
+				printf(" UNKNOWN");
+				break;
+		}
+
+		/*
+		 * If we get here then we've got WEP support so we need
+		 * to print WEP status.
+		 */ 
+
+		ireq.i_type = IEEE80211_IOC_WEPTXKEY;
+		if (ioctl(s, SIOCG80211, &ireq) < 0) {
+			warn("WEP support, but no tx key!");
+			goto end;
+		}
+		printf(" weptxkey %d", ireq.i_val+1);
+
+		ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
+		if (ioctl(s, SIOCG80211, &ireq) < 0) {
+			warn("WEP support, but no NUMWEPKEYS support!");
+			goto end;
+		}
+		num = ireq.i_val;
+
+		printf("\n");
+
+		ireq.i_type = IEEE80211_IOC_WEPKEY;
+		spacer = '\t';
+		for(i = 0; i < num; i++) {
+			ireq.i_val = i;
+			if (ioctl(s, SIOCG80211, &ireq) < 0) {
+				warn("WEP support, but can get keys!");
+				goto end;
+			}
+			if(ireq.i_len == 0 || ireq.i_len > 13)
+				continue;
+			printf("%cwepkey %d:%s", spacer, i+1,
+			    ireq.i_len <= 5 ? "64-bit" : "128-bit");
+			if(spacer == '\t')
+				spacer = ' ';
+		}
+
+		printf("\n");
+	}
+nowep:
+
+
+end:
+	return;
+}
+
+static void
+set80211(int s, int type, int val, int len, u_int8_t *data)
+{
+	struct ieee80211req	ireq;
+
+	(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;
+	ireq.i_data = data;
+	if(ioctl(s, SIOCS80211, &ireq) < 0)
+		err(1, "SIOCS80211");
+}
+
+static const char *
+get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
+{
+	int len;
+	int hexstr;
+	u_int8_t *p;
+
+	len = *lenp;
+	p = buf;
+	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
+	if (hexstr)
+		val += 2;
+	for (;;) {
+		if (*val == '\0')
+			break;
+		if (sep != NULL && strchr(sep, *val) != NULL) {
+			val++;
+			break;
+		}
+		if (hexstr) {
+			if (!isxdigit((u_char)val[0]) ||
+			    !isxdigit((u_char)val[1])) {
+				warnx("bad hexadecimal digits");
+				return NULL;
+			}
+		}
+		if (p > buf + len) {
+			if (hexstr)
+				warnx("hexadecimal digits too long");
+			else
+				warnx("strings too long");
+			return NULL;
+		}
+		if (hexstr) {
+#define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
+			*p++ = (tohex((u_char)val[0]) << 4) |
+			    tohex((u_char)val[1]);
+#undef tohex
+			val += 2;
+		} else
+			*p++ = *val++;
+	}
+	len = p - buf;
+	/* The string "-" is treated as the empty string. */
+	if (!hexstr && len == 1 && buf[0] == '-')
+		len = 0;
+	if (len < *lenp)
+		memset(p, 0, *lenp - len);
+	*lenp = len;
+	return val;
+}
+
+static void
+print_string(const u_int8_t *buf, int len)
+{
+	int i;
+	int hasspc;
+
+	i = 0;
+	hasspc = 0;
+	for(; i < len; i++) {
+		if (!isprint(buf[i]) && buf[i] != '\0')
+			break;
+		if (isspace(buf[i]))
+			hasspc++;
+	}
+	if (i == len) {
+		if (hasspc || len == 0 || buf[0] == '\0')
+			printf("\"%.*s\"", len, buf);
+		else
+			printf("%.*s", len, buf);
+	} else {
+		printf("0x");
+		for (i = 0; i < len; i++)
+			printf("%02x", buf[i]);
+	}
+}
+
Index: sys/dev/an/if_aironet_ieee.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/an/if_aironet_ieee.h,v
retrieving revision 1.3
diff -u -u -r1.3 if_aironet_ieee.h
--- sys/dev/an/if_aironet_ieee.h	2000/12/08 19:00:10	1.3
+++ sys/dev/an/if_aironet_ieee.h	2001/01/24 23:50:12
@@ -336,6 +336,7 @@
 	u_int8_t		an_magic_packet_ctl;	/* 0x99 */
 	u_int16_t		an_rsvd9;
 };
+#endif
 
 #define AN_OPMODE_IBSS_ADHOC			0x0000
 #define AN_OPMODE_INFRASTRUCTURE_STATION	0x0001
@@ -392,6 +393,7 @@
 #define AN_TXPOWER_100MW			100
 #define AN_TXPOWER_250MW			250
 
+#ifndef _KERNEL
 struct an_ltv_ssidlist {
 	u_int16_t		an_len;
 	u_int16_t		an_type;
Index: sys/dev/an/if_an.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/an/if_an.c,v
retrieving revision 1.14
diff -u -u -r1.14 if_an.c
--- sys/dev/an/if_an.c	2001/01/19 01:58:28	1.14
+++ sys/dev/an/if_an.c	2001/03/02 20:38:31
@@ -113,6 +113,8 @@
 #include <net/ethernet.h>
 #include <net/if_dl.h>
 #include <net/if_types.h>
+#include <net/if_ieee80211.h>
+#include <net/if_media.h>
 
 #ifdef INET
 #include <netinet/in.h>
@@ -160,6 +162,9 @@
 					struct mbuf *, unsigned short));
 #endif
 
+static int an_media_change	__P((struct ifnet *));
+static void an_media_status	__P((struct ifnet *, struct ifmediareq *));
+
 /* 
  * We probe for an Aironet 4500/4800 card by attempting to
  * read the default SSID list. On reset, the first entry in
@@ -375,11 +380,36 @@
 	sc->an_ssidlist.an_ssid1_len = strlen(AN_DEFAULT_NETNAME);
 
 	sc->an_config.an_opmode =
-	    AN_OPMODE_IBSS_ADHOC;
+	    AN_OPMODE_INFRASTRUCTURE_STATION;
 
 	sc->an_tx_rate = 0;
 	bzero((char *)&sc->an_stats, sizeof(sc->an_stats));
 
+	ifmedia_init(&sc->an_ifmedia, 0, an_media_change, an_media_status);
+#define	ADD(m, c)	ifmedia_add(&sc->an_ifmedia, (m), (c), NULL)
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
+	    IFM_IEEE80211_ADHOC, 0), 0);
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0);
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
+	    IFM_IEEE80211_ADHOC, 0), 0);
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0);
+	if(sc->an_caps.an_rates[2] == AN_RATE_5_5MBPS) {
+		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
+		    IFM_IEEE80211_ADHOC, 0), 0);
+		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0);
+	}
+	if(sc->an_caps.an_rates[3] == AN_RATE_11MBPS) {
+		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
+		    IFM_IEEE80211_ADHOC, 0), 0);
+		ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0);
+	}
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
+	    IFM_IEEE80211_ADHOC, 0), 0);
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0);
+#undef	ADD
+	ifmedia_set(&sc->an_ifmedia, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
+	    0, 0));
+
 	/*
 	 * Call MI attach routine.
 	 */
@@ -1012,14 +1042,29 @@
 	caddr_t			data;
 {
 	int			error = 0;
+	int			len;
+	int			i;
 	struct an_softc		*sc;
 	struct an_req		areq;
 	struct ifreq		*ifr;
 	struct proc		*p = curproc;
+	struct ieee80211req	*ireq;
+	u_int8_t		tmpstr[IEEE80211_NWID_LEN*2];
+	u_int8_t		*tmpptr;
+	struct an_ltv_genconfig	*config;
+	struct an_ltv_key	*key;
+	struct an_ltv_status	*status;
+	struct an_ltv_ssidlist	*ssids;
 
 	sc = ifp->if_softc;
 	AN_LOCK(sc);
 	ifr = (struct ifreq *)data;
+	ireq = (struct ieee80211req *)data;
+
+	config = (struct an_ltv_genconfig *)&areq;
+	key = (struct an_ltv_key *)&areq;
+	status = (struct an_ltv_status *)&areq;
+	ssids = (struct an_ltv_ssidlist *)&areq;
 
 	if (sc->an_gone) {
 		error = ENODEV;
@@ -1051,6 +1096,10 @@
 		sc->an_if_flags = ifp->if_flags;
 		error = 0;
 		break;
+	case SIOCSIFMEDIA:
+	case SIOCGIFMEDIA:
+		error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command);
+		break;
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
 		/* The Aironet has no multicast filter. */
@@ -1090,6 +1139,366 @@
 			break;
 		an_setdef(sc, &areq);
 		break;
+	case SIOCG80211:
+		areq.an_len = sizeof(areq);
+		switch(ireq->i_type) {
+		case IEEE80211_IOC_SSID:
+			if(ireq->i_val == -1) {
+				areq.an_type = AN_RID_STATUS;
+				if (an_read_record(sc,
+				    (struct an_ltv_gen *)&areq)) {
+					error = EINVAL;
+					break;
+				}
+				len = status->an_ssidlen;
+				tmpptr = status->an_ssid;
+			} else if(ireq->i_val >= 0) {
+				areq.an_type = AN_RID_SSIDLIST;
+				if (an_read_record(sc,
+				    (struct an_ltv_gen *)&areq)) {
+					error = EINVAL;
+					break;
+				}
+				if(ireq->i_val == 0) {
+					len = ssids->an_ssid1_len;
+					tmpptr = ssids->an_ssid1;
+				} else if(ireq->i_val == 1) {
+					len = ssids->an_ssid2_len;
+					tmpptr = ssids->an_ssid3;
+				} else if(ireq->i_val == 1) {
+					len = ssids->an_ssid3_len;
+					tmpptr = ssids->an_ssid3;
+				} else {
+					error = EINVAL;
+					break;
+				}
+			} else {
+				error = EINVAL;
+				break;
+			}
+			if(len > IEEE80211_NWID_LEN) {
+				error = EINVAL;
+				break;
+			}
+			ireq->i_len = len;
+			bzero(tmpstr, IEEE80211_NWID_LEN);
+			bcopy(tmpptr, tmpstr, len);
+			error = copyout(tmpstr, ireq->i_data,
+			    IEEE80211_NWID_LEN);
+			break;
+		case IEEE80211_IOC_NUMSSIDS:
+			ireq->i_val = 3;
+			break;
+		case IEEE80211_IOC_WEP:
+			areq.an_type = AN_RID_ACTUALCFG;
+			if (an_read_record(sc,
+			    (struct an_ltv_gen *)&areq)) {
+				error = EINVAL;
+				break;
+			}
+			if(config->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) {
+				if(config->an_authtype &
+				    AN_AUTHTYPE_ALLOW_UNENCRYPTED)
+					ireq->i_val = IEEE80211_WEP_MIXED;
+				else
+					ireq->i_val = IEEE80211_WEP_ON;
+				
+			} else {
+				ireq->i_val = IEEE80211_WEP_OFF;
+			}
+			break;
+		case IEEE80211_IOC_WEPKEY:
+			/*
+			 * XXX: I'm not entierly convinced this is
+			 * correct, but it's what is implemented in
+			 * ancontrol so it will have to do until we get
+			 * access to actual Cisco code.
+			 */
+			if(ireq->i_val < 0 || ireq->i_val > 7) {
+				error = EINVAL;
+				break;
+			}
+			len = 0;
+			if(ireq->i_val < 4) {
+				areq.an_type = AN_RID_WEP_TEMP;
+				for(i=0; i<4; i++) {
+					if (an_read_record(sc,
+					    (struct an_ltv_gen *)&areq)) {
+						error = EINVAL;
+						break;
+					}
+					len = key->klen;
+					if(i == ireq->i_val)
+						break;
+					/* Required to get next entry */
+					areq.an_type = AN_RID_WEP_PERM;
+				}
+				if(error)
+					break;
+			}
+			/* We aren't allowed to read the value of the
+			 * key from the card so we just output zeros
+			 * like we would if we could read the card, but
+			 * denied the user access.
+			 */
+			bzero(tmpstr, len);
+			ireq->i_len = len;
+			error = copyout(tmpstr, ireq->i_data, len);
+			break;
+		case IEEE80211_IOC_NUMWEPKEYS:
+			ireq->i_val = 8;
+			break;
+		case IEEE80211_IOC_WEPTXKEY:
+			areq.an_type = AN_RID_WEP_PERM;
+			key->kindex = 0xffff;
+			if (an_read_record(sc,
+			    (struct an_ltv_gen *)&areq)) {
+				error = EINVAL;
+				break;
+			}
+			ireq->i_val = key->mac[0];
+			break;
+		case IEEE80211_IOC_AUTHMODE:
+			areq.an_type = AN_RID_ACTUALCFG;
+			if (an_read_record(sc,
+			    (struct an_ltv_gen *)&areq)) {
+				error = EINVAL;
+				break;
+			}
+			if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
+			    AN_AUTHTYPE_NONE) {
+			    ireq->i_val = IEEE80211_AUTH_NONE;
+			} else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
+			    AN_AUTHTYPE_OPEN) {
+			    ireq->i_val = IEEE80211_AUTH_OPEN;
+			} else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
+			    AN_AUTHTYPE_SHAREDKEY) {
+			    ireq->i_val = IEEE80211_AUTH_SHARED;
+			} else
+				error = EINVAL;
+			break;
+		case IEEE80211_IOC_STATIONNAME:
+			areq.an_type = AN_RID_ACTUALCFG;
+			if (an_read_record(sc,
+			    (struct an_ltv_gen *)&areq)) {
+				error = EINVAL;
+				break;
+			}
+			ireq->i_len = sizeof(config->an_nodename);
+			tmpptr = config->an_nodename;
+			bzero(tmpstr, IEEE80211_NWID_LEN);
+			bcopy(tmpptr, tmpstr, ireq->i_len);
+			error = copyout(tmpstr, ireq->i_data,
+			    IEEE80211_NWID_LEN);
+			break;
+		case IEEE80211_IOC_CHANNEL:
+			areq.an_type = AN_RID_STATUS;
+			if (an_read_record(sc,
+			    (struct an_ltv_gen *)&areq)) {
+				error = EINVAL;
+				break;
+			}
+			ireq->i_val = status->an_cur_channel;
+			break;
+		case IEEE80211_IOC_POWERSAVE:
+			areq.an_type = AN_RID_ACTUALCFG;
+			if (an_read_record(sc,
+			    (struct an_ltv_gen *)&areq)) {
+				error = EINVAL;
+				break;
+			}
+			if(config->an_psave_mode == AN_PSAVE_NONE) {
+				ireq->i_val = IEEE80211_POWERSAVE_OFF;
+			} else if(config->an_psave_mode == AN_PSAVE_CAM) {
+				ireq->i_val = IEEE80211_POWERSAVE_CAM;
+			} else if(config->an_psave_mode == AN_PSAVE_PSP) {
+				ireq->i_val = IEEE80211_POWERSAVE_PSP;
+			} else if(config->an_psave_mode == AN_PSAVE_PSP_CAM) {
+				ireq->i_val = IEEE80211_POWERSAVE_PSP_CAM;
+			} else
+				error = EINVAL;
+			break;
+		case IEEE80211_IOC_POWERSAVESLEEP:
+			areq.an_type = AN_RID_ACTUALCFG;
+			if (an_read_record(sc,
+			    (struct an_ltv_gen *)&areq)) {
+				error = EINVAL;
+				break;
+			}
+			ireq->i_val = config->an_listen_interval;
+			break;
+		}	
+		break;
+	case SIOCS80211:
+		areq.an_len = sizeof(areq);
+		/*
+		 * We need a config structure for everything but the WEP
+		 * key management and SSIDs so we get it now so avoid
+		 * duplicating this code every time.
+		 */
+		if (ireq->i_type != IEEE80211_IOC_SSID &&
+		    ireq->i_type != IEEE80211_IOC_WEPKEY &&
+		    ireq->i_type != IEEE80211_IOC_WEPTXKEY) {
+			areq.an_type = AN_RID_GENCONFIG;
+			if (an_read_record(sc,
+			    (struct an_ltv_gen *)&areq)) {
+				error = EINVAL;
+				break;
+			}
+		}
+		switch(ireq->i_type) {
+		case IEEE80211_IOC_SSID:
+			areq.an_type = AN_RID_SSIDLIST;
+			if (an_read_record(sc,
+			    (struct an_ltv_gen *)&areq)) {
+				error = EINVAL;
+				break;
+			}
+			if(ireq->i_len > IEEE80211_NWID_LEN) {
+				error = EINVAL;
+				break;
+			}
+			switch (ireq->i_val) {
+			case 0:
+				error = copyin(ireq->i_data,
+				    ssids->an_ssid1, ireq->i_len);
+				ssids->an_ssid1_len = ireq->i_len;
+				break;
+			case 1:
+				error = copyin(ireq->i_data,
+				    ssids->an_ssid2, ireq->i_len);
+				ssids->an_ssid2_len = ireq->i_len;
+				break;
+			case 2:
+				error = copyin(ireq->i_data,
+				    ssids->an_ssid3, ireq->i_len);
+				ssids->an_ssid3_len = ireq->i_len;
+				break;
+			default:
+				error = EINVAL;
+				break;
+			}
+			break;
+		case IEEE80211_IOC_WEP:
+			switch (ireq->i_val) {
+			case IEEE80211_WEP_OFF:
+				config->an_authtype &=
+				    ~(AN_AUTHTYPE_PRIVACY_IN_USE |
+				    AN_AUTHTYPE_ALLOW_UNENCRYPTED);
+				break;
+			case IEEE80211_WEP_ON:
+				config->an_authtype |=
+				    AN_AUTHTYPE_PRIVACY_IN_USE;
+				config->an_authtype &=
+				    ~AN_AUTHTYPE_ALLOW_UNENCRYPTED;
+				break;
+			case IEEE80211_WEP_MIXED:
+				config->an_authtype |=
+				    AN_AUTHTYPE_PRIVACY_IN_USE |
+				    AN_AUTHTYPE_ALLOW_UNENCRYPTED;
+				break;
+			default:
+				error = EINVAL;
+				break;
+			}
+			break;
+		case IEEE80211_IOC_WEPKEY:
+			if (ireq->i_val < 0 || ireq->i_val > 7 ||
+			    ireq->i_len > 13) {
+				error = EINVAL;
+				break;
+			}
+			error = copyin(ireq->i_data, tmpstr, 13);
+			if(error)
+				break;
+			bzero(&areq, sizeof(struct an_ltv_key));
+			areq.an_len = sizeof(struct an_ltv_key);
+			key->mac[0] = 1;	/* The others are 0. */
+			key->kindex = ireq->i_val % 4;
+			if(ireq->i_val < 4)
+				areq.an_type = AN_RID_WEP_TEMP;
+			else
+				areq.an_type = AN_RID_WEP_PERM;
+			key->klen = ireq->i_len;
+			bcopy(tmpstr, key->key, key->klen);
+			break;
+		case IEEE80211_IOC_WEPTXKEY:
+			if(ireq->i_val < 0 || ireq->i_val > 3) {
+				error = EINVAL;
+				break;
+			}
+			bzero(&areq, sizeof(struct an_ltv_key));
+			areq.an_len = sizeof(struct an_ltv_key);
+			areq.an_type = AN_RID_WEP_PERM;
+			key->kindex = 0xffff;
+			key->mac[0] = ireq->i_val;
+			break;
+		case IEEE80211_IOC_AUTHMODE:
+			switch (ireq->i_val) {
+			case IEEE80211_AUTH_NONE:
+				config->an_authtype = AN_AUTHTYPE_NONE |
+				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
+				break;
+			case IEEE80211_AUTH_OPEN:
+				config->an_authtype = AN_AUTHTYPE_OPEN |
+				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
+				break;
+			case IEEE80211_AUTH_SHARED:
+				config->an_authtype = AN_AUTHTYPE_SHAREDKEY |
+				    (config->an_authtype & ~AN_AUTHTYPE_MASK);
+				break;
+			default:
+				error = EINVAL;
+			}
+			break;
+		case IEEE80211_IOC_STATIONNAME:
+			if(ireq->i_len > 16) {
+				error = EINVAL;
+				break;
+			}
+			bzero(config->an_nodename, 16);
+			error = copyin(ireq->i_data,
+			    config->an_nodename, ireq->i_len);
+			break;
+		case IEEE80211_IOC_CHANNEL:
+			/*
+			 * The actual range is 1-14, but if you set it
+			 * to 0 you get the default so we let that work
+			 * too.
+			 */
+			if (ireq->i_val < 0 || ireq->i_val >14) {
+				error = EINVAL;
+				break;
+			}
+			config->an_ds_channel = ireq->i_val;
+			break;
+		case IEEE80211_IOC_POWERSAVE:
+			switch (ireq->i_val) {
+			case IEEE80211_POWERSAVE_OFF:
+				config->an_psave_mode = AN_PSAVE_NONE;
+				break;
+			case IEEE80211_POWERSAVE_CAM:
+				config->an_psave_mode = AN_PSAVE_CAM;
+				break;
+			case IEEE80211_POWERSAVE_PSP:
+				config->an_psave_mode = AN_PSAVE_PSP;
+				break;
+			case IEEE80211_POWERSAVE_PSP_CAM:
+				config->an_psave_mode = AN_PSAVE_PSP_CAM;
+				break;
+			default:
+				error = EINVAL;
+				break;
+			}
+			break;
+		case IEEE80211_IOC_POWERSAVESLEEP:
+			config->an_listen_interval = ireq->i_val;
+			break;
+		}
+
+		if (!error)
+			an_setdef(sc, &areq);
+		break;
 	default:
 		error = EINVAL;
 		break;
@@ -1447,6 +1856,7 @@
 	static int cache_slot = 0; 	/* use this cache entry */
 	static int wrapindex = 0;       /* next "free" cache entry */
 	int saanp=0;
+	int sig, noise;
 
 	/* filters:
 	 * 1. ip only
@@ -1554,3 +1964,84 @@
 	return;
 }
 #endif
+
+static int an_media_change(ifp)
+	struct ifnet		*ifp;
+{
+	struct an_softc *sc = ifp->if_softc;
+	int otype = sc->an_config.an_opmode;
+	int orate = sc->an_tx_rate;
+
+	if ((sc->an_ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0)
+		sc->an_config.an_opmode = AN_OPMODE_IBSS_ADHOC;
+	else
+		sc->an_config.an_opmode = AN_OPMODE_INFRASTRUCTURE_STATION;
+
+	switch (IFM_SUBTYPE(sc->an_ifmedia.ifm_cur->ifm_media)) {
+	case IFM_IEEE80211_DS1:
+		sc->an_tx_rate = AN_RATE_1MBPS;
+		break;
+	case IFM_IEEE80211_DS2:
+		sc->an_tx_rate = AN_RATE_2MBPS;
+		break;
+	case IFM_IEEE80211_DS5:
+		sc->an_tx_rate = AN_RATE_5_5MBPS;
+		break;
+	case IFM_IEEE80211_DS11:
+		sc->an_tx_rate = AN_RATE_11MBPS;
+		break;
+	case IFM_AUTO:
+		sc->an_tx_rate = 0;
+		break;
+	}
+
+	if (otype != sc->an_config.an_opmode ||
+	    orate != sc->an_tx_rate)
+		an_init(sc);
+
+	return(0);
+}
+
+static void an_media_status(ifp, imr)
+	struct ifnet		*ifp;
+	struct ifmediareq	*imr;
+{
+	struct an_ltv_status	status;
+	struct an_softc		*sc = ifp->if_softc;
+
+	status.an_len = sizeof(status);
+	status.an_type = AN_RID_STATUS;
+	if (an_read_record(sc, (struct an_ltv_gen *)&status)) {
+		/* If the status read fails, just lie. */
+		imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media;
+		imr->ifm_status = IFM_AVALID|IFM_ACTIVE;
+	}
+
+	if(sc->an_tx_rate == 0) {
+		imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
+		if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC)
+			imr->ifm_active |= IFM_IEEE80211_ADHOC;
+		switch(status.an_current_tx_rate) {
+		case AN_RATE_1MBPS:
+			imr->ifm_active |= IFM_IEEE80211_DS1;
+			break;
+		case AN_RATE_2MBPS:
+			imr->ifm_active |= IFM_IEEE80211_DS2;
+			break;
+		case AN_RATE_5_5MBPS:
+			imr->ifm_active |= IFM_IEEE80211_DS5;
+			break;
+		case AN_RATE_11MBPS:
+			imr->ifm_active |= IFM_IEEE80211_DS11;
+			break;
+		}
+	} else {
+		imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media;
+	}
+
+	imr->ifm_status = IFM_AVALID;
+	if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC)
+		imr->ifm_status |= IFM_ACTIVE;
+	else if (status.an_opmode & AN_STATUS_OPMODE_ASSOCIATED)
+			imr->ifm_status |= IFM_ACTIVE;
+}
Index: sys/dev/an/if_an_isa.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/an/if_an_isa.c,v
retrieving revision 1.4
diff -u -u -r1.4 if_an_isa.c
--- sys/dev/an/if_an_isa.c	2000/10/13 22:04:20	1.4
+++ sys/dev/an/if_an_isa.c	2001/02/28 01:28:16
@@ -63,6 +63,7 @@
 #include <net/ethernet.h>
 #include <net/if_dl.h>
 #include <net/if_types.h>
+#include <net/if_media.h>
 
 #include <isa/isavar.h>
 #include <isa/pnpvar.h>
@@ -137,6 +138,7 @@
 	struct ifnet		*ifp = &sc->arpcom.ac_if;
 
 	an_stop(sc);
+	ifmedia_removeall(&sc->an_ifmedia);
 	ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
 	bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
 	an_release_resources(dev);
Index: sys/dev/an/if_an_pccard.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/an/if_an_pccard.c,v
retrieving revision 1.6
diff -u -u -r1.6 if_an_pccard.c
--- sys/dev/an/if_an_pccard.c	2000/10/20 07:57:56	1.6
+++ sys/dev/an/if_an_pccard.c	2001/02/28 01:28:20
@@ -63,6 +63,7 @@
 #include <net/ethernet.h>
 #include <net/if_dl.h>
 #include <net/if_types.h>
+#include <net/if_media.h>
 
 #ifndef lint
 static const char rcsid[] =
@@ -110,6 +111,7 @@
 		return(0);
 	}
 	an_stop(sc);
+	ifmedia_removeall(&sc->an_ifmedia);
 	ifp->if_flags &= ~IFF_RUNNING;
 	ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
 	sc->an_gone = 1;
Index: sys/dev/an/if_an_pci.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/an/if_an_pci.c,v
retrieving revision 1.8
diff -u -u -r1.8 if_an_pci.c
--- sys/dev/an/if_an_pci.c	2000/10/20 07:57:56	1.8
+++ sys/dev/an/if_an_pci.c	2001/02/28 01:28:27
@@ -76,6 +76,7 @@
 #include <net/if_arp.h>
 #include <net/ethernet.h>
 #include <net/if_dl.h>
+#include <net/if_media.h>
 
 #include <pci/pcireg.h>
 #include <pci/pcivar.h>
@@ -195,6 +196,7 @@
 	struct ifnet		*ifp = &sc->arpcom.ac_if;
 
 	an_stop(sc);
+	ifmedia_removeall(&sc->an_ifmedia);
 	ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
 	bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
 	an_release_resources(dev);
Index: sys/dev/an/if_anreg.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/an/if_anreg.h,v
retrieving revision 1.5
diff -u -u -r1.5 if_anreg.h
--- sys/dev/an/if_anreg.h	2001/02/09 06:08:38	1.5
+++ sys/dev/an/if_anreg.h	2001/02/28 01:17:51
@@ -842,6 +842,7 @@
 	struct callout_handle	an_stat_ch;
 	struct mtx		an_mtx;
 	device_t		an_dev;
+	struct ifmedia		an_ifmedia;
 };
 
 #define AN_LOCK(_sc)		mtx_lock(&(_sc)->an_mtx)
Index: sys/dev/awi/awi.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/awi/awi.c,v
retrieving revision 1.12
diff -u -u -r1.12 awi.c
--- sys/dev/awi/awi.c	2001/02/06 10:10:57	1.12
+++ sys/dev/awi/awi.c	2001/02/11 01:05:42
@@ -455,9 +455,12 @@
 	struct awi_softc *sc = ifp->if_softc;
 	struct ifreq *ifr = (struct ifreq *)data;
 	struct ifaddr *ifa = (struct ifaddr *)data;
+	struct ieee80211req *ireq = (struct ieee80211req *)data;
 	int s, error;
 	struct ieee80211_nwid nwid;
 	u_int8_t *p;
+	int len;
+	u_int8_t tmpstr[IEEE80211_NWID_LEN*2];
 
 	s = splnet();
 
@@ -566,6 +569,184 @@
 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
 		break;
 #endif
+#ifdef __FreeBSD__
+	case SIOCG80211:
+		switch(ireq->i_type) {
+		case IEEE80211_IOC_SSID:
+			bzero(tmpstr, IEEE80211_NWID_LEN);
+			if(ireq->i_val == -1 && ifp->if_flags & IFF_RUNNING) {
+				if (sc->sc_mib_local.Network_Mode) {
+					p = sc->sc_bss.essid;
+					len = p[1];
+					p += 2;
+				} else {
+					len = ETHER_ADDR_LEN;
+					p = sc->sc_bss.bssid;
+				}
+			} else if(ireq->i_val == 0) {
+				if (sc->sc_mib_local.Network_Mode)
+					p = sc->sc_mib_mac.aDesired_ESS_ID;
+				else
+					p = sc->sc_ownssid;
+				len = p[1];
+				p += 2;
+			} else {
+				error = EINVAL;
+				break;
+			}
+			if(len > IEEE80211_NWID_LEN) {
+				error = EINVAL;
+				break;
+			}
+			bcopy(p, tmpstr, len);
+			error = copyout(tmpstr, ireq->i_data,
+			    IEEE80211_NWID_LEN);
+			break;
+		case IEEE80211_IOC_NUMSSIDS:
+			ireq->i_val = 1;
+			break;
+		case IEEE80211_IOC_WEP:
+			/* XXX: I'm not sure this is entierly correct */
+			ireq->i_val = awi_wep_getalgo(sc);
+			if(ireq->i_val != IEEE80211_WEP_OFF)
+				ireq->i_val = IEEE80211_WEP_ON;
+			break;
+		case IEEE80211_IOC_WEPKEY:
+			if(ireq->i_val < 0 || ireq->i_val > 3) {
+				error = EINVAL;
+				break;
+			}
+			len = sizeof(tmpstr);
+			error = awi_wep_getkey(sc, ireq->i_val, tmpstr, &len);
+			if(error)
+				break;
+			if(!suser(curproc))
+				bzero(tmpstr, len);
+			ireq->i_val = len;
+			error = copyout(tmpstr, ireq->i_data, len);
+			break;
+		case IEEE80211_IOC_NUMWEPKEYS:
+			ireq->i_val = 4;
+			break;
+		case IEEE80211_IOC_WEPTXKEY:
+			ireq->i_val = sc->sc_wep_defkid;
+			break;
+		case IEEE80211_IOC_AUTHMODE:
+			/* XXX: Is this correct? */
+			ireq->i_val = IEEE80211_AUTH_OPEN;
+			break;
+		case IEEE80211_IOC_STATIONNAME:
+			bzero(tmpstr, IEEE80211_NWID_LEN);
+			p = hostname;
+			len = strlen(hostname);
+			if(len > IEEE80211_NWID_LEN) {
+				error = EINVAL;
+				break;
+			}
+			bcopy(p, tmpstr, len);
+			error = copyout(tmpstr, ireq->i_data,
+			    IEEE80211_NWID_LEN);
+			break;
+		case IEEE80211_IOC_CHANNEL:
+			/* XXX: Handle FH cards */
+			ireq->i_val = sc->sc_bss.chanset;
+			break;
+		case IEEE80211_IOC_POWERSAVE:
+			/*
+			 * There appears to be a mib for this in the
+			 * softc, but since there's no way to enable
+			 * powersaving reporting it's value isn't really
+			 * meaningfull.
+			 */
+			ireq->i_val = IEEE80211_POWERSAVE_NOSUP;
+			break;
+		case IEEE80211_IOC_POWERSAVESLEEP:
+			error = EINVAL;
+			break;
+		default:
+			error = EINVAL;
+			break;
+		}
+		break;
+	case SIOCS80211:
+		error = suser(curproc);
+		if(error)
+			break;
+		switch(ireq->i_type) {
+		case IEEE80211_IOC_SSID:
+			if(ireq->i_val != 0) {
+				error = EINVAL;
+				break;
+			}
+			bzero(tmpstr, AWI_ESS_ID_SIZE);
+			tmpstr[0] = IEEE80211_ELEMID_SSID;
+			tmpstr[1] = ireq->i_val;
+			error = copyin(ireq->i_data, tmpstr+2, ireq->i_val);
+			if(error)
+				break;
+			bcopy(tmpstr, sc->sc_mib_mac.aDesired_ESS_ID, 
+				AWI_ESS_ID_SIZE);
+			bcopy(tmpstr, sc->sc_ownssid, AWI_ESS_ID_SIZE);
+			break;
+		case IEEE80211_IOC_WEP:
+			if(ireq->i_val == IEEE80211_WEP_OFF)
+				error = awi_wep_setalgo(sc, 0);
+			else
+				error = awi_wep_setalgo(sc, 1);
+			break;
+		case IEEE80211_IOC_WEPKEY:
+			error = copyin(ireq->i_data, tmpstr, 14);
+			if(error)
+				break;
+			if(ireq->i_val < 0 || ireq->i_val > 3 ||
+			    tmpstr[0] > 13) {
+				error = EINVAL;
+				break;
+			}
+			error = awi_wep_setkey(sc, ireq->i_val, tmpstr+1,
+			    tmpstr[0]);
+			break;
+		case IEEE80211_IOC_WEPTXKEY:
+			if(ireq->i_val < 0 || ireq->i_val > 3) {
+				error = EINVAL;
+				break;
+			}
+			sc->sc_wep_defkid = ireq->i_val;
+			break;
+		case IEEE80211_IOC_AUTHMODE:
+			error = EINVAL;
+			break;
+		case IEEE80211_IOC_STATIONNAME:
+			error = EPERM;
+			break;
+		case IEEE80211_IOC_CHANNEL:
+			if(ireq->i_val < sc->sc_scan_min ||
+			    ireq->i_val > sc->sc_scan_max) {
+				error = EINVAL;
+				break;
+			}
+			sc->sc_ownch = ireq->i_val;
+			break;
+		case IEEE80211_IOC_POWERSAVE:
+			if(ireq->i_val != 0)
+				error = EINVAL;
+			break;
+		case IEEE80211_IOC_POWERSAVESLEEP:
+			error = EINVAL;
+			break;
+		default:
+			error = EINVAL;
+			break;
+		}
+		/* Restart the card so the change takes effect */
+		if(!error) {
+			if(sc->sc_enabled) {
+				awi_stop(sc);
+				error = awi_init(sc);
+			}
+		}
+		break;
+#endif /* __FreeBSD__ */
 	default:
 		error = awi_wicfg(ifp, cmd, data);
 		break;
Index: sys/dev/wi/if_wavelan_ieee.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/wi/if_wavelan_ieee.h,v
retrieving revision 1.5
diff -u -u -r1.5 if_wavelan_ieee.h
--- sys/dev/wi/if_wavelan_ieee.h	2000/02/02 17:59:13	1.5
+++ sys/dev/wi/if_wavelan_ieee.h	2001/01/22 20:05:07
@@ -169,6 +169,7 @@
 	u_int32_t		wi_rx_msg_in_msg_frags;
 	u_int32_t		wi_rx_msg_in_bad_msg_frags;
 };
+#endif
 
 /*
  * These are all the LTV record types that we can read or write
@@ -247,6 +248,7 @@
 #define WI_RID_TX_CRYPT_KEY	0xFCB1
 #define WI_RID_TICK_TIME	0xFCE0
 
+#ifndef _KERNEL
 struct wi_key {
 	u_int16_t		wi_keylen;
 	u_int8_t		wi_keydat[14];
@@ -257,6 +259,7 @@
 	u_int16_t		wi_type;
 	struct wi_key		wi_keys[4];
 };
+#endif
 
 /*
  * NIC information
@@ -315,7 +318,6 @@
 #define WI_RID_CCA_TIME		0xFDC4 /* clear chan assess time */
 #define WI_RID_MAC_PROC_DELAY	0xFDC5 /* MAC processing delay time */
 #define WI_RID_DATA_RATES	0xFDC6 /* supported data rates */
-#endif
 
 
 #endif
Index: sys/dev/wi/if_wi.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/wi/if_wi.c,v
retrieving revision 1.37
diff -u -u -r1.37 if_wi.c
--- sys/dev/wi/if_wi.c	2001/02/06 10:11:17	1.37
+++ sys/dev/wi/if_wi.c	2001/03/02 02:07:42
@@ -91,6 +91,7 @@
 #include <net/if_dl.h>
 #include <net/if_media.h>
 #include <net/if_types.h>
+#include <net/if_ieee80211.h>
 
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
@@ -157,6 +158,10 @@
 static int wi_alloc		__P((device_t));
 static void wi_free		__P((device_t));
 
+static int wi_get_cur_ssid	__P((struct wi_softc *, char *, int *));
+static int wi_media_change	__P((struct ifnet *));
+static void wi_media_status	__P((struct ifnet *, struct ifmediareq *));
+
 static device_method_t wi_pccard_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		pccard_compat_probe),
@@ -242,6 +247,9 @@
 
 	wi_stop(sc);
 
+	/* Delete all remaining media. */
+	ifmedia_removeall(&sc->ifmedia);
+
 	ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
 	bus_teardown_intr(dev, sc->irq, sc->wi_intrhand);
 	wi_free(dev);
@@ -346,7 +354,7 @@
 	    sizeof(WI_DEFAULT_IBSS) - 1);
 
 	sc->wi_portnum = WI_DEFAULT_PORT;
-	sc->wi_ptype = WI_PORTTYPE_ADHOC;
+	sc->wi_ptype = WI_PORTTYPE_BSS;
 	sc->wi_ap_density = WI_DEFAULT_AP_DENSITY;
 	sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH;
 	sc->wi_tx_rate = WI_DEFAULT_TX_RATE;
@@ -385,6 +393,29 @@
 	wi_init(sc);
 	wi_stop(sc);
 
+	ifmedia_init(&sc->ifmedia, 0, wi_media_change, wi_media_status);
+	/* XXX: Should read from card capabilities */
+#define ADD(m, c)       ifmedia_add(&sc->ifmedia, (m), (c), NULL)
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
+	    IFM_IEEE80211_ADHOC, 0), 0);
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0);
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
+	    IFM_IEEE80211_ADHOC, 0), 0);
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0);
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
+	    IFM_IEEE80211_ADHOC, 0), 0);
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0);
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
+	    IFM_IEEE80211_ADHOC, 0), 0);
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0);
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 
+		IFM_IEEE80211_ADHOC, 0), 0);
+	ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0);
+#undef	ADD
+	ifmedia_set(&sc->ifmedia, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
+	    0, 0));
+
+
 	/*
 	 * Call MI attach routine.
 	 */
@@ -1137,14 +1168,19 @@
 	caddr_t			data;
 {
 	int			error = 0;
+	int			len;
+	u_int8_t		tmpkey[14];
+	char			tmpssid[IEEE80211_NWID_LEN];
 	struct wi_softc		*sc;
 	struct wi_req		wreq;
 	struct ifreq		*ifr;
+	struct ieee80211req	*ireq;
 	struct proc		*p = curproc;
 
 	sc = ifp->if_softc;
 	WI_LOCK(sc);
 	ifr = (struct ifreq *)data;
+	ireq = (struct ieee80211req *)data;
 
 	if (sc->wi_gone) {
 		error = ENODEV;
@@ -1177,6 +1213,10 @@
 		sc->wi_if_flags = ifp->if_flags;
 		error = 0;
 		break;
+	case SIOCSIFMEDIA:
+	case SIOCGIFMEDIA:
+		error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
+		break;
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
 		wi_setmulti(sc);
@@ -1238,6 +1278,204 @@
 				wi_setdef(sc, &wreq);
 		}
 		break;
+	case SIOCG80211:
+		switch(ireq->i_type) {
+		case IEEE80211_IOC_SSID:
+			if(ireq->i_val == -1) {
+				bzero(tmpssid, IEEE80211_NWID_LEN);
+				error = wi_get_cur_ssid(sc, tmpssid, &len);
+				printf("wi: '%s' %d\n", tmpssid, len);
+				if (error != 0)
+					break;
+				error = copyout(tmpssid, ireq->i_data,
+					IEEE80211_NWID_LEN);
+				ireq->i_len = len;
+			} else if (ireq->i_val == 0) {
+				error = copyout(sc->wi_net_name,
+				    ireq->i_data,
+				    IEEE80211_NWID_LEN);
+				ireq->i_len = IEEE80211_NWID_LEN;
+			} else
+				error = EINVAL;
+			break;
+		case IEEE80211_IOC_NUMSSIDS:
+			ireq->i_val = 1;
+			break;
+		case IEEE80211_IOC_WEP:
+			if(!sc->wi_has_wep) {
+				ireq->i_val = IEEE80211_WEP_NOSUP; 
+			} else {
+				if(sc->wi_use_wep) {
+					ireq->i_val =
+					    IEEE80211_WEP_MIXED;
+				} else {
+					ireq->i_val =
+					    IEEE80211_WEP_OFF;
+				}
+			}
+			break;
+		case IEEE80211_IOC_WEPKEY:
+			if(!sc->wi_has_wep ||
+			    ireq->i_val < 0 || ireq->i_val > 3) {
+				error = EINVAL;
+				break;
+			}
+			len = sc->wi_keys.wi_keys[ireq->i_val].wi_keylen;
+			if (suser(p))
+				bcopy(sc->wi_keys.wi_keys[ireq->i_val].wi_keydat,
+				    tmpkey, len);
+			else
+				bzero(tmpkey, len);
+
+			ireq->i_len = len;
+			error = copyout(tmpkey, ireq->i_data, len);
+
+			break;
+		case IEEE80211_IOC_NUMWEPKEYS:
+			if(!sc->wi_has_wep)
+				error = EINVAL;
+			else
+				ireq->i_val = 4;
+			break;
+		case IEEE80211_IOC_WEPTXKEY:
+			if(!sc->wi_has_wep)
+				error = EINVAL;
+			else
+				ireq->i_val = sc->wi_tx_key;
+			break;
+		case IEEE80211_IOC_AUTHMODE:
+			ireq->i_val = IEEE80211_AUTH_NONE;
+			break;
+		case IEEE80211_IOC_STATIONNAME:
+			error = copyout(sc->wi_node_name,
+			    ireq->i_data, IEEE80211_NWID_LEN);
+			ireq->i_len = IEEE80211_NWID_LEN;
+			break;
+		case IEEE80211_IOC_CHANNEL:
+			wreq.wi_type = WI_RID_CURRENT_CHAN;
+			wreq.wi_len = WI_MAX_DATALEN;
+			if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq))
+				error = EINVAL;
+			else {
+				ireq->i_val = wreq.wi_val[0];
+			}
+			break;
+		case IEEE80211_IOC_POWERSAVE:
+			if(sc->wi_pm_enabled)
+				ireq->i_val = IEEE80211_POWERSAVE_ON;
+			else
+				ireq->i_val = IEEE80211_POWERSAVE_OFF;
+			break;
+		case IEEE80211_IOC_POWERSAVESLEEP:
+			ireq->i_val = sc->wi_max_sleep;
+			break;
+		default:
+			error = EINVAL;
+		}
+		break;
+	case SIOCS80211:
+		if ((error = suser(p)))
+			goto out;
+		switch(ireq->i_type) {
+		case IEEE80211_IOC_SSID:
+			if (ireq->i_val != 0 ||
+			    ireq->i_len > IEEE80211_NWID_LEN) {
+				error = EINVAL;
+				break;
+			}
+			/* We set both of them */
+			bzero(sc->wi_net_name, IEEE80211_NWID_LEN);
+			error = copyin(ireq->i_data,
+			    sc->wi_net_name, ireq->i_len);
+			bcopy(sc->wi_net_name, sc->wi_ibss_name, IEEE80211_NWID_LEN);
+			break;
+		case IEEE80211_IOC_WEP:
+			/*
+			 * These cards only support one mode so
+			 * we just turn wep on what ever is
+			 * passed in if it's not OFF.
+			 */
+			if (ireq->i_val == IEEE80211_WEP_OFF) {
+				sc->wi_use_wep = 0;
+			} else {
+				sc->wi_use_wep = 1;
+			}
+			break;
+		case IEEE80211_IOC_WEPKEY:
+			if (ireq->i_val < 0 || ireq->i_val > 3 ||
+				ireq->i_len > 13) {
+				error = EINVAL;
+				break;
+			} 
+			bzero(sc->wi_keys.wi_keys[ireq->i_val].wi_keydat, 13);
+			error = copyin(ireq->i_data, 
+			    sc->wi_keys.wi_keys[ireq->i_val].wi_keydat,
+			    ireq->i_len);
+			if(error)
+				break;
+			sc->wi_keys.wi_keys[ireq->i_val].wi_keylen =
+				    ireq->i_len;
+			break;
+		case IEEE80211_IOC_WEPTXKEY:
+			if (ireq->i_val < 0 || ireq->i_val > 3) {
+				error = EINVAL;
+				break;
+			}
+			sc->wi_tx_key = ireq->i_val;
+			break;
+		case IEEE80211_IOC_AUTHMODE:
+			error = EINVAL;
+			break;
+		case IEEE80211_IOC_STATIONNAME:
+			if (ireq->i_len > 32) {
+				error = EINVAL;
+				break;
+			}
+			bzero(sc->wi_node_name, 32);
+			error = copyin(ireq->i_data,
+			    sc->wi_node_name, ireq->i_len);
+			break;
+		case IEEE80211_IOC_CHANNEL:
+			/*
+			 * The actual range is 1-14, but if you
+			 * set it to 0 you get the default. So
+			 * we let that work too.
+			 */
+			if (ireq->i_val < 0 || ireq->i_val > 14) {
+				error = EINVAL;
+				break;
+			}
+			sc->wi_channel = ireq->i_val;
+			break;
+		case IEEE80211_IOC_POWERSAVE:
+			switch (ireq->i_val) {
+			case IEEE80211_POWERSAVE_OFF:
+				sc->wi_pm_enabled = 0;
+				break;
+			case IEEE80211_POWERSAVE_ON:
+				sc->wi_pm_enabled = 1;
+				break;
+			default:
+				error = EINVAL;
+				break;
+			}
+			break;
+		case IEEE80211_IOC_POWERSAVESLEEP:
+			if (ireq->i_val < 0) {
+				error = EINVAL;
+				break;
+			}
+			sc->wi_max_sleep = ireq->i_val;
+			break;
+		default:
+			error = EINVAL;
+			break;
+		}
+
+		/* Reinitialize WaveLAN. */
+		wi_init(sc);
+
+		break;
 	default:
 		error = EINVAL;
 		break;
@@ -1796,3 +2034,142 @@
 	return;
 }
 #endif
+
+static int wi_get_cur_ssid(sc, ssid, len)
+	struct wi_softc		*sc;
+	char			*ssid;
+	int			*len;
+{
+	int			error = 0;
+	struct wi_req		wreq;
+
+	wreq.wi_len = WI_MAX_DATALEN;
+	switch (sc->wi_ptype) {
+	case WI_PORTTYPE_ADHOC:
+		wreq.wi_type = WI_RID_CURRENT_SSID;
+		error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq);
+		if (error != 0)
+			break;
+		if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
+			error = EINVAL;
+			break;
+		}
+		*len = wreq.wi_val[0];
+		bcopy(&wreq.wi_val[1], ssid, IEEE80211_NWID_LEN);
+		break;
+	case WI_PORTTYPE_BSS:
+		wreq.wi_type = WI_RID_COMMQUAL;
+		error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq);
+		if (error != 0)
+			break;
+		if (wreq.wi_val[0] != 0) /* associated */ {
+			wreq.wi_type = WI_RID_CURRENT_SSID;
+			wreq.wi_len = WI_MAX_DATALEN;
+			error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq);
+			if (error != 0)
+				break;
+			if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
+				error = EINVAL;
+				break;
+			}
+			*len = wreq.wi_val[0];
+			bcopy(&wreq.wi_val[1], ssid, IEEE80211_NWID_LEN);
+		} else {
+			*len = IEEE80211_NWID_LEN;
+			bcopy(sc->wi_net_name, ssid, IEEE80211_NWID_LEN);
+		}
+		break;
+	default:
+		error = EINVAL;
+		break;
+	}
+
+	return error;
+}
+
+static int wi_media_change(ifp)
+	struct ifnet		*ifp;
+{
+	struct wi_softc		*sc = ifp->if_softc;
+	int			otype = sc->wi_ptype;
+	int			orate = sc->wi_tx_rate;
+
+	if ((sc->ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0)
+		sc->wi_ptype = WI_PORTTYPE_ADHOC;
+	else
+		sc->wi_ptype = WI_PORTTYPE_BSS;
+
+	switch (IFM_SUBTYPE(sc->ifmedia.ifm_cur->ifm_media)) {
+	case IFM_IEEE80211_DS1:
+		sc->wi_tx_rate = 1;
+		break;
+	case IFM_IEEE80211_DS2:
+		sc->wi_tx_rate = 2;
+		break;
+	case IFM_IEEE80211_DS5:
+		sc->wi_tx_rate = 5;
+		break;
+	case IFM_IEEE80211_DS11:
+		sc->wi_tx_rate = 11;
+		break;
+	case IFM_AUTO:
+		sc->wi_tx_rate = 3;
+		break;
+	}
+
+	if (otype != sc->wi_ptype ||
+	    orate != sc->wi_tx_rate)
+		wi_init(sc);
+
+	return(0);
+}
+
+static void wi_media_status(ifp, imr)
+	struct ifnet		*ifp;
+	struct ifmediareq	*imr;
+{
+	struct wi_req		wreq;
+	struct wi_softc		*sc = ifp->if_softc;
+
+	if (sc->wi_tx_rate == 3) {
+		imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
+		if (sc->wi_ptype == WI_PORTTYPE_ADHOC)
+			imr->ifm_active |= IFM_IEEE80211_ADHOC;
+		wreq.wi_type = WI_RID_CUR_TX_RATE;
+		wreq.wi_len = WI_MAX_DATALEN;
+		if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0) {
+			switch(wreq.wi_val[0]) {
+			case 1:
+				imr->ifm_active |= IFM_IEEE80211_DS1;
+				break;
+			case 2:
+				imr->ifm_active |= IFM_IEEE80211_DS2;
+				break;
+			case 6:
+				imr->ifm_active |= IFM_IEEE80211_DS5;
+				break;
+			case 11:
+				imr->ifm_active |= IFM_IEEE80211_DS11;
+				break;
+				}
+		}
+	} else {
+		imr->ifm_active = sc->ifmedia.ifm_cur->ifm_media;
+	}
+
+	imr->ifm_status = IFM_AVALID;
+	if (sc->wi_ptype == WI_PORTTYPE_ADHOC)
+		/*
+		 * XXX: It would be nice if we could give some actually
+		 * useful status like whether we joined another IBSS or
+		 * created one ourselves.
+		 */
+		imr->ifm_status |= IFM_ACTIVE;
+	else {
+		wreq.wi_type = WI_RID_COMMQUAL;
+		wreq.wi_len = WI_MAX_DATALEN;
+		if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 &&
+		    wreq.wi_val[0] != 0)
+			imr->ifm_status |= IFM_ACTIVE;
+	}
+}
Index: sys/net/if_ieee80211.h
===================================================================
RCS file: /home/ncvs/src/sys/net/if_ieee80211.h,v
retrieving revision 1.3
diff -u -u -r1.3 if_ieee80211.h
--- sys/net/if_ieee80211.h	2000/10/30 06:03:57	1.3
+++ sys/net/if_ieee80211.h	2001/02/06 00:59:28
@@ -168,4 +168,43 @@
 #define	SIOCS80211NWKEY		 _IOW('i', 232, struct ieee80211_nwkey)
 #define	SIOCG80211NWKEY		_IOWR('i', 233, struct ieee80211_nwkey)
 
+#define IEEE80211_WEP_NOSUP	-1
+#define IEEE80211_WEP_OFF	0
+#define IEEE80211_WEP_ON	1
+#define IEEE80211_WEP_MIXED	2
+
+#define IEEE80211_AUTH_NONE	0
+#define IEEE80211_AUTH_OPEN	1
+#define IEEE80211_AUTH_SHARED	2
+
+#define IEEE80211_POWERSAVE_NOSUP	-1
+#define IEEE80211_POWERSAVE_OFF		0
+#define IEEE80211_POWERSAVE_CAM		1
+#define IEEE80211_POWERSAVE_PSP		2
+#define IEEE80211_POWERSAVE_PSP_CAM	3
+#define IEEE80211_POWERSAVE_ON		IEEE80211_POWERSAVE_CAM
+
+/* the first member must be matched with struct ifreq */
+struct ieee80211req {
+	char		i_name[IFNAMSIZ];	/* if_name, e.g. "wi0" */
+	u_int16_t	i_type;			/* req type */
+	int16_t		i_val;			/* Index or simple value */
+	int16_t		i_len;			/* Index or simple value */
+	void		*i_data;		/* Extra data */
+};
+#define	SIOCS80211		 _IOW('i', 234, struct ieee80211req)
+#define	SIOCG80211		_IOWR('i', 235, struct ieee80211req)
+
+#define IEEE80211_IOC_SSID		1
+#define IEEE80211_IOC_NUMSSIDS		2
+#define IEEE80211_IOC_WEP		3
+#define IEEE80211_IOC_WEPKEY		4
+#define IEEE80211_IOC_NUMWEPKEYS	5
+#define IEEE80211_IOC_WEPTXKEY		6
+#define IEEE80211_IOC_AUTHMODE		7
+#define IEEE80211_IOC_STATIONNAME	8
+#define IEEE80211_IOC_CHANNEL		9
+#define IEEE80211_IOC_POWERSAVE		10
+#define IEEE80211_IOC_POWERSAVESLEEP	11
+
 #endif /* !_NET_IF_IEEE80211_H_ */
Index: sys/net/if_media.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_media.c,v
retrieving revision 1.14
diff -u -u -r1.14 if_media.c
--- sys/net/if_media.c	2001/02/26 09:52:43	1.14
+++ sys/net/if_media.c	2001/02/26 23:46:53
@@ -401,6 +401,12 @@
 struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
     IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
 
+struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
+    IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
+
+struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
+    IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
+
 struct ifmedia_description ifm_subtype_shared_descriptions[] =
     IFM_SUBTYPE_SHARED_DESCRIPTIONS;
 
@@ -425,6 +431,10 @@
 	{
 	  &ifm_subtype_fddi_descriptions[0],
 	  &ifm_subtype_fddi_option_descriptions[0]
+	},
+	{
+	  &ifm_subtype_ieee80211_descriptions[0],
+	  &ifm_subtype_ieee80211_option_descriptions[0]
 	},
 };
 
Index: sys/net/if_media.h
===================================================================
RCS file: /home/ncvs/src/sys/net/if_media.h,v
retrieving revision 1.11
diff -u -u -r1.11 if_media.h
--- sys/net/if_media.h	2000/05/26 02:05:31	1.11
+++ sys/net/if_media.h	2001/02/28 23:17:12
@@ -167,6 +167,18 @@
 #define IFM_FDDI_DA	0x00000100	/* Dual attach / single attach */
 
 /*
+ * IEEE 802.11 Wireless
+ */
+#define IFM_IEEE80211		0x00000080
+#define IFM_IEEE80211_FH1	3	/* Frequency Hopping 1Mbps */
+#define IFM_IEEE80211_FH2	4	/* Frequency Hopping 2Mbps */
+#define IFM_IEEE80211_DS1	5	/* Direct Sequence 1Mbps */
+#define IFM_IEEE80211_DS2	6	/* Direct Sequence 2Mbps */
+#define IFM_IEEE80211_DS5	7	/* Direct Sequence 5.5Mbps */
+#define IFM_IEEE80211_DS11	8	/* Direct Sequence 11Mbps */
+#define IFM_IEEE80211_ADHOC	0x00000100	/* Operate in Adhoc mode */
+
+/*
  * Shared media sub-types
  */
 #define	IFM_AUTO	0		/* Autoselect best media */
@@ -229,9 +241,10 @@
 };
 
 #define	IFM_TYPE_DESCRIPTIONS {						\
-	{ IFM_ETHER,	"Ethernet" },					\
-	{ IFM_TOKEN,	"Token ring" },					\
-	{ IFM_FDDI,	"FDDI" },					\
+	{ IFM_ETHER,		"Ethernet" },				\
+	{ IFM_TOKEN,		"Token ring" },				\
+	{ IFM_FDDI,		"FDDI" },				\
+	{ IFM_IEEE80211,	"IEEE 802.11 Wireless Ethernet" },	\
 	{ 0, NULL },							\
 }
 
@@ -327,6 +340,37 @@
 
 #define	IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS {				\
 	{ IFM_FDDI_DA, "Dual-attach" },					\
+	{ 0, NULL },							\
+}
+
+#define	IFM_SUBTYPE_IEEE80211_DESCRIPTIONS {				\
+	{ IFM_IEEE80211_FH1, "FH/1Mbps" },				\
+	{ IFM_IEEE80211_FH2, "FH/2Mbps" },				\
+	{ IFM_IEEE80211_DS1, "DS/1Mbps" },				\
+	{ IFM_IEEE80211_DS2, "DS/2Mbps" },				\
+	{ IFM_IEEE80211_DS5, "DS/5.5Mbps" },				\
+	{ IFM_IEEE80211_DS11, "DS/11Mbps" },				\
+	{ 0, NULL },							\
+}
+
+#define	IFM_SUBTYPE_IEEE80211_ALIASES {					\
+	{ IFM_IEEE80211_FH1, "FH1" },					\
+	{ IFM_IEEE80211_FH2, "FH2" },					\
+	{ IFM_IEEE80211_FH1, "FrequencyHopping/1Mbps" },		\
+	{ IFM_IEEE80211_FH2, "FrequencyHopping/2Mbps" },		\
+	{ IFM_IEEE80211_DS1, "DS1" },					\
+	{ IFM_IEEE80211_DS2, "DS2" },					\
+	{ IFM_IEEE80211_DS5, "DS5.5" },					\
+	{ IFM_IEEE80211_DS11, "DS11" },					\
+	{ IFM_IEEE80211_DS1, "DirectSequence/1Mbps" },			\
+	{ IFM_IEEE80211_DS2, "DirectSequence/2Mbps" },			\
+	{ IFM_IEEE80211_DS5, "DirectSequence/5.5Mbps" },		\
+	{ IFM_IEEE80211_DS11, "DirectSequence/11Mbps" },		\
+	{ 0, NULL },							\
+}
+
+#define	IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS {			\
+	{ IFM_IEEE80211_ADHOC, "adhoc" },				\
 	{ 0, NULL },							\
 }
 
Index: share/man/man4/Makefile
===================================================================
RCS file: /home/ncvs/src/share/man/man4/Makefile,v
retrieving revision 1.116
diff -u -u -r1.116 Makefile
--- share/man/man4/Makefile	2001/03/03 22:47:19	1.116
+++ share/man/man4/Makefile	2001/03/05 19:18:45
@@ -43,6 +43,7 @@
 	ichsmb.4 \
 	icmp.4 \
 	icmp6.4 \
+	ieee80211.4 \
 	ifmib.4 \
 	iic.4 \
 	iicbb.4 \
--- share/man/man4/ieee80211.4.orig	Fri Feb 23 17:14:04 2001
+++ share/man/man4/ieee80211.4	Wed Feb 28 15:52:00 2001
@@ -0,0 +1,234 @@
+.\" Copyright (c) 2001
+.\"	The Aerospace Corporation.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 23, 2001
+.Dt IEEE80211 4
+.Os FreeBSD 4.3
+.Sh NAME
+.Nm ieee80211
+.Nd standard interface to IEEE 802.11 devices
+.Sh SYNOPSIS
+.Fd #include <net/if_ieee80211.h>
+.Sh DESCRIPTION
+This section describes the interface standard interface to configuration
+and status information on IEEE 802.11 devices.  Most devices support
+options not configurable by this interface.  They must be set by their
+respective, specific control program.  The interface is via one
+of the following
+.Xr ioctl 2
+calls on a socket:
+.Bl -tag -width SIOCG80211
+.It Dv SIOCG80211
+Get configuration or status information.
+.It Dv SIOCS80211
+Set configuration information.
+.El
+These requests are made via a modified
+.Ar ifreq
+structure.  This structure is defined as follows:
+.Bd -literal
+struct ieee80211req {
+	char		i_name[IFNAMSIZ];	/* if_name, e.g. "wi0" */
+	u_int16_t	i_type;			/* req type */
+	int16_t		i_val;			/* Index or simple value */
+	int16_t		i_len;			/* Index or simple value */
+	void		*i_data;		/* Extra data */
+};
+.Ed
+.Pp
+For
+.Dv SIOCG80211
+the following values of
+.Ar i_type
+are valid:
+.Bl -tag -width IEEE80211_IOC_POWERSAVESLEEP
+.It Dv IEEE80211_IOC_SSID
+Returns the requested SSID by copying it into the buffer pointed to by
+.Ar i_data
+and setting
+.Ar i_len
+to the length.  If 
+.Ar i_val
+is >= 0 then the request refers to the configured value for that slot.
+Generally, 0 is the only valid value, but some interfaces support more
+SSIDs.  If
+.Ar i_val
+is -1 then the request refers to the currently active value.
+.It Dv IEEE80211_IOC_NUMSSIDS
+Returns the number of SSIDs this card supports.  In most cases, this is
+1, but some devices such as
+.Xr an 4
+support more.
+.It Dv IEEE80211_IOC_WEP
+Returns the current WEP status in
+.Ar i_val .
+Valid values are
+.Dv IEEE80211_WEP_NOSUP ,
+.Dv IEEE80211_WEP_ON ,
+.Dv IEEE80211_WEP_OFF ,
+and
+.Dv IEEE80211_WEP_MIXED .
+Respectively, these values mean unsupported, mandatory for all devices,
+off, and on, but not required for all devices.
+.It Dv IEEE80211_IOC_WEPKEY
+Returns the requested WEP key via
+.Ar i_data
+and it's length via
+.Ar i_len .
+If the device does not support returning the WEP key or the user is not
+root then the key may be returned as all zeros.  Technically this is a
+valid key, but it's the kind of key an idiot would put on his luggage so
+we use it as a special value.  Generally, only four WEP keys are
+allowed, but some devices support more.  If so, the first four (0-3) are
+the standard keys stored in volatile storage and the others are device
+specific.
+.It Dv IEEE80211_IOC_NUMWEPKEYS
+Returns the number of WEP keys supported by this device, generally 4.
+A device that does not support WEP may either report 0 or simply return
+.Dv EINVAL .
+.It Dv IEEE80211_IOC_WEPTXKEY
+Returns the WEP key used for transmission.
+.It Dv IEEE80211_IOC_AUTHMODE
+Returns the current authentication mode in
+.Ar i_val .
+Valid values are
+.Dv IEEE80211_AUTH_NONE ,
+.Dv IEEE80211_AUTH_OPEN ,
+and
+.Dv IEEE80211_AUTH_SHARED .
+.It Dv IEEE80211_IOC_STATIONNAME
+Returns the station name via
+.Ar i_data
+and its length via
+.Ar i_len .
+While all known devices seem to support this is some way or another,
+they all do it differently and it appears to not have anything to do
+with the actual IEEE 802.11 standard so making up an answer may be
+necessary for future devices.
+.It Dv IEEE80211_IOC_CHANNEL
+Returns the current direct sequence spread spectrum channel in use.
+.It Dv IEEE80211_IOC_POWERSAVE
+Returns the current powersaving mode.  Valid values are
+.Dv IEEE80211_POWERSAVE_NOSUP ,
+.Dv IEEE80211_POWERSAVE_OFF ,
+.Dv IEEE80211_POWERSAVE_ON ,
+.Dv IEEE80211_POWERSAVE_CAM ,
+.Dv IEEE80211_POWERSAVE_PSP ,
+and
+.Dv IEEE80211_POWERSAVE_PSP_CAM .
+Currently,
+.Dv IEEE80211_POWERSAVE_ON
+is defined to be equal to
+.Dv IEEE80211_POWERSAVE_CAM ,
+but this may be incorrect.
+.It Dv IEEE80211_IOC_POWERSAVESLEEP
+Returns the powersave sleep time in msec in
+.Ar i_val .
+.El
+.Pp
+For
+.Dv SIOCS80211
+the following values of
+.Ar i_type
+are valid:
+.Bl -tag -width IEEE80211_IOC_POWERSAVESLEEP
+.It Dv IEEE80211_IOC_SSID
+Set the desired SSID for infrastructure and ad-hoc modes to value given
+by
+.Ar i_data
+and
+.Ar i_len .
+The length should be no longer then 32 characters.
+.It Dv IEEE80211_IOC_WEP
+Set the current WEP mode to the value given in
+.Ar i_val .
+Valid values are the same as those for this value above.  Devices which
+do not support all modes may choose to either return
+.Dv EINVAL
+or choose a reasonable alternate (supported) setting.
+.It Dv IEEE80211_IOC_WEPKEY
+Set the WEP key indicated by
+.Ar i_val
+to the value given by
+.Ar i_data
+and
+.Ar i_len .
+Generally, valid values of
+.Ar i_len
+are 0, 5, and 13 though not all devices with WEP support have support
+for 13-byte keys.
+.It Dv IEEE80211_IOC_WEPTXKEY
+Set the WEP key used for transmission to the value in
+.Ar i_val .
+Not all values which are valid for setting keys may be valid for setting
+transmit keys due to strange device interfaces.
+.It Dv IEEE80211_IOC_AUTHMODE
+Set the current authorization mode to the value given in
+.Ar i_val .
+Valid values are given above.  No all devices support this.
+.It Dv IEEE80211_IOC_STATIONNAME
+Set the station name to the value given by
+.Ar i_data
+and
+.Ar i_len .
+The standard does not appear to deal with this feature so the range of
+valid values may vary from device to device.
+.It Dv IEEE80211_IOC_CHANNEL
+Set the desired ad-hoc channel to the value given by
+.Ar i_val .
+On some devices this has an impact on infrastructure mode as well.
+Valid values are 1-14, but 0 should be allowed and should return the
+device to the default value.  May devices support this directly by
+converting any invalid value to the default value.
+.It Dv IEEE80211_IOC_POWERSAVE
+Set the current powersaving mode to the value given in
+.Ar i_val .
+Valid values are the same as those for this value above.  Devices which
+do not support all modes may choose to either return
+.Dv EINVAL
+or choose a reasonable alternate (supported) setting.  Most devices only
+support CAM mode.
+.It Dv IEEE80211_IOC_POWERSAVESLEEP
+Set the powersave sleep time in msec to the value in
+.Ar i_val .
+.El
+.Sh SEE ALSO
+.Xr ioctl 2 ,
+.Xr an 4 ,
+.Xr ray 4 ,
+.Xr wi 4 ,
+.Xr ancontrol 8 ,
+.Xr ifconfig 8 ,
+.Xr raycontrol 8 ,
+.Xr wicontrol 8 ,
+.Sh HISTORY
+The
+.Nm ieee80211
+manual appeared in
+.Fx 4.3 .

>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010307015009.4624E24D22>