xref: /haiku/src/libs/compat/openbsd_wlan/net80211/ieee80211_ioctl.c (revision 97f11716bfaa0f385eb0e28a52bf56a5023b9e99)
1 /*	$OpenBSD: ieee80211_ioctl.c,v 1.81 2022/03/07 08:13:13 stsp Exp $	*/
2 /*	$NetBSD: ieee80211_ioctl.c,v 1.15 2004/05/06 02:58:16 dyoung Exp $	*/
3 
4 /*-
5  * Copyright (c) 2001 Atsushi Onoe
6  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * IEEE 802.11 ioctl support
34  */
35 
36 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/socket.h>
39 #include <sys/sockio.h>
40 #include <sys/systm.h>
41 #include <sys/endian.h>
42 #include <sys/tree.h>
43 #ifdef __HAIKU__
44 #include <sys/ucred.h>
45 #endif
46 
47 #include <net/if.h>
48 #include <net/if_media.h>
49 
50 #include <netinet/in.h>
51 #include <netinet/if_ether.h>
52 
53 #include <net80211/ieee80211_var.h>
54 #include <net80211/ieee80211_crypto.h>
55 #include <net80211/ieee80211_ioctl.h>
56 
57 void	 ieee80211_node2req(struct ieee80211com *,
58 	    const struct ieee80211_node *, struct ieee80211_nodereq *);
59 void	 ieee80211_req2node(struct ieee80211com *,
60 	    const struct ieee80211_nodereq *, struct ieee80211_node *);
61 
62 void
ieee80211_node2req(struct ieee80211com * ic,const struct ieee80211_node * ni,struct ieee80211_nodereq * nr)63 ieee80211_node2req(struct ieee80211com *ic, const struct ieee80211_node *ni,
64     struct ieee80211_nodereq *nr)
65 {
66 	uint8_t rssi;
67 
68 	memset(nr, 0, sizeof(*nr));
69 
70 	strlcpy(nr->nr_ifname, ic->ic_if.if_xname, sizeof(nr->nr_ifname));
71 
72 	/* Node address and name information */
73 	IEEE80211_ADDR_COPY(nr->nr_macaddr, ni->ni_macaddr);
74 	IEEE80211_ADDR_COPY(nr->nr_bssid, ni->ni_bssid);
75 	nr->nr_nwid_len = ni->ni_esslen;
76 	bcopy(ni->ni_essid, nr->nr_nwid, IEEE80211_NWID_LEN);
77 
78 	/* Channel and rates */
79 	nr->nr_channel = ieee80211_chan2ieee(ic, ni->ni_chan);
80 	if (ni->ni_chan != IEEE80211_CHAN_ANYC)
81 		nr->nr_chan_flags = ni->ni_chan->ic_flags;
82 	if (ic->ic_curmode != IEEE80211_MODE_11N)
83 		nr->nr_chan_flags &= ~IEEE80211_CHAN_HT;
84 	nr->nr_nrates = ni->ni_rates.rs_nrates;
85 	bcopy(ni->ni_rates.rs_rates, nr->nr_rates, IEEE80211_RATE_MAXSIZE);
86 
87 	/* Node status information */
88 	rssi = (*ic->ic_node_getrssi)(ic, ni);
89 	if (ic->ic_max_rssi) {
90 		/* Driver reports RSSI relative to ic_max_rssi. */
91 		nr->nr_rssi = rssi;
92 	} else {
93 		/*
94 		 * Driver reports RSSI value in dBm.
95 		 * Convert from unsigned to signed.
96 		 * Some drivers report a negative value, some don't.
97 		 * Reasonable range is -20dBm to -80dBm.
98 		 */
99 		nr->nr_rssi = (rssi < 128) ? -rssi : rssi;
100 	}
101 	nr->nr_max_rssi = ic->ic_max_rssi;
102 	bcopy(ni->ni_tstamp, nr->nr_tstamp, sizeof(nr->nr_tstamp));
103 	nr->nr_intval = ni->ni_intval;
104 	nr->nr_capinfo = ni->ni_capinfo;
105 	nr->nr_erp = ni->ni_erp;
106 	nr->nr_pwrsave = ni->ni_pwrsave;
107 	nr->nr_associd = ni->ni_associd;
108 	nr->nr_txseq = ni->ni_txseq;
109 	nr->nr_rxseq = ni->ni_rxseq;
110 	nr->nr_fails = ni->ni_fails;
111 	nr->nr_assoc_fail = ni->ni_assoc_fail; /* flag values are the same */
112 	nr->nr_inact = ni->ni_inact;
113 	nr->nr_txrate = ni->ni_txrate;
114 	nr->nr_state = ni->ni_state;
115 
116 	/* RSN */
117 	nr->nr_rsnciphers = ni->ni_rsnciphers;
118 	nr->nr_rsnakms = 0;
119 	nr->nr_rsnprotos = 0;
120 	if (ni->ni_supported_rsnprotos & IEEE80211_PROTO_RSN)
121 		nr->nr_rsnprotos |= IEEE80211_WPA_PROTO_WPA2;
122 	if (ni->ni_supported_rsnprotos & IEEE80211_PROTO_WPA)
123 		nr->nr_rsnprotos |= IEEE80211_WPA_PROTO_WPA1;
124 	if (ni->ni_supported_rsnakms & IEEE80211_AKM_8021X)
125 		nr->nr_rsnakms |= IEEE80211_WPA_AKM_8021X;
126 	if (ni->ni_supported_rsnakms & IEEE80211_AKM_PSK)
127 		nr->nr_rsnakms |= IEEE80211_WPA_AKM_PSK;
128 	if (ni->ni_supported_rsnakms & IEEE80211_AKM_SHA256_8021X)
129 		nr->nr_rsnakms |= IEEE80211_WPA_AKM_SHA256_8021X;
130 	if (ni->ni_supported_rsnakms & IEEE80211_AKM_SHA256_PSK)
131 		nr->nr_rsnakms |= IEEE80211_WPA_AKM_SHA256_PSK;
132 #ifdef __FreeBSD_version
133 	if (ni->ni_rsnie != NULL)
134 		memcpy(nr->nr_rsnie, ni->ni_rsnie, 2 + ni->ni_rsnie[1]);
135 	else
136 		nr->nr_rsnie[1] = 0;
137 #endif
138 
139 	/* Node flags */
140 	nr->nr_flags = 0;
141 	if (bcmp(nr->nr_macaddr, nr->nr_bssid, IEEE80211_ADDR_LEN) == 0)
142 		nr->nr_flags |= IEEE80211_NODEREQ_AP;
143 	if (ni == ic->ic_bss)
144 		nr->nr_flags |= IEEE80211_NODEREQ_AP_BSS;
145 
146 	/* HT */
147 	nr->nr_htcaps = ni->ni_htcaps;
148 	memcpy(nr->nr_rxmcs, ni->ni_rxmcs, sizeof(nr->nr_rxmcs));
149 	nr->nr_max_rxrate = ni->ni_max_rxrate;
150 	nr->nr_tx_mcs_set = ni->ni_tx_mcs_set;
151 	if (ni->ni_flags & IEEE80211_NODE_HT)
152 		nr->nr_flags |= IEEE80211_NODEREQ_HT;
153 
154 	/* HT / VHT */
155 	nr->nr_txmcs = ni->ni_txmcs;
156 
157 	/* VHT */
158 	nr->nr_vht_ss = ni->ni_vht_ss;
159 	if (ni->ni_flags & IEEE80211_NODE_VHT)
160 		nr->nr_flags |= IEEE80211_NODEREQ_VHT;
161 }
162 
163 void
ieee80211_req2node(struct ieee80211com * ic,const struct ieee80211_nodereq * nr,struct ieee80211_node * ni)164 ieee80211_req2node(struct ieee80211com *ic, const struct ieee80211_nodereq *nr,
165     struct ieee80211_node *ni)
166 {
167 	/* Node address and name information */
168 	IEEE80211_ADDR_COPY(ni->ni_macaddr, nr->nr_macaddr);
169 	IEEE80211_ADDR_COPY(ni->ni_bssid, nr->nr_bssid);
170 	ni->ni_esslen = nr->nr_nwid_len;
171 	bcopy(nr->nr_nwid, ni->ni_essid, IEEE80211_NWID_LEN);
172 
173 	/* Rates */
174 	ni->ni_rates.rs_nrates = nr->nr_nrates;
175 	bcopy(nr->nr_rates, ni->ni_rates.rs_rates, IEEE80211_RATE_MAXSIZE);
176 
177 	/* Node information */
178 	ni->ni_intval = nr->nr_intval;
179 	ni->ni_capinfo = nr->nr_capinfo;
180 	ni->ni_erp = nr->nr_erp;
181 	ni->ni_pwrsave = nr->nr_pwrsave;
182 	ni->ni_associd = nr->nr_associd;
183 	ni->ni_txseq = nr->nr_txseq;
184 	ni->ni_rxseq = nr->nr_rxseq;
185 	ni->ni_fails = nr->nr_fails;
186 	ni->ni_inact = nr->nr_inact;
187 	ni->ni_txrate = nr->nr_txrate;
188 	ni->ni_state = nr->nr_state;
189 }
190 
191 void
ieee80211_disable_wep(struct ieee80211com * ic)192 ieee80211_disable_wep(struct ieee80211com *ic)
193 {
194 	struct ieee80211_key *k;
195 	int i;
196 
197 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
198 		k = &ic->ic_nw_keys[i];
199 		if (k->k_cipher != IEEE80211_CIPHER_NONE)
200 			(*ic->ic_delete_key)(ic, NULL, k);
201 		explicit_bzero(k, sizeof(*k));
202 	}
203 	ic->ic_flags &= ~IEEE80211_F_WEPON;
204 }
205 
206 void
ieee80211_disable_rsn(struct ieee80211com * ic)207 ieee80211_disable_rsn(struct ieee80211com *ic)
208 {
209 	ic->ic_flags &= ~(IEEE80211_F_PSK | IEEE80211_F_RSNON);
210 	explicit_bzero(ic->ic_psk, sizeof(ic->ic_psk));
211 	ic->ic_rsnprotos = 0;
212 	ic->ic_rsnakms = 0;
213 	ic->ic_rsngroupcipher = 0;
214 	ic->ic_rsnciphers = 0;
215 }
216 
217 /* Keep in sync with ieee80211_node.c:ieee80211_ess_setnwkeys() */
218 static int
ieee80211_ioctl_setnwkeys(struct ieee80211com * ic,const struct ieee80211_nwkey * nwkey)219 ieee80211_ioctl_setnwkeys(struct ieee80211com *ic,
220     const struct ieee80211_nwkey *nwkey)
221 {
222 	struct ieee80211_key *k;
223 	int error, i;
224 
225 	if (!(ic->ic_caps & IEEE80211_C_WEP))
226 		return ENODEV;
227 
228 	if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN) {
229 		if (!(ic->ic_flags & IEEE80211_F_WEPON))
230 			return 0;
231 		ic->ic_flags &= ~IEEE80211_F_WEPON;
232 		return ENETRESET;
233 	}
234 	if (nwkey->i_defkid < 1 || nwkey->i_defkid > IEEE80211_WEP_NKID)
235 		return EINVAL;
236 
237 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
238 		if (nwkey->i_key[i].i_keylen == 0 ||
239 		    nwkey->i_key[i].i_keydat == NULL)
240 			continue;	/* entry not set */
241 		if (nwkey->i_key[i].i_keylen > IEEE80211_KEYBUF_SIZE)
242 			return EINVAL;
243 
244 		/* map wep key to ieee80211_key */
245 		k = &ic->ic_nw_keys[i];
246 		if (k->k_cipher != IEEE80211_CIPHER_NONE)
247 			(*ic->ic_delete_key)(ic, NULL, k);
248 		memset(k, 0, sizeof(*k));
249 		if (nwkey->i_key[i].i_keylen <= 5)
250 			k->k_cipher = IEEE80211_CIPHER_WEP40;
251 		else
252 			k->k_cipher = IEEE80211_CIPHER_WEP104;
253 		k->k_len = ieee80211_cipher_keylen(k->k_cipher);
254 		k->k_flags = IEEE80211_KEY_GROUP | IEEE80211_KEY_TX;
255 		error = copyin(nwkey->i_key[i].i_keydat, k->k_key, k->k_len);
256 		if (error != 0)
257 			return error;
258 		error = (*ic->ic_set_key)(ic, NULL, k);
259 		switch (error) {
260 		case 0:
261 		case EBUSY:
262 			break;
263 		default:
264 			return error;
265 		}
266 	}
267 
268 	ic->ic_def_txkey = nwkey->i_defkid - 1;
269 	ic->ic_flags |= IEEE80211_F_WEPON;
270 	if (ic->ic_flags & IEEE80211_F_RSNON)
271 		ieee80211_disable_rsn(ic);
272 
273 	return ENETRESET;
274 }
275 
276 static int
ieee80211_ioctl_getnwkeys(struct ieee80211com * ic,struct ieee80211_nwkey * nwkey)277 ieee80211_ioctl_getnwkeys(struct ieee80211com *ic,
278     struct ieee80211_nwkey *nwkey)
279 {
280 	int i;
281 
282 	if (ic->ic_flags & IEEE80211_F_WEPON)
283 		nwkey->i_wepon = IEEE80211_NWKEY_WEP;
284 	else
285 		nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
286 
287 	nwkey->i_defkid = ic->ic_wep_txkey + 1;
288 
289 	for (i = 0; i < IEEE80211_WEP_NKID; i++) {
290 		if (nwkey->i_key[i].i_keydat == NULL)
291 			continue;
292 		/* do not show any keys to userland */
293 		return EPERM;
294 	}
295 	return 0;
296 }
297 
298 /* Keep in sync with ieee80211_node.c:ieee80211_ess_setwpaparms() */
299 static int
ieee80211_ioctl_setwpaparms(struct ieee80211com * ic,const struct ieee80211_wpaparams * wpa)300 ieee80211_ioctl_setwpaparms(struct ieee80211com *ic,
301     const struct ieee80211_wpaparams *wpa)
302 {
303 	if (!(ic->ic_caps & IEEE80211_C_RSN))
304 		return ENODEV;
305 
306 	if (!wpa->i_enabled) {
307 		if (!(ic->ic_flags & IEEE80211_F_RSNON))
308 			return 0;
309 		ic->ic_flags &= ~IEEE80211_F_RSNON;
310 		ic->ic_rsnprotos = 0;
311 		ic->ic_rsnakms = 0;
312 		ic->ic_rsngroupcipher = 0;
313 		ic->ic_rsnciphers = 0;
314 		return ENETRESET;
315 	}
316 
317 	ic->ic_rsnprotos = 0;
318 	if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA1)
319 		ic->ic_rsnprotos |= IEEE80211_PROTO_WPA;
320 	if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA2)
321 		ic->ic_rsnprotos |= IEEE80211_PROTO_RSN;
322 	if (ic->ic_rsnprotos == 0)	/* set to default (RSN) */
323 		ic->ic_rsnprotos = IEEE80211_PROTO_RSN;
324 
325 	ic->ic_rsnakms = 0;
326 	if (wpa->i_akms & IEEE80211_WPA_AKM_PSK)
327 		ic->ic_rsnakms |= IEEE80211_AKM_PSK;
328 	if (wpa->i_akms & IEEE80211_WPA_AKM_SHA256_PSK)
329 		ic->ic_rsnakms |= IEEE80211_AKM_SHA256_PSK;
330 	if (wpa->i_akms & IEEE80211_WPA_AKM_8021X)
331 		ic->ic_rsnakms |= IEEE80211_AKM_8021X;
332 	if (wpa->i_akms & IEEE80211_WPA_AKM_SHA256_8021X)
333 		ic->ic_rsnakms |= IEEE80211_AKM_SHA256_8021X;
334 	if (ic->ic_rsnakms == 0)	/* set to default (PSK) */
335 		ic->ic_rsnakms = IEEE80211_AKM_PSK;
336 
337 	if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP40)
338 		ic->ic_rsngroupcipher = IEEE80211_CIPHER_WEP40;
339 	else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_TKIP)
340 		ic->ic_rsngroupcipher = IEEE80211_CIPHER_TKIP;
341 	else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_CCMP)
342 		ic->ic_rsngroupcipher = IEEE80211_CIPHER_CCMP;
343 	else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP104)
344 		ic->ic_rsngroupcipher = IEEE80211_CIPHER_WEP104;
345 	else  {	/* set to default */
346 		if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA)
347 			ic->ic_rsngroupcipher = IEEE80211_CIPHER_TKIP;
348 		else
349 			ic->ic_rsngroupcipher = IEEE80211_CIPHER_CCMP;
350 	}
351 
352 	ic->ic_rsnciphers = 0;
353 	if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_TKIP)
354 		ic->ic_rsnciphers |= IEEE80211_CIPHER_TKIP;
355 	if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_CCMP)
356 		ic->ic_rsnciphers |= IEEE80211_CIPHER_CCMP;
357 	if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_USEGROUP)
358 		ic->ic_rsnciphers = IEEE80211_CIPHER_USEGROUP;
359 	if (ic->ic_rsnciphers == 0) { /* set to default (CCMP, TKIP if WPA1) */
360 		ic->ic_rsnciphers = IEEE80211_CIPHER_CCMP;
361 		if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA)
362 			ic->ic_rsnciphers |= IEEE80211_CIPHER_TKIP;
363 	}
364 
365 	ic->ic_flags |= IEEE80211_F_RSNON;
366 
367 	return ENETRESET;
368 }
369 
370 static int
ieee80211_ioctl_getwpaparms(struct ieee80211com * ic,struct ieee80211_wpaparams * wpa)371 ieee80211_ioctl_getwpaparms(struct ieee80211com *ic,
372     struct ieee80211_wpaparams *wpa)
373 {
374 	wpa->i_enabled = (ic->ic_flags & IEEE80211_F_RSNON) ? 1 : 0;
375 
376 	wpa->i_protos = 0;
377 	if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA)
378 		wpa->i_protos |= IEEE80211_WPA_PROTO_WPA1;
379 	if (ic->ic_rsnprotos & IEEE80211_PROTO_RSN)
380 		wpa->i_protos |= IEEE80211_WPA_PROTO_WPA2;
381 
382 	wpa->i_akms = 0;
383 	if (ic->ic_rsnakms & IEEE80211_AKM_PSK)
384 		wpa->i_akms |= IEEE80211_WPA_AKM_PSK;
385 	if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_PSK)
386 		wpa->i_akms |= IEEE80211_WPA_AKM_SHA256_PSK;
387 	if (ic->ic_rsnakms & IEEE80211_AKM_8021X)
388 		wpa->i_akms |= IEEE80211_WPA_AKM_8021X;
389 	if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_8021X)
390 		wpa->i_akms |= IEEE80211_WPA_AKM_SHA256_8021X;
391 
392 	if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_WEP40)
393 		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP40;
394 	else if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_TKIP)
395 		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_TKIP;
396 	else if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_CCMP)
397 		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_CCMP;
398 	else if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_WEP104)
399 		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP104;
400 	else
401 		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_NONE;
402 
403 	wpa->i_ciphers = 0;
404 	if (ic->ic_rsnciphers & IEEE80211_CIPHER_TKIP)
405 		wpa->i_ciphers |= IEEE80211_WPA_CIPHER_TKIP;
406 	if (ic->ic_rsnciphers & IEEE80211_CIPHER_CCMP)
407 		wpa->i_ciphers |= IEEE80211_WPA_CIPHER_CCMP;
408 	if (ic->ic_rsnciphers & IEEE80211_CIPHER_USEGROUP)
409 		wpa->i_ciphers = IEEE80211_WPA_CIPHER_USEGROUP;
410 
411 	return 0;
412 }
413 
414 static void
ieee80211_ess_getwpaparms(struct ieee80211_ess * ess,struct ieee80211_wpaparams * wpa)415 ieee80211_ess_getwpaparms(struct ieee80211_ess *ess,
416     struct ieee80211_wpaparams *wpa)
417 {
418 	wpa->i_enabled = (ess->flags & IEEE80211_F_RSNON) ? 1 : 0;
419 
420 	wpa->i_protos = 0;
421 	if (ess->rsnprotos & IEEE80211_PROTO_WPA)
422 		wpa->i_protos |= IEEE80211_WPA_PROTO_WPA1;
423 	if (ess->rsnprotos & IEEE80211_PROTO_RSN)
424 		wpa->i_protos |= IEEE80211_WPA_PROTO_WPA2;
425 
426 	wpa->i_akms = 0;
427 	if (ess->rsnakms & IEEE80211_AKM_PSK)
428 		wpa->i_akms |= IEEE80211_WPA_AKM_PSK;
429 	if (ess->rsnakms & IEEE80211_AKM_SHA256_PSK)
430 		wpa->i_akms |= IEEE80211_WPA_AKM_SHA256_PSK;
431 	if (ess->rsnakms & IEEE80211_AKM_8021X)
432 		wpa->i_akms |= IEEE80211_WPA_AKM_8021X;
433 	if (ess->rsnakms & IEEE80211_AKM_SHA256_8021X)
434 		wpa->i_akms |= IEEE80211_WPA_AKM_SHA256_8021X;
435 
436 	if (ess->rsngroupcipher == IEEE80211_CIPHER_WEP40)
437 		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP40;
438 	else if (ess->rsngroupcipher == IEEE80211_CIPHER_TKIP)
439 		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_TKIP;
440 	else if (ess->rsngroupcipher == IEEE80211_CIPHER_CCMP)
441 		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_CCMP;
442 	else if (ess->rsngroupcipher == IEEE80211_CIPHER_WEP104)
443 		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP104;
444 	else
445 		wpa->i_groupcipher = IEEE80211_WPA_CIPHER_NONE;
446 
447 	wpa->i_ciphers = 0;
448 	if (ess->rsnciphers & IEEE80211_CIPHER_TKIP)
449 		wpa->i_ciphers |= IEEE80211_WPA_CIPHER_TKIP;
450 	if (ess->rsnciphers & IEEE80211_CIPHER_CCMP)
451 		wpa->i_ciphers |= IEEE80211_WPA_CIPHER_CCMP;
452 	if (ess->rsnciphers & IEEE80211_CIPHER_USEGROUP)
453 		wpa->i_ciphers = IEEE80211_WPA_CIPHER_USEGROUP;
454 }
455 
456 int
ieee80211_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)457 ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
458 {
459 	struct ieee80211com *ic = (void *)ifp;
460 	struct ifreq *ifr = (struct ifreq *)data;
461 	int i, error = 0;
462 	size_t len;
463 	struct ieee80211_nwid nwid;
464 	struct ieee80211_join join;
465 	struct ieee80211_joinreq_all *ja;
466 	struct ieee80211_ess *ess;
467 	struct ieee80211_wpapsk *psk;
468 	struct ieee80211_keyavail *ka;
469 	struct ieee80211_keyrun *kr;
470 	struct ieee80211_power *power;
471 	struct ieee80211_bssid *bssid;
472 	struct ieee80211chanreq *chanreq;
473 	struct ieee80211_channel *chan;
474 	struct ieee80211_txpower *txpower;
475 	static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
476 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00
477 	};
478 	struct ieee80211_nodereq *nr, nrbuf;
479 	struct ieee80211_nodereq_all *na;
480 	struct ieee80211_node *ni;
481 	struct ieee80211_chaninfo chaninfo;
482 	struct ieee80211_chanreq_all *allchans;
483 	u_int32_t flags;
484 
485 	switch (cmd) {
486 	case SIOCSIFMEDIA:
487 	case SIOCGIFMEDIA:
488 		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
489 		break;
490 	case SIOCS80211NWID:
491 		if ((error = suser(curproc)) != 0)
492 			break;
493 		if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
494 			break;
495 		if (nwid.i_len > IEEE80211_NWID_LEN) {
496 			error = EINVAL;
497 			break;
498 		}
499 		memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
500 		ic->ic_des_esslen = nwid.i_len;
501 		memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len);
502 		if (ic->ic_des_esslen > 0) {
503 			/* 'nwid' disables auto-join magic */
504 			ic->ic_flags &= ~IEEE80211_F_AUTO_JOIN;
505 		} else if (!TAILQ_EMPTY(&ic->ic_ess)) {
506 			/* '-nwid' re-enables auto-join */
507 			ic->ic_flags |= IEEE80211_F_AUTO_JOIN;
508 		}
509 		/* disable WPA/WEP */
510 		ieee80211_disable_rsn(ic);
511 		ieee80211_disable_wep(ic);
512 		error = ENETRESET;
513 		break;
514 	case SIOCG80211NWID:
515 		memset(&nwid, 0, sizeof(nwid));
516 		switch (ic->ic_state) {
517 		case IEEE80211_S_INIT:
518 		case IEEE80211_S_SCAN:
519 			nwid.i_len = ic->ic_des_esslen;
520 			memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len);
521 			break;
522 		default:
523 			nwid.i_len = ic->ic_bss->ni_esslen;
524 			memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
525 			break;
526 		}
527 		error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
528 		break;
529 	case SIOCS80211JOIN:
530 		if ((error = suser(curproc)) != 0)
531 			break;
532 		if (ic->ic_opmode != IEEE80211_M_STA)
533 			break;
534 		if ((error = copyin(ifr->ifr_data, &join, sizeof(join))) != 0)
535 			break;
536 		if (join.i_len > IEEE80211_NWID_LEN) {
537 			error = EINVAL;
538 			break;
539 		}
540 		if (join.i_flags & IEEE80211_JOIN_DEL) {
541 			int update_ic = 0;
542 			if (ic->ic_des_esslen == join.i_len &&
543 			    memcmp(join.i_nwid, ic->ic_des_essid,
544 			    join.i_len) == 0)
545 				update_ic = 1;
546 			if (join.i_flags & IEEE80211_JOIN_DEL_ALL &&
547 			    ieee80211_get_ess(ic, ic->ic_des_essid,
548 			    ic->ic_des_esslen) != NULL)
549 				update_ic = 1;
550 			ieee80211_del_ess(ic, join.i_nwid, join.i_len,
551 			    join.i_flags & IEEE80211_JOIN_DEL_ALL ? 1 : 0);
552 			if (update_ic == 1) {
553 				/* Unconfigure this essid */
554 				memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
555 				ic->ic_des_esslen = 0;
556 				/* disable WPA/WEP */
557 				ieee80211_disable_rsn(ic);
558 				ieee80211_disable_wep(ic);
559 				error = ENETRESET;
560 			}
561 		} else {
562 			if (ic->ic_des_esslen == join.i_len &&
563 			    memcmp(join.i_nwid, ic->ic_des_essid,
564 			    join.i_len) == 0) {
565 				struct ieee80211_node *ni;
566 
567 				ieee80211_deselect_ess(ic);
568 				ni = ieee80211_find_node(ic,
569 				    ic->ic_bss->ni_bssid);
570 				if (ni != NULL)
571 					ieee80211_free_node(ic, ni);
572 				error = ENETRESET;
573 			}
574 			/* save nwid for auto-join */
575 			if (ieee80211_add_ess(ic, &join) == 0)
576 				ic->ic_flags |= IEEE80211_F_AUTO_JOIN;
577 		}
578 		break;
579 	case SIOCG80211JOIN:
580 		memset(&join, 0, sizeof(join));
581 		error = ENOENT;
582 		if (ic->ic_bss == NULL)
583 			break;
584 		TAILQ_FOREACH(ess, &ic->ic_ess, ess_next) {
585 			if (memcmp(ess->essid, ic->ic_bss->ni_essid,
586 			    IEEE80211_NWID_LEN) == 0) {
587 				join.i_len = ic->ic_bss->ni_esslen;
588 				memcpy(join.i_nwid, ic->ic_bss->ni_essid,
589 				    join.i_len);
590 				if (ic->ic_flags & IEEE80211_F_AUTO_JOIN)
591 					join.i_flags = IEEE80211_JOIN_FOUND;
592 				error = copyout(&join, ifr->ifr_data,
593 				    sizeof(join));
594 				break;
595 			}
596 		}
597 		break;
598 	case SIOCG80211JOINALL:
599 		ja = (struct ieee80211_joinreq_all *)data;
600 		ja->ja_nodes = len = 0;
601 		TAILQ_FOREACH(ess, &ic->ic_ess, ess_next) {
602 			if (len + sizeof(ja->ja_node[0]) >= ja->ja_size) {
603 				error = E2BIG;
604 				break;
605 			}
606 			memset(&join, 0, sizeof(join));
607 			join.i_len = ess->esslen;
608 			memcpy(&join.i_nwid, ess->essid, join.i_len);
609 			if (ess->flags & IEEE80211_F_RSNON)
610 				join.i_flags |= IEEE80211_JOIN_WPA;
611 			if (ess->flags & IEEE80211_F_PSK)
612 				join.i_flags |= IEEE80211_JOIN_WPAPSK;
613 			if (ess->flags & IEEE80211_JOIN_8021X)
614 				join.i_flags |= IEEE80211_JOIN_8021X;
615 			if (ess->flags & IEEE80211_F_WEPON)
616 				join.i_flags |= IEEE80211_JOIN_NWKEY;
617 			if (ess->flags & IEEE80211_JOIN_ANY)
618 				join.i_flags |= IEEE80211_JOIN_ANY;
619 			ieee80211_ess_getwpaparms(ess, &join.i_wpaparams);
620 			error = copyout(&join, &ja->ja_node[ja->ja_nodes],
621 			    sizeof(ja->ja_node[0]));
622 			if (error)
623 				break;
624 			len += sizeof(join);
625 			ja->ja_nodes++;
626 		}
627 		break;
628 	case SIOCS80211NWKEY:
629 		if ((error = suser(curproc)) != 0)
630 			break;
631 		error = ieee80211_ioctl_setnwkeys(ic, (void *)data);
632 		break;
633 	case SIOCG80211NWKEY:
634 		error = ieee80211_ioctl_getnwkeys(ic, (void *)data);
635 		break;
636 	case SIOCS80211WPAPARMS:
637 		if ((error = suser(curproc)) != 0)
638 			break;
639 		error = ieee80211_ioctl_setwpaparms(ic, (void *)data);
640 		break;
641 	case SIOCG80211WPAPARMS:
642 		error = ieee80211_ioctl_getwpaparms(ic, (void *)data);
643 		break;
644 	case SIOCS80211WPAPSK:
645 		if ((error = suser(curproc)) != 0)
646 			break;
647 		psk = (struct ieee80211_wpapsk *)data;
648 		if (psk->i_enabled) {
649 			ic->ic_flags |= IEEE80211_F_PSK;
650 			memcpy(ic->ic_psk, psk->i_psk, sizeof(ic->ic_psk));
651 			if (ic->ic_flags & IEEE80211_F_WEPON)
652 				ieee80211_disable_wep(ic);
653 		} else {
654 			ic->ic_flags &= ~IEEE80211_F_PSK;
655 			memset(ic->ic_psk, 0, sizeof(ic->ic_psk));
656 		}
657 		error = ENETRESET;
658 		break;
659 	case SIOCG80211WPAPSK:
660 		psk = (struct ieee80211_wpapsk *)data;
661 		if (ic->ic_flags & IEEE80211_F_PSK) {
662 			/* do not show any keys to userland */
663 			psk->i_enabled = 2;
664 			memset(psk->i_psk, 0, sizeof(psk->i_psk));
665 			break;	/* return ok but w/o key */
666 		} else
667 			psk->i_enabled = 0;
668 		break;
669 	case SIOCS80211KEYAVAIL:
670 		if ((error = suser(curproc)) != 0)
671 			break;
672 		ka = (struct ieee80211_keyavail *)data;
673 		(void)ieee80211_pmksa_add(ic, IEEE80211_AKM_8021X,
674 		    ka->i_macaddr, ka->i_key, ka->i_lifetime);
675 		break;
676 	case SIOCS80211KEYRUN:
677 		if ((error = suser(curproc)) != 0)
678 			break;
679 		kr = (struct ieee80211_keyrun *)data;
680 		error = ieee80211_keyrun(ic, kr->i_macaddr);
681 		if (error == 0 && (ic->ic_flags & IEEE80211_F_WEPON))
682 			ieee80211_disable_wep(ic);
683 		break;
684 	case SIOCS80211POWER:
685 		if ((error = suser(curproc)) != 0)
686 			break;
687 		power = (struct ieee80211_power *)data;
688 		ic->ic_lintval = power->i_maxsleep;
689 		if (power->i_enabled != 0) {
690 			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
691 				error = EINVAL;
692 			else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
693 				ic->ic_flags |= IEEE80211_F_PMGTON;
694 				error = ENETRESET;
695 			}
696 		} else {
697 			if (ic->ic_flags & IEEE80211_F_PMGTON) {
698 				ic->ic_flags &= ~IEEE80211_F_PMGTON;
699 				error = ENETRESET;
700 			}
701 		}
702 		break;
703 	case SIOCG80211POWER:
704 		power = (struct ieee80211_power *)data;
705 		power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
706 		power->i_maxsleep = ic->ic_lintval;
707 		break;
708 	case SIOCS80211BSSID:
709 		if ((error = suser(curproc)) != 0)
710 			break;
711 		bssid = (struct ieee80211_bssid *)data;
712 		if (IEEE80211_ADDR_EQ(bssid->i_bssid, empty_macaddr))
713 			ic->ic_flags &= ~IEEE80211_F_DESBSSID;
714 		else {
715 			ic->ic_flags |= IEEE80211_F_DESBSSID;
716 			IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid);
717 		}
718 #ifndef IEEE80211_STA_ONLY
719 		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
720 			break;
721 #endif
722 		switch (ic->ic_state) {
723 		case IEEE80211_S_INIT:
724 		case IEEE80211_S_SCAN:
725 			error = ENETRESET;
726 			break;
727 		default:
728 			if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
729 			    !IEEE80211_ADDR_EQ(ic->ic_des_bssid,
730 			    ic->ic_bss->ni_bssid))
731 				error = ENETRESET;
732 			break;
733 		}
734 		break;
735 	case SIOCG80211BSSID:
736 		bssid = (struct ieee80211_bssid *)data;
737 		switch (ic->ic_state) {
738 		case IEEE80211_S_INIT:
739 		case IEEE80211_S_SCAN:
740 #ifndef IEEE80211_STA_ONLY
741 			if (ic->ic_opmode == IEEE80211_M_HOSTAP)
742 				IEEE80211_ADDR_COPY(bssid->i_bssid,
743 				    ic->ic_myaddr);
744 			else
745 #endif
746 			if (ic->ic_flags & IEEE80211_F_DESBSSID)
747 				IEEE80211_ADDR_COPY(bssid->i_bssid,
748 				    ic->ic_des_bssid);
749 			else
750 				memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
751 			break;
752 		default:
753 			IEEE80211_ADDR_COPY(bssid->i_bssid,
754 			    ic->ic_bss->ni_bssid);
755 			break;
756 		}
757 		break;
758 	case SIOCS80211CHANNEL:
759 		if ((error = suser(curproc)) != 0)
760 			break;
761 		chanreq = (struct ieee80211chanreq *)data;
762 		if (chanreq->i_channel == IEEE80211_CHAN_ANY)
763 			ic->ic_des_chan = IEEE80211_CHAN_ANYC;
764 		else if (chanreq->i_channel > IEEE80211_CHAN_MAX ||
765 		    isclr(ic->ic_chan_active, chanreq->i_channel)) {
766 			error = EINVAL;
767 			break;
768 		} else
769 			ic->ic_ibss_chan = ic->ic_des_chan =
770 			    &ic->ic_channels[chanreq->i_channel];
771 		switch (ic->ic_state) {
772 		case IEEE80211_S_INIT:
773 		case IEEE80211_S_SCAN:
774 			error = ENETRESET;
775 			break;
776 		default:
777 			if (ic->ic_opmode == IEEE80211_M_STA) {
778 				if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
779 				    ic->ic_bss->ni_chan != ic->ic_des_chan)
780 					error = ENETRESET;
781 			} else {
782 				if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
783 					error = ENETRESET;
784 			}
785 			break;
786 		}
787 		break;
788 	case SIOCG80211CHANNEL:
789 		chanreq = (struct ieee80211chanreq *)data;
790 		switch (ic->ic_state) {
791 		case IEEE80211_S_INIT:
792 		case IEEE80211_S_SCAN:
793 			if (ic->ic_opmode == IEEE80211_M_STA)
794 				chan = ic->ic_des_chan;
795 			else
796 				chan = ic->ic_ibss_chan;
797 			break;
798 		default:
799 			chan = ic->ic_bss->ni_chan;
800 			break;
801 		}
802 		chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
803 		break;
804 	case SIOCG80211ALLCHANS:
805 		allchans = (struct ieee80211_chanreq_all *)data;
806 		for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
807 			chan = &ic->ic_channels[i];
808 			chaninfo.ic_freq = chan->ic_freq;
809 			chaninfo.ic_flags = 0;
810 			if (chan->ic_flags & IEEE80211_CHAN_2GHZ)
811 				chaninfo.ic_flags |= IEEE80211_CHANINFO_2GHZ;
812 			if (chan->ic_flags & IEEE80211_CHAN_5GHZ)
813 				chaninfo.ic_flags |= IEEE80211_CHANINFO_5GHZ;
814 			if (chan->ic_flags & IEEE80211_CHAN_PASSIVE)
815 				chaninfo.ic_flags |= IEEE80211_CHANINFO_PASSIVE;
816 			error = copyout(&chaninfo, &allchans->i_chans[i],
817 			    sizeof(chaninfo));
818 			if (error)
819 				break;
820 		}
821 		break;
822 #if 0
823 	case SIOCG80211ZSTATS:
824 #endif
825 	case SIOCG80211STATS:
826 		ifr = (struct ifreq *)data;
827 		error = copyout(&ic->ic_stats, ifr->ifr_data,
828 		    sizeof(ic->ic_stats));
829 #if 0
830 		if (cmd == SIOCG80211ZSTATS)
831 			memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
832 #endif
833 		break;
834 	case SIOCS80211TXPOWER:
835 		if ((error = suser(curproc)) != 0)
836 			break;
837 		txpower = (struct ieee80211_txpower *)data;
838 		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) {
839 			error = EINVAL;
840 			break;
841 		}
842 		if (!(IEEE80211_TXPOWER_MIN <= txpower->i_val &&
843 			txpower->i_val <= IEEE80211_TXPOWER_MAX)) {
844 			error = EINVAL;
845 			break;
846 		}
847 		ic->ic_txpower = txpower->i_val;
848 		error = ENETRESET;
849 		break;
850 	case SIOCG80211TXPOWER:
851 		txpower = (struct ieee80211_txpower *)data;
852 		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
853 			error = EINVAL;
854 		else
855 			txpower->i_val = ic->ic_txpower;
856 		break;
857 	case SIOCSIFMTU:
858 		ifr = (struct ifreq *)data;
859 		if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
860 		    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
861 			error = EINVAL;
862 		else
863 			ifp->if_mtu = ifr->ifr_mtu;
864 		break;
865 	case SIOCS80211SCAN:
866 		/* Disabled. SIOCG80211ALLNODES is enough. */
867 		break;
868 	case SIOCG80211NODE:
869 		nr = (struct ieee80211_nodereq *)data;
870 		if (ic->ic_bss &&
871 		    IEEE80211_ADDR_EQ(nr->nr_macaddr, ic->ic_bss->ni_macaddr))
872 			ni = ic->ic_bss;
873 		else
874 			ni = ieee80211_find_node(ic, nr->nr_macaddr);
875 		if (ni == NULL) {
876 			error = ENOENT;
877 			break;
878 		}
879 		ieee80211_node2req(ic, ni, nr);
880 		break;
881 	case SIOCS80211NODE:
882 		if ((error = suser(curproc)) != 0)
883 			break;
884 #ifndef IEEE80211_STA_ONLY
885 		if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
886 			error = EINVAL;
887 			break;
888 		}
889 #endif
890 		nr = (struct ieee80211_nodereq *)data;
891 
892 		ni = ieee80211_find_node(ic, nr->nr_macaddr);
893 		if (ni == NULL)
894 			ni = ieee80211_alloc_node(ic, nr->nr_macaddr);
895 		if (ni == NULL) {
896 			error = ENOENT;
897 			break;
898 		}
899 
900 		if (nr->nr_flags & IEEE80211_NODEREQ_COPY)
901 			ieee80211_req2node(ic, nr, ni);
902 		break;
903 #ifndef IEEE80211_STA_ONLY
904 	case SIOCS80211DELNODE:
905 		if ((error = suser(curproc)) != 0)
906 			break;
907 		nr = (struct ieee80211_nodereq *)data;
908 		ni = ieee80211_find_node(ic, nr->nr_macaddr);
909 		if (ni == NULL)
910 			error = ENOENT;
911 		else if (ni == ic->ic_bss)
912 			error = EPERM;
913 		else {
914 			if (ni->ni_state == IEEE80211_STA_COLLECT)
915 				break;
916 
917 			/* Disassociate station. */
918 			if (ni->ni_state == IEEE80211_STA_ASSOC)
919 				IEEE80211_SEND_MGMT(ic, ni,
920 				    IEEE80211_FC0_SUBTYPE_DISASSOC,
921 				    IEEE80211_REASON_ASSOC_LEAVE);
922 
923 			/* Deauth station. */
924 			if (ni->ni_state >= IEEE80211_STA_AUTH)
925 				IEEE80211_SEND_MGMT(ic, ni,
926 				    IEEE80211_FC0_SUBTYPE_DEAUTH,
927 				    IEEE80211_REASON_AUTH_LEAVE);
928 
929 			ieee80211_node_leave(ic, ni);
930 		}
931 		break;
932 #endif
933 	case SIOCG80211ALLNODES:
934 		if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) !=
935 		    (IFF_UP | IFF_RUNNING)) {
936 			error = ENETDOWN;
937 			break;
938 		}
939 
940 		na = (struct ieee80211_nodereq_all *)data;
941 		na->na_nodes = i = 0;
942 		ni = RBT_MIN(ieee80211_tree, &ic->ic_tree);
943 #ifdef __FreeBSD_version
944 		while (ni && na->na_startnode) {
945 			ni = RBT_NEXT(ieee80211_tree, ni);
946 			na->na_startnode--;
947 		}
948 #endif
949 		while (ni && na->na_size >=
950 		    i + sizeof(struct ieee80211_nodereq)) {
951 			ieee80211_node2req(ic, ni, &nrbuf);
952 			error = copyout(&nrbuf, (caddr_t)na->na_node + i,
953 			    sizeof(struct ieee80211_nodereq));
954 			if (error)
955 				break;
956 			i += sizeof(struct ieee80211_nodereq);
957 			na->na_nodes++;
958 			ni = RBT_NEXT(ieee80211_tree, ni);
959 		}
960 		if (suser(curproc) == 0)
961 			ieee80211_begin_bgscan(ifp);
962 		break;
963 	case SIOCG80211FLAGS:
964 		flags = ic->ic_userflags;
965 #ifndef IEEE80211_STA_ONLY
966 		if (ic->ic_opmode != IEEE80211_M_HOSTAP)
967 #endif
968 			flags &= ~IEEE80211_F_HOSTAPMASK;
969 		ifr->ifr_flags = flags;
970 		break;
971 	case SIOCS80211FLAGS:
972 		if ((error = suser(curproc)) != 0)
973 			break;
974 		flags = ifr->ifr_flags;
975 		if (
976 #ifndef IEEE80211_STA_ONLY
977 		    ic->ic_opmode != IEEE80211_M_HOSTAP &&
978 #endif
979 		    (flags & IEEE80211_F_HOSTAPMASK)) {
980 			error = EINVAL;
981 			break;
982 		}
983 		ic->ic_userflags = flags;
984 		error = ENETRESET;
985 		break;
986 #ifndef __HAIKU__
987 	case SIOCADDMULTI:
988 	case SIOCDELMULTI:
989 		error = (cmd == SIOCADDMULTI) ?
990 		    ether_addmulti(ifr, &ic->ic_ac) :
991 		    ether_delmulti(ifr, &ic->ic_ac);
992 		if (error == ENETRESET)
993 			error = 0;
994 		break;
995 #endif
996 	default:
997 #ifdef __FreeBSD_version
998 		error = ether_ioctl(ifp, cmd, data);
999 #else
1000 		error = ether_ioctl(ifp, &ic->ic_ac, cmd, data);
1001 #endif
1002 	}
1003 
1004 	return error;
1005 }
1006