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