Home | History | Annotate | Line # | Download | only in net80211
ieee80211_ioctl.c revision 1.1.1.3
      1 /*-
      2  * Copyright (c) 2001 Atsushi Onoe
      3  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. The name of the author may not be used to endorse or promote products
     15  *    derived from this software without specific prior written permission.
     16  *
     17  * Alternatively, this software may be distributed under the terms of the
     18  * GNU General Public License ("GPL") version 2 as published by the Free
     19  * Software Foundation.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_ioctl.c,v 1.13 2004/03/30 22:57:57 sam Exp $");
     35 
     36 /*
     37  * IEEE 802.11 ioctl support (FreeBSD-specific)
     38  */
     39 
     40 #include "opt_inet.h"
     41 #include "opt_ipx.h"
     42 
     43 #include <sys/endian.h>
     44 #include <sys/param.h>
     45 #include <sys/kernel.h>
     46 #include <sys/socket.h>
     47 #include <sys/sockio.h>
     48 #include <sys/systm.h>
     49 
     50 #include <net/if.h>
     51 #include <net/if_arp.h>
     52 #include <net/if_media.h>
     53 #include <net/ethernet.h>
     54 
     55 #ifdef INET
     56 #include <netinet/in.h>
     57 #include <netinet/if_ether.h>
     58 #endif
     59 
     60 #ifdef IPX
     61 #include <netipx/ipx.h>
     62 #include <netipx/ipx_if.h>
     63 #endif
     64 
     65 #include <net80211/ieee80211_var.h>
     66 #include <net80211/ieee80211_ioctl.h>
     67 
     68 #include <dev/wi/if_wavelan_ieee.h>
     69 
     70 /*
     71  * XXX
     72  * Wireless LAN specific configuration interface, which is compatible
     73  * with wicontrol(8).
     74  */
     75 
     76 int
     77 ieee80211_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data)
     78 {
     79 	struct ieee80211com *ic = (void *)ifp;
     80 	int i, j, error;
     81 	struct ifreq *ifr = (struct ifreq *)data;
     82 	struct wi_req wreq;
     83 	struct wi_ltv_keys *keys;
     84 	struct wi_apinfo *ap;
     85 	struct ieee80211_node *ni;
     86 	struct ieee80211_rateset *rs;
     87 	struct wi_sigcache wsc;
     88 	struct wi_scan_p2_hdr *p2;
     89 	struct wi_scan_res *res;
     90 
     91 	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
     92 	if (error)
     93 		return error;
     94 	wreq.wi_len = 0;
     95 	switch (wreq.wi_type) {
     96 	case WI_RID_SERIALNO:
     97 		/* nothing appropriate */
     98 		break;
     99 	case WI_RID_NODENAME:
    100 		strcpy((char *)&wreq.wi_val[1], hostname);
    101 		wreq.wi_val[0] = htole16(strlen(hostname));
    102 		wreq.wi_len = (1 + strlen(hostname) + 1) / 2;
    103 		break;
    104 	case WI_RID_CURRENT_SSID:
    105 		if (ic->ic_state != IEEE80211_S_RUN) {
    106 			wreq.wi_val[0] = 0;
    107 			wreq.wi_len = 1;
    108 			break;
    109 		}
    110 		wreq.wi_val[0] = htole16(ic->ic_bss->ni_esslen);
    111 		memcpy(&wreq.wi_val[1], ic->ic_bss->ni_essid,
    112 		    ic->ic_bss->ni_esslen);
    113 		wreq.wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2;
    114 		break;
    115 	case WI_RID_OWN_SSID:
    116 	case WI_RID_DESIRED_SSID:
    117 		wreq.wi_val[0] = htole16(ic->ic_des_esslen);
    118 		memcpy(&wreq.wi_val[1], ic->ic_des_essid, ic->ic_des_esslen);
    119 		wreq.wi_len = (1 + ic->ic_des_esslen + 1) / 2;
    120 		break;
    121 	case WI_RID_CURRENT_BSSID:
    122 		if (ic->ic_state == IEEE80211_S_RUN)
    123 			IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_bss->ni_bssid);
    124 		else
    125 			memset(wreq.wi_val, 0, IEEE80211_ADDR_LEN);
    126 		wreq.wi_len = IEEE80211_ADDR_LEN / 2;
    127 		break;
    128 	case WI_RID_CHANNEL_LIST:
    129 		memset(wreq.wi_val, 0, sizeof(wreq.wi_val));
    130 		/*
    131 		 * Since channel 0 is not available for DS, channel 1
    132 		 * is assigned to LSB on WaveLAN.
    133 		 */
    134 		if (ic->ic_phytype == IEEE80211_T_DS)
    135 			i = 1;
    136 		else
    137 			i = 0;
    138 		for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++)
    139 			if (isset(ic->ic_chan_active, i)) {
    140 				setbit((u_int8_t *)wreq.wi_val, j);
    141 				wreq.wi_len = j / 16 + 1;
    142 			}
    143 		break;
    144 	case WI_RID_OWN_CHNL:
    145 		wreq.wi_val[0] = htole16(
    146 			ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
    147 		wreq.wi_len = 1;
    148 		break;
    149 	case WI_RID_CURRENT_CHAN:
    150 		wreq.wi_val[0] = htole16(
    151 			ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
    152 		wreq.wi_len = 1;
    153 		break;
    154 	case WI_RID_COMMS_QUALITY:
    155 		wreq.wi_val[0] = 0;				/* quality */
    156 		wreq.wi_val[1] =
    157 			htole16((*ic->ic_node_getrssi)(ic, ic->ic_bss));
    158 		wreq.wi_val[2] = 0;				/* noise */
    159 		wreq.wi_len = 3;
    160 		break;
    161 	case WI_RID_PROMISC:
    162 		wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
    163 		wreq.wi_len = 1;
    164 		break;
    165 	case WI_RID_PORTTYPE:
    166 		wreq.wi_val[0] = htole16(ic->ic_opmode);
    167 		wreq.wi_len = 1;
    168 		break;
    169 	case WI_RID_MAC_NODE:
    170 		IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr);
    171 		wreq.wi_len = IEEE80211_ADDR_LEN / 2;
    172 		break;
    173 	case WI_RID_TX_RATE:
    174 		if (ic->ic_fixed_rate == -1)
    175 			wreq.wi_val[0] = 0;	/* auto */
    176 		else
    177 			wreq.wi_val[0] = htole16(
    178 			    (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] &
    179 			    IEEE80211_RATE_VAL) / 2);
    180 		wreq.wi_len = 1;
    181 		break;
    182 	case WI_RID_CUR_TX_RATE:
    183 		wreq.wi_val[0] = htole16(
    184 		    (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
    185 		    IEEE80211_RATE_VAL) / 2);
    186 		wreq.wi_len = 1;
    187 		break;
    188 	case WI_RID_RTS_THRESH:
    189 		wreq.wi_val[0] = htole16(ic->ic_rtsthreshold);
    190 		wreq.wi_len = 1;
    191 		break;
    192 	case WI_RID_CREATE_IBSS:
    193 		wreq.wi_val[0] =
    194 		    htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
    195 		wreq.wi_len = 1;
    196 		break;
    197 	case WI_RID_MICROWAVE_OVEN:
    198 		wreq.wi_val[0] = 0;	/* no ... not supported */
    199 		wreq.wi_len = 1;
    200 		break;
    201 	case WI_RID_ROAMING_MODE:
    202 		wreq.wi_val[0] = htole16(1);	/* enabled ... not supported */
    203 		wreq.wi_len = 1;
    204 		break;
    205 	case WI_RID_SYSTEM_SCALE:
    206 		wreq.wi_val[0] = htole16(1);	/* low density ... not supp */
    207 		wreq.wi_len = 1;
    208 		break;
    209 	case WI_RID_PM_ENABLED:
    210 		wreq.wi_val[0] =
    211 		    htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
    212 		wreq.wi_len = 1;
    213 		break;
    214 	case WI_RID_MAX_SLEEP:
    215 		wreq.wi_val[0] = htole16(ic->ic_lintval);
    216 		wreq.wi_len = 1;
    217 		break;
    218 	case WI_RID_CUR_BEACON_INT:
    219 		wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval);
    220 		wreq.wi_len = 1;
    221 		break;
    222 	case WI_RID_WEP_AVAIL:
    223 		wreq.wi_val[0] =
    224 		    htole16((ic->ic_caps & IEEE80211_C_WEP) ? 1 : 0);
    225 		wreq.wi_len = 1;
    226 		break;
    227 	case WI_RID_CNFAUTHMODE:
    228 		wreq.wi_val[0] = htole16(1);	/* TODO: open system only */
    229 		wreq.wi_len = 1;
    230 		break;
    231 	case WI_RID_ENCRYPTION:
    232 		wreq.wi_val[0] =
    233 		    htole16((ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0);
    234 		wreq.wi_len = 1;
    235 		break;
    236 	case WI_RID_TX_CRYPT_KEY:
    237 		wreq.wi_val[0] = htole16(ic->ic_wep_txkey);
    238 		wreq.wi_len = 1;
    239 		break;
    240 	case WI_RID_DEFLT_CRYPT_KEYS:
    241 		keys = (struct wi_ltv_keys *)&wreq;
    242 		/* do not show keys to non-root user */
    243 		error = suser(curthread);
    244 		if (error) {
    245 			memset(keys, 0, sizeof(*keys));
    246 			error = 0;
    247 			break;
    248 		}
    249 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
    250 			keys->wi_keys[i].wi_keylen =
    251 			    htole16(ic->ic_nw_keys[i].wk_len);
    252 			memcpy(keys->wi_keys[i].wi_keydat,
    253 			    ic->ic_nw_keys[i].wk_key, ic->ic_nw_keys[i].wk_len);
    254 		}
    255 		wreq.wi_len = sizeof(*keys) / 2;
    256 		break;
    257 	case WI_RID_MAX_DATALEN:
    258 		wreq.wi_val[0] = htole16(IEEE80211_MAX_LEN);	/* TODO: frag */
    259 		wreq.wi_len = 1;
    260 		break;
    261 	case WI_RID_IFACE_STATS:
    262 		/* XXX: should be implemented in lower drivers */
    263 		break;
    264 	case WI_RID_READ_APS:
    265 		if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
    266 			/*
    267 			 * Don't return results until active scan completes.
    268 			 */
    269 			if (ic->ic_state == IEEE80211_S_SCAN &&
    270 			    (ic->ic_flags & IEEE80211_F_ASCAN)) {
    271 				error = EINPROGRESS;
    272 				break;
    273 			}
    274 		}
    275 		i = 0;
    276 		ap = (void *)((char *)wreq.wi_val + sizeof(i));
    277 		TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
    278 			if ((caddr_t)(ap + 1) > (caddr_t)(&wreq + 1))
    279 				break;
    280 			memset(ap, 0, sizeof(*ap));
    281 			if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
    282 				IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
    283 				ap->namelen = ic->ic_des_esslen;
    284 				if (ic->ic_des_esslen)
    285 					memcpy(ap->name, ic->ic_des_essid,
    286 					    ic->ic_des_esslen);
    287 			} else {
    288 				IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
    289 				ap->namelen = ni->ni_esslen;
    290 				if (ni->ni_esslen)
    291 					memcpy(ap->name, ni->ni_essid,
    292 					    ni->ni_esslen);
    293 			}
    294 			ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
    295 			ap->signal = (*ic->ic_node_getrssi)(ic, ni);
    296 			ap->capinfo = ni->ni_capinfo;
    297 			ap->interval = ni->ni_intval;
    298 			rs = &ni->ni_rates;
    299 			for (j = 0; j < rs->rs_nrates; j++) {
    300 				if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
    301 					ap->rate = (rs->rs_rates[j] &
    302 					    IEEE80211_RATE_VAL) * 5; /* XXX */
    303 				}
    304 			}
    305 			i++;
    306 			ap++;
    307 		}
    308 		memcpy(wreq.wi_val, &i, sizeof(i));
    309 		wreq.wi_len = (sizeof(int) + sizeof(*ap) * i) / 2;
    310 		break;
    311 	case WI_RID_PRISM2:
    312 		wreq.wi_val[0] = 1;	/* XXX lie so SCAN_RES can give rates */
    313 		wreq.wi_len = sizeof(u_int16_t) / 2;
    314 		break;
    315 	case WI_RID_SCAN_RES:			/* compatibility interface */
    316 		if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
    317 		    ic->ic_state == IEEE80211_S_SCAN &&
    318 		    (ic->ic_flags & IEEE80211_F_ASCAN)) {
    319 			error = EINPROGRESS;
    320 			break;
    321 		}
    322 		/* NB: we use the Prism2 format so we can return rate info */
    323 		p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
    324 		res = (void *)&p2[1];
    325 		i = 0;
    326 		TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
    327 			if ((caddr_t)(res + 1) > (caddr_t)(&wreq + 1))
    328 				break;
    329 			res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
    330 			res->wi_noise = 0;
    331 			res->wi_signal = (*ic->ic_node_getrssi)(ic, ni);
    332 			IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
    333 			res->wi_interval = ni->ni_intval;
    334 			res->wi_capinfo = ni->ni_capinfo;
    335 			res->wi_ssid_len = ni->ni_esslen;
    336 			memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
    337 			/* NB: assumes wi_srates holds <= ni->ni_rates */
    338 			memcpy(res->wi_srates, ni->ni_rates.rs_rates,
    339 				sizeof(res->wi_srates));
    340 			if (ni->ni_rates.rs_nrates < 10)
    341 				res->wi_srates[ni->ni_rates.rs_nrates] = 0;
    342 			res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
    343 			res->wi_rsvd = 0;
    344 			res++, i++;
    345 		}
    346 		p2->wi_rsvd = 0;
    347 		p2->wi_reason = i;
    348 		wreq.wi_len = (sizeof(*p2) + sizeof(*res) * i) / 2;
    349 		break;
    350 	case WI_RID_READ_CACHE:
    351 		i = 0;
    352 		TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
    353 			if (i == (WI_MAX_DATALEN/sizeof(struct wi_sigcache))-1)
    354 				break;
    355 			IEEE80211_ADDR_COPY(wsc.macsrc, ni->ni_macaddr);
    356 			memset(&wsc.ipsrc, 0, sizeof(wsc.ipsrc));
    357 			wsc.signal = (*ic->ic_node_getrssi)(ic, ni);
    358 			wsc.noise = 0;
    359 			wsc.quality = 0;
    360 			memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
    361 			    &wsc, sizeof(wsc));
    362 			i++;
    363 		}
    364 		wreq.wi_len = sizeof(wsc) * i / 2;
    365 		break;
    366 	case WI_RID_SCAN_APS:
    367 		error = EINVAL;
    368 		break;
    369 	default:
    370 		error = EINVAL;
    371 		break;
    372 	}
    373 	if (error == 0) {
    374 		wreq.wi_len++;
    375 		error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
    376 	}
    377 	return error;
    378 }
    379 
    380 static int
    381 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
    382 {
    383 #define	IEEERATE(_ic,_m,_i) \
    384 	((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
    385 	int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
    386 	for (i = 0; i < nrates; i++)
    387 		if (IEEERATE(ic, mode, i) == rate)
    388 			return i;
    389 	return -1;
    390 #undef IEEERATE
    391 }
    392 
    393 /*
    394  * Prepare to do a user-initiated scan for AP's.  If no
    395  * current/default channel is setup or the current channel
    396  * is invalid then pick the first available channel from
    397  * the active list as the place to start the scan.
    398  */
    399 static int
    400 ieee80211_setupscan(struct ieee80211com *ic)
    401 {
    402 	u_char *chanlist = ic->ic_chan_active;
    403 	int i;
    404 
    405 	if (ic->ic_ibss_chan == NULL ||
    406 	    isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
    407 		for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
    408 			if (isset(chanlist, i)) {
    409 				ic->ic_ibss_chan = &ic->ic_channels[i];
    410 				goto found;
    411 			}
    412 		return EINVAL;			/* no active channels */
    413 found:
    414 		;
    415 	}
    416 	if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC ||
    417 	    isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan)))
    418 		ic->ic_bss->ni_chan = ic->ic_ibss_chan;
    419 	/*
    420 	 * XXX don't permit a scan to be started unless we
    421 	 * know the device is ready.  For the moment this means
    422 	 * the device is marked up as this is the required to
    423 	 * initialize the hardware.  It would be better to permit
    424 	 * scanning prior to being up but that'll require some
    425 	 * changes to the infrastructure.
    426 	 */
    427 	return (ic->ic_if.if_flags & IFF_UP) ? 0 : ENETRESET;
    428 }
    429 
    430 int
    431 ieee80211_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data)
    432 {
    433 	struct ieee80211com *ic = (void *)ifp;
    434 	int i, j, len, error, rate;
    435 	struct ifreq *ifr = (struct ifreq *)data;
    436 	struct wi_ltv_keys *keys;
    437 	struct wi_req wreq;
    438 	u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)];
    439 
    440 	error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
    441 	if (error)
    442 		return error;
    443 	len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0;
    444 	switch (wreq.wi_type) {
    445 	case WI_RID_SERIALNO:
    446 	case WI_RID_NODENAME:
    447 		return EPERM;
    448 	case WI_RID_CURRENT_SSID:
    449 		return EPERM;
    450 	case WI_RID_OWN_SSID:
    451 	case WI_RID_DESIRED_SSID:
    452 		if (le16toh(wreq.wi_val[0]) * 2 > len ||
    453 		    le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) {
    454 			error = ENOSPC;
    455 			break;
    456 		}
    457 		memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid));
    458 		ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
    459 		memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
    460 		error = ENETRESET;
    461 		break;
    462 	case WI_RID_CURRENT_BSSID:
    463 		return EPERM;
    464 	case WI_RID_OWN_CHNL:
    465 		if (len != 2)
    466 			return EINVAL;
    467 		i = le16toh(wreq.wi_val[0]);
    468 		if (i < 0 ||
    469 		    i > IEEE80211_CHAN_MAX ||
    470 		    isclr(ic->ic_chan_active, i))
    471 			return EINVAL;
    472 		ic->ic_ibss_chan = &ic->ic_channels[i];
    473 		if (ic->ic_flags & IEEE80211_F_SIBSS)
    474 			error = ENETRESET;
    475 		break;
    476 	case WI_RID_CURRENT_CHAN:
    477 		return EPERM;
    478 	case WI_RID_COMMS_QUALITY:
    479 		return EPERM;
    480 	case WI_RID_PROMISC:
    481 		if (len != 2)
    482 			return EINVAL;
    483 		if (ifp->if_flags & IFF_PROMISC) {
    484 			if (wreq.wi_val[0] == 0) {
    485 				ifp->if_flags &= ~IFF_PROMISC;
    486 				error = ENETRESET;
    487 			}
    488 		} else {
    489 			if (wreq.wi_val[0] != 0) {
    490 				ifp->if_flags |= IFF_PROMISC;
    491 				error = ENETRESET;
    492 			}
    493 		}
    494 		break;
    495 	case WI_RID_PORTTYPE:
    496 		if (len != 2)
    497 			return EINVAL;
    498 		switch (le16toh(wreq.wi_val[0])) {
    499 		case IEEE80211_M_STA:
    500 			break;
    501 		case IEEE80211_M_IBSS:
    502 			if (!(ic->ic_caps & IEEE80211_C_IBSS))
    503 				return EINVAL;
    504 			break;
    505 		case IEEE80211_M_AHDEMO:
    506 			if (ic->ic_phytype != IEEE80211_T_DS ||
    507 			    !(ic->ic_caps & IEEE80211_C_AHDEMO))
    508 				return EINVAL;
    509 			break;
    510 		case IEEE80211_M_HOSTAP:
    511 			if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
    512 				return EINVAL;
    513 			break;
    514 		default:
    515 			return EINVAL;
    516 		}
    517 		if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) {
    518 			ic->ic_opmode = le16toh(wreq.wi_val[0]);
    519 			error = ENETRESET;
    520 		}
    521 		break;
    522 #if 0
    523 	case WI_RID_MAC_NODE:
    524 		if (len != IEEE80211_ADDR_LEN)
    525 			return EINVAL;
    526 		IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val);
    527 		/* if_init will copy lladdr into ic_myaddr */
    528 		error = ENETRESET;
    529 		break;
    530 #endif
    531 	case WI_RID_TX_RATE:
    532 		if (len != 2)
    533 			return EINVAL;
    534 		if (wreq.wi_val[0] == 0) {
    535 			/* auto */
    536 			ic->ic_fixed_rate = -1;
    537 			break;
    538 		}
    539 		rate = 2 * le16toh(wreq.wi_val[0]);
    540 		if (ic->ic_curmode == IEEE80211_MODE_AUTO) {
    541 			/*
    542 			 * In autoselect mode search for the rate.  We take
    543 			 * the first instance which may not be right, but we
    544 			 * are limited by the interface.  Note that we also
    545 			 * lock the mode to insure the rate is meaningful
    546 			 * when it is used.
    547 			 */
    548 			for (j = IEEE80211_MODE_11A;
    549 			     j < IEEE80211_MODE_MAX; j++) {
    550 				if ((ic->ic_modecaps & (1<<j)) == 0)
    551 					continue;
    552 				i = findrate(ic, j, rate);
    553 				if (i != -1) {
    554 					/* lock mode too */
    555 					ic->ic_curmode = j;
    556 					goto setrate;
    557 				}
    558 			}
    559 		} else {
    560 			i = findrate(ic, ic->ic_curmode, rate);
    561 			if (i != -1)
    562 				goto setrate;
    563 		}
    564 		return EINVAL;
    565 	setrate:
    566 		ic->ic_fixed_rate = i;
    567 		error = ENETRESET;
    568 		break;
    569 	case WI_RID_CUR_TX_RATE:
    570 		return EPERM;
    571 	case WI_RID_RTS_THRESH:
    572 		if (len != 2)
    573 			return EINVAL;
    574 		if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN)
    575 			return EINVAL;		/* TODO: RTS */
    576 		break;
    577 	case WI_RID_CREATE_IBSS:
    578 		if (len != 2)
    579 			return EINVAL;
    580 		if (wreq.wi_val[0] != 0) {
    581 			if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
    582 				return EINVAL;
    583 			if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
    584 				ic->ic_flags |= IEEE80211_F_IBSSON;
    585 				if (ic->ic_opmode == IEEE80211_M_IBSS &&
    586 				    ic->ic_state == IEEE80211_S_SCAN)
    587 					error = ENETRESET;
    588 			}
    589 		} else {
    590 			if (ic->ic_flags & IEEE80211_F_IBSSON) {
    591 				ic->ic_flags &= ~IEEE80211_F_IBSSON;
    592 				if (ic->ic_flags & IEEE80211_F_SIBSS) {
    593 					ic->ic_flags &= ~IEEE80211_F_SIBSS;
    594 					error = ENETRESET;
    595 				}
    596 			}
    597 		}
    598 		break;
    599 	case WI_RID_MICROWAVE_OVEN:
    600 		if (len != 2)
    601 			return EINVAL;
    602 		if (wreq.wi_val[0] != 0)
    603 			return EINVAL;		/* not supported */
    604 		break;
    605 	case WI_RID_ROAMING_MODE:
    606 		if (len != 2)
    607 			return EINVAL;
    608 		if (le16toh(wreq.wi_val[0]) != 1)
    609 			return EINVAL;		/* not supported */
    610 		break;
    611 	case WI_RID_SYSTEM_SCALE:
    612 		if (len != 2)
    613 			return EINVAL;
    614 		if (le16toh(wreq.wi_val[0]) != 1)
    615 			return EINVAL;		/* not supported */
    616 		break;
    617 	case WI_RID_PM_ENABLED:
    618 		if (len != 2)
    619 			return EINVAL;
    620 		if (wreq.wi_val[0] != 0) {
    621 			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
    622 				return EINVAL;
    623 			if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
    624 				ic->ic_flags |= IEEE80211_F_PMGTON;
    625 				error = ENETRESET;
    626 			}
    627 		} else {
    628 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
    629 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
    630 				error = ENETRESET;
    631 			}
    632 		}
    633 		break;
    634 	case WI_RID_MAX_SLEEP:
    635 		if (len != 2)
    636 			return EINVAL;
    637 		ic->ic_lintval = le16toh(wreq.wi_val[0]);
    638 		if (ic->ic_flags & IEEE80211_F_PMGTON)
    639 			error = ENETRESET;
    640 		break;
    641 	case WI_RID_CUR_BEACON_INT:
    642 		return EPERM;
    643 	case WI_RID_WEP_AVAIL:
    644 		return EPERM;
    645 	case WI_RID_CNFAUTHMODE:
    646 		if (len != 2)
    647 			return EINVAL;
    648 		if (le16toh(wreq.wi_val[0]) != 1)
    649 			return EINVAL;		/* TODO: shared key auth */
    650 		break;
    651 	case WI_RID_ENCRYPTION:
    652 		if (len != 2)
    653 			return EINVAL;
    654 		if (wreq.wi_val[0] != 0) {
    655 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
    656 				return EINVAL;
    657 			if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) {
    658 				ic->ic_flags |= IEEE80211_F_WEPON;
    659 				error = ENETRESET;
    660 			}
    661 		} else {
    662 			if (ic->ic_flags & IEEE80211_F_WEPON) {
    663 				ic->ic_flags &= ~IEEE80211_F_WEPON;
    664 				error = ENETRESET;
    665 			}
    666 		}
    667 		break;
    668 	case WI_RID_TX_CRYPT_KEY:
    669 		if (len != 2)
    670 			return EINVAL;
    671 		i = le16toh(wreq.wi_val[0]);
    672 		if (i >= IEEE80211_WEP_NKID)
    673 			return EINVAL;
    674 		ic->ic_wep_txkey = i;
    675 		break;
    676 	case WI_RID_DEFLT_CRYPT_KEYS:
    677 		if (len != sizeof(struct wi_ltv_keys))
    678 			return EINVAL;
    679 		keys = (struct wi_ltv_keys *)&wreq;
    680 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
    681 			len = le16toh(keys->wi_keys[i].wi_keylen);
    682 			if (len != 0 && len < IEEE80211_WEP_KEYLEN)
    683 				return EINVAL;
    684 			if (len > sizeof(ic->ic_nw_keys[i].wk_key))
    685 				return EINVAL;
    686 		}
    687 		memset(ic->ic_nw_keys, 0, sizeof(ic->ic_nw_keys));
    688 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
    689 			len = le16toh(keys->wi_keys[i].wi_keylen);
    690 			ic->ic_nw_keys[i].wk_len = len;
    691 			memcpy(ic->ic_nw_keys[i].wk_key,
    692 			    keys->wi_keys[i].wi_keydat, len);
    693 		}
    694 		error = ENETRESET;
    695 		break;
    696 	case WI_RID_MAX_DATALEN:
    697 		if (len != 2)
    698 			return EINVAL;
    699 		len = le16toh(wreq.wi_val[0]);
    700 		if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
    701 			return EINVAL;
    702 		if (len != IEEE80211_MAX_LEN)
    703 			return EINVAL;		/* TODO: fragment */
    704 		ic->ic_fragthreshold = len;
    705 		error = ENETRESET;
    706 		break;
    707 	case WI_RID_IFACE_STATS:
    708 		error = EPERM;
    709 		break;
    710 	case WI_RID_SCAN_REQ:			/* XXX wicontrol */
    711 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
    712 			break;
    713 		error = ieee80211_setupscan(ic);
    714 		if (error == 0)
    715 			error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
    716 		break;
    717 	case WI_RID_SCAN_APS:
    718 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
    719 			break;
    720 		len--;			/* XXX: tx rate? */
    721 		/* FALLTHRU */
    722 	case WI_RID_CHANNEL_LIST:
    723 		memset(chanlist, 0, sizeof(chanlist));
    724 		/*
    725 		 * Since channel 0 is not available for DS, channel 1
    726 		 * is assigned to LSB on WaveLAN.
    727 		 */
    728 		if (ic->ic_phytype == IEEE80211_T_DS)
    729 			i = 1;
    730 		else
    731 			i = 0;
    732 		for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
    733 			if ((j / 8) >= len)
    734 				break;
    735 			if (isclr((u_int8_t *)wreq.wi_val, j))
    736 				continue;
    737 			if (isclr(ic->ic_chan_active, i)) {
    738 				if (wreq.wi_type != WI_RID_CHANNEL_LIST)
    739 					continue;
    740 				if (isclr(ic->ic_chan_avail, i))
    741 					return EPERM;
    742 			}
    743 			setbit(chanlist, i);
    744 		}
    745 		memcpy(ic->ic_chan_active, chanlist,
    746 		    sizeof(ic->ic_chan_active));
    747 		error = ieee80211_setupscan(ic);
    748 		if (wreq.wi_type == WI_RID_CHANNEL_LIST) {
    749 			/* NB: ignore error from ieee80211_setupscan */
    750 			error = ENETRESET;
    751 		} else if (error == 0)
    752 			error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
    753 		break;
    754 	default:
    755 		error = EINVAL;
    756 		break;
    757 	}
    758 	return error;
    759 }
    760 
    761 int
    762 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
    763 {
    764 	struct ieee80211com *ic = (void *)ifp;
    765 	int error = 0;
    766 	u_int kid, len;
    767 	struct ieee80211req *ireq;
    768 	struct ifreq *ifr;
    769 	u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
    770 	char tmpssid[IEEE80211_NWID_LEN];
    771 	struct ieee80211_channel *chan;
    772 	struct ifaddr *ifa;			/* XXX */
    773 
    774 	switch (cmd) {
    775 	case SIOCSIFMEDIA:
    776 	case SIOCGIFMEDIA:
    777 		error = ifmedia_ioctl(ifp, (struct ifreq *) data,
    778 				&ic->ic_media, cmd);
    779 		break;
    780 	case SIOCG80211:
    781 		ireq = (struct ieee80211req *) data;
    782 		switch (ireq->i_type) {
    783 		case IEEE80211_IOC_SSID:
    784 			switch (ic->ic_state) {
    785 			case IEEE80211_S_INIT:
    786 			case IEEE80211_S_SCAN:
    787 				ireq->i_len = ic->ic_des_esslen;
    788 				memcpy(tmpssid, ic->ic_des_essid, ireq->i_len);
    789 				break;
    790 			default:
    791 				ireq->i_len = ic->ic_bss->ni_esslen;
    792 				memcpy(tmpssid, ic->ic_bss->ni_essid,
    793 					ireq->i_len);
    794 				break;
    795 			}
    796 			error = copyout(tmpssid, ireq->i_data, ireq->i_len);
    797 			break;
    798 		case IEEE80211_IOC_NUMSSIDS:
    799 			ireq->i_val = 1;
    800 			break;
    801 		case IEEE80211_IOC_WEP:
    802 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
    803 				ireq->i_val = IEEE80211_WEP_NOSUP;
    804 			} else {
    805 				if (ic->ic_flags & IEEE80211_F_WEPON) {
    806 					ireq->i_val =
    807 					    IEEE80211_WEP_MIXED;
    808 				} else {
    809 					ireq->i_val =
    810 					    IEEE80211_WEP_OFF;
    811 				}
    812 			}
    813 			break;
    814 		case IEEE80211_IOC_WEPKEY:
    815 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
    816 				error = EINVAL;
    817 				break;
    818 			}
    819 			kid = (u_int) ireq->i_val;
    820 			if (kid >= IEEE80211_WEP_NKID) {
    821 				error = EINVAL;
    822 				break;
    823 			}
    824 			len = (u_int) ic->ic_nw_keys[kid].wk_len;
    825 			/* NB: only root can read WEP keys */
    826 			if (suser(curthread) == 0) {
    827 				bcopy(ic->ic_nw_keys[kid].wk_key, tmpkey, len);
    828 			} else {
    829 				bzero(tmpkey, len);
    830 			}
    831 			ireq->i_len = len;
    832 			error = copyout(tmpkey, ireq->i_data, len);
    833 			break;
    834 		case IEEE80211_IOC_NUMWEPKEYS:
    835 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
    836 				error = EINVAL;
    837 			else
    838 				ireq->i_val = IEEE80211_WEP_NKID;
    839 			break;
    840 		case IEEE80211_IOC_WEPTXKEY:
    841 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
    842 				error = EINVAL;
    843 			else
    844 				ireq->i_val = ic->ic_wep_txkey;
    845 			break;
    846 		case IEEE80211_IOC_AUTHMODE:
    847 			ireq->i_val = IEEE80211_AUTH_OPEN;
    848 			break;
    849 		case IEEE80211_IOC_CHANNEL:
    850 			switch (ic->ic_state) {
    851 			case IEEE80211_S_INIT:
    852 			case IEEE80211_S_SCAN:
    853 				if (ic->ic_opmode == IEEE80211_M_STA)
    854 					chan = ic->ic_des_chan;
    855 				else
    856 					chan = ic->ic_ibss_chan;
    857 				break;
    858 			default:
    859 				chan = ic->ic_bss->ni_chan;
    860 				break;
    861 			}
    862 			ireq->i_val = ieee80211_chan2ieee(ic, chan);
    863 			break;
    864 		case IEEE80211_IOC_POWERSAVE:
    865 			if (ic->ic_flags & IEEE80211_F_PMGTON)
    866 				ireq->i_val = IEEE80211_POWERSAVE_ON;
    867 			else
    868 				ireq->i_val = IEEE80211_POWERSAVE_OFF;
    869 			break;
    870 		case IEEE80211_IOC_POWERSAVESLEEP:
    871 			ireq->i_val = ic->ic_lintval;
    872 			break;
    873 		case IEEE80211_IOC_RTSTHRESHOLD:
    874 			ireq->i_val = ic->ic_rtsthreshold;
    875 			break;
    876 		case IEEE80211_IOC_PROTMODE:
    877 			ireq->i_val = ic->ic_protmode;
    878 			break;
    879 		case IEEE80211_IOC_TXPOWER:
    880 			if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
    881 				error = EINVAL;
    882 			else
    883 				ireq->i_val = ic->ic_txpower;
    884 			break;
    885 		default:
    886 			error = EINVAL;
    887 			break;
    888 		}
    889 		break;
    890 	case SIOCS80211:
    891 		error = suser(curthread);
    892 		if (error)
    893 			break;
    894 		ireq = (struct ieee80211req *) data;
    895 		switch (ireq->i_type) {
    896 		case IEEE80211_IOC_SSID:
    897 			if (ireq->i_val != 0 ||
    898 			    ireq->i_len > IEEE80211_NWID_LEN) {
    899 				error = EINVAL;
    900 				break;
    901 			}
    902 			error = copyin(ireq->i_data, tmpssid, ireq->i_len);
    903 			if (error)
    904 				break;
    905 			memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
    906 			ic->ic_des_esslen = ireq->i_len;
    907 			memcpy(ic->ic_des_essid, tmpssid, ireq->i_len);
    908 			error = ENETRESET;
    909 			break;
    910 		case IEEE80211_IOC_WEP:
    911 			/*
    912 			 * These cards only support one mode so
    913 			 * we just turn wep on if what ever is
    914 			 * passed in is not OFF.
    915 			 */
    916 			if (ireq->i_val == IEEE80211_WEP_OFF) {
    917 				ic->ic_flags &= ~IEEE80211_F_WEPON;
    918 			} else {
    919 				ic->ic_flags |= IEEE80211_F_WEPON;
    920 			}
    921 			error = ENETRESET;
    922 			break;
    923 		case IEEE80211_IOC_WEPKEY:
    924 			if ((ic->ic_caps & IEEE80211_C_WEP) == 0) {
    925 				error = EINVAL;
    926 				break;
    927 			}
    928 			kid = (u_int) ireq->i_val;
    929 			if (kid >= IEEE80211_WEP_NKID) {
    930 				error = EINVAL;
    931 				break;
    932 			}
    933 			if (ireq->i_len > sizeof(tmpkey)) {
    934 				error = EINVAL;
    935 				break;
    936 			}
    937 			memset(tmpkey, 0, sizeof(tmpkey));
    938 			error = copyin(ireq->i_data, tmpkey, ireq->i_len);
    939 			if (error)
    940 				break;
    941 			memcpy(ic->ic_nw_keys[kid].wk_key, tmpkey,
    942 				sizeof(tmpkey));
    943 			ic->ic_nw_keys[kid].wk_len = ireq->i_len;
    944 			error = ENETRESET;
    945 			break;
    946 		case IEEE80211_IOC_WEPTXKEY:
    947 			kid = (u_int) ireq->i_val;
    948 			if (kid >= IEEE80211_WEP_NKID) {
    949 				error = EINVAL;
    950 				break;
    951 			}
    952 			ic->ic_wep_txkey = kid;
    953 			error = ENETRESET;
    954 			break;
    955 #if 0
    956 		case IEEE80211_IOC_AUTHMODE:
    957 			sc->wi_authmode = ireq->i_val;
    958 			break;
    959 #endif
    960 		case IEEE80211_IOC_CHANNEL:
    961 			/* XXX 0xffff overflows 16-bit signed */
    962 			if (ireq->i_val == 0 ||
    963 			    ireq->i_val == (int16_t) IEEE80211_CHAN_ANY)
    964 				ic->ic_des_chan = IEEE80211_CHAN_ANYC;
    965 			else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX ||
    966 			    isclr(ic->ic_chan_active, ireq->i_val)) {
    967 				error = EINVAL;
    968 				break;
    969 			} else
    970 				ic->ic_ibss_chan = ic->ic_des_chan =
    971 					&ic->ic_channels[ireq->i_val];
    972 			switch (ic->ic_state) {
    973 			case IEEE80211_S_INIT:
    974 			case IEEE80211_S_SCAN:
    975 				error = ENETRESET;
    976 				break;
    977 			default:
    978 				if (ic->ic_opmode == IEEE80211_M_STA) {
    979 					if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
    980 					    ic->ic_bss->ni_chan != ic->ic_des_chan)
    981 						error = ENETRESET;
    982 				} else {
    983 					if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
    984 						error = ENETRESET;
    985 				}
    986 				break;
    987 			}
    988 			break;
    989 		case IEEE80211_IOC_POWERSAVE:
    990 			switch (ireq->i_val) {
    991 			case IEEE80211_POWERSAVE_OFF:
    992 				if (ic->ic_flags & IEEE80211_F_PMGTON) {
    993 					ic->ic_flags &= ~IEEE80211_F_PMGTON;
    994 					error = ENETRESET;
    995 				}
    996 				break;
    997 			case IEEE80211_POWERSAVE_ON:
    998 				if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
    999 					error = EINVAL;
   1000 				else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
   1001 					ic->ic_flags |= IEEE80211_F_PMGTON;
   1002 					error = ENETRESET;
   1003 				}
   1004 				break;
   1005 			default:
   1006 				error = EINVAL;
   1007 				break;
   1008 			}
   1009 			break;
   1010 		case IEEE80211_IOC_POWERSAVESLEEP:
   1011 			if (ireq->i_val < 0) {
   1012 				error = EINVAL;
   1013 				break;
   1014 			}
   1015 			ic->ic_lintval = ireq->i_val;
   1016 			error = ENETRESET;
   1017 			break;
   1018 		case IEEE80211_IOC_RTSTHRESHOLD:
   1019 			if (!(IEEE80211_RTS_MIN < ireq->i_val &&
   1020 			      ireq->i_val < IEEE80211_RTS_MAX)) {
   1021 				error = EINVAL;
   1022 				break;
   1023 			}
   1024 			ic->ic_rtsthreshold = ireq->i_val;
   1025 			error = ENETRESET;
   1026 			break;
   1027 		case IEEE80211_IOC_PROTMODE:
   1028 			if (ireq->i_val > IEEE80211_PROT_RTSCTS) {
   1029 				error = EINVAL;
   1030 				break;
   1031 			}
   1032 			ic->ic_protmode = ireq->i_val;
   1033 			/* NB: if not operating in 11g this can wait */
   1034 			if (ic->ic_curmode == IEEE80211_MODE_11G)
   1035 				error = ENETRESET;
   1036 			break;
   1037 		case IEEE80211_IOC_TXPOWER:
   1038 			if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) {
   1039 				error = EINVAL;
   1040 				break;
   1041 			}
   1042 			if (!(IEEE80211_TXPOWER_MIN < ireq->i_val &&
   1043 			      ireq->i_val < IEEE80211_TXPOWER_MAX)) {
   1044 				error = EINVAL;
   1045 				break;
   1046 			}
   1047 			ic->ic_txpower = ireq->i_val;
   1048 			error = ENETRESET;
   1049 			break;
   1050 		default:
   1051 			error = EINVAL;
   1052 			break;
   1053 		}
   1054 		break;
   1055 	case SIOCGIFGENERIC:
   1056 		error = ieee80211_cfgget(ifp, cmd, data);
   1057 		break;
   1058 	case SIOCSIFGENERIC:
   1059 		error = suser(curthread);
   1060 		if (error)
   1061 			break;
   1062 		error = ieee80211_cfgset(ifp, cmd, data);
   1063 		break;
   1064 	case SIOCG80211STATS:
   1065 		ifr = (struct ifreq *)data;
   1066 		copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
   1067 		break;
   1068 	case SIOCSIFMTU:
   1069 		ifr = (struct ifreq *)data;
   1070 		if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
   1071 		    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
   1072 			error = EINVAL;
   1073 		else
   1074 			ifp->if_mtu = ifr->ifr_mtu;
   1075 		break;
   1076 	case SIOCSIFADDR:
   1077 		/*
   1078 		 * XXX Handle this directly so we can supress if_init calls.
   1079 		 * XXX This should be done in ether_ioctl but for the moment
   1080 		 * XXX there are too many other parts of the system that
   1081 		 * XXX set IFF_UP and so supress if_init being called when
   1082 		 * XXX it should be.
   1083 		 */
   1084 		ifa = (struct ifaddr *) data;
   1085 		switch (ifa->ifa_addr->sa_family) {
   1086 #ifdef INET
   1087 		case AF_INET:
   1088 			if ((ifp->if_flags & IFF_UP) == 0) {
   1089 				ifp->if_flags |= IFF_UP;
   1090 				ifp->if_init(ifp->if_softc);
   1091 			}
   1092 			arp_ifinit(ifp, ifa);
   1093 			break;
   1094 #endif
   1095 #ifdef IPX
   1096 		/*
   1097 		 * XXX - This code is probably wrong,
   1098 		 *	 but has been copied many times.
   1099 		 */
   1100 		case AF_IPX: {
   1101 			struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
   1102 			struct arpcom *ac = (struct arpcom *)ifp;
   1103 
   1104 			if (ipx_nullhost(*ina))
   1105 				ina->x_host = *(union ipx_host *) ac->ac_enaddr;
   1106 			else
   1107 				bcopy((caddr_t) ina->x_host.c_host,
   1108 				      (caddr_t) ac->ac_enaddr,
   1109 				      sizeof(ac->ac_enaddr));
   1110 			/* fall thru... */
   1111 		}
   1112 #endif
   1113 		default:
   1114 			if ((ifp->if_flags & IFF_UP) == 0) {
   1115 				ifp->if_flags |= IFF_UP;
   1116 				ifp->if_init(ifp->if_softc);
   1117 			}
   1118 			break;
   1119 		}
   1120 		break;
   1121 	default:
   1122 		error = ether_ioctl(ifp, cmd, data);
   1123 		break;
   1124 	}
   1125 	return error;
   1126 }
   1127