xref: /freebsd/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.c (revision 1de7b4b805ddbf2429da511c053686ac4591ed89)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2010 The FreeBSD Foundation
5  * All rights reserved.
6  *
7  * This software was developed by Shteryana Sotirova Shopova under
8  * sponsorship from the FreeBSD Foundation.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33 
34 #include <sys/queue.h>
35 #include <sys/socket.h>
36 #include <sys/types.h>
37 
38 #include <net/if.h>
39 #include <net/if_media.h>
40 #include <net/if_mib.h>
41 #include <net/if_types.h>
42 #include <net80211/ieee80211.h>
43 #include <net80211/ieee80211_ioctl.h>
44 
45 #include <errno.h>
46 #include <stdarg.h>
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <syslog.h>
51 
52 #include <bsnmp/snmpmod.h>
53 #include <bsnmp/snmp_mibII.h>
54 
55 #include "wlan_tree.h"
56 #include "wlan_snmp.h"
57 #include "wlan_oid.h"
58 
59 static struct lmodule *wlan_module;
60 
61 /* For the registration. */
62 static const struct asn_oid oid_wlan = OIDX_begemotWlan;
63 /* The registration. */
64 static uint reg_wlan;
65 
66 /* Periodic timer for polling the module's data. */
67 static void *wlan_data_timer;
68 
69 /*
70  * Poll data from kernel every 15 minutes unless explicitly requested by an
71  * SNMP client.
72  * XXX: make that configurable.
73  */
74 static int wlan_poll_ticks = (15 * 60) * 100;
75 
76 /* The age of each table. */
77 #define	WLAN_LIST_MAXAGE	5
78 
79 static time_t wlan_iflist_age;
80 static time_t wlan_peerlist_age;
81 static time_t wlan_chanlist_age;
82 static time_t wlan_roamlist_age;
83 static time_t wlan_tx_paramlist_age;
84 static time_t wlan_scanlist_age;
85 static time_t wlan_maclist_age;
86 static time_t wlan_mrlist_age;
87 
88 /*
89  * The list of all virtual wireless interfaces - sorted by name.
90  */
91 SLIST_HEAD(wlan_ifaces, wlan_iface);
92 static struct wlan_ifaces wlan_ifaces = SLIST_HEAD_INITIALIZER(wlan_ifaces);
93 
94 static struct wlan_config wlan_config;
95 
96 /* Forward declarations */
97 static int	bits_get(struct snmp_value *, const u_char *, ssize_t);
98 
99 static int	wlan_add_wif(struct wlan_iface *);
100 static void	wlan_delete_wif(struct wlan_iface *);
101 static int	wlan_attach_newif(struct mibif *);
102 static int	wlan_iface_create(struct wlan_iface *);
103 static int	wlan_iface_destroy(struct wlan_iface *);
104 static struct wlan_iface *	wlan_new_wif(char *);
105 
106 static void	wlan_free_interface(struct wlan_iface *);
107 static void	wlan_free_iflist(void);
108 static void	wlan_free_peerlist(struct wlan_iface *);
109 static void	wlan_scan_free_results(struct wlan_iface *);
110 static void	wlan_mac_free_maclist(struct wlan_iface *);
111 static void	wlan_mesh_free_routes(struct wlan_iface *);
112 
113 static int	wlan_update_interface(struct wlan_iface *);
114 static void	wlan_update_interface_list(void);
115 static void	wlan_update_peers(void);
116 static void	wlan_update_channels(void);
117 static void	wlan_update_roam_params(void);
118 static void	wlan_update_tx_params(void);
119 static void	wlan_scan_update_results(void);
120 static void	wlan_mac_update_aclmacs(void);
121 static void	wlan_mesh_update_routes(void);
122 
123 static struct wlan_iface *	wlan_find_interface(const char *);
124 static struct wlan_peer *	wlan_find_peer(struct wlan_iface *, uint8_t *);
125 static struct ieee80211_channel*	wlan_find_channel(struct wlan_iface *,
126     uint32_t);
127 static struct wlan_scan_result *	wlan_scan_find_result(struct wlan_iface *,
128     uint8_t *, uint8_t *);
129 static struct wlan_mac_mac *		wlan_mac_find_mac(struct wlan_iface *,
130     uint8_t *);
131 static struct wlan_mesh_route *		wlan_mesh_find_route(struct wlan_iface *,
132     uint8_t *);
133 
134 static struct wlan_iface *	wlan_first_interface(void);
135 static struct wlan_iface *	wlan_next_interface(struct wlan_iface *);
136 static struct wlan_iface *	wlan_mesh_first_interface(void);
137 static struct wlan_iface *	wlan_mesh_next_interface(struct wlan_iface *);
138 
139 static struct wlan_iface *	wlan_get_interface(const struct asn_oid *, uint);
140 static struct wlan_iface *	wlan_get_snmp_interface(const struct asn_oid *,
141     uint);
142 static struct wlan_peer *	wlan_get_peer(const struct asn_oid *, uint,
143     struct wlan_iface **);
144 static struct ieee80211_channel *wlan_get_channel(const struct asn_oid *, uint,
145     struct wlan_iface **);
146 static struct ieee80211_roamparam *wlan_get_roam_param(const struct asn_oid *,
147     uint, struct wlan_iface **);
148 static struct ieee80211_txparam *wlan_get_tx_param(const struct asn_oid *,
149     uint, struct wlan_iface **, uint32_t *);
150 static struct wlan_scan_result *wlan_get_scanr(const struct asn_oid *, uint,
151     struct wlan_iface **);
152 static struct wlan_mac_mac *	wlan_get_acl_mac(const struct asn_oid *,
153     uint, struct wlan_iface **);
154 static struct wlan_iface *	wlan_mesh_get_iface(const struct asn_oid *, uint);
155 static struct wlan_peer *	wlan_mesh_get_peer(const struct asn_oid *, uint,
156     struct wlan_iface **);
157 static struct wlan_mesh_route *	wlan_mesh_get_route(const struct asn_oid *,
158     uint, struct wlan_iface **);
159 
160 static struct wlan_iface *	wlan_get_next_interface(const struct asn_oid *,
161     uint);
162 static struct wlan_iface *	wlan_get_next_snmp_interface(const struct
163     asn_oid *, uint);
164 static struct wlan_peer *	wlan_get_next_peer(const struct asn_oid *, uint,
165     struct wlan_iface **);
166 static struct ieee80211_channel *wlan_get_next_channel(const struct asn_oid *,
167     uint, struct wlan_iface **);
168 static struct ieee80211_roamparam *wlan_get_next_roam_param(const struct
169     asn_oid *, uint sub, struct wlan_iface **, uint32_t *);
170 static struct ieee80211_txparam *wlan_get_next_tx_param(const struct asn_oid *,
171     uint, struct wlan_iface **, uint32_t *);
172 static struct wlan_scan_result *wlan_get_next_scanr(const struct asn_oid *,
173     uint , struct wlan_iface **);
174 static struct wlan_mac_mac *	wlan_get_next_acl_mac(const struct asn_oid *,
175     uint, struct wlan_iface **);
176 static struct wlan_iface *	wlan_mesh_get_next_iface(const struct asn_oid *,
177     uint);
178 static struct wlan_peer *	wlan_mesh_get_next_peer(const struct asn_oid *,
179     uint, struct wlan_iface **);
180 static struct wlan_mesh_route *	wlan_mesh_get_next_route(const struct asn_oid *,
181     uint sub, struct wlan_iface **);
182 
183 static uint8_t *wlan_get_ifname(const struct asn_oid *, uint, uint8_t *);
184 static int	wlan_mac_index_decode(const struct asn_oid *, uint, char *,
185     uint8_t *);
186 static int	wlan_channel_index_decode(const struct asn_oid *, uint,
187     char *, uint32_t *);
188 static int	wlan_phy_index_decode(const struct asn_oid *, uint, char *,
189     uint32_t *);
190 static int wlan_scanr_index_decode(const struct asn_oid *oid, uint sub,
191     char *wname, uint8_t *ssid, uint8_t *bssid);
192 
193 static void	wlan_append_ifindex(struct asn_oid *, uint,
194     const struct wlan_iface *);
195 static void	wlan_append_mac_index(struct asn_oid *, uint, char *, uint8_t *);
196 static void	wlan_append_channel_index(struct asn_oid *, uint,
197     const struct wlan_iface *, const struct ieee80211_channel *);
198 static void	wlan_append_phy_index(struct asn_oid *, uint, char *, uint32_t);
199 static void	wlan_append_scanr_index(struct asn_oid *, uint, char *,
200     uint8_t *, uint8_t *);
201 
202 static int	wlan_acl_mac_set_status(struct snmp_context *,
203     struct snmp_value *, uint);
204 static int	wlan_mesh_route_set_status(struct snmp_context *,
205     struct snmp_value *, uint);
206 
207 static int32_t	wlan_get_channel_type(struct ieee80211_channel *);
208 static int	wlan_scan_compare_result(struct wlan_scan_result *,
209     struct wlan_scan_result *);
210 static int	wlan_mac_delete_mac(struct wlan_iface *, struct wlan_mac_mac *);
211 static int	wlan_mesh_delete_route(struct wlan_iface *,
212     struct wlan_mesh_route *);
213 
214 /*
215  * The module's GET/SET data hooks per each table or group of objects as
216  * required by bsnmpd(1).
217  */
218 int
219 op_wlan_iface(struct snmp_context *ctx, struct snmp_value *val, uint32_t sub,
220     uint32_t iidx __unused, enum snmp_op op)
221 {
222 	int rc;
223 	char wname[IFNAMSIZ];
224 	struct wlan_iface *wif;
225 
226 	wlan_update_interface_list();
227 
228 	switch (op) {
229 	case SNMP_OP_GET:
230 		if ((wif = wlan_get_snmp_interface(&val->var, sub)) == NULL)
231 			return (SNMP_ERR_NOSUCHNAME);
232 		break;
233 
234 	case SNMP_OP_GETNEXT:
235 		if ((wif = wlan_get_next_snmp_interface(&val->var, sub)) == NULL)
236 			return (SNMP_ERR_NOSUCHNAME);
237 		wlan_append_ifindex(&val->var, sub, wif);
238 		break;
239 
240 	case SNMP_OP_SET:
241 		if ((wif = wlan_get_snmp_interface(&val->var, sub)) == NULL) {
242 			if (val->var.subs[sub - 1] != LEAF_wlanIfaceName)
243 				return (SNMP_ERR_NOSUCHNAME);
244 			if (wlan_get_ifname(&val->var, sub, wname) == NULL)
245 				return (SNMP_ERR_INCONS_VALUE);
246 			if ((wif = wlan_new_wif(wname)) == NULL)
247 				return (SNMP_ERR_GENERR);
248 			wif->internal = 1;
249 		}
250 		if (wif->status == RowStatus_active &&
251 		    val->var.subs[sub - 1] != LEAF_wlanIfaceStatus &&
252 		    val->var.subs[sub - 1] != LEAF_wlanIfaceState)
253 			return (SNMP_ERR_INCONS_VALUE);
254 
255 		switch (val->var.subs[sub - 1]) {
256 		case LEAF_wlanIfaceIndex:
257 			return (SNMP_ERR_NOT_WRITEABLE);
258 
259 		case LEAF_wlanIfaceName:
260 			if (val->v.octetstring.len >= IFNAMSIZ)
261 				return (SNMP_ERR_INCONS_VALUE);
262 			if ((ctx->scratch->ptr1 = malloc(IFNAMSIZ)) == NULL)
263 				return (SNMP_ERR_GENERR);
264 			strlcpy(ctx->scratch->ptr1, wif->wname, IFNAMSIZ);
265 			memcpy(wif->wname, val->v.octetstring.octets,
266 			    val->v.octetstring.len);
267 			wif->wname[val->v.octetstring.len] = '\0';
268 			return (SNMP_ERR_NOERROR);
269 
270 		case LEAF_wlanParentIfName:
271 			if (val->v.octetstring.len >= IFNAMSIZ)
272 				return (SNMP_ERR_INCONS_VALUE);
273 			if ((ctx->scratch->ptr1 = malloc(IFNAMSIZ)) == NULL)
274 				return (SNMP_ERR_GENERR);
275 			strlcpy(ctx->scratch->ptr1, wif->pname, IFNAMSIZ);
276 			memcpy(wif->pname, val->v.octetstring.octets,
277 			    val->v.octetstring.len);
278 			wif->pname[val->v.octetstring.len] = '\0';
279 			return (SNMP_ERR_NOERROR);
280 
281 		case LEAF_wlanIfaceOperatingMode:
282 			ctx->scratch->int1 = wif->mode;
283 			wif->mode = val->v.integer;
284 			return (SNMP_ERR_NOERROR);
285 
286 		case LEAF_wlanIfaceFlags:
287 			if (val->v.octetstring.len > sizeof(wif->flags))
288 				return (SNMP_ERR_INCONS_VALUE);
289 			ctx->scratch->ptr1 = malloc(sizeof(wif->flags));
290 			if (ctx->scratch->ptr1 == NULL)
291 				return (SNMP_ERR_GENERR);
292 			memcpy(ctx->scratch->ptr1, (uint8_t *)&wif->flags,
293 			    sizeof(wif->flags));
294 			memcpy((uint8_t *)&wif->flags, val->v.octetstring.octets,
295 			    sizeof(wif->flags));
296 			return (SNMP_ERR_NOERROR);
297 
298 		case LEAF_wlanIfaceBssid:
299 			if (val->v.octetstring.len != IEEE80211_ADDR_LEN)
300 				return (SNMP_ERR_INCONS_VALUE);
301 			ctx->scratch->ptr1 = malloc(IEEE80211_ADDR_LEN);
302 			if (ctx->scratch->ptr1 == NULL)
303 				return (SNMP_ERR_GENERR);
304 			memcpy(ctx->scratch->ptr1, wif->dbssid,
305 			    IEEE80211_ADDR_LEN);
306 			memcpy(wif->dbssid, val->v.octetstring.octets,
307 			    IEEE80211_ADDR_LEN);
308 			return (SNMP_ERR_NOERROR);
309 
310 		case LEAF_wlanIfaceLocalAddress:
311 			if (val->v.octetstring.len != IEEE80211_ADDR_LEN)
312 				return (SNMP_ERR_INCONS_VALUE);
313 			ctx->scratch->ptr1 = malloc(IEEE80211_ADDR_LEN);
314 			if (ctx->scratch->ptr1 == NULL)
315 				return (SNMP_ERR_GENERR);
316 			memcpy(ctx->scratch->ptr1, wif->dlmac,
317 			    IEEE80211_ADDR_LEN);
318 			memcpy(wif->dlmac, val->v.octetstring.octets,
319 			    IEEE80211_ADDR_LEN);
320 			return (SNMP_ERR_NOERROR);
321 
322 		case LEAF_wlanIfaceStatus:
323 			ctx->scratch->int1 = wif->status;
324 			wif->status = val->v.integer;
325 			if (wif->status == RowStatus_active) {
326 				rc = wlan_iface_create(wif); /* XXX */
327 				if (rc != SNMP_ERR_NOERROR) {
328 					wif->status = ctx->scratch->int1;
329 					return (rc);
330 				}
331 			} else if (wif->status == RowStatus_destroy)
332 				return (wlan_iface_destroy(wif));
333 			else
334 				wif->status = RowStatus_notReady;
335 			return (SNMP_ERR_NOERROR);
336 
337 		case LEAF_wlanIfaceState:
338 			ctx->scratch->int1 = wif->state;
339 			wif->state = val->v.integer;
340 			if (wif->status == RowStatus_active)
341 				if (wlan_config_state(wif, 1) < 0)
342 					return (SNMP_ERR_GENERR);
343 			return (SNMP_ERR_NOERROR);
344 		}
345 		abort();
346 
347 	case SNMP_OP_ROLLBACK:
348 		if ((wif = wlan_get_snmp_interface(&val->var, sub)) == NULL)
349 			return (SNMP_ERR_NOSUCHNAME);
350 		switch (val->var.subs[sub - 1]) {
351 		case LEAF_wlanIfaceName:
352 			strlcpy(wif->wname, ctx->scratch->ptr1, IFNAMSIZ);
353 			free(ctx->scratch->ptr1);
354 			break;
355 
356 		case LEAF_wlanParentIfName:
357 			strlcpy(wif->pname, ctx->scratch->ptr1, IFNAMSIZ);
358 			free(ctx->scratch->ptr1);
359 			break;
360 
361 		case LEAF_wlanIfaceOperatingMode:
362 			wif->mode = ctx->scratch->int1;
363 			break;
364 
365 		case LEAF_wlanIfaceFlags:
366 			memcpy((uint8_t *)&wif->flags, ctx->scratch->ptr1,
367 			    sizeof(wif->flags));
368 			free(ctx->scratch->ptr1);
369 			break;
370 
371 		case LEAF_wlanIfaceBssid:
372 			memcpy(wif->dbssid, ctx->scratch->ptr1,
373 			    IEEE80211_ADDR_LEN);
374 			free(ctx->scratch->ptr1);
375 			break;
376 
377 		case LEAF_wlanIfaceLocalAddress:
378 			memcpy(wif->dlmac, ctx->scratch->ptr1,
379 			    IEEE80211_ADDR_LEN);
380 			free(ctx->scratch->ptr1);
381 			break;
382 
383 		case LEAF_wlanIfaceStatus:
384 			wif->status = ctx->scratch->int1;
385 			if (ctx->scratch->int1 == RowStatus_active)
386 				return (SNMP_ERR_GENERR); /* XXX: FIXME */
387 			else if (wif->internal != 0)
388 				return (wlan_iface_destroy(wif));
389 			break;
390 
391 		case LEAF_wlanIfaceState:
392 			wif->state = ctx->scratch->int1;
393 			if (wif->status == RowStatus_active)
394 				if (wlan_config_state(wif, 1) < 0)
395 					return (SNMP_ERR_GENERR);
396 			break;
397 		}
398 		return (SNMP_ERR_NOERROR);
399 
400 	case SNMP_OP_COMMIT:
401 		switch (val->var.subs[sub - 1]) {
402 		case LEAF_wlanIfaceName:
403 		case LEAF_wlanParentIfName:
404 		case LEAF_wlanIfaceFlags:
405 		case LEAF_wlanIfaceBssid:
406 		case LEAF_wlanIfaceLocalAddress:
407 			free(ctx->scratch->ptr1);
408 			/* FALLTHROUGH */
409 		default:
410 			return (SNMP_ERR_NOERROR);
411 		}
412 	default:
413 		abort();
414 	}
415 
416 	switch (val->var.subs[sub - 1]) {
417 	case LEAF_wlanIfaceIndex:
418 		val->v.integer = wif->index;
419 		return (SNMP_ERR_NOERROR);
420 	case LEAF_wlanIfaceName:
421 		return (string_get(val, wif->wname, -1));
422 	case LEAF_wlanParentIfName:
423 		return (string_get(val, wif->pname, -1));
424 	case LEAF_wlanIfaceOperatingMode:
425 		val->v.integer = wif->mode;
426 		return (SNMP_ERR_NOERROR);
427 	case LEAF_wlanIfaceFlags:
428 		return (bits_get(val, (uint8_t *)&wif->flags,
429 		    sizeof(wif->flags)));
430 	case LEAF_wlanIfaceBssid:
431 		return (string_get(val, wif->dbssid, IEEE80211_ADDR_LEN));
432 	case LEAF_wlanIfaceLocalAddress:
433 		return (string_get(val, wif->dlmac, IEEE80211_ADDR_LEN));
434 	case LEAF_wlanIfaceStatus:
435 		val->v.integer = wif->status;
436 		return (SNMP_ERR_NOERROR);
437 	case LEAF_wlanIfaceState:
438 		val->v.integer = wif->state;
439 		return (SNMP_ERR_NOERROR);
440 	}
441 
442 	abort();
443 }
444 
445 int
446 op_wlan_if_parent(struct snmp_context *ctx __unused, struct snmp_value *val,
447     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
448 {
449 	struct wlan_iface *wif;
450 
451 	wlan_update_interface_list();
452 
453 	switch (op) {
454 	case SNMP_OP_GET:
455 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
456 			return (SNMP_ERR_NOSUCHNAME);
457 		break;
458 	case SNMP_OP_GETNEXT:
459 		if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
460 			return (SNMP_ERR_NOSUCHNAME);
461 		wlan_append_ifindex(&val->var, sub, wif);
462 		break;
463 	case SNMP_OP_SET:
464 		return (SNMP_ERR_NOT_WRITEABLE);
465 	case SNMP_OP_COMMIT:
466 		/* FALLTHROUGH */
467 	case SNMP_OP_ROLLBACK:
468 		/* FALLTHROUGH */
469 	default:
470 		abort();
471 	}
472 
473 	switch (val->var.subs[sub - 1]) {
474 	case LEAF_wlanIfParentDriverCapabilities:
475 		return (bits_get(val, (uint8_t *)&wif->drivercaps,
476 		    sizeof(wif->drivercaps)));
477 	case LEAF_wlanIfParentCryptoCapabilities:
478 		return (bits_get(val, (uint8_t *)&wif->cryptocaps,
479 		    sizeof(wif->cryptocaps)));
480 	case LEAF_wlanIfParentHTCapabilities:
481 		return (bits_get(val, (uint8_t *)&wif->htcaps,
482 		    sizeof(wif->htcaps)));
483 	}
484 
485 	abort();
486 }
487 
488 int
489 op_wlan_iface_config(struct snmp_context *ctx, struct snmp_value *val,
490     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
491 {
492 	int intval, vlen, rc;
493 	char *strval;
494 	struct wlan_iface *wif;
495 
496 	wlan_update_interface_list();
497 
498 	switch (op) {
499 	case SNMP_OP_GET:
500 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
501 			return (SNMP_ERR_NOSUCHNAME);
502 		goto get_config;
503 
504 	case SNMP_OP_GETNEXT:
505 		if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
506 			return (SNMP_ERR_NOSUCHNAME);
507 		wlan_append_ifindex(&val->var, sub, wif);
508 		goto get_config;
509 
510 	case SNMP_OP_SET:
511 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
512 			return (SNMP_ERR_NOSUCHNAME);
513 
514 		intval = val->v.integer;
515 		strval = NULL;
516 		vlen = 0;
517 
518 		/* Simple sanity checks & save old data. */
519 		switch (val->var.subs[sub - 1]) {
520 		case LEAF_wlanIfaceCountryCode:
521 			if (val->v.octetstring.len != WLAN_COUNTRY_CODE_SIZE)
522 				return (SNMP_ERR_INCONS_VALUE);
523 			break;
524 		case LEAF_wlanIfaceDesiredSsid:
525 			if (val->v.octetstring.len > IEEE80211_NWID_LEN)
526 				return (SNMP_ERR_INCONS_VALUE);
527 			break;
528 		case LEAF_wlanIfaceDesiredBssid:
529 			if (val->v.octetstring.len != IEEE80211_ADDR_LEN)
530 				return (SNMP_ERR_INCONS_VALUE);
531 			break;
532 		case LEAF_wlanIfacePacketBurst:
533 			ctx->scratch->int1 = wif->packet_burst;
534 			break;
535 		case LEAF_wlanIfaceRegDomain:
536 			ctx->scratch->int1 = wif->reg_domain;
537 			break;
538 		case LEAF_wlanIfaceDesiredChannel:
539 			ctx->scratch->int1 = wif->desired_channel;
540 			break;
541 		case LEAF_wlanIfaceDynamicFreqSelection:
542 			ctx->scratch->int1 = wif->dyn_frequency;
543 			break;
544 		case LEAF_wlanIfaceFastFrames:
545 			ctx->scratch->int1 = wif->fast_frames;
546 			break;
547 		case LEAF_wlanIfaceDturbo:
548 			ctx->scratch->int1 = wif->dturbo;
549 			break;
550 		case LEAF_wlanIfaceTxPower:
551 			ctx->scratch->int1 = wif->tx_power;
552 			break;
553 		case LEAF_wlanIfaceFragmentThreshold:
554 			ctx->scratch->int1 = wif->frag_threshold;
555 			break;
556 		case LEAF_wlanIfaceRTSThreshold:
557 			ctx->scratch->int1 = wif->rts_threshold;
558 			break;
559 		case LEAF_wlanIfaceWlanPrivacySubscribe:
560 			ctx->scratch->int1 = wif->priv_subscribe;
561 			break;
562 		case LEAF_wlanIfaceBgScan:
563 			ctx->scratch->int1 = wif->bg_scan;
564 			break;
565 		case LEAF_wlanIfaceBgScanIdle:
566 			ctx->scratch->int1 = wif->bg_scan_idle;
567 			break;
568 		case LEAF_wlanIfaceBgScanInterval:
569 			ctx->scratch->int1 = wif->bg_scan_interval;
570 			break;
571 		case LEAF_wlanIfaceBeaconMissedThreshold:
572 			ctx->scratch->int1 = wif->beacons_missed;
573 			break;
574 		case LEAF_wlanIfaceRoamingMode:
575 			ctx->scratch->int1 = wif->roam_mode;
576 			break;
577 		case LEAF_wlanIfaceDot11d:
578 			ctx->scratch->int1 = wif->dot11d;
579 			break;
580 		case LEAF_wlanIfaceDot11h:
581 			ctx->scratch->int1 = wif->dot11h;
582 			break;
583 		case LEAF_wlanIfaceDynamicWds:
584 			ctx->scratch->int1 = wif->dynamic_wds;
585 			break;
586 		case LEAF_wlanIfacePowerSave:
587 			ctx->scratch->int1 = wif->power_save;
588 			break;
589 		case LEAF_wlanIfaceApBridge:
590 			ctx->scratch->int1 = wif->ap_bridge;
591 			break;
592 		case LEAF_wlanIfaceBeaconInterval:
593 			ctx->scratch->int1 = wif->beacon_interval;
594 			break;
595 		case LEAF_wlanIfaceDtimPeriod:
596 			ctx->scratch->int1 = wif->dtim_period;
597 			break;
598 		case LEAF_wlanIfaceHideSsid:
599 			ctx->scratch->int1 = wif->hide_ssid;
600 			break;
601 		case LEAF_wlanIfaceInactivityProccess:
602 			ctx->scratch->int1 = wif->inact_process;
603 			break;
604 		case LEAF_wlanIfaceDot11gProtMode:
605 			ctx->scratch->int1 = wif->do11g_protect;
606 			break;
607 		case LEAF_wlanIfaceDot11gPureMode:
608 			ctx->scratch->int1 = wif->dot11g_pure;
609 			break;
610 		case LEAF_wlanIfaceDot11nPureMode:
611 			ctx->scratch->int1 = wif->dot11n_pure;
612 			break;
613 		case LEAF_wlanIfaceDot11nAmpdu:
614 			ctx->scratch->int1 = wif->ampdu;
615 			break;
616 		case LEAF_wlanIfaceDot11nAmpduDensity:
617 			ctx->scratch->int1 = wif->ampdu_density;
618 			break;
619 		case LEAF_wlanIfaceDot11nAmpduLimit:
620 			ctx->scratch->int1 = wif->ampdu_limit;
621 			break;
622 		case LEAF_wlanIfaceDot11nAmsdu:
623 			ctx->scratch->int1 = wif->amsdu;
624 			break;
625 		case LEAF_wlanIfaceDot11nAmsduLimit:
626 			ctx->scratch->int1 = wif->amsdu_limit;
627 			break;
628 		case LEAF_wlanIfaceDot11nHighThroughput:
629 			ctx->scratch->int1 = wif->ht_enabled;
630 			break;
631 		case LEAF_wlanIfaceDot11nHTCompatible:
632 			ctx->scratch->int1 = wif->ht_compatible;
633 			break;
634 		case LEAF_wlanIfaceDot11nHTProtMode:
635 			ctx->scratch->int1 = wif->ht_prot_mode;
636 			break;
637 		case LEAF_wlanIfaceDot11nRIFS:
638 			ctx->scratch->int1 = wif->rifs;
639 			break;
640 		case LEAF_wlanIfaceDot11nShortGI:
641 			ctx->scratch->int1 = wif->short_gi;
642 			break;
643 		case LEAF_wlanIfaceDot11nSMPSMode:
644 			ctx->scratch->int1 = wif->smps_mode;
645 			break;
646 		case LEAF_wlanIfaceTdmaSlot:
647 			ctx->scratch->int1 = wif->tdma_slot;
648 			break;
649 		case LEAF_wlanIfaceTdmaSlotCount:
650 			ctx->scratch->int1 = wif->tdma_slot_count;
651 			break;
652 		case LEAF_wlanIfaceTdmaSlotLength:
653 			ctx->scratch->int1 = wif->tdma_slot_length;
654 			break;
655 		case LEAF_wlanIfaceTdmaBeaconInterval:
656 			ctx->scratch->int1 = wif->tdma_binterval;
657 			break;
658 		default:
659 			abort();
660 		}
661 
662 		if (val->syntax != SNMP_SYNTAX_OCTETSTRING)
663 			goto set_config;
664 
665 		ctx->scratch->int1 = val->v.octetstring.len;
666 		ctx->scratch->ptr1 = malloc(val->v.octetstring.len + 1);
667 		if (ctx->scratch->ptr1 == NULL)
668 			return (SNMP_ERR_GENERR); /* XXX */
669 		if (val->var.subs[sub - 1] == LEAF_wlanIfaceDesiredSsid)
670 			strlcpy(ctx->scratch->ptr1, val->v.octetstring.octets,
671 			    val->v.octetstring.len + 1);
672 		else
673 			memcpy(ctx->scratch->ptr1, val->v.octetstring.octets,
674 			    val->v.octetstring.len);
675 		strval = val->v.octetstring.octets;
676 		vlen = val->v.octetstring.len;
677 		goto set_config;
678 
679 	case SNMP_OP_ROLLBACK:
680 		intval = ctx->scratch->int1;
681 		strval = NULL;
682 		vlen = 0;
683 
684 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
685 			return (SNMP_ERR_NOSUCHNAME);
686 		switch (val->var.subs[sub - 1]) {
687 		case LEAF_wlanIfaceCountryCode:
688 		case LEAF_wlanIfaceDesiredSsid:
689 		case LEAF_wlanIfaceDesiredBssid:
690 			strval = ctx->scratch->ptr1;
691 			vlen = ctx->scratch->int1;
692 			break;
693 		default:
694 			break;
695 		}
696 		goto set_config;
697 
698 	case SNMP_OP_COMMIT:
699 		switch (val->var.subs[sub - 1]) {
700 		case LEAF_wlanIfaceCountryCode:
701 		case LEAF_wlanIfaceDesiredSsid:
702 		case LEAF_wlanIfaceDesiredBssid:
703 			free(ctx->scratch->ptr1);
704 			/* FALLTHROUGH */
705 		default:
706 			return (SNMP_ERR_NOERROR);
707 		}
708 	}
709 	abort();
710 
711 get_config:
712 
713 	if (wlan_config_get_ioctl(wif, val->var.subs[sub - 1]) < 0)
714 		return (SNMP_ERR_GENERR);
715 
716 	switch (val->var.subs[sub - 1]) {
717 	case LEAF_wlanIfacePacketBurst:
718 		val->v.integer = wif->packet_burst;
719 		break;
720 	case LEAF_wlanIfaceCountryCode:
721 		return (string_get(val, wif->country_code,
722 		    WLAN_COUNTRY_CODE_SIZE));
723 	case LEAF_wlanIfaceRegDomain:
724 		val->v.integer = wif->reg_domain;
725 		break;
726 	case LEAF_wlanIfaceDesiredSsid:
727 		return (string_get(val, wif->desired_ssid, -1));
728 	case LEAF_wlanIfaceDesiredChannel:
729 		val->v.integer = wif->desired_channel;
730 		break;
731 	case LEAF_wlanIfaceDynamicFreqSelection:
732 		val->v.integer = wif->dyn_frequency;
733 		break;
734 	case LEAF_wlanIfaceFastFrames:
735 		val->v.integer = wif->fast_frames;
736 		break;
737 	case LEAF_wlanIfaceDturbo:
738 		val->v.integer = wif->dturbo;
739 		break;
740 	case LEAF_wlanIfaceTxPower:
741 		val->v.integer = wif->tx_power;
742 		break;
743 	case LEAF_wlanIfaceFragmentThreshold:
744 		val->v.integer = wif->frag_threshold;
745 		break;
746 	case LEAF_wlanIfaceRTSThreshold:
747 		val->v.integer = wif->rts_threshold;
748 		break;
749 	case LEAF_wlanIfaceWlanPrivacySubscribe:
750 		val->v.integer = wif->priv_subscribe;
751 		break;
752 	case LEAF_wlanIfaceBgScan:
753 		val->v.integer = wif->bg_scan;
754 		break;
755 	case LEAF_wlanIfaceBgScanIdle:
756 		val->v.integer = wif->bg_scan_idle;
757 		break;
758 	case LEAF_wlanIfaceBgScanInterval:
759 		val->v.integer = wif->bg_scan_interval;
760 		break;
761 	case LEAF_wlanIfaceBeaconMissedThreshold:
762 		val->v.integer = wif->beacons_missed;
763 		break;
764 	case LEAF_wlanIfaceDesiredBssid:
765 		return (string_get(val, wif->desired_bssid,
766 		    IEEE80211_ADDR_LEN));
767 	case LEAF_wlanIfaceRoamingMode:
768 		val->v.integer = wif->roam_mode;
769 		break;
770 	case LEAF_wlanIfaceDot11d:
771 		val->v.integer = wif->dot11d;
772 		break;
773 	case LEAF_wlanIfaceDot11h:
774 		val->v.integer = wif->dot11h;
775 		break;
776 	case LEAF_wlanIfaceDynamicWds:
777 		val->v.integer = wif->dynamic_wds;
778 		break;
779 	case LEAF_wlanIfacePowerSave:
780 		val->v.integer = wif->power_save;
781 		break;
782 	case LEAF_wlanIfaceApBridge:
783 		val->v.integer = wif->ap_bridge;
784 		break;
785 	case LEAF_wlanIfaceBeaconInterval:
786 		val->v.integer = wif->beacon_interval;
787 		break;
788 	case LEAF_wlanIfaceDtimPeriod:
789 		val->v.integer = wif->dtim_period;
790 		break;
791 	case LEAF_wlanIfaceHideSsid:
792 		val->v.integer = wif->hide_ssid;
793 		break;
794 	case LEAF_wlanIfaceInactivityProccess:
795 		val->v.integer = wif->inact_process;
796 		break;
797 	case LEAF_wlanIfaceDot11gProtMode:
798 		val->v.integer = wif->do11g_protect;
799 		break;
800 	case LEAF_wlanIfaceDot11gPureMode:
801 		val->v.integer = wif->dot11g_pure;
802 		break;
803 	case LEAF_wlanIfaceDot11nPureMode:
804 		val->v.integer = wif->dot11n_pure;
805 		break;
806 	case LEAF_wlanIfaceDot11nAmpdu:
807 		val->v.integer = wif->ampdu;
808 		break;
809 	case LEAF_wlanIfaceDot11nAmpduDensity:
810 		val->v.integer = wif->ampdu_density;
811 		break;
812 	case LEAF_wlanIfaceDot11nAmpduLimit:
813 		val->v.integer = wif->ampdu_limit;
814 		break;
815 	case LEAF_wlanIfaceDot11nAmsdu:
816 		val->v.integer = wif->amsdu;
817 		break;
818 	case LEAF_wlanIfaceDot11nAmsduLimit:
819 		val->v.integer = wif->amsdu_limit;
820 		break;
821 	case LEAF_wlanIfaceDot11nHighThroughput:
822 		val->v.integer = wif->ht_enabled;
823 		break;
824 	case LEAF_wlanIfaceDot11nHTCompatible:
825 		val->v.integer = wif->ht_compatible;
826 		break;
827 	case LEAF_wlanIfaceDot11nHTProtMode:
828 		val->v.integer = wif->ht_prot_mode;
829 		break;
830 	case LEAF_wlanIfaceDot11nRIFS:
831 		val->v.integer = wif->rifs;
832 		break;
833 	case LEAF_wlanIfaceDot11nShortGI:
834 		val->v.integer = wif->short_gi;
835 		break;
836 	case LEAF_wlanIfaceDot11nSMPSMode:
837 		val->v.integer = wif->smps_mode;
838 		break;
839 	case LEAF_wlanIfaceTdmaSlot:
840 		val->v.integer = wif->tdma_slot;
841 		break;
842 	case LEAF_wlanIfaceTdmaSlotCount:
843 		val->v.integer = wif->tdma_slot_count;
844 		break;
845 	case LEAF_wlanIfaceTdmaSlotLength:
846 		val->v.integer = wif->tdma_slot_length;
847 		break;
848 	case LEAF_wlanIfaceTdmaBeaconInterval:
849 		val->v.integer = wif->tdma_binterval;
850 		break;
851 	}
852 
853 	return (SNMP_ERR_NOERROR);
854 
855 set_config:
856 	rc = wlan_config_set_ioctl(wif, val->var.subs[sub - 1], intval,
857 	    strval, vlen);
858 
859 	if (op == SNMP_OP_ROLLBACK) {
860 		switch (val->var.subs[sub - 1]) {
861 		case LEAF_wlanIfaceCountryCode:
862 		case LEAF_wlanIfaceDesiredSsid:
863 		case LEAF_wlanIfaceDesiredBssid:
864 			free(ctx->scratch->ptr1);
865 			/* FALLTHROUGH */
866 		default:
867 			break;
868 		}
869 	}
870 
871 	if (rc < 0)
872 		return (SNMP_ERR_GENERR);
873 
874 	return (SNMP_ERR_NOERROR);
875 }
876 
877 int
878 op_wlan_if_peer(struct snmp_context *ctx, struct snmp_value *val, uint32_t sub,
879     uint32_t iidx __unused, enum snmp_op op)
880 {
881 	struct wlan_peer *wip;
882 	struct wlan_iface *wif;
883 
884 	wlan_update_interface_list();
885 	wlan_update_peers();
886 
887 	switch (op) {
888 	case SNMP_OP_GET:
889 		if ((wip = wlan_get_peer(&val->var, sub, &wif)) == NULL)
890 			return (SNMP_ERR_NOSUCHNAME);
891 		break;
892 	case SNMP_OP_GETNEXT:
893 		if ((wip = wlan_get_next_peer(&val->var, sub, &wif)) == NULL)
894 			return (SNMP_ERR_NOSUCHNAME);
895 		wlan_append_mac_index(&val->var, sub, wif->wname, wip->pmac);
896 		break;
897 	case SNMP_OP_SET:
898 		if ((wip = wlan_get_peer(&val->var, sub, &wif)) == NULL)
899 			return (SNMP_ERR_NOSUCHNAME);
900 		if (val->var.subs[sub - 1] != LEAF_wlanIfacePeerVlanTag)
901 			return (SNMP_ERR_GENERR);
902 		ctx->scratch->int1 = wip->vlan;
903 		if (wlan_peer_set_vlan(wif, wip, val->v.integer) < 0)
904 			return (SNMP_ERR_GENERR);
905 		return (SNMP_ERR_NOERROR);
906 	case SNMP_OP_COMMIT:
907 		return (SNMP_ERR_NOERROR);
908 	case SNMP_OP_ROLLBACK:
909 		if ((wip = wlan_get_peer(&val->var, sub, &wif)) == NULL)
910 			return (SNMP_ERR_NOSUCHNAME);
911 		if (val->var.subs[sub - 1] != LEAF_wlanIfacePeerVlanTag)
912 			return (SNMP_ERR_GENERR);
913 		if (wlan_peer_set_vlan(wif, wip, ctx->scratch->int1) < 0)
914 			return (SNMP_ERR_GENERR);
915 		return (SNMP_ERR_NOERROR);
916 	default:
917 		abort();
918 	}
919 
920 	switch (val->var.subs[sub - 1]) {
921 	case LEAF_wlanIfacePeerAddress:
922 		return (string_get(val, wip->pmac, IEEE80211_ADDR_LEN));
923 	case LEAF_wlanIfacePeerAssociationId:
924 		val->v.integer = wip->associd;
925 		break;
926 	case LEAF_wlanIfacePeerVlanTag:
927 		val->v.integer = wip->vlan;
928 		break;
929 	case LEAF_wlanIfacePeerFrequency:
930 		val->v.integer = wip->frequency;
931 		break;
932 	case LEAF_wlanIfacePeerCurrentTXRate:
933 		val->v.integer = wip->txrate;
934 		break;
935 	case LEAF_wlanIfacePeerRxSignalStrength:
936 		val->v.integer = wip->rssi;
937 		break;
938 	case LEAF_wlanIfacePeerIdleTimer:
939 		val->v.integer = wip->idle;
940 		break;
941 	case LEAF_wlanIfacePeerTxSequenceNo:
942 		val->v.integer = wip->txseqs;
943 		break;
944 	case LEAF_wlanIfacePeerRxSequenceNo:
945 		val->v.integer = wip->rxseqs;
946 		break;
947 	case LEAF_wlanIfacePeerTxPower:
948 		val->v.integer = wip->txpower;
949 		break;
950 	case LEAF_wlanIfacePeerCapabilities:
951 		return (bits_get(val, (uint8_t *)&wip->capinfo,
952 		    sizeof(wip->capinfo)));
953 	case LEAF_wlanIfacePeerFlags:
954 		return (bits_get(val, (uint8_t *)&wip->state,
955 		    sizeof(wip->state)));
956 	default:
957 		abort();
958 	}
959 
960 	return (SNMP_ERR_NOERROR);
961 }
962 
963 int
964 op_wlan_channels(struct snmp_context *ctx __unused, struct snmp_value *val,
965     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
966 {
967 	int32_t bits;
968 	struct ieee80211_channel *channel;
969 	struct wlan_iface *wif;
970 
971 	wlan_update_interface_list();
972 	wlan_update_channels();
973 
974 	switch (op) {
975 	case SNMP_OP_GET:
976 		if ((channel = wlan_get_channel(&val->var, sub, &wif)) == NULL)
977 			return (SNMP_ERR_NOSUCHNAME);
978 		break;
979 	case SNMP_OP_GETNEXT:
980 		channel = wlan_get_next_channel(&val->var, sub, &wif);
981 		if (channel == NULL || wif == NULL)
982 			return (SNMP_ERR_NOSUCHNAME);
983 		wlan_append_channel_index(&val->var, sub, wif, channel);
984 		break;
985 	case SNMP_OP_SET:
986 		return (SNMP_ERR_NOT_WRITEABLE);
987 	case SNMP_OP_COMMIT:
988 		/* FALLTHROUGH */
989 	case SNMP_OP_ROLLBACK:
990 		/* FALLTHROUGH */
991 	default:
992 		abort();
993 	}
994 
995 	switch (val->var.subs[sub - 1]) {
996 	case LEAF_wlanIfaceChannelIeeeId:
997 		val->v.integer = channel->ic_ieee;
998 		break;
999 	case LEAF_wlanIfaceChannelType:
1000 		val->v.integer = wlan_get_channel_type(channel);
1001 		break;
1002 	case LEAF_wlanIfaceChannelFlags:
1003 		bits = wlan_channel_flags_to_snmp(channel->ic_flags);
1004 		return (bits_get(val, (uint8_t *)&bits, sizeof(bits)));
1005 	case LEAF_wlanIfaceChannelFrequency:
1006 		val->v.integer = channel->ic_freq;
1007 		break;
1008 	case LEAF_wlanIfaceChannelMaxRegPower:
1009 		val->v.integer = channel->ic_maxregpower;
1010 		break;
1011 	case LEAF_wlanIfaceChannelMaxTxPower:
1012 		val->v.integer = channel->ic_maxpower;
1013 		break;
1014 	case LEAF_wlanIfaceChannelMinTxPower:
1015 		val->v.integer = channel->ic_minpower;
1016 		break;
1017 	case LEAF_wlanIfaceChannelState:
1018 		bits = wlan_channel_state_to_snmp(channel->ic_state);
1019 		return (bits_get(val, (uint8_t *)&bits, sizeof(bits)));
1020 	case LEAF_wlanIfaceChannelHTExtension:
1021 		val->v.integer = channel->ic_extieee;
1022 		break;
1023 	case LEAF_wlanIfaceChannelMaxAntennaGain:
1024 		val->v.integer = channel->ic_maxantgain;
1025 		break;
1026 	}
1027 
1028 	return (SNMP_ERR_NOERROR);
1029 }
1030 
1031 int
1032 op_wlan_roam_params(struct snmp_context *ctx __unused, struct snmp_value *val,
1033     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
1034 {
1035 	uint32_t phy;
1036 	struct ieee80211_roamparam *rparam;
1037 	struct wlan_iface *wif;
1038 
1039 	wlan_update_interface_list();
1040 	wlan_update_roam_params();
1041 
1042 	switch (op) {
1043 	case SNMP_OP_GET:
1044 		rparam = wlan_get_roam_param(&val->var, sub, &wif);
1045 		if (rparam == NULL)
1046 			return (SNMP_ERR_NOSUCHNAME);
1047 		break;
1048 	case SNMP_OP_GETNEXT:
1049 		rparam = wlan_get_next_roam_param(&val->var, sub, &wif, &phy);
1050 		if (rparam == NULL || wif == NULL)
1051 			return (SNMP_ERR_NOSUCHNAME);
1052 		wlan_append_phy_index(&val->var, sub, wif->wname, phy);
1053 		break;
1054 	case SNMP_OP_SET:
1055 		return (SNMP_ERR_NOT_WRITEABLE);
1056 	case SNMP_OP_COMMIT:
1057 		/* FALLTHROUGH */
1058 	case SNMP_OP_ROLLBACK:
1059 		/* FALLTHROUGH */
1060 	default:
1061 		abort();
1062 	}
1063 
1064 	switch (val->var.subs[sub - 1]) {
1065 	case LEAF_wlanIfRoamRxSignalStrength:
1066 		val->v.integer = rparam->rssi/2;
1067 		break;
1068 	case LEAF_wlanIfRoamTxRateThreshold:
1069 		val->v.integer = rparam->rate/2;
1070 		break;
1071 	default:
1072 		abort();
1073 	}
1074 
1075 	return (SNMP_ERR_NOERROR);
1076 }
1077 
1078 int
1079 op_wlan_tx_params(struct snmp_context *ctx, struct snmp_value *val,
1080     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
1081 {
1082 	uint32_t phy;
1083 	struct ieee80211_txparam *txparam;
1084 	struct wlan_iface *wif;
1085 
1086 	wlan_update_interface_list();
1087 	wlan_update_tx_params();
1088 
1089 	switch (op) {
1090 	case SNMP_OP_GET:
1091 		txparam = wlan_get_tx_param(&val->var, sub, &wif, &phy);
1092 		if (txparam == NULL)
1093 			return (SNMP_ERR_NOSUCHNAME);
1094 		goto get_txparams;
1095 
1096 	case SNMP_OP_GETNEXT:
1097 		txparam = wlan_get_next_tx_param(&val->var, sub, &wif, &phy);
1098 		if (txparam == NULL || wif == NULL)
1099 			return (SNMP_ERR_NOSUCHNAME);
1100 		wlan_append_phy_index(&val->var, sub, wif->wname, phy);
1101 		goto get_txparams;
1102 
1103 	case SNMP_OP_SET:
1104 		txparam = wlan_get_tx_param(&val->var, sub, &wif, &phy);
1105 		if (txparam == NULL || wif == NULL)
1106 			return (SNMP_ERR_NOSUCHNAME);
1107 		switch (val->var.subs[sub - 1]) {
1108 		case LEAF_wlanIfTxUnicastRate:
1109 			ctx->scratch->int1 = txparam->ucastrate;
1110 			txparam->ucastrate = val->v.integer * 2;
1111 			break;
1112 		case LEAF_wlanIfTxMcastRate:
1113 			ctx->scratch->int1 = txparam->mcastrate;
1114 			txparam->mcastrate = val->v.integer * 2;
1115 			break;
1116 		case LEAF_wlanIfTxMgmtRate:
1117 			ctx->scratch->int1 = txparam->mgmtrate;
1118 			txparam->mgmtrate = val->v.integer * 2;
1119 			break;
1120 		case LEAF_wlanIfTxMaxRetryCount:
1121 			ctx->scratch->int1 = txparam->maxretry;
1122 			txparam->maxretry = val->v.integer;
1123 			break;
1124 		default:
1125 			abort();
1126 		}
1127 		if (wlan_set_tx_params(wif, phy) < 0)
1128 			return (SNMP_ERR_GENERR);
1129 		return (SNMP_ERR_NOERROR);
1130 
1131 	case SNMP_OP_COMMIT:
1132 		return (SNMP_ERR_NOERROR);
1133 
1134 	case SNMP_OP_ROLLBACK:
1135 		txparam = wlan_get_tx_param(&val->var, sub, &wif, &phy);
1136 		if (txparam == NULL || wif == NULL)
1137 			return (SNMP_ERR_NOSUCHNAME);
1138 		switch (val->var.subs[sub - 1]) {
1139 		case LEAF_wlanIfTxUnicastRate:
1140 			txparam->ucastrate = ctx->scratch->int1;
1141 			break;
1142 		case LEAF_wlanIfTxMcastRate:
1143 			txparam->mcastrate = ctx->scratch->int1;
1144 			break;
1145 		case LEAF_wlanIfTxMgmtRate:
1146 			txparam->mgmtrate = ctx->scratch->int1;
1147 			break;
1148 		case LEAF_wlanIfTxMaxRetryCount:
1149 			txparam->maxretry = ctx->scratch->int1;
1150 			break;
1151 		default:
1152 			abort();
1153 		}
1154 		if (wlan_set_tx_params(wif, phy) < 0)
1155 			return (SNMP_ERR_GENERR);
1156 		return (SNMP_ERR_NOERROR);
1157 	default:
1158 		abort();
1159 	}
1160 
1161 get_txparams:
1162 	switch (val->var.subs[sub - 1]) {
1163 	case LEAF_wlanIfTxUnicastRate:
1164 		val->v.integer = txparam->ucastrate / 2;
1165 		break;
1166 	case LEAF_wlanIfTxMcastRate:
1167 		val->v.integer = txparam->mcastrate / 2;
1168 		break;
1169 	case LEAF_wlanIfTxMgmtRate:
1170 		val->v.integer = txparam->mgmtrate / 2;
1171 		break;
1172 	case LEAF_wlanIfTxMaxRetryCount:
1173 		val->v.integer = txparam->maxretry;
1174 		break;
1175 	default:
1176 		abort();
1177 	}
1178 
1179 	return (SNMP_ERR_NOERROR);
1180 }
1181 
1182 int
1183 op_wlan_scan_config(struct snmp_context *ctx, struct snmp_value *val,
1184     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
1185 {
1186 	struct wlan_iface *wif;
1187 
1188 	wlan_update_interface_list();
1189 
1190 	switch (op) {
1191 	case SNMP_OP_GET:
1192 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
1193 			return (SNMP_ERR_NOSUCHNAME);
1194 		break;
1195 
1196 	case SNMP_OP_GETNEXT:
1197 		if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
1198 			return (SNMP_ERR_NOSUCHNAME);
1199 		wlan_append_ifindex(&val->var, sub, wif);
1200 		break;
1201 
1202 	case SNMP_OP_SET:
1203 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
1204 			return (SNMP_ERR_NOSUCHNAME);
1205 		if (wif->scan_status ==  wlanScanConfigStatus_running
1206 		    && val->var.subs[sub - 1] != LEAF_wlanScanConfigStatus)
1207 			return (SNMP_ERR_INCONS_VALUE);
1208 		switch (val->var.subs[sub - 1]) {
1209 		case LEAF_wlanScanFlags:
1210 			ctx->scratch->int1 = wif->scan_flags;
1211 			wif->scan_flags = val->v.integer;
1212 			break;
1213 		case LEAF_wlanScanDuration:
1214 			ctx->scratch->int1 = wif->scan_duration;
1215 			wif->scan_duration = val->v.integer;
1216 			break;
1217 		case LEAF_wlanScanMinChannelDwellTime:
1218 			ctx->scratch->int1 = wif->scan_mindwell;
1219 			wif->scan_mindwell = val->v.integer;
1220 			break;
1221 		case LEAF_wlanScanMaxChannelDwellTime:
1222 			ctx->scratch->int1 = wif->scan_maxdwell;
1223 			wif->scan_maxdwell = val->v.integer;
1224 			break;
1225 		case LEAF_wlanScanConfigStatus:
1226 			if (val->v.integer == wlanScanConfigStatus_running ||
1227 			    val->v.integer == wlanScanConfigStatus_cancel) {
1228 				ctx->scratch->int1 = wif->scan_status;
1229 				wif->scan_status = val->v.integer;
1230 				break;
1231 			}
1232 			return (SNMP_ERR_INCONS_VALUE);
1233 		}
1234 		return (SNMP_ERR_NOERROR);
1235 
1236 	case SNMP_OP_COMMIT:
1237 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
1238 			return (SNMP_ERR_NOSUCHNAME);
1239 		if (val->var.subs[sub - 1] == LEAF_wlanScanConfigStatus)
1240 			if (wif->scan_status == wlanScanConfigStatus_running)
1241 				(void)wlan_set_scan_config(wif); /* XXX */
1242 		return (SNMP_ERR_NOERROR);
1243 
1244 	case SNMP_OP_ROLLBACK:
1245 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
1246 			return (SNMP_ERR_NOSUCHNAME);
1247 		switch (val->var.subs[sub - 1]) {
1248 		case LEAF_wlanScanFlags:
1249 			wif->scan_flags = ctx->scratch->int1;
1250 			break;
1251 		case LEAF_wlanScanDuration:
1252 			wif->scan_duration = ctx->scratch->int1;
1253 			break;
1254 		case LEAF_wlanScanMinChannelDwellTime:
1255 			wif->scan_mindwell = ctx->scratch->int1;
1256 			break;
1257 		case LEAF_wlanScanMaxChannelDwellTime:
1258 			wif->scan_maxdwell = ctx->scratch->int1;
1259 			break;
1260 		case LEAF_wlanScanConfigStatus:
1261 			wif->scan_status = ctx->scratch->int1;
1262 			break;
1263 		}
1264 		return (SNMP_ERR_NOERROR);
1265 	default:
1266 		abort();
1267 	}
1268 
1269 	switch (val->var.subs[sub - 1]) {
1270 	case LEAF_wlanScanFlags:
1271 		val->v.integer = wif->scan_flags;
1272 		break;
1273 	case LEAF_wlanScanDuration:
1274 		val->v.integer = wif->scan_duration;
1275 		break;
1276 	case LEAF_wlanScanMinChannelDwellTime:
1277 		val->v.integer = wif->scan_mindwell;
1278 		break;
1279 	case LEAF_wlanScanMaxChannelDwellTime:
1280 		val->v.integer = wif->scan_maxdwell;
1281 		break;
1282 	case LEAF_wlanScanConfigStatus:
1283 		val->v.integer = wif->scan_status;
1284 		break;
1285 	}
1286 
1287 	return (SNMP_ERR_NOERROR);
1288 }
1289 
1290 int
1291 op_wlan_scan_results(struct snmp_context *ctx __unused, struct snmp_value *val,
1292     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
1293 {
1294 	struct wlan_scan_result *sr;
1295 	struct wlan_iface *wif;
1296 
1297 	wlan_update_interface_list();
1298 	wlan_scan_update_results();
1299 
1300 	switch (op) {
1301 	case SNMP_OP_GET:
1302 		if ((sr = wlan_get_scanr(&val->var, sub, &wif)) == NULL)
1303 			return (SNMP_ERR_NOSUCHNAME);
1304 		break;
1305 
1306 	case SNMP_OP_GETNEXT:
1307 		if ((sr = wlan_get_next_scanr(&val->var, sub, &wif)) == NULL)
1308 			return (SNMP_ERR_NOSUCHNAME);
1309 		wlan_append_scanr_index(&val->var, sub, wif->wname, sr->ssid,
1310 		    sr->bssid);
1311 		break;
1312 
1313 	case SNMP_OP_SET:
1314 		return (SNMP_ERR_NOT_WRITEABLE);
1315 	case SNMP_OP_COMMIT:
1316 		/* FALLTHROUGH */
1317 	case SNMP_OP_ROLLBACK:
1318 		/* FALLTHROUGH */
1319 	default:
1320 		abort();
1321 	}
1322 
1323 	switch (val->var.subs[sub - 1]) {
1324 	case LEAF_wlanScanResultID:
1325 		return (string_get(val, sr->ssid, -1));
1326 	case LEAF_wlanScanResultBssid:
1327 		return (string_get(val, sr->bssid, IEEE80211_ADDR_LEN));
1328 	case LEAF_wlanScanResultChannel:
1329 		val->v.integer = sr->opchannel; /* XXX */
1330 		break;
1331 	case LEAF_wlanScanResultRate:
1332 		val->v.integer = sr->rssi;
1333 		break;
1334 	case LEAF_wlanScanResultNoise:
1335 		val->v.integer = sr->noise;
1336 		break;
1337 	case LEAF_wlanScanResultBeaconInterval:
1338 		val->v.integer = sr->bintval;
1339 		break;
1340 	case LEAF_wlanScanResultCapabilities:
1341 		return (bits_get(val, &sr->capinfo, sizeof(sr->capinfo)));
1342 	default:
1343 		abort();
1344 	}
1345 
1346 	return (SNMP_ERR_NOERROR);
1347 }
1348 
1349 int
1350 op_wlan_iface_stats(struct snmp_context *ctx __unused, struct snmp_value *val,
1351     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
1352 {
1353 	struct wlan_iface *wif;
1354 
1355 	wlan_update_interface_list();
1356 
1357 	switch (op) {
1358 	case SNMP_OP_GET:
1359 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
1360 			return (SNMP_ERR_NOSUCHNAME);
1361 		break;
1362 	case SNMP_OP_GETNEXT:
1363 		if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
1364 			return (SNMP_ERR_NOSUCHNAME);
1365 		wlan_append_ifindex(&val->var, sub, wif);
1366 		break;
1367 	case SNMP_OP_SET:
1368 		/* XXX: LEAF_wlanStatsReset */
1369 		return (SNMP_ERR_NOT_WRITEABLE);
1370 	case SNMP_OP_COMMIT:
1371 		/* FALLTHROUGH */
1372 	case SNMP_OP_ROLLBACK:
1373 		/* FALLTHROUGH */
1374 	default:
1375 		abort();
1376 	}
1377 
1378 	if (wlan_get_stats(wif) < 0)
1379 		return (SNMP_ERR_GENERR);
1380 
1381 	switch (val->var.subs[sub - 1]) {
1382 	case LEAF_wlanStatsRxBadVersion:
1383 		val->v.uint32 = wif->stats.is_rx_badversion;
1384 		break;
1385 	case LEAF_wlanStatsRxTooShort:
1386 		val->v.uint32 = wif->stats.is_rx_tooshort;
1387 		break;
1388 	case LEAF_wlanStatsRxWrongBssid:
1389 		val->v.uint32 = wif->stats.is_rx_wrongbss;
1390 		break;
1391 	case LEAF_wlanStatsRxDiscardedDups:
1392 		val->v.uint32 = wif->stats.is_rx_dup;
1393 		break;
1394 	case LEAF_wlanStatsRxWrongDir:
1395 		val->v.uint32 = wif->stats.is_rx_wrongdir;
1396 		break;
1397 	case LEAF_wlanStatsRxDiscardMcastEcho:
1398 		val->v.uint32 = wif->stats.is_rx_mcastecho;
1399 		break;
1400 	case LEAF_wlanStatsRxDiscardNoAssoc:
1401 		val->v.uint32 = wif->stats.is_rx_notassoc;
1402 		break;
1403 	case LEAF_wlanStatsRxWepNoPrivacy:
1404 		val->v.uint32 = wif->stats.is_rx_noprivacy;
1405 		break;
1406 	case LEAF_wlanStatsRxWepUnencrypted:
1407 		val->v.uint32 = wif->stats.is_rx_unencrypted;
1408 		break;
1409 	case LEAF_wlanStatsRxWepFailed:
1410 		val->v.uint32 = wif->stats.is_rx_wepfail;
1411 		break;
1412 	case LEAF_wlanStatsRxDecapsulationFailed:
1413 		val->v.uint32 = wif->stats.is_rx_decap;
1414 		break;
1415 	case LEAF_wlanStatsRxDiscardMgmt:
1416 		val->v.uint32 = wif->stats.is_rx_mgtdiscard;
1417 		break;
1418 	case LEAF_wlanStatsRxControl:
1419 		val->v.uint32 = wif->stats.is_rx_ctl;
1420 		break;
1421 	case LEAF_wlanStatsRxBeacon:
1422 		val->v.uint32 = wif->stats.is_rx_beacon;
1423 		break;
1424 	case LEAF_wlanStatsRxRateSetTooBig:
1425 		val->v.uint32 = wif->stats.is_rx_rstoobig;
1426 		break;
1427 	case LEAF_wlanStatsRxElemMissing:
1428 		val->v.uint32 = wif->stats.is_rx_elem_missing;
1429 		break;
1430 	case LEAF_wlanStatsRxElemTooBig:
1431 		val->v.uint32 = wif->stats.is_rx_elem_toobig;
1432 		break;
1433 	case LEAF_wlanStatsRxElemTooSmall:
1434 		val->v.uint32 = wif->stats.is_rx_elem_toosmall;
1435 		break;
1436 	case LEAF_wlanStatsRxElemUnknown:
1437 		val->v.uint32 = wif->stats.is_rx_elem_unknown;
1438 		break;
1439 	case LEAF_wlanStatsRxChannelMismatch:
1440 		val->v.uint32 = wif->stats.is_rx_chanmismatch;
1441 		break;
1442 	case LEAF_wlanStatsRxDropped:
1443 		val->v.uint32 = wif->stats.is_rx_nodealloc;
1444 		break;
1445 	case LEAF_wlanStatsRxSsidMismatch:
1446 		val->v.uint32 = wif->stats.is_rx_ssidmismatch;
1447 		break;
1448 	case LEAF_wlanStatsRxAuthNotSupported:
1449 		val->v.uint32 = wif->stats.is_rx_auth_unsupported;
1450 		break;
1451 	case LEAF_wlanStatsRxAuthFailed:
1452 		val->v.uint32 = wif->stats.is_rx_auth_fail;
1453 		break;
1454 	case LEAF_wlanStatsRxAuthCM:
1455 		val->v.uint32 = wif->stats.is_rx_auth_countermeasures;
1456 		break;
1457 	case LEAF_wlanStatsRxAssocWrongBssid:
1458 		val->v.uint32 = wif->stats.is_rx_assoc_bss;
1459 		break;
1460 	case LEAF_wlanStatsRxAssocNoAuth:
1461 		val->v.uint32 = wif->stats.is_rx_assoc_notauth;
1462 		break;
1463 	case LEAF_wlanStatsRxAssocCapMismatch:
1464 		val->v.uint32 = wif->stats.is_rx_assoc_capmismatch;
1465 		break;
1466 	case LEAF_wlanStatsRxAssocNoRateMatch:
1467 		val->v.uint32 = wif->stats.is_rx_assoc_norate;
1468 		break;
1469 	case LEAF_wlanStatsRxBadWpaIE:
1470 		val->v.uint32 = wif->stats.is_rx_assoc_badwpaie;
1471 		break;
1472 	case LEAF_wlanStatsRxDeauthenticate:
1473 		val->v.uint32 = wif->stats.is_rx_deauth;
1474 		break;
1475 	case LEAF_wlanStatsRxDisassociate:
1476 		val->v.uint32 = wif->stats.is_rx_disassoc;
1477 		break;
1478 	case LEAF_wlanStatsRxUnknownSubtype:
1479 		val->v.uint32 = wif->stats.is_rx_badsubtype;
1480 		break;
1481 	case LEAF_wlanStatsRxFailedNoBuf:
1482 		val->v.uint32 = wif->stats.is_rx_nobuf;
1483 		break;
1484 	case LEAF_wlanStatsRxBadAuthRequest:
1485 		val->v.uint32 = wif->stats.is_rx_bad_auth;
1486 		break;
1487 	case LEAF_wlanStatsRxUnAuthorized:
1488 		val->v.uint32 = wif->stats.is_rx_unauth;
1489 		break;
1490 	case LEAF_wlanStatsRxBadKeyId:
1491 		val->v.uint32 = wif->stats.is_rx_badkeyid;
1492 		break;
1493 	case LEAF_wlanStatsRxCCMPSeqViolation:
1494 		val->v.uint32 = wif->stats.is_rx_ccmpreplay;
1495 		break;
1496 	case LEAF_wlanStatsRxCCMPBadFormat:
1497 		val->v.uint32 = wif->stats.is_rx_ccmpformat;
1498 		break;
1499 	case LEAF_wlanStatsRxCCMPFailedMIC:
1500 		val->v.uint32 = wif->stats.is_rx_ccmpmic;
1501 		break;
1502 	case LEAF_wlanStatsRxTKIPSeqViolation:
1503 		val->v.uint32 = wif->stats.is_rx_tkipreplay;
1504 		break;
1505 	case LEAF_wlanStatsRxTKIPBadFormat:
1506 		val->v.uint32 = wif->stats.is_rx_tkipformat;
1507 		break;
1508 	case LEAF_wlanStatsRxTKIPFailedMIC:
1509 		val->v.uint32 = wif->stats.is_rx_tkipmic;
1510 		break;
1511 	case LEAF_wlanStatsRxTKIPFailedICV:
1512 		val->v.uint32 = wif->stats.is_rx_tkipicv;
1513 		break;
1514 	case LEAF_wlanStatsRxDiscardACL:
1515 		val->v.uint32 = wif->stats.is_rx_acl;
1516 		break;
1517 	case LEAF_wlanStatsTxFailedNoBuf:
1518 		val->v.uint32 = wif->stats.is_tx_nobuf;
1519 		break;
1520 	case LEAF_wlanStatsTxFailedNoNode:
1521 		val->v.uint32 = wif->stats.is_tx_nonode;
1522 		break;
1523 	case LEAF_wlanStatsTxUnknownMgmt:
1524 		val->v.uint32 = wif->stats.is_tx_unknownmgt;
1525 		break;
1526 	case LEAF_wlanStatsTxBadCipher:
1527 		val->v.uint32 = wif->stats.is_tx_badcipher;
1528 		break;
1529 	case LEAF_wlanStatsTxNoDefKey:
1530 		val->v.uint32 = wif->stats.is_tx_nodefkey;
1531 		break;
1532 	case LEAF_wlanStatsTxFragmented:
1533 		val->v.uint32 = wif->stats.is_tx_fragframes;
1534 		break;
1535 	case LEAF_wlanStatsTxFragmentsCreated:
1536 		val->v.uint32 = wif->stats.is_tx_frags;
1537 		break;
1538 	case LEAF_wlanStatsActiveScans:
1539 		val->v.uint32 = wif->stats.is_scan_active;
1540 		break;
1541 	case LEAF_wlanStatsPassiveScans:
1542 		val->v.uint32 = wif->stats.is_scan_passive;
1543 		break;
1544 	case LEAF_wlanStatsTimeoutInactivity:
1545 		val->v.uint32 = wif->stats.is_node_timeout;
1546 		break;
1547 	case LEAF_wlanStatsCryptoNoMem:
1548 		val->v.uint32 = wif->stats.is_crypto_nomem;
1549 		break;
1550 	case LEAF_wlanStatsSwCryptoTKIP:
1551 		val->v.uint32 = wif->stats.is_crypto_tkip;
1552 		break;
1553 	case LEAF_wlanStatsSwCryptoTKIPEnMIC:
1554 		val->v.uint32 = wif->stats.is_crypto_tkipenmic;
1555 		break;
1556 	case LEAF_wlanStatsSwCryptoTKIPDeMIC:
1557 		val->v.uint32 = wif->stats.is_crypto_tkipdemic;
1558 		break;
1559 	case LEAF_wlanStatsCryptoTKIPCM:
1560 		val->v.uint32 = wif->stats.is_crypto_tkipcm;
1561 		break;
1562 	case LEAF_wlanStatsSwCryptoCCMP:
1563 		val->v.uint32 = wif->stats.is_crypto_ccmp;
1564 		break;
1565 	case LEAF_wlanStatsSwCryptoWEP:
1566 		val->v.uint32 = wif->stats.is_crypto_wep;
1567 		break;
1568 	case LEAF_wlanStatsCryptoCipherKeyRejected:
1569 		val->v.uint32 = wif->stats.is_crypto_setkey_cipher;
1570 		break;
1571 	case LEAF_wlanStatsCryptoNoKey:
1572 		val->v.uint32 = wif->stats.is_crypto_setkey_nokey;
1573 		break;
1574 	case LEAF_wlanStatsCryptoDeleteKeyFailed:
1575 		val->v.uint32 = wif->stats.is_crypto_delkey;
1576 		break;
1577 	case LEAF_wlanStatsCryptoUnknownCipher:
1578 		val->v.uint32 = wif->stats.is_crypto_badcipher;
1579 		break;
1580 	case LEAF_wlanStatsCryptoAttachFailed:
1581 		val->v.uint32 = wif->stats.is_crypto_attachfail;
1582 		break;
1583 	case LEAF_wlanStatsCryptoKeyFailed:
1584 		val->v.uint32 = wif->stats.is_crypto_keyfail;
1585 		break;
1586 	case LEAF_wlanStatsCryptoEnMICFailed:
1587 		val->v.uint32 = wif->stats.is_crypto_enmicfail;
1588 		break;
1589 	case LEAF_wlanStatsIBSSCapMismatch:
1590 		val->v.uint32 = wif->stats.is_ibss_capmismatch;
1591 		break;
1592 	case LEAF_wlanStatsUnassocStaPSPoll:
1593 		val->v.uint32 = wif->stats.is_ps_unassoc;
1594 		break;
1595 	case LEAF_wlanStatsBadAidPSPoll:
1596 		val->v.uint32 = wif->stats.is_ps_badaid;
1597 		break;
1598 	case LEAF_wlanStatsEmptyPSPoll:
1599 		val->v.uint32 = wif->stats.is_ps_qempty;
1600 		break;
1601 	case LEAF_wlanStatsRxFFBadHdr:
1602 		val->v.uint32 = wif->stats.is_ff_badhdr;
1603 		break;
1604 	case LEAF_wlanStatsRxFFTooShort:
1605 		val->v.uint32 = wif->stats.is_ff_tooshort;
1606 		break;
1607 	case LEAF_wlanStatsRxFFSplitError:
1608 		val->v.uint32 = wif->stats.is_ff_split;
1609 		break;
1610 	case LEAF_wlanStatsRxFFDecap:
1611 		val->v.uint32 = wif->stats.is_ff_decap;
1612 		break;
1613 	case LEAF_wlanStatsTxFFEncap:
1614 		val->v.uint32 = wif->stats.is_ff_encap;
1615 		break;
1616 	case LEAF_wlanStatsRxBadBintval:
1617 		val->v.uint32 = wif->stats.is_rx_badbintval;
1618 		break;
1619 	case LEAF_wlanStatsRxDemicFailed:
1620 		val->v.uint32 = wif->stats.is_rx_demicfail;
1621 		break;
1622 	case LEAF_wlanStatsRxDefragFailed:
1623 		val->v.uint32 = wif->stats.is_rx_defrag;
1624 		break;
1625 	case LEAF_wlanStatsRxMgmt:
1626 		val->v.uint32 = wif->stats.is_rx_mgmt;
1627 		break;
1628 	case LEAF_wlanStatsRxActionMgmt:
1629 		val->v.uint32 = wif->stats.is_rx_action;
1630 		break;
1631 	case LEAF_wlanStatsRxAMSDUTooShort:
1632 		val->v.uint32 = wif->stats.is_amsdu_tooshort;
1633 		break;
1634 	case LEAF_wlanStatsRxAMSDUSplitError:
1635 		val->v.uint32 = wif->stats.is_amsdu_split;
1636 		break;
1637 	case LEAF_wlanStatsRxAMSDUDecap:
1638 		val->v.uint32 = wif->stats.is_amsdu_decap;
1639 		break;
1640 	case LEAF_wlanStatsTxAMSDUEncap:
1641 		val->v.uint32 = wif->stats.is_amsdu_encap;
1642 		break;
1643 	case LEAF_wlanStatsAMPDUBadBAR:
1644 		val->v.uint32 = wif->stats.is_ampdu_bar_bad;
1645 		break;
1646 	case LEAF_wlanStatsAMPDUOowBar:
1647 		val->v.uint32 = wif->stats.is_ampdu_bar_oow;
1648 		break;
1649 	case LEAF_wlanStatsAMPDUMovedBAR:
1650 		val->v.uint32 = wif->stats.is_ampdu_bar_move;
1651 		break;
1652 	case LEAF_wlanStatsAMPDURxBAR:
1653 		val->v.uint32 = wif->stats.is_ampdu_bar_rx;
1654 		break;
1655 	case LEAF_wlanStatsAMPDURxOor:
1656 		val->v.uint32 = wif->stats.is_ampdu_rx_oor;
1657 		break;
1658 	case LEAF_wlanStatsAMPDURxCopied:
1659 		val->v.uint32 = wif->stats.is_ampdu_rx_copy;
1660 		break;
1661 	case LEAF_wlanStatsAMPDURxDropped:
1662 		val->v.uint32 = wif->stats.is_ampdu_rx_drop;
1663 		break;
1664 	case LEAF_wlanStatsTxDiscardBadState:
1665 		val->v.uint32 = wif->stats.is_tx_badstate;
1666 		break;
1667 	case LEAF_wlanStatsTxFailedNoAssoc:
1668 		val->v.uint32 = wif->stats.is_tx_notassoc;
1669 		break;
1670 	case LEAF_wlanStatsTxClassifyFailed:
1671 		val->v.uint32 = wif->stats.is_tx_classify;
1672 		break;
1673 	case LEAF_wlanStatsDwdsMcastDiscard:
1674 		val->v.uint32 = wif->stats.is_dwds_mcast;
1675 		break;
1676 	case LEAF_wlanStatsHTAssocRejectNoHT:
1677 		val->v.uint32 = wif->stats.is_ht_assoc_nohtcap;
1678 		break;
1679 	case LEAF_wlanStatsHTAssocDowngrade:
1680 		val->v.uint32 = wif->stats.is_ht_assoc_downgrade;
1681 		break;
1682 	case LEAF_wlanStatsHTAssocRateMismatch:
1683 		val->v.uint32 = wif->stats.is_ht_assoc_norate;
1684 		break;
1685 	case LEAF_wlanStatsAMPDURxAge:
1686 		val->v.uint32 = wif->stats.is_ampdu_rx_age;
1687 		break;
1688 	case LEAF_wlanStatsAMPDUMoved:
1689 		val->v.uint32 = wif->stats.is_ampdu_rx_move;
1690 		break;
1691 	case LEAF_wlanStatsADDBADisabledReject:
1692 		val->v.uint32 = wif->stats.is_addba_reject;
1693 		break;
1694 	case LEAF_wlanStatsADDBANoRequest:
1695 		val->v.uint32 = wif->stats.is_addba_norequest;
1696 		break;
1697 	case LEAF_wlanStatsADDBABadToken:
1698 		val->v.uint32 = wif->stats.is_addba_badtoken;
1699 		break;
1700 	case LEAF_wlanStatsADDBABadPolicy:
1701 		val->v.uint32 = wif->stats.is_addba_badpolicy;
1702 		break;
1703 	case LEAF_wlanStatsAMPDUStopped:
1704 		val->v.uint32 = wif->stats.is_ampdu_stop;
1705 		break;
1706 	case LEAF_wlanStatsAMPDUStopFailed:
1707 		val->v.uint32 = wif->stats.is_ampdu_stop_failed;
1708 		break;
1709 	case LEAF_wlanStatsAMPDURxReorder:
1710 		val->v.uint32 = wif->stats.is_ampdu_rx_reorder;
1711 		break;
1712 	case LEAF_wlanStatsScansBackground:
1713 		val->v.uint32 = wif->stats.is_scan_bg;
1714 		break;
1715 	case LEAF_wlanLastDeauthReason:
1716 		val->v.uint32 = wif->stats.is_rx_deauth_code;
1717 		break;
1718 	case LEAF_wlanLastDissasocReason:
1719 		val->v.uint32 = wif->stats.is_rx_disassoc_code;
1720 		break;
1721 	case LEAF_wlanLastAuthFailReason:
1722 		val->v.uint32 = wif->stats.is_rx_authfail_code;
1723 		break;
1724 	case LEAF_wlanStatsBeaconMissedEvents:
1725 		val->v.uint32 = wif->stats.is_beacon_miss;
1726 		break;
1727 	case LEAF_wlanStatsRxDiscardBadStates:
1728 		val->v.uint32 = wif->stats.is_rx_badstate;
1729 		break;
1730 	case LEAF_wlanStatsFFFlushed:
1731 		val->v.uint32 = wif->stats.is_ff_flush;
1732 		break;
1733 	case LEAF_wlanStatsTxControlFrames:
1734 		val->v.uint32 = wif->stats.is_tx_ctl;
1735 		break;
1736 	case LEAF_wlanStatsAMPDURexmt:
1737 		val->v.uint32 = wif->stats.is_ampdu_rexmt;
1738 		break;
1739 	case LEAF_wlanStatsAMPDURexmtFailed:
1740 		val->v.uint32 = wif->stats.is_ampdu_rexmt_fail;
1741 		break;
1742 	case LEAF_wlanStatsReset:
1743 		val->v.uint32 = wlanStatsReset_no_op;
1744 		break;
1745 	default:
1746 		abort();
1747 	}
1748 
1749 	return (SNMP_ERR_NOERROR);
1750 }
1751 
1752 int
1753 op_wlan_wep_iface(struct snmp_context *ctx, struct snmp_value *val,
1754     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
1755 {
1756 	struct wlan_iface *wif;
1757 
1758 	wlan_update_interface_list();
1759 
1760 	switch (op) {
1761 	case SNMP_OP_GET:
1762 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL ||
1763 		    !wif->wepsupported)
1764 			return (SNMP_ERR_NOSUCHNAME);
1765 		break;
1766 
1767 	case SNMP_OP_GETNEXT:
1768 		/* XXX: filter wif->wepsupported */
1769 		if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
1770 			return (SNMP_ERR_NOSUCHNAME);
1771 		wlan_append_ifindex(&val->var, sub, wif);
1772 		break;
1773 
1774 	case SNMP_OP_SET:
1775 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL ||
1776 		    !wif->wepsupported)
1777 			return (SNMP_ERR_NOSUCHNAME);
1778 		switch (val->var.subs[sub - 1]) {
1779 		case LEAF_wlanWepMode:
1780 			if (val->v.integer < wlanWepMode_off ||
1781 			    val->v.integer > wlanWepMode_mixed)
1782 				return (SNMP_ERR_INCONS_VALUE);
1783 			ctx->scratch->int1 = wif->wepmode;
1784 			wif->wepmode = val->v.integer;
1785 			if (wlan_set_wepmode(wif) < 0) {
1786 				wif->wepmode = ctx->scratch->int1;
1787 				return (SNMP_ERR_GENERR);
1788 			}
1789 			break;
1790 		case LEAF_wlanWepDefTxKey:
1791 			if (val->v.integer < 0 ||
1792 			    val->v.integer > IEEE80211_WEP_NKID)
1793 				return (SNMP_ERR_INCONS_VALUE);
1794 			ctx->scratch->int1 = wif->weptxkey;
1795 			wif->weptxkey = val->v.integer;
1796 			if (wlan_set_weptxkey(wif) < 0) {
1797 				wif->weptxkey = ctx->scratch->int1;
1798 				return (SNMP_ERR_GENERR);
1799 			}
1800 			break;
1801 		default:
1802 			abort();
1803 		}
1804 		return (SNMP_ERR_NOERROR);
1805 
1806 	case SNMP_OP_COMMIT:
1807 		return (SNMP_ERR_NOERROR);
1808 
1809 	case SNMP_OP_ROLLBACK:
1810 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
1811 			return (SNMP_ERR_NOSUCHNAME);
1812 		switch (val->var.subs[sub - 1]) {
1813 		case LEAF_wlanWepMode:
1814 			wif->wepmode = ctx->scratch->int1;
1815 			if (wlan_set_wepmode(wif) < 0)
1816 				return (SNMP_ERR_GENERR);
1817 			break;
1818 		case LEAF_wlanWepDefTxKey:
1819 			wif->weptxkey = ctx->scratch->int1;
1820 			if (wlan_set_weptxkey(wif) < 0)
1821 				return (SNMP_ERR_GENERR);
1822 			break;
1823 		default:
1824 			abort();
1825 		}
1826 		return (SNMP_ERR_NOERROR);
1827 
1828 	default:
1829 		abort();
1830 	}
1831 
1832 	switch (val->var.subs[sub - 1]) {
1833 	case LEAF_wlanWepMode:
1834 		if (wlan_get_wepmode(wif) < 0)
1835 			return (SNMP_ERR_GENERR);
1836 		val->v.integer = wif->wepmode;
1837 		break;
1838 	case LEAF_wlanWepDefTxKey:
1839 		if (wlan_get_weptxkey(wif) < 0)
1840 			return (SNMP_ERR_GENERR);
1841 		val->v.integer = wif->weptxkey;
1842 		break;
1843 	default:
1844 		abort();
1845 	}
1846 
1847 	return (SNMP_ERR_NOERROR);
1848 }
1849 
1850 int
1851 op_wlan_wep_key(struct snmp_context *ctx __unused,
1852     struct snmp_value *val __unused, uint32_t sub __unused,
1853     uint32_t iidx __unused, enum snmp_op op __unused)
1854 {
1855 	return (SNMP_ERR_NOSUCHNAME);
1856 }
1857 
1858 int
1859 op_wlan_mac_access_control(struct snmp_context *ctx, struct snmp_value *val,
1860     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
1861 {
1862 	struct wlan_iface *wif;
1863 
1864 	wlan_update_interface_list();
1865 
1866 	switch (op) {
1867 	case SNMP_OP_GET:
1868 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL ||
1869 		    !wif->macsupported)
1870 			return (SNMP_ERR_NOSUCHNAME);
1871 		break;
1872 
1873 	case SNMP_OP_GETNEXT:
1874 		/* XXX: filter wif->macsupported */
1875 		if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
1876 			return (SNMP_ERR_NOSUCHNAME);
1877 		wlan_append_ifindex(&val->var, sub, wif);
1878 		break;
1879 
1880 	case SNMP_OP_SET:
1881 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL ||
1882 		    !wif->macsupported)
1883 			return (SNMP_ERR_NOSUCHNAME);
1884 		switch (val->var.subs[sub - 1]) {
1885 		case LEAF_wlanMACAccessControlPolicy:
1886 			ctx->scratch->int1 = wif->mac_policy;
1887 			wif->mac_policy = val->v.integer;
1888 			break;
1889 		case LEAF_wlanMACAccessControlNacl:
1890 			return (SNMP_ERR_NOT_WRITEABLE);
1891 		case LEAF_wlanMACAccessControlFlush:
1892 			break;
1893 		default:
1894 			abort();
1895 		}
1896 		return (SNMP_ERR_NOERROR);
1897 
1898 	case SNMP_OP_COMMIT:
1899 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
1900 			return (SNMP_ERR_NOSUCHNAME);
1901 		switch (val->var.subs[sub - 1]) {
1902 		case LEAF_wlanMACAccessControlPolicy:
1903 			if (wlan_set_mac_policy(wif) < 0) {
1904 				wif->mac_policy = ctx->scratch->int1;
1905 				return (SNMP_ERR_GENERR);
1906 			}
1907 			break;
1908 		case LEAF_wlanMACAccessControlFlush:
1909 			if (wlan_flush_mac_mac(wif) < 0)
1910 				return (SNMP_ERR_GENERR);
1911 			break;
1912 		default:
1913 			abort();
1914 		}
1915 		return (SNMP_ERR_NOERROR);
1916 
1917 	case SNMP_OP_ROLLBACK:
1918 		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
1919 			return (SNMP_ERR_NOSUCHNAME);
1920 		if (val->var.subs[sub - 1] == LEAF_wlanMACAccessControlPolicy)
1921 			wif->mac_policy = ctx->scratch->int1;
1922 		return (SNMP_ERR_NOERROR);
1923 
1924 	default:
1925 		abort();
1926 	}
1927 
1928 	if (wlan_get_mac_policy(wif) < 0)
1929 		return (SNMP_ERR_GENERR);
1930 
1931 	switch (val->var.subs[sub - 1]) {
1932 	case LEAF_wlanMACAccessControlPolicy:
1933 		val->v.integer = wif->mac_policy;
1934 		break;
1935 	case LEAF_wlanMACAccessControlNacl:
1936 		val->v.integer = wif->mac_nacls;
1937 		break;
1938 	case LEAF_wlanMACAccessControlFlush:
1939 		val->v.integer = wlanMACAccessControlFlush_no_op;
1940 		break;
1941 	default:
1942 		abort();
1943 	}
1944 
1945 	return (SNMP_ERR_NOERROR);
1946 }
1947 
1948 int
1949 op_wlan_mac_acl_mac(struct snmp_context *ctx, struct snmp_value *val,
1950     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
1951 {
1952 	struct wlan_iface *wif;
1953 	struct wlan_mac_mac *macl;
1954 
1955 	wlan_update_interface_list();
1956 	wlan_mac_update_aclmacs();
1957 
1958 	switch (op) {
1959 	case SNMP_OP_GET:
1960 		if ((macl = wlan_get_acl_mac(&val->var, sub, &wif)) == NULL)
1961 			return (SNMP_ERR_NOSUCHNAME);
1962 		break;
1963 
1964 	case SNMP_OP_GETNEXT:
1965 		if ((macl = wlan_get_next_acl_mac(&val->var, sub, &wif))
1966 		    == NULL)
1967 			return (SNMP_ERR_NOSUCHNAME);
1968 		wlan_append_mac_index(&val->var, sub, wif->wname, macl->mac);
1969 		break;
1970 
1971 	case SNMP_OP_SET:
1972 		switch (val->var.subs[sub - 1]) {
1973 		case LEAF_wlanMACAccessControlMAC:
1974 			return (SNMP_ERR_INCONS_NAME);
1975 		case LEAF_wlanMACAccessControlMACStatus:
1976 			return(wlan_acl_mac_set_status(ctx, val, sub));
1977 		default:
1978 			abort();
1979 		}
1980 
1981 	case SNMP_OP_COMMIT:
1982 		if ((macl = wlan_get_acl_mac(&val->var, sub, &wif)) == NULL)
1983 			return (SNMP_ERR_NOSUCHNAME);
1984 		if (val->v.integer == RowStatus_destroy &&
1985 		    wlan_mac_delete_mac(wif, macl) < 0)
1986 			return (SNMP_ERR_GENERR);
1987 		return (SNMP_ERR_NOERROR);
1988 
1989 	case SNMP_OP_ROLLBACK:
1990 		if ((macl = wlan_get_acl_mac(&val->var, sub, &wif)) == NULL)
1991 			return (SNMP_ERR_NOSUCHNAME);
1992 		if (ctx->scratch->int1 == RowStatus_destroy &&
1993 		    wlan_mac_delete_mac(wif, macl) < 0)
1994 			return (SNMP_ERR_GENERR);
1995 		return (SNMP_ERR_NOERROR);
1996 
1997 	default:
1998 		abort();
1999 	}
2000 
2001 	switch (val->var.subs[sub - 1]) {
2002 	case LEAF_wlanMACAccessControlMAC:
2003 		return (string_get(val, macl->mac, IEEE80211_ADDR_LEN));
2004 	case LEAF_wlanMACAccessControlMACStatus:
2005 		val->v.integer = macl->mac_status;
2006 		break;
2007 	default:
2008 		abort();
2009 	}
2010 
2011 	return (SNMP_ERR_NOERROR);
2012 }
2013 
2014 int
2015 op_wlan_mesh_config(struct snmp_context *ctx, struct snmp_value *val,
2016     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
2017 {
2018 	int which;
2019 
2020 	switch (val->var.subs[sub - 1]) {
2021 	case LEAF_wlanMeshMaxRetries:
2022 		which = WLAN_MESH_MAX_RETRIES;
2023 		break;
2024 	case LEAF_wlanMeshHoldingTimeout:
2025 		which = WLAN_MESH_HOLDING_TO;
2026 		break;
2027 	case LEAF_wlanMeshConfirmTimeout:
2028 		which = WLAN_MESH_CONFIRM_TO;
2029 		break;
2030 	case LEAF_wlanMeshRetryTimeout:
2031 		which = WLAN_MESH_RETRY_TO;
2032 		break;
2033 	default:
2034 		abort();
2035 	}
2036 
2037 	switch (op) {
2038 	case SNMP_OP_GET:
2039 		if (wlan_do_sysctl(&wlan_config, which, 0) < 0)
2040 			return (SNMP_ERR_GENERR);
2041 		break;
2042 
2043 	case SNMP_OP_GETNEXT:
2044 		abort();
2045 
2046 	case SNMP_OP_SET:
2047 		switch (val->var.subs[sub - 1]) {
2048 		case LEAF_wlanMeshRetryTimeout :
2049 			ctx->scratch->int1 = wlan_config.mesh_retryto;
2050 			wlan_config.mesh_retryto = val->v.integer;
2051 			break;
2052 		case LEAF_wlanMeshHoldingTimeout:
2053 			ctx->scratch->int1 = wlan_config.mesh_holdingto;
2054 			wlan_config.mesh_holdingto = val->v.integer;
2055 			break;
2056 		case LEAF_wlanMeshConfirmTimeout:
2057 			ctx->scratch->int1 = wlan_config.mesh_confirmto;
2058 			wlan_config.mesh_confirmto = val->v.integer;
2059 			break;
2060 		case LEAF_wlanMeshMaxRetries:
2061 			ctx->scratch->int1 = wlan_config.mesh_maxretries;
2062 			wlan_config.mesh_maxretries = val->v.integer;
2063 			break;
2064 		}
2065 		if (wlan_do_sysctl(&wlan_config, which, 1) < 0)
2066 			return (SNMP_ERR_GENERR);
2067 		return (SNMP_ERR_NOERROR);
2068 
2069 	case SNMP_OP_COMMIT:
2070 		return (SNMP_ERR_NOERROR);
2071 
2072 	case SNMP_OP_ROLLBACK:
2073 		switch (val->var.subs[sub - 1]) {
2074 		case LEAF_wlanMeshRetryTimeout:
2075 			wlan_config.mesh_retryto = ctx->scratch->int1;
2076 			break;
2077 		case LEAF_wlanMeshConfirmTimeout:
2078 			wlan_config.mesh_confirmto = ctx->scratch->int1;
2079 			break;
2080 		case LEAF_wlanMeshHoldingTimeout:
2081 			wlan_config.mesh_holdingto= ctx->scratch->int1;
2082 			break;
2083 		case LEAF_wlanMeshMaxRetries:
2084 			wlan_config.mesh_maxretries = ctx->scratch->int1;
2085 			break;
2086 		}
2087 		if (wlan_do_sysctl(&wlan_config, which, 1) < 0)
2088 			return (SNMP_ERR_GENERR);
2089 		return (SNMP_ERR_NOERROR);
2090 
2091 	default:
2092 		abort();
2093 	}
2094 
2095 	switch (val->var.subs[sub - 1]) {
2096 	case LEAF_wlanMeshRetryTimeout:
2097 		val->v.integer = wlan_config.mesh_retryto;
2098 		break;
2099 	case LEAF_wlanMeshHoldingTimeout:
2100 		val->v.integer = wlan_config.mesh_holdingto;
2101 		break;
2102 	case LEAF_wlanMeshConfirmTimeout:
2103 		val->v.integer = wlan_config.mesh_confirmto;
2104 		break;
2105 	case LEAF_wlanMeshMaxRetries:
2106 		val->v.integer = wlan_config.mesh_maxretries;
2107 		break;
2108 	}
2109 
2110 	return (SNMP_ERR_NOERROR);
2111 }
2112 
2113 int
2114 op_wlan_mesh_iface(struct snmp_context *ctx, struct snmp_value *val,
2115     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
2116 {
2117 	int rc;
2118 	struct wlan_iface *wif;
2119 
2120 	wlan_update_interface_list();
2121 
2122 	switch (op) {
2123 	case SNMP_OP_GET:
2124 		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
2125 			return (SNMP_ERR_NOSUCHNAME);
2126 		break;
2127 
2128 	case SNMP_OP_GETNEXT:
2129 		if ((wif = wlan_mesh_get_next_iface(&val->var, sub)) == NULL)
2130 			return (SNMP_ERR_NOSUCHNAME);
2131 		wlan_append_ifindex(&val->var, sub, wif);
2132 		break;
2133 
2134 	case SNMP_OP_SET:
2135 		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
2136 			return (SNMP_ERR_NOSUCHNAME);
2137 		switch (val->var.subs[sub - 1]) {
2138 		case LEAF_wlanMeshId:
2139 			if (val->v.octetstring.len > IEEE80211_NWID_LEN)
2140 				return (SNMP_ERR_INCONS_VALUE);
2141 			ctx->scratch->ptr1 = malloc(val->v.octetstring.len + 1);
2142 			if (ctx->scratch->ptr1 == NULL)
2143 				return (SNMP_ERR_GENERR);
2144 			strlcpy(ctx->scratch->ptr1, wif->desired_ssid,
2145 			    val->v.octetstring.len + 1);
2146 			ctx->scratch->int1 = strlen(wif->desired_ssid);
2147 			memcpy(wif->desired_ssid, val->v.octetstring.octets,
2148 			    val->v.octetstring.len);
2149 			wif->desired_ssid[val->v.octetstring.len] = '\0';
2150 			break;
2151 		case LEAF_wlanMeshTTL:
2152 			ctx->scratch->int1 = wif->mesh_ttl;
2153 			wif->mesh_ttl = val->v.integer;
2154 			break;
2155 		case LEAF_wlanMeshPeeringEnabled:
2156 			ctx->scratch->int1 = wif->mesh_peering;
2157 			wif->mesh_peering = val->v.integer;
2158 			break;
2159 		case LEAF_wlanMeshForwardingEnabled:
2160 			ctx->scratch->int1 = wif->mesh_forwarding;
2161 			wif->mesh_forwarding = val->v.integer;
2162 			break;
2163 		case LEAF_wlanMeshMetric:
2164 			ctx->scratch->int1 = wif->mesh_metric;
2165 			wif->mesh_metric = val->v.integer;
2166 			break;
2167 		case LEAF_wlanMeshPath:
2168 			ctx->scratch->int1 = wif->mesh_path;
2169 			wif->mesh_path = val->v.integer;
2170 			break;
2171 		case LEAF_wlanMeshRoutesFlush:
2172 			if (val->v.integer != wlanMeshRoutesFlush_flush)
2173 				return (SNMP_ERR_INCONS_VALUE);
2174 			return (SNMP_ERR_NOERROR);
2175 		default:
2176 			abort();
2177 		}
2178 		if (val->var.subs[sub - 1] == LEAF_wlanMeshId)
2179 			rc = wlan_config_set_dssid(wif,
2180 			    val->v.octetstring.octets, val->v.octetstring.len);
2181 		else
2182 			rc = wlan_mesh_config_set(wif, val->var.subs[sub - 1]);
2183 		if (rc < 0)
2184 			return (SNMP_ERR_GENERR);
2185 		return (SNMP_ERR_NOERROR);
2186 
2187 	case SNMP_OP_COMMIT:
2188 		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
2189 			return (SNMP_ERR_NOSUCHNAME);
2190 		if (val->var.subs[sub - 1] == LEAF_wlanMeshRoutesFlush &&
2191 		    wlan_mesh_flush_routes(wif) < 0)
2192 			return (SNMP_ERR_GENERR);
2193 		if (val->var.subs[sub - 1] == LEAF_wlanMeshId)
2194 			free(ctx->scratch->ptr1);
2195 		return (SNMP_ERR_NOERROR);
2196 
2197 	case SNMP_OP_ROLLBACK:
2198 		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
2199 			return (SNMP_ERR_NOSUCHNAME);
2200 		switch (val->var.subs[sub - 1]) {
2201 		case LEAF_wlanMeshId:
2202 			strlcpy(wif->desired_ssid, ctx->scratch->ptr1,
2203 			    IEEE80211_NWID_LEN);
2204 			free(ctx->scratch->ptr1);
2205 			break;
2206 		case LEAF_wlanMeshTTL:
2207 			wif->mesh_ttl = ctx->scratch->int1;
2208 			break;
2209 		case LEAF_wlanMeshPeeringEnabled:
2210 			wif->mesh_peering = ctx->scratch->int1;
2211 			break;
2212 		case LEAF_wlanMeshForwardingEnabled:
2213 			wif->mesh_forwarding = ctx->scratch->int1;
2214 			break;
2215 		case LEAF_wlanMeshMetric:
2216 			wif->mesh_metric = ctx->scratch->int1;
2217 			break;
2218 		case LEAF_wlanMeshPath:
2219 			wif->mesh_path = ctx->scratch->int1;
2220 			break;
2221 		case LEAF_wlanMeshRoutesFlush:
2222 			return (SNMP_ERR_NOERROR);
2223 		default:
2224 			abort();
2225 		}
2226 		if (val->var.subs[sub - 1] == LEAF_wlanMeshId)
2227 			rc = wlan_config_set_dssid(wif, wif->desired_ssid,
2228 			    strlen(wif->desired_ssid));
2229 		else
2230 			rc = wlan_mesh_config_set(wif, val->var.subs[sub - 1]);
2231 		if (rc < 0)
2232 			return (SNMP_ERR_GENERR);
2233 		return (SNMP_ERR_NOERROR);
2234 
2235 	default:
2236 		abort();
2237 	}
2238 
2239 	if (val->var.subs[sub - 1] == LEAF_wlanMeshId)
2240 		rc = wlan_config_get_dssid(wif);
2241 	else
2242 		rc = wlan_mesh_config_get(wif, val->var.subs[sub - 1]);
2243 	if (rc < 0)
2244 		return (SNMP_ERR_GENERR);
2245 
2246 	switch (val->var.subs[sub - 1]) {
2247 	case LEAF_wlanMeshId:
2248 		return (string_get(val, wif->desired_ssid, -1));
2249 	case LEAF_wlanMeshTTL:
2250 		val->v.integer = wif->mesh_ttl;
2251 		break;
2252 	case LEAF_wlanMeshPeeringEnabled:
2253 		val->v.integer = wif->mesh_peering;
2254 		break;
2255 	case LEAF_wlanMeshForwardingEnabled:
2256 		val->v.integer = wif->mesh_forwarding;
2257 		break;
2258 	case LEAF_wlanMeshMetric:
2259 		val->v.integer = wif->mesh_metric;
2260 		break;
2261 	case LEAF_wlanMeshPath:
2262 		val->v.integer = wif->mesh_path;
2263 		break;
2264 	case LEAF_wlanMeshRoutesFlush:
2265 		val->v.integer = wlanMeshRoutesFlush_no_op;
2266 		break;
2267 	default:
2268 		abort();
2269 	}
2270 
2271 	return (SNMP_ERR_NOERROR);
2272 }
2273 
2274 int
2275 op_wlan_mesh_neighbor(struct snmp_context *ctx __unused, struct snmp_value *val,
2276     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
2277 {
2278 	struct wlan_peer *wip;
2279 	struct wlan_iface *wif;
2280 
2281 	wlan_update_interface_list();
2282 	wlan_update_peers();
2283 
2284 	switch (op) {
2285 	case SNMP_OP_GET:
2286 		if ((wip = wlan_mesh_get_peer(&val->var, sub, &wif)) == NULL)
2287 			return (SNMP_ERR_NOSUCHNAME);
2288 		break;
2289 	case SNMP_OP_GETNEXT:
2290 		wip = wlan_mesh_get_next_peer(&val->var, sub, &wif);
2291 		if (wip == NULL)
2292 			return (SNMP_ERR_NOSUCHNAME);
2293 		wlan_append_mac_index(&val->var, sub, wif->wname,
2294 		    wip->pmac);
2295 		break;
2296 	case SNMP_OP_SET:
2297 		return (SNMP_ERR_NOT_WRITEABLE);
2298 	case SNMP_OP_COMMIT:
2299 		/* FALLTHROUGH */
2300 	case SNMP_OP_ROLLBACK:
2301 		/* FALLTHROUGH */
2302 	default:
2303 		abort();
2304 	}
2305 
2306 	switch (val->var.subs[sub - 1]) {
2307 	case LEAF_wlanMeshNeighborAddress:
2308 		return (string_get(val, wip->pmac, IEEE80211_ADDR_LEN));
2309 	case LEAF_wlanMeshNeighborFrequency:
2310 		val->v.integer = wip->frequency;
2311 		break;
2312 	case LEAF_wlanMeshNeighborLocalId:
2313 		val->v.integer = wip->local_id;
2314 		break;
2315 	case LEAF_wlanMeshNeighborPeerId:
2316 		val->v.integer = wip->peer_id;
2317 		break;
2318 	case LEAF_wlanMeshNeighborPeerState:
2319 		return (bits_get(val, (uint8_t *)&wip->state,
2320 		    sizeof(wip->state)));
2321 	case LEAF_wlanMeshNeighborCurrentTXRate:
2322 		val->v.integer = wip->txrate;
2323 		break;
2324 	case LEAF_wlanMeshNeighborRxSignalStrength:
2325 		val->v.integer = wip->rssi;
2326 		break;
2327 	case LEAF_wlanMeshNeighborIdleTimer:
2328 		val->v.integer = wip->idle;
2329 		break;
2330 	case LEAF_wlanMeshNeighborTxSequenceNo:
2331 		val->v.integer = wip->txseqs;
2332 		break;
2333 	case LEAF_wlanMeshNeighborRxSequenceNo:
2334 		val->v.integer = wip->rxseqs;
2335 		break;
2336 	default:
2337 		abort();
2338 	}
2339 
2340 	return (SNMP_ERR_NOERROR);
2341 }
2342 
2343 int
2344 op_wlan_mesh_route(struct snmp_context *ctx, struct snmp_value *val,
2345     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
2346 {
2347 	struct wlan_mesh_route *wmr;
2348 	struct wlan_iface *wif;
2349 
2350 	wlan_update_interface_list();
2351 	wlan_mesh_update_routes();
2352 
2353 	switch (op) {
2354 	case SNMP_OP_GET:
2355 		if ((wmr = wlan_mesh_get_route(&val->var, sub, &wif)) == NULL)
2356 			return (SNMP_ERR_NOSUCHNAME);
2357 		break;
2358 
2359 	case SNMP_OP_GETNEXT:
2360 		wmr = wlan_mesh_get_next_route(&val->var, sub, &wif);
2361 		if (wmr == NULL)
2362 			return (SNMP_ERR_NOSUCHNAME);
2363 		wlan_append_mac_index(&val->var, sub, wif->wname,
2364 		    wmr->imroute.imr_dest);
2365 		break;
2366 
2367 	case SNMP_OP_SET:
2368 		switch (val->var.subs[sub - 1]) {
2369 		case LEAF_wlanMeshRouteDestination:
2370 			return (SNMP_ERR_INCONS_NAME);
2371 		case LEAF_wlanMeshRouteStatus:
2372 			return(wlan_mesh_route_set_status(ctx, val, sub));
2373 		default:
2374 			return (SNMP_ERR_NOT_WRITEABLE);
2375 		}
2376 		abort();
2377 
2378 	case SNMP_OP_COMMIT:
2379 		if ((wmr = wlan_mesh_get_route(&val->var, sub, &wif)) == NULL)
2380 			return (SNMP_ERR_NOSUCHNAME);
2381 		if (val->v.integer == RowStatus_destroy &&
2382 		    wlan_mesh_delete_route(wif, wmr) < 0)
2383 			return (SNMP_ERR_GENERR);
2384 		return (SNMP_ERR_NOERROR);
2385 
2386 	case SNMP_OP_ROLLBACK:
2387 		if ((wmr = wlan_mesh_get_route(&val->var, sub, &wif)) == NULL)
2388 			return (SNMP_ERR_NOSUCHNAME);
2389 		if (ctx->scratch->int1 == RowStatus_destroy &&
2390 		    wlan_mesh_delete_route(wif, wmr) < 0)
2391 			return (SNMP_ERR_GENERR);
2392 		return (SNMP_ERR_NOERROR);
2393 
2394 	default:
2395 		abort();
2396 	}
2397 
2398 	switch (val->var.subs[sub - 1]) {
2399 	case LEAF_wlanMeshRouteDestination:
2400 		return (string_get(val, wmr->imroute.imr_dest,
2401 		    IEEE80211_ADDR_LEN));
2402 	case LEAF_wlanMeshRouteNextHop:
2403 		return (string_get(val, wmr->imroute.imr_nexthop,
2404 		    IEEE80211_ADDR_LEN));
2405 	case LEAF_wlanMeshRouteHops:
2406 		val->v.integer = wmr->imroute.imr_nhops;
2407 		break;
2408 	case LEAF_wlanMeshRouteMetric:
2409 		val->v.integer = wmr->imroute.imr_metric;
2410 		break;
2411 	case LEAF_wlanMeshRouteLifeTime:
2412 		val->v.integer = wmr->imroute.imr_lifetime;
2413 		break;
2414 	case LEAF_wlanMeshRouteLastMseq:
2415 		val->v.integer = wmr->imroute.imr_lastmseq;
2416 		break;
2417 	case LEAF_wlanMeshRouteFlags:
2418 		val->v.integer = 0;
2419 		if ((wmr->imroute.imr_flags &
2420 		    IEEE80211_MESHRT_FLAGS_VALID) != 0)
2421 			val->v.integer |= (0x1 << wlanMeshRouteFlags_valid);
2422 		if ((wmr->imroute.imr_flags &
2423 		    IEEE80211_MESHRT_FLAGS_PROXY) != 0)
2424 			val->v.integer |= (0x1 << wlanMeshRouteFlags_proxy);
2425 		return (bits_get(val, (uint8_t *)&val->v.integer,
2426 		    sizeof(val->v.integer)));
2427 	case LEAF_wlanMeshRouteStatus:
2428 		val->v.integer = wmr->mroute_status;
2429 		break;
2430 	}
2431 
2432 	return (SNMP_ERR_NOERROR);
2433 }
2434 
2435 int
2436 op_wlan_mesh_stats(struct snmp_context *ctx __unused, struct snmp_value *val,
2437     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
2438 {
2439 	struct wlan_iface *wif;
2440 
2441 	wlan_update_interface_list();
2442 
2443 	switch (op) {
2444 	case SNMP_OP_GET:
2445 		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
2446 			return (SNMP_ERR_NOSUCHNAME);
2447 		break;
2448 	case SNMP_OP_GETNEXT:
2449 		if ((wif = wlan_mesh_get_next_iface(&val->var, sub)) == NULL)
2450 			return (SNMP_ERR_NOSUCHNAME);
2451 		wlan_append_ifindex(&val->var, sub, wif);
2452 		break;
2453 	case SNMP_OP_SET:
2454 		return (SNMP_ERR_NOT_WRITEABLE);
2455 	case SNMP_OP_COMMIT:
2456 		/* FALLTHROUGH */
2457 	case SNMP_OP_ROLLBACK:
2458 		/* FALLTHROUGH */
2459 	default:
2460 		abort();
2461 	}
2462 
2463 	if (wlan_get_stats(wif) < 0)
2464 		return (SNMP_ERR_GENERR);
2465 
2466 	switch (val->var.subs[sub - 1]) {
2467 	case LEAF_wlanMeshDroppedBadSta:
2468 		val->v.uint32 = wif->stats.is_mesh_wrongmesh;
2469 		break;
2470 	case LEAF_wlanMeshDroppedNoLink:
2471 		val->v.uint32 = wif->stats.is_mesh_nolink;
2472 		break;
2473 	case LEAF_wlanMeshNoFwdTtl:
2474 		val->v.uint32 = wif->stats.is_mesh_fwd_ttl;
2475 		break;
2476 	case LEAF_wlanMeshNoFwdBuf:
2477 		val->v.uint32 = wif->stats.is_mesh_fwd_nobuf;
2478 		break;
2479 	case LEAF_wlanMeshNoFwdTooShort:
2480 		val->v.uint32 = wif->stats.is_mesh_fwd_tooshort;
2481 		break;
2482 	case LEAF_wlanMeshNoFwdDisabled:
2483 		val->v.uint32 = wif->stats.is_mesh_fwd_disabled;
2484 		break;
2485 	case LEAF_wlanMeshNoFwdPathUnknown:
2486 		val->v.uint32 = wif->stats.is_mesh_fwd_nopath;
2487 		break;
2488 	case LEAF_wlanMeshDroppedBadAE:
2489 		val->v.uint32 = wif->stats.is_mesh_badae;
2490 		break;
2491 	case LEAF_wlanMeshRouteAddFailed:
2492 		val->v.uint32 = wif->stats.is_mesh_rtaddfailed;
2493 		break;
2494 	case LEAF_wlanMeshDroppedNoProxy:
2495 		val->v.uint32 = wif->stats.is_mesh_notproxy;
2496 		break;
2497 	case LEAF_wlanMeshDroppedMisaligned:
2498 		val->v.uint32 = wif->stats.is_rx_badalign;
2499 		break;
2500 	default:
2501 		abort();
2502 	}
2503 
2504 	return (SNMP_ERR_NOERROR);
2505 }
2506 
2507 int
2508 op_wlan_hwmp_config(struct snmp_context *ctx, struct snmp_value *val,
2509     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
2510 {
2511 	int which;
2512 
2513 	switch (val->var.subs[sub - 1]) {
2514 	case LEAF_wlanHWMPRouteInactiveTimeout:
2515 		which = WLAN_HWMP_INACTIVITY_TO;
2516 		break;
2517 	case LEAF_wlanHWMPRootAnnounceInterval:
2518 		which = WLAN_HWMP_RANN_INT;
2519 		break;
2520 	case LEAF_wlanHWMPRootInterval:
2521 		which = WLAN_HWMP_ROOT_INT;
2522 		break;
2523 	case LEAF_wlanHWMPRootTimeout:
2524 		which = WLAN_HWMP_ROOT_TO;
2525 		break;
2526 	case LEAF_wlanHWMPPathLifetime:
2527 		which = WLAN_HWMP_PATH_LIFETIME;
2528 		break;
2529 	case LEAF_wlanHWMPReplyForwardBit:
2530 		which = WLAN_HWMP_REPLY_FORWARD;
2531 		break;
2532 	case LEAF_wlanHWMPTargetOnlyBit:
2533 		which = WLAN_HWMP_TARGET_ONLY;
2534 		break;
2535 	default:
2536 		abort();
2537 	}
2538 
2539 	switch (op) {
2540 	case SNMP_OP_GET:
2541 		if (wlan_do_sysctl(&wlan_config, which, 0) < 0)
2542 			return (SNMP_ERR_GENERR);
2543 		break;
2544 
2545 	case SNMP_OP_GETNEXT:
2546 		abort();
2547 
2548 	case SNMP_OP_SET:
2549 		switch (val->var.subs[sub - 1]) {
2550 		case LEAF_wlanHWMPRouteInactiveTimeout:
2551 			ctx->scratch->int1 = wlan_config.hwmp_inact;
2552 			wlan_config.hwmp_inact = val->v.integer;
2553 			break;
2554 		case LEAF_wlanHWMPRootAnnounceInterval:
2555 			ctx->scratch->int1 = wlan_config.hwmp_rannint;
2556 			wlan_config.hwmp_rannint = val->v.integer;
2557 			break;
2558 		case LEAF_wlanHWMPRootInterval:
2559 			ctx->scratch->int1 = wlan_config.hwmp_rootint;
2560 			wlan_config.hwmp_rootint = val->v.integer;
2561 			break;
2562 		case LEAF_wlanHWMPRootTimeout:
2563 			ctx->scratch->int1 = wlan_config.hwmp_roottimeout;
2564 			wlan_config.hwmp_roottimeout = val->v.integer;
2565 			break;
2566 		case LEAF_wlanHWMPPathLifetime:
2567 			ctx->scratch->int1 = wlan_config.hwmp_pathlifetime;
2568 			wlan_config.hwmp_pathlifetime = val->v.integer;
2569 			break;
2570 		case LEAF_wlanHWMPReplyForwardBit:
2571 			ctx->scratch->int1 = wlan_config.hwmp_replyforward;
2572 			wlan_config.hwmp_replyforward = val->v.integer;
2573 			break;
2574 		case LEAF_wlanHWMPTargetOnlyBit:
2575 			ctx->scratch->int1 = wlan_config.hwmp_targetonly;
2576 			wlan_config.hwmp_targetonly = val->v.integer;
2577 			break;
2578 		}
2579 		if (wlan_do_sysctl(&wlan_config, which, 1) < 0)
2580 			return (SNMP_ERR_GENERR);
2581 		return (SNMP_ERR_NOERROR);
2582 
2583 	case SNMP_OP_COMMIT:
2584 		return (SNMP_ERR_NOERROR);
2585 
2586 	case SNMP_OP_ROLLBACK:
2587 		switch (val->var.subs[sub - 1]) {
2588 		case LEAF_wlanHWMPRouteInactiveTimeout:
2589 			wlan_config.hwmp_inact = ctx->scratch->int1;
2590 			break;
2591 		case LEAF_wlanHWMPRootAnnounceInterval:
2592 			wlan_config.hwmp_rannint = ctx->scratch->int1;
2593 			break;
2594 		case LEAF_wlanHWMPRootInterval:
2595 			wlan_config.hwmp_rootint = ctx->scratch->int1;
2596 			break;
2597 		case LEAF_wlanHWMPRootTimeout:
2598 			wlan_config.hwmp_roottimeout = ctx->scratch->int1;
2599 			break;
2600 		case LEAF_wlanHWMPPathLifetime:
2601 			wlan_config.hwmp_pathlifetime = ctx->scratch->int1;
2602 			break;
2603 		case LEAF_wlanHWMPReplyForwardBit:
2604 			wlan_config.hwmp_replyforward = ctx->scratch->int1;
2605 			break;
2606 		case LEAF_wlanHWMPTargetOnlyBit:
2607 			wlan_config.hwmp_targetonly = ctx->scratch->int1;
2608 			break;
2609 		}
2610 		if (wlan_do_sysctl(&wlan_config, which, 1) < 0)
2611 			return (SNMP_ERR_GENERR);
2612 		return (SNMP_ERR_NOERROR);
2613 
2614 	default:
2615 		abort();
2616 	}
2617 
2618 	switch (val->var.subs[sub - 1]) {
2619 	case LEAF_wlanHWMPRouteInactiveTimeout:
2620 		val->v.integer = wlan_config.hwmp_inact;
2621 		break;
2622 	case LEAF_wlanHWMPRootAnnounceInterval:
2623 		val->v.integer = wlan_config.hwmp_rannint;
2624 		break;
2625 	case LEAF_wlanHWMPRootInterval:
2626 		val->v.integer = wlan_config.hwmp_rootint;
2627 		break;
2628 	case LEAF_wlanHWMPRootTimeout:
2629 		val->v.integer = wlan_config.hwmp_roottimeout;
2630 		break;
2631 	case LEAF_wlanHWMPPathLifetime:
2632 		val->v.integer = wlan_config.hwmp_pathlifetime;
2633 		break;
2634 	case LEAF_wlanHWMPReplyForwardBit:
2635 		val->v.integer = wlan_config.hwmp_replyforward;
2636 		break;
2637 	case LEAF_wlanHWMPTargetOnlyBit:
2638 		val->v.integer = wlan_config.hwmp_targetonly;
2639 		break;
2640 	}
2641 
2642 	return (SNMP_ERR_NOERROR);
2643 }
2644 
2645 int
2646 op_wlan_hwmp_iface(struct snmp_context *ctx, struct snmp_value *val,
2647     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
2648 {
2649 	struct wlan_iface *wif;
2650 
2651 	wlan_update_interface_list();
2652 
2653 	switch (op) {
2654 	case SNMP_OP_GET:
2655 		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
2656 			return (SNMP_ERR_NOSUCHNAME);
2657 		break;
2658 
2659 	case SNMP_OP_GETNEXT:
2660 		if ((wif = wlan_mesh_get_next_iface(&val->var, sub)) == NULL)
2661 			return (SNMP_ERR_NOSUCHNAME);
2662 		wlan_append_ifindex(&val->var, sub, wif);
2663 		break;
2664 
2665 	case SNMP_OP_SET:
2666 		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
2667 			return (SNMP_ERR_NOSUCHNAME);
2668 		switch (val->var.subs[sub - 1]) {
2669 		case LEAF_wlanHWMPRootMode:
2670 			ctx->scratch->int1 = wif->hwmp_root_mode;
2671 			wif->hwmp_root_mode = val->v.integer;
2672 			break;
2673 		case LEAF_wlanHWMPMaxHops:
2674 			ctx->scratch->int1 = wif->hwmp_max_hops;
2675 			wif->hwmp_max_hops = val->v.integer;
2676 			break;
2677 		default:
2678 			abort();
2679 		}
2680 		if (wlan_hwmp_config_set(wif, val->var.subs[sub - 1]) < 0)
2681 			return (SNMP_ERR_GENERR);
2682 		return (SNMP_ERR_NOERROR);
2683 
2684 	case SNMP_OP_COMMIT:
2685 		return (SNMP_ERR_NOERROR);
2686 
2687 	case SNMP_OP_ROLLBACK:
2688 		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
2689 			return (SNMP_ERR_NOSUCHNAME);
2690 		switch (val->var.subs[sub - 1]) {
2691 		case LEAF_wlanHWMPRootMode:
2692 			wif->hwmp_root_mode = ctx->scratch->int1;
2693 			break;
2694 		case LEAF_wlanHWMPMaxHops:
2695 			wif->hwmp_max_hops = ctx->scratch->int1;
2696 			break;
2697 		default:
2698 			abort();
2699 		}
2700 		if (wlan_hwmp_config_set(wif, val->var.subs[sub - 1]) < 0)
2701 			return (SNMP_ERR_GENERR);
2702 		return (SNMP_ERR_NOERROR);
2703 
2704 	default:
2705 		abort();
2706 	}
2707 
2708 	if (wlan_hwmp_config_get(wif, val->var.subs[sub - 1]) < 0)
2709 		return (SNMP_ERR_GENERR);
2710 
2711 	switch (val->var.subs[sub - 1]) {
2712 	case LEAF_wlanHWMPRootMode:
2713 		val->v.integer = wif->hwmp_root_mode;
2714 		break;
2715 	case LEAF_wlanHWMPMaxHops:
2716 		val->v.integer = wif->hwmp_max_hops;
2717 		break;
2718 	default:
2719 		abort();
2720 	}
2721 
2722 	return (SNMP_ERR_NOERROR);
2723 }
2724 
2725 int
2726 op_wlan_hwmp_stats(struct snmp_context *ctx __unused, struct snmp_value *val,
2727     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
2728 {
2729 	struct wlan_iface *wif;
2730 
2731 	wlan_update_interface_list();
2732 
2733 	switch (op) {
2734 	case SNMP_OP_GET:
2735 		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
2736 			return (SNMP_ERR_NOSUCHNAME);
2737 		break;
2738 	case SNMP_OP_GETNEXT:
2739 		if ((wif = wlan_mesh_get_next_iface(&val->var, sub)) == NULL)
2740 			return (SNMP_ERR_NOSUCHNAME);
2741 		wlan_append_ifindex(&val->var, sub, wif);
2742 		break;
2743 	case SNMP_OP_SET:
2744 		return (SNMP_ERR_NOT_WRITEABLE);
2745 	case SNMP_OP_COMMIT:
2746 		/* FALLTHROUGH */
2747 	case SNMP_OP_ROLLBACK:
2748 		/* FALLTHROUGH */
2749 	default:
2750 		abort();
2751 	}
2752 
2753 	if (wlan_get_stats(wif) < 0)
2754 		return (SNMP_ERR_GENERR);
2755 
2756 	switch (val->var.subs[sub - 1]) {
2757 	case LEAF_wlanMeshHWMPWrongSeqNo:
2758 		val->v.uint32 = wif->stats.is_hwmp_wrongseq;
2759 		break;
2760 	case LEAF_wlanMeshHWMPTxRootPREQ:
2761 		val->v.uint32 = wif->stats.is_hwmp_rootreqs;
2762 		break;
2763 	case LEAF_wlanMeshHWMPTxRootRANN:
2764 		val->v.uint32 = wif->stats.is_hwmp_rootrann;
2765 		break;
2766 	case LEAF_wlanMeshHWMPProxy:
2767 		val->v.uint32 = wif->stats.is_hwmp_proxy;
2768 		break;
2769 	default:
2770 		abort();
2771 	}
2772 
2773 	return (SNMP_ERR_NOERROR);
2774 }
2775 
2776 /*
2777  * Encode BITS type for a response packet - XXX: this belongs to the snmp lib.
2778  */
2779 static int
2780 bits_get(struct snmp_value *value, const u_char *ptr, ssize_t len)
2781 {
2782 	int size;
2783 
2784 	if (ptr == NULL) {
2785 		value->v.octetstring.len = 0;
2786 		value->v.octetstring.octets = NULL;
2787 		return (SNMP_ERR_NOERROR);
2788 	}
2789 
2790 	/* Determine length - up to 8 octets supported so far. */
2791 	for (size = len; size > 0; size--)
2792 		if (ptr[size - 1] != 0)
2793 			break;
2794 	if (size == 0)
2795 		size = 1;
2796 
2797 	value->v.octetstring.len = (u_long)size;
2798 	if ((value->v.octetstring.octets = malloc((size_t)size)) == NULL)
2799 		return (SNMP_ERR_RES_UNAVAIL);
2800 	memcpy(value->v.octetstring.octets, ptr, (size_t)size);
2801 	return (SNMP_ERR_NOERROR);
2802 }
2803 
2804 /*
2805  * Calls for adding/updating/freeing/etc of wireless interfaces.
2806  */
2807 static void
2808 wlan_free_interface(struct wlan_iface *wif)
2809 {
2810 	wlan_free_peerlist(wif);
2811 	free(wif->chanlist);
2812 	wlan_scan_free_results(wif);
2813 	wlan_mac_free_maclist(wif);
2814 	wlan_mesh_free_routes(wif);
2815 	free(wif);
2816 }
2817 
2818 static void
2819 wlan_free_iflist(void)
2820 {
2821 	struct wlan_iface *w;
2822 
2823 	while ((w = SLIST_FIRST(&wlan_ifaces)) != NULL) {
2824 		SLIST_REMOVE_HEAD(&wlan_ifaces, w_if);
2825 		wlan_free_interface(w);
2826 	}
2827 }
2828 
2829 static struct wlan_iface *
2830 wlan_find_interface(const char *wname)
2831 {
2832 	struct wlan_iface *wif;
2833 
2834 	SLIST_FOREACH(wif, &wlan_ifaces, w_if)
2835 		if (strcmp(wif->wname, wname) == 0) {
2836 			if (wif->status != RowStatus_active)
2837 				return (NULL);
2838 			break;
2839 		}
2840 
2841 	return (wif);
2842 }
2843 
2844 static struct wlan_iface *
2845 wlan_first_interface(void)
2846 {
2847 	return (SLIST_FIRST(&wlan_ifaces));
2848 }
2849 
2850 static struct wlan_iface *
2851 wlan_next_interface(struct wlan_iface *wif)
2852 {
2853 	if (wif == NULL)
2854 		return (NULL);
2855 
2856 	return (SLIST_NEXT(wif, w_if));
2857 }
2858 
2859 /*
2860  * Add a new interface to the list - sorted by name.
2861  */
2862 static int
2863 wlan_add_wif(struct wlan_iface *wif)
2864 {
2865 	int cmp;
2866 	struct wlan_iface *temp, *prev;
2867 
2868 	if ((prev = SLIST_FIRST(&wlan_ifaces)) == NULL ||
2869 	    strcmp(wif->wname, prev->wname) < 0) {
2870 		SLIST_INSERT_HEAD(&wlan_ifaces, wif, w_if);
2871 		return (0);
2872 	}
2873 
2874 	SLIST_FOREACH(temp, &wlan_ifaces, w_if) {
2875 		if ((cmp = strcmp(wif->wname, temp->wname)) <= 0)
2876 			break;
2877 		prev = temp;
2878 	}
2879 
2880 	if (temp == NULL)
2881 		SLIST_INSERT_AFTER(prev, wif, w_if);
2882 	else if (cmp > 0)
2883 		SLIST_INSERT_AFTER(temp, wif, w_if);
2884 	else {
2885 		syslog(LOG_ERR, "Wlan iface %s already in list", wif->wname);
2886 		return (-1);
2887 	}
2888 
2889 	return (0);
2890 }
2891 
2892 static struct wlan_iface *
2893 wlan_new_wif(char *wname)
2894 {
2895 	struct wlan_iface *wif;
2896 
2897 	/* Make sure it's not in the list. */
2898 	for (wif = wlan_first_interface(); wif != NULL;
2899 	    wif = wlan_next_interface(wif))
2900 		if (strcmp(wname, wif->wname) == 0) {
2901 			wif->internal = 0;
2902 			return (wif);
2903 		}
2904 
2905 	if ((wif = (struct wlan_iface *)malloc(sizeof(*wif))) == NULL)
2906 		return (NULL);
2907 
2908 	memset(wif, 0, sizeof(struct wlan_iface));
2909 	strlcpy(wif->wname, wname, IFNAMSIZ);
2910 	wif->status = RowStatus_notReady;
2911 	wif->state = wlanIfaceState_down;
2912 	wif->mode = WlanIfaceOperatingModeType_station;
2913 
2914 	if (wlan_add_wif(wif) < 0) {
2915 		free(wif);
2916 		return (NULL);
2917 	}
2918 
2919 	return (wif);
2920 }
2921 
2922 static void
2923 wlan_delete_wif(struct wlan_iface *wif)
2924 {
2925 	SLIST_REMOVE(&wlan_ifaces, wif, wlan_iface, w_if);
2926 	wlan_free_interface(wif);
2927 }
2928 
2929 static int
2930 wlan_attach_newif(struct mibif *mif)
2931 {
2932 	struct wlan_iface *wif;
2933 
2934 	if (mif->mib.ifmd_data.ifi_type != IFT_ETHER ||
2935 	    wlan_check_media(mif->name) != IFM_IEEE80211)
2936 		return (0);
2937 
2938 	if ((wif = wlan_new_wif(mif->name)) == NULL)
2939 		return (-1);
2940 
2941 	(void)wlan_get_opmode(wif);
2942 	wif->index = mif->index;
2943 	wif->status = RowStatus_active;
2944 	(void)wlan_update_interface(wif);
2945 
2946 	return (0);
2947 }
2948 
2949 static int
2950 wlan_iface_create(struct wlan_iface *wif)
2951 {
2952 	int rc;
2953 
2954 	if ((rc = wlan_clone_create(wif)) == SNMP_ERR_NOERROR) {
2955 		/*
2956 		 * The rest of the info will be updated once the
2957 		 * snmp_mibII module notifies us of the interface.
2958 		 */
2959 		wif->status = RowStatus_active;
2960 		if (wif->state == wlanIfaceState_up)
2961 			(void)wlan_config_state(wif, 1);
2962 	}
2963 
2964 	return (rc);
2965 }
2966 
2967 static int
2968 wlan_iface_destroy(struct wlan_iface *wif)
2969 {
2970 	int rc = SNMP_ERR_NOERROR;
2971 
2972 	if (wif->internal == 0)
2973 		rc = wlan_clone_destroy(wif);
2974 
2975 	if (rc == SNMP_ERR_NOERROR)
2976 		wlan_delete_wif(wif);
2977 
2978 	return (rc);
2979 }
2980 
2981 static int
2982 wlan_update_interface(struct wlan_iface *wif)
2983 {
2984 	int i;
2985 
2986 	(void)wlan_config_state(wif, 0);
2987 	(void)wlan_get_driver_caps(wif);
2988 	for (i = LEAF_wlanIfacePacketBurst;
2989 	    i <= LEAF_wlanIfaceTdmaBeaconInterval; i++)
2990 		(void)wlan_config_get_ioctl(wif, i);
2991 	(void)wlan_get_stats(wif);
2992 	/*
2993 	 * XXX: wlan_get_channel_list() not needed -
2994 	 * fetched with wlan_get_driver_caps()
2995 	 */
2996 	(void)wlan_get_channel_list(wif);
2997 	(void)wlan_get_roam_params(wif);
2998 	(void)wlan_get_tx_params(wif);
2999 	(void)wlan_get_scan_results(wif);
3000 	(void)wlan_get_wepmode(wif);
3001 	(void)wlan_get_weptxkey(wif);
3002 	(void)wlan_get_mac_policy(wif);
3003 	(void)wlan_get_mac_acl_macs(wif);
3004 	(void)wlan_get_peerinfo(wif);
3005 
3006 	if (wif->mode == WlanIfaceOperatingModeType_meshPoint) {
3007 		for (i = LEAF_wlanMeshTTL; i <= LEAF_wlanMeshPath; i++)
3008 			(void)wlan_mesh_config_get(wif, i);
3009 		(void)wlan_mesh_get_routelist(wif);
3010 		for (i = LEAF_wlanHWMPRootMode; i <= LEAF_wlanHWMPMaxHops; i++)
3011 			(void)wlan_hwmp_config_get(wif, i);
3012 	}
3013 
3014 	return (0);
3015 }
3016 
3017 static void
3018 wlan_update_interface_list(void)
3019 {
3020 	struct wlan_iface *wif, *twif;
3021 
3022 	if ((time(NULL) - wlan_iflist_age) <= WLAN_LIST_MAXAGE)
3023 		return;
3024 
3025 	/*
3026 	 * The snmp_mibII module would have notified us for new interfaces,
3027 	 * so only check if any have been deleted.
3028 	 */
3029 	SLIST_FOREACH_SAFE(wif, &wlan_ifaces, w_if, twif)
3030 		if (wif->status == RowStatus_active && wlan_get_opmode(wif) < 0)
3031 			wlan_delete_wif(wif);
3032 
3033 	wlan_iflist_age = time(NULL);
3034 }
3035 
3036 static void
3037 wlan_append_ifindex(struct asn_oid *oid, uint sub, const struct wlan_iface *w)
3038 {
3039 	uint32_t i;
3040 
3041 	oid->len = sub + strlen(w->wname) + 1;
3042 	oid->subs[sub] = strlen(w->wname);
3043 	for (i = 1; i <= strlen(w->wname); i++)
3044 		oid->subs[sub + i] = w->wname[i - 1];
3045 }
3046 
3047 static uint8_t *
3048 wlan_get_ifname(const struct asn_oid *oid, uint sub, uint8_t *wname)
3049 {
3050 	uint32_t i;
3051 
3052 	memset(wname, 0, IFNAMSIZ);
3053 
3054 	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
3055 		return (NULL);
3056 
3057 	for (i = 0; i < oid->subs[sub]; i++)
3058 		wname[i] = oid->subs[sub + i + 1];
3059 	wname[i] = '\0';
3060 
3061 	return (wname);
3062 }
3063 
3064 static struct wlan_iface *
3065 wlan_get_interface(const struct asn_oid *oid, uint sub)
3066 {
3067 	uint8_t wname[IFNAMSIZ];
3068 
3069 	if (wlan_get_ifname(oid, sub, wname) == NULL)
3070 		return (NULL);
3071 
3072 	return (wlan_find_interface(wname));
3073 }
3074 
3075 static struct wlan_iface *
3076 wlan_get_next_interface(const struct asn_oid *oid, uint sub)
3077 {
3078 	uint32_t i;
3079 	uint8_t wname[IFNAMSIZ];
3080 	struct wlan_iface *wif;
3081 
3082 	if (oid->len - sub == 0) {
3083 		for (wif = wlan_first_interface(); wif != NULL;
3084 		    wif = wlan_next_interface(wif))
3085 			if (wif->status == RowStatus_active)
3086 				break;
3087 		return (wif);
3088 	}
3089 
3090 	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
3091 		return (NULL);
3092 
3093 	memset(wname, 0, IFNAMSIZ);
3094 	for (i = 0; i < oid->subs[sub]; i++)
3095 		wname[i] = oid->subs[sub + i + 1];
3096 	wname[i] = '\0';
3097 	if ((wif = wlan_find_interface(wname)) == NULL)
3098 		return (NULL);
3099 
3100 	while ((wif = wlan_next_interface(wif)) != NULL)
3101 		if (wif->status == RowStatus_active)
3102 			break;
3103 
3104 	return (wif);
3105 }
3106 
3107 static struct wlan_iface *
3108 wlan_get_snmp_interface(const struct asn_oid *oid, uint sub)
3109 {
3110 	uint8_t wname[IFNAMSIZ];
3111 	struct wlan_iface *wif;
3112 
3113 	if (wlan_get_ifname(oid, sub, wname) == NULL)
3114 		return (NULL);
3115 
3116 	for (wif = wlan_first_interface(); wif != NULL;
3117 	    wif = wlan_next_interface(wif))
3118 		if (strcmp(wif->wname, wname) == 0)
3119 			break;
3120 
3121 	return (wif);
3122 }
3123 
3124 static struct wlan_iface *
3125 wlan_get_next_snmp_interface(const struct asn_oid *oid, uint sub)
3126 {
3127 	uint32_t i;
3128 	uint8_t wname[IFNAMSIZ];
3129 	struct wlan_iface *wif;
3130 
3131 	if (oid->len - sub == 0)
3132 		return (wlan_first_interface());
3133 
3134 	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
3135 		return (NULL);
3136 
3137 	memset(wname, 0, IFNAMSIZ);
3138 	for (i = 0; i < oid->subs[sub]; i++)
3139 		wname[i] = oid->subs[sub + i + 1];
3140 	wname[i] = '\0';
3141 
3142 	for (wif = wlan_first_interface(); wif != NULL;
3143 	    wif = wlan_next_interface(wif))
3144 		if (strcmp(wif->wname, wname) == 0)
3145 			break;
3146 
3147 	return (wlan_next_interface(wif));
3148 }
3149 
3150 /*
3151  * Decode/Append an index for tables indexed by the wireless interface
3152  * name and a MAC address - ACL MACs and Mesh Routes.
3153  */
3154 static int
3155 wlan_mac_index_decode(const struct asn_oid *oid, uint sub,
3156     char *wname, uint8_t *mac)
3157 {
3158 	uint32_t i;
3159 	int mac_off;
3160 
3161 	if (oid->len - sub != oid->subs[sub] + 2 + IEEE80211_ADDR_LEN
3162 	    || oid->subs[sub] >= IFNAMSIZ)
3163 		return (-1);
3164 
3165 	for (i = 0; i < oid->subs[sub]; i++)
3166 		wname[i] = oid->subs[sub + i + 1];
3167 	wname[i] = '\0';
3168 
3169 	mac_off = sub + oid->subs[sub] + 1;
3170 	if (oid->subs[mac_off] != IEEE80211_ADDR_LEN)
3171 		return (-1);
3172 	for (i = 0; i < IEEE80211_ADDR_LEN; i++)
3173 		mac[i] = oid->subs[mac_off + i + 1];
3174 
3175 	return (0);
3176 }
3177 
3178 static void
3179 wlan_append_mac_index(struct asn_oid *oid, uint sub, char *wname, uint8_t *mac)
3180 {
3181 	uint32_t i;
3182 
3183 	oid->len = sub + strlen(wname) + IEEE80211_ADDR_LEN + 2;
3184 	oid->subs[sub] = strlen(wname);
3185 	for (i = 1; i <= strlen(wname); i++)
3186 		oid->subs[sub + i] = wname[i - 1];
3187 
3188 	sub += strlen(wname) + 1;
3189 	oid->subs[sub] = IEEE80211_ADDR_LEN;
3190 	for (i = 1; i <= IEEE80211_ADDR_LEN; i++)
3191 		oid->subs[sub + i] = mac[i - 1];
3192 }
3193 
3194 /*
3195  * Decode/Append an index for tables indexed by the wireless interface
3196  * name and the PHY mode - Roam and TX params.
3197  */
3198 static int
3199 wlan_phy_index_decode(const struct asn_oid *oid, uint sub, char *wname,
3200     uint32_t *phy)
3201 {
3202 	uint32_t i;
3203 
3204 	if (oid->len - sub != oid->subs[sub] + 2 || oid->subs[sub] >= IFNAMSIZ)
3205 		return (-1);
3206 
3207 	for (i = 0; i < oid->subs[sub]; i++)
3208 		wname[i] = oid->subs[sub + i + 1];
3209 	wname[i] = '\0';
3210 
3211 	*phy = oid->subs[sub + oid->subs[sub] + 1];
3212 	return (0);
3213 }
3214 
3215 static void
3216 wlan_append_phy_index(struct asn_oid *oid, uint sub, char *wname, uint32_t phy)
3217 {
3218 	uint32_t i;
3219 
3220 	oid->len = sub + strlen(wname) + 2;
3221 	oid->subs[sub] = strlen(wname);
3222 	for (i = 1; i <= strlen(wname); i++)
3223 		oid->subs[sub + i] = wname[i - 1];
3224 	oid->subs[sub + strlen(wname) + 1] = phy;
3225 }
3226 
3227 /*
3228  * Calls for manipulating the peerlist of a wireless interface.
3229  */
3230 static void
3231 wlan_free_peerlist(struct wlan_iface *wif)
3232 {
3233 	struct wlan_peer *wip;
3234 
3235 	while ((wip = SLIST_FIRST(&wif->peerlist)) != NULL) {
3236 		SLIST_REMOVE_HEAD(&wif->peerlist, wp);
3237 		free(wip);
3238 	}
3239 
3240 	SLIST_INIT(&wif->peerlist);
3241 }
3242 
3243 static struct wlan_peer *
3244 wlan_find_peer(struct wlan_iface *wif, uint8_t *peermac)
3245 {
3246 	struct wlan_peer *wip;
3247 
3248 	SLIST_FOREACH(wip, &wif->peerlist, wp)
3249 		if (memcmp(wip->pmac, peermac, IEEE80211_ADDR_LEN) == 0)
3250 			break;
3251 
3252 	return (wip);
3253 }
3254 
3255 struct wlan_peer *
3256 wlan_new_peer(const uint8_t *pmac)
3257 {
3258 	struct wlan_peer *wip;
3259 
3260 	if ((wip = (struct wlan_peer *)malloc(sizeof(*wip))) == NULL)
3261 		return (NULL);
3262 
3263 	memset(wip, 0, sizeof(struct wlan_peer));
3264 	memcpy(wip->pmac, pmac, IEEE80211_ADDR_LEN);
3265 
3266 	return (wip);
3267 }
3268 
3269 void
3270 wlan_free_peer(struct wlan_peer *wip)
3271 {
3272 	free(wip);
3273 }
3274 
3275 int
3276 wlan_add_peer(struct wlan_iface *wif, struct wlan_peer *wip)
3277 {
3278 	struct wlan_peer *temp, *prev;
3279 
3280 	SLIST_FOREACH(temp, &wif->peerlist, wp)
3281 		if (memcmp(temp->pmac, wip->pmac, IEEE80211_ADDR_LEN) == 0)
3282 			return (-1);
3283 
3284 	if ((prev = SLIST_FIRST(&wif->peerlist)) == NULL ||
3285 	    memcmp(wip->pmac, prev->pmac, IEEE80211_ADDR_LEN) < 0) {
3286 	    	SLIST_INSERT_HEAD(&wif->peerlist, wip, wp);
3287 	    	return (0);
3288 	}
3289 
3290 	SLIST_FOREACH(temp, &wif->peerlist, wp) {
3291 		if (memcmp(wip->pmac, temp->pmac, IEEE80211_ADDR_LEN) < 0)
3292 			break;
3293 		prev = temp;
3294 	}
3295 
3296 	SLIST_INSERT_AFTER(prev, wip, wp);
3297 	return (0);
3298 }
3299 
3300 static void
3301 wlan_update_peers(void)
3302 {
3303 	struct wlan_iface *wif;
3304 
3305 	if ((time(NULL) - wlan_peerlist_age) <= WLAN_LIST_MAXAGE)
3306 		return;
3307 
3308 	for (wif = wlan_first_interface(); wif != NULL;
3309 	    wif = wlan_next_interface(wif)) {
3310 		if (wif->status != RowStatus_active)
3311 			continue;
3312 		wlan_free_peerlist(wif);
3313 		(void)wlan_get_peerinfo(wif);
3314 	}
3315 	wlan_peerlist_age = time(NULL);
3316 }
3317 
3318 static struct wlan_peer *
3319 wlan_get_peer(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
3320 {
3321 	char wname[IFNAMSIZ];
3322 	uint8_t pmac[IEEE80211_ADDR_LEN];
3323 
3324 	if (wlan_mac_index_decode(oid, sub, wname, pmac) < 0)
3325 		return (NULL);
3326 
3327 	if ((*wif = wlan_find_interface(wname)) == NULL)
3328 		return (NULL);
3329 
3330 	return (wlan_find_peer(*wif, pmac));
3331 }
3332 
3333 static struct wlan_peer *
3334 wlan_get_next_peer(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
3335 {
3336 	char wname[IFNAMSIZ];
3337 	char pmac[IEEE80211_ADDR_LEN];
3338 	struct wlan_peer *wip;
3339 
3340 	if (oid->len - sub == 0) {
3341 		for (*wif = wlan_first_interface(); *wif != NULL;
3342 		    *wif = wlan_next_interface(*wif)) {
3343 			if ((*wif)->mode ==
3344 			    WlanIfaceOperatingModeType_meshPoint)
3345 				continue;
3346 			wip = SLIST_FIRST(&(*wif)->peerlist);
3347 			if (wip != NULL)
3348 				return (wip);
3349 		}
3350 		return (NULL);
3351 	}
3352 
3353 	if (wlan_mac_index_decode(oid, sub, wname, pmac) < 0 ||
3354 	    (*wif = wlan_find_interface(wname)) == NULL ||
3355 	    (wip = wlan_find_peer(*wif, pmac)) == NULL)
3356 		return (NULL);
3357 
3358 	if ((wip = SLIST_NEXT(wip, wp)) != NULL)
3359 		return (wip);
3360 
3361 	while ((*wif = wlan_next_interface(*wif)) != NULL) {
3362 		if ((*wif)->mode == WlanIfaceOperatingModeType_meshPoint)
3363 			continue;
3364 		if ((wip = SLIST_FIRST(&(*wif)->peerlist)) != NULL)
3365 			break;
3366 	}
3367 
3368 	return (wip);
3369 }
3370 
3371 /*
3372  * Calls for manipulating the active channel list of a wireless interface.
3373  */
3374 static void
3375 wlan_update_channels(void)
3376 {
3377 	struct wlan_iface *wif;
3378 
3379 	if ((time(NULL) - wlan_chanlist_age) <= WLAN_LIST_MAXAGE)
3380 		return;
3381 
3382 	for (wif = wlan_first_interface(); wif != NULL;
3383 	    wif = wlan_next_interface(wif)) {
3384 		if (wif->status != RowStatus_active)
3385 			continue;
3386 		(void)wlan_get_channel_list(wif);
3387 	}
3388 	wlan_chanlist_age = time(NULL);
3389 }
3390 
3391 static int
3392 wlan_channel_index_decode(const struct asn_oid *oid, uint sub, char *wname,
3393     uint32_t *cindex)
3394 {
3395 	uint32_t i;
3396 	if (oid->len - sub != oid->subs[sub] + 2 || oid->subs[sub] >= IFNAMSIZ)
3397 		return (-1);
3398 
3399 	for (i = 0; i < oid->subs[sub]; i++)
3400 		wname[i] = oid->subs[sub + i + 1];
3401 	wname[i] = '\0';
3402 
3403 	*cindex = oid->subs[sub + oid->subs[sub] + 1];
3404 
3405 	return (0);
3406 }
3407 
3408 static void
3409 wlan_append_channel_index(struct asn_oid *oid, uint sub,
3410     const struct wlan_iface *wif, const struct ieee80211_channel *channel)
3411 {
3412 	uint32_t i;
3413 
3414 	oid->len = sub + strlen(wif->wname) + 2;
3415 	oid->subs[sub] = strlen(wif->wname);
3416 	for (i = 1; i <= strlen(wif->wname); i++)
3417 		oid->subs[sub + i] = wif->wname[i - 1];
3418 	oid->subs[sub + strlen(wif->wname) + 1] = (channel - wif->chanlist) + 1;
3419 }
3420 
3421 static int32_t
3422 wlan_get_channel_type(struct ieee80211_channel *c)
3423 {
3424 	if (IEEE80211_IS_CHAN_FHSS(c))
3425 		return (WlanChannelType_fhss);
3426 	if (IEEE80211_IS_CHAN_A(c))
3427 		return (WlanChannelType_dot11a);
3428 	if (IEEE80211_IS_CHAN_B(c))
3429 		return (WlanChannelType_dot11b);
3430 	if (IEEE80211_IS_CHAN_ANYG(c))
3431 		return (WlanChannelType_dot11g);
3432 	if (IEEE80211_IS_CHAN_HALF(c))
3433 		return (WlanChannelType_tenMHz);
3434 	if (IEEE80211_IS_CHAN_QUARTER(c))
3435 		return (WlanChannelType_fiveMHz);
3436 	if (IEEE80211_IS_CHAN_TURBO(c))
3437 		return (WlanChannelType_turbo);
3438 	if (IEEE80211_IS_CHAN_HT(c))
3439 		return (WlanChannelType_ht);
3440 
3441 	return (-1);
3442 }
3443 
3444 static struct ieee80211_channel *
3445 wlan_find_channel(struct wlan_iface *wif, uint32_t cindex)
3446 {
3447 	if (wif->chanlist == NULL || cindex > wif->nchannels)
3448 		return (NULL);
3449 
3450 	return (wif->chanlist + cindex - 1);
3451 }
3452 
3453 static struct ieee80211_channel *
3454 wlan_get_channel(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
3455 {
3456 	uint32_t cindex;
3457 	char wname[IFNAMSIZ];
3458 
3459 	if (wlan_channel_index_decode(oid, sub, wname, &cindex) < 0)
3460 		return (NULL);
3461 
3462 	if ((*wif = wlan_find_interface(wname)) == NULL)
3463 		return (NULL);
3464 
3465 	return (wlan_find_channel(*wif, cindex));
3466 }
3467 
3468 static struct ieee80211_channel *
3469 wlan_get_next_channel(const struct asn_oid *oid, uint sub,
3470     struct wlan_iface **wif)
3471 {
3472 	uint32_t cindex;
3473 	char wname[IFNAMSIZ];
3474 
3475 	if (oid->len - sub == 0) {
3476 		for (*wif = wlan_first_interface(); *wif != NULL;
3477 		    *wif = wlan_next_interface(*wif)) {
3478 			if ((*wif)->status != RowStatus_active)
3479 				continue;
3480 			if ((*wif)->nchannels != 0 && (*wif)->chanlist != NULL)
3481 				return ((*wif)->chanlist);
3482 		}
3483 		return (NULL);
3484 	}
3485 
3486 	if (wlan_channel_index_decode(oid, sub, wname, &cindex) < 0)
3487 		return (NULL);
3488 
3489 	if ((*wif = wlan_find_interface(wname)) == NULL)
3490 		return (NULL);
3491 
3492 	if (cindex < (*wif)->nchannels)
3493 		return ((*wif)->chanlist + cindex);
3494 
3495 	while ((*wif = wlan_next_interface(*wif)) != NULL)
3496 		if ((*wif)->status == RowStatus_active)
3497 			if ((*wif)->nchannels != 0 && (*wif)->chanlist != NULL)
3498 				return ((*wif)->chanlist);
3499 
3500 	return (NULL);
3501 }
3502 
3503 /*
3504  * Calls for manipulating the roam params of a wireless interface.
3505  */
3506 static void
3507 wlan_update_roam_params(void)
3508 {
3509 	struct wlan_iface *wif;
3510 
3511 	if ((time(NULL) - wlan_roamlist_age) <= WLAN_LIST_MAXAGE)
3512 		return;
3513 
3514 	for (wif = wlan_first_interface(); wif != NULL;
3515 	    wif = wlan_next_interface(wif)) {
3516 		if (wif->status != RowStatus_active)
3517 			continue;
3518 		(void)wlan_get_roam_params(wif);
3519 	}
3520 	wlan_roamlist_age = time(NULL);
3521 }
3522 
3523 static struct ieee80211_roamparam *
3524 wlan_get_roam_param(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
3525 {
3526 	uint32_t phy;
3527 	char wname[IFNAMSIZ];
3528 
3529 	if (wlan_phy_index_decode(oid, sub, wname, &phy) < 0)
3530 		return (NULL);
3531 
3532 	if ((*wif = wlan_find_interface(wname)) == NULL)
3533 		return (NULL);
3534 
3535 	if (phy == 0 || phy > IEEE80211_MODE_MAX)
3536 		return (NULL);
3537 
3538 	return ((*wif)->roamparams.params + phy - 1);
3539 }
3540 
3541 static struct ieee80211_roamparam *
3542 wlan_get_next_roam_param(const struct asn_oid *oid, uint sub,
3543     struct wlan_iface **wif, uint32_t *phy)
3544 {
3545 	char wname[IFNAMSIZ];
3546 
3547 	if (oid->len - sub == 0) {
3548 		for (*wif = wlan_first_interface(); *wif != NULL;
3549 		    *wif = wlan_next_interface(*wif)) {
3550 			if ((*wif)->status != RowStatus_active)
3551 				continue;
3552 			*phy = 1;
3553 			return ((*wif)->roamparams.params);
3554 		}
3555 		return (NULL);
3556 	}
3557 
3558 	if (wlan_phy_index_decode(oid, sub, wname, phy) < 0)
3559 		return (NULL);
3560 
3561 	if (*phy == 0  || (*wif = wlan_find_interface(wname)) == NULL)
3562 		return (NULL);
3563 
3564 	if (++(*phy) <= IEEE80211_MODE_MAX)
3565 		return ((*wif)->roamparams.params + *phy - 1);
3566 
3567 	*phy = 1;
3568 	while ((*wif = wlan_next_interface(*wif)) != NULL)
3569 		if ((*wif)->status == RowStatus_active)
3570 			return ((*wif)->roamparams.params);
3571 
3572 	return (NULL);
3573 }
3574 
3575 /*
3576  * Calls for manipulating the tx params of a wireless interface.
3577  */
3578 static void
3579 wlan_update_tx_params(void)
3580 {
3581 	struct wlan_iface *wif;
3582 
3583 	if ((time(NULL) - wlan_tx_paramlist_age) <= WLAN_LIST_MAXAGE)
3584 		return;
3585 
3586 	for (wif = wlan_first_interface(); wif != NULL;
3587 	    wif = wlan_next_interface(wif)) {
3588 		if (wif->status != RowStatus_active)
3589 			continue;
3590 		(void)wlan_get_tx_params(wif);
3591 	}
3592 
3593 	wlan_tx_paramlist_age = time(NULL);
3594 }
3595 
3596 static struct ieee80211_txparam *
3597 wlan_get_tx_param(const struct asn_oid *oid, uint sub, struct wlan_iface **wif,
3598     uint32_t *phy)
3599 {
3600 	char wname[IFNAMSIZ];
3601 
3602 	if (wlan_phy_index_decode(oid, sub, wname, phy) < 0)
3603 		return (NULL);
3604 
3605 	if ((*wif = wlan_find_interface(wname)) == NULL)
3606 		return (NULL);
3607 
3608 	if (*phy == 0 || *phy > IEEE80211_MODE_MAX)
3609 		return (NULL);
3610 
3611 	return ((*wif)->txparams.params + *phy - 1);
3612 }
3613 
3614 static struct ieee80211_txparam *
3615 wlan_get_next_tx_param(const struct asn_oid *oid, uint sub,
3616     struct wlan_iface **wif, uint32_t *phy)
3617 {
3618 	char wname[IFNAMSIZ];
3619 
3620 	if (oid->len - sub == 0) {
3621 		for (*wif = wlan_first_interface(); *wif != NULL;
3622 		    *wif = wlan_next_interface(*wif)) {
3623 			if ((*wif)->status != RowStatus_active)
3624 				continue;
3625 			*phy = 1;
3626 			return ((*wif)->txparams.params);
3627 		}
3628 		return (NULL);
3629 	}
3630 
3631 	if (wlan_phy_index_decode(oid, sub, wname, phy) < 0)
3632 		return (NULL);
3633 
3634 	if (*phy == 0 || (*wif = wlan_find_interface(wname)) == NULL)
3635 		return (NULL);
3636 
3637 	if (++(*phy) <= IEEE80211_MODE_MAX)
3638 		return ((*wif)->txparams.params + *phy - 1);
3639 
3640 	*phy = 1;
3641 	while ((*wif = wlan_next_interface(*wif)) != NULL)
3642 		if ((*wif)->status == RowStatus_active)
3643 			return ((*wif)->txparams.params);
3644 
3645 	return (NULL);
3646 }
3647 
3648 /*
3649  * Calls for manipulating the scan results for a wireless interface.
3650  */
3651 static void
3652 wlan_scan_free_results(struct wlan_iface *wif)
3653 {
3654 	struct wlan_scan_result *sr;
3655 
3656 	while ((sr = SLIST_FIRST(&wif->scanlist)) != NULL) {
3657 		SLIST_REMOVE_HEAD(&wif->scanlist, wsr);
3658 		free(sr);
3659 	}
3660 
3661 	SLIST_INIT(&wif->scanlist);
3662 }
3663 
3664 static struct wlan_scan_result *
3665 wlan_scan_find_result(struct wlan_iface *wif, uint8_t *ssid, uint8_t *bssid)
3666 {
3667 	struct wlan_scan_result *sr;
3668 
3669 	SLIST_FOREACH(sr, &wif->scanlist, wsr)
3670 		if (strlen(ssid) == strlen(sr->ssid) &&
3671 		    strcmp(sr->ssid, ssid) == 0 &&
3672 		    memcmp(sr->bssid, bssid, IEEE80211_ADDR_LEN) == 0)
3673 			break;
3674 
3675 	return (sr);
3676 }
3677 
3678 struct wlan_scan_result *
3679 wlan_scan_new_result(const uint8_t *ssid, const uint8_t *bssid)
3680 {
3681 	struct wlan_scan_result *sr;
3682 
3683 	sr = (struct wlan_scan_result *)malloc(sizeof(*sr));
3684 	if (sr == NULL)
3685 		return (NULL);
3686 
3687 	memset(sr, 0, sizeof(*sr));
3688 	if (ssid[0] != '\0')
3689 		strlcpy(sr->ssid, ssid, IEEE80211_NWID_LEN + 1);
3690 	memcpy(sr->bssid, bssid, IEEE80211_ADDR_LEN);
3691 
3692 	return (sr);
3693 }
3694 
3695 void
3696 wlan_scan_free_result(struct wlan_scan_result *sr)
3697 {
3698 	free(sr);
3699 }
3700 
3701 static int
3702 wlan_scan_compare_result(struct wlan_scan_result *sr1,
3703     struct wlan_scan_result *sr2)
3704 {
3705 	uint32_t i;
3706 
3707 	if (strlen(sr1->ssid) < strlen(sr2->ssid))
3708 		return (-1);
3709 	if (strlen(sr1->ssid) > strlen(sr2->ssid))
3710 		return (1);
3711 
3712 	for (i = 0; i < strlen(sr1->ssid) && i < strlen(sr2->ssid); i++) {
3713 		if (sr1->ssid[i] < sr2->ssid[i])
3714 			return (-1);
3715 		if (sr1->ssid[i] > sr2->ssid[i])
3716 			return (1);
3717 	}
3718 
3719 	for (i = 0; i < IEEE80211_ADDR_LEN; i++) {
3720 		if (sr1->bssid[i] < sr2->bssid[i])
3721 			return (-1);
3722 		if (sr1->bssid[i] > sr2->bssid[i])
3723 			return (1);
3724 	}
3725 
3726 	return (0);
3727 }
3728 
3729 int
3730 wlan_scan_add_result(struct wlan_iface *wif, struct wlan_scan_result *sr)
3731 {
3732 	struct wlan_scan_result *prev, *temp;
3733 
3734 	SLIST_FOREACH(temp, &wif->scanlist, wsr)
3735 		if (strlen(temp->ssid) == strlen(sr->ssid) &&
3736 		    strcmp(sr->ssid, temp->ssid) == 0 &&
3737 		    memcmp(sr->bssid, temp->bssid, IEEE80211_ADDR_LEN) == 0)
3738 			return (-1);
3739 
3740 	if ((prev = SLIST_FIRST(&wif->scanlist)) == NULL ||
3741 	    wlan_scan_compare_result(sr, prev) < 0) {
3742 	    	SLIST_INSERT_HEAD(&wif->scanlist, sr, wsr);
3743 	    	return (0);
3744 	}
3745 
3746 	SLIST_FOREACH(temp, &wif->scanlist, wsr) {
3747 		if (wlan_scan_compare_result(sr, temp) < 0)
3748 			break;
3749 		prev = temp;
3750 	}
3751 
3752 	SLIST_INSERT_AFTER(prev, sr, wsr);
3753 	return (0);
3754 }
3755 
3756 static void
3757 wlan_scan_update_results(void)
3758 {
3759 	struct wlan_iface *wif;
3760 
3761 	if ((time(NULL) - wlan_scanlist_age) <= WLAN_LIST_MAXAGE)
3762 		return;
3763 
3764 	for (wif = wlan_first_interface(); wif != NULL;
3765 	    wif = wlan_next_interface(wif)) {
3766 		if (wif->status != RowStatus_active)
3767 			continue;
3768 		wlan_scan_free_results(wif);
3769 		(void)wlan_get_scan_results(wif);
3770 	}
3771 	wlan_scanlist_age = time(NULL);
3772 }
3773 
3774 static int
3775 wlan_scanr_index_decode(const struct asn_oid *oid, uint sub,
3776     char *wname, uint8_t *ssid, uint8_t *bssid)
3777 {
3778 	uint32_t i;
3779 	int offset;
3780 
3781 	if (oid->subs[sub] >= IFNAMSIZ)
3782 		return (-1);
3783 	for (i = 0; i < oid->subs[sub]; i++)
3784 		wname[i] = oid->subs[sub + i + 1];
3785 	wname[oid->subs[sub]] = '\0';
3786 
3787 	offset = sub + oid->subs[sub] + 1;
3788 	if (oid->subs[offset] > IEEE80211_NWID_LEN)
3789 		return (-1);
3790 	for (i = 0; i < oid->subs[offset]; i++)
3791 		ssid[i] = oid->subs[offset + i + 1];
3792 	ssid[i] = '\0';
3793 
3794 	offset = sub + oid->subs[sub] + oid->subs[offset] + 2;
3795 	if (oid->subs[offset] != IEEE80211_ADDR_LEN)
3796 		return (-1);
3797 	for (i = 0; i < IEEE80211_ADDR_LEN; i++)
3798 		bssid[i] = oid->subs[offset + i + 1];
3799 
3800 	return (0);
3801 }
3802 
3803 static void
3804 wlan_append_scanr_index(struct asn_oid *oid, uint sub, char *wname,
3805     uint8_t *ssid, uint8_t *bssid)
3806 {
3807 	uint32_t i;
3808 
3809 	oid->len = sub + strlen(wname) + strlen(ssid) + IEEE80211_ADDR_LEN + 3;
3810 	oid->subs[sub] = strlen(wname);
3811 	for (i = 1; i <= strlen(wname); i++)
3812 		oid->subs[sub + i] = wname[i - 1];
3813 
3814 	sub += strlen(wname) + 1;
3815 	oid->subs[sub] = strlen(ssid);
3816 	for (i = 1; i <= strlen(ssid); i++)
3817 		oid->subs[sub + i] = ssid[i - 1];
3818 
3819 	sub += strlen(ssid) + 1;
3820 	oid->subs[sub] = IEEE80211_ADDR_LEN;
3821 	for (i = 1; i <= IEEE80211_ADDR_LEN; i++)
3822 		oid->subs[sub + i] = bssid[i - 1];
3823 }
3824 
3825 static struct wlan_scan_result *
3826 wlan_get_scanr(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
3827 {
3828 	char wname[IFNAMSIZ];
3829 	uint8_t ssid[IEEE80211_NWID_LEN + 1];
3830 	uint8_t bssid[IEEE80211_ADDR_LEN];
3831 
3832 	if (wlan_scanr_index_decode(oid, sub, wname, ssid, bssid) < 0)
3833 		return (NULL);
3834 
3835 	if ((*wif = wlan_find_interface(wname)) == NULL)
3836 		return (NULL);
3837 
3838 	return (wlan_scan_find_result(*wif, ssid, bssid));
3839 }
3840 
3841 static struct wlan_scan_result *
3842 wlan_get_next_scanr(const struct asn_oid *oid, uint sub,
3843     struct wlan_iface **wif)
3844 {
3845 	char wname[IFNAMSIZ];
3846 	uint8_t ssid[IEEE80211_NWID_LEN + 1];
3847 	uint8_t bssid[IEEE80211_ADDR_LEN];
3848 	struct wlan_scan_result *sr;
3849 
3850 	if (oid->len - sub == 0) {
3851 		for (*wif = wlan_first_interface(); *wif != NULL;
3852 		    *wif = wlan_next_interface(*wif)) {
3853 			sr = SLIST_FIRST(&(*wif)->scanlist);
3854 			if (sr != NULL)
3855 				return (sr);
3856 		}
3857 		return (NULL);
3858 	}
3859 
3860 	if (wlan_scanr_index_decode(oid, sub, wname, ssid, bssid) < 0 ||
3861 	    (*wif = wlan_find_interface(wname)) == NULL ||
3862 	    (sr = wlan_scan_find_result(*wif, ssid, bssid)) == NULL)
3863 		return (NULL);
3864 
3865 	if ((sr = SLIST_NEXT(sr, wsr)) != NULL)
3866 		return (sr);
3867 
3868 	while ((*wif = wlan_next_interface(*wif)) != NULL)
3869 		if ((sr = SLIST_FIRST(&(*wif)->scanlist)) != NULL)
3870 			break;
3871 
3872 	return (sr);
3873 }
3874 
3875 /*
3876  * MAC Access Control.
3877  */
3878 static void
3879 wlan_mac_free_maclist(struct wlan_iface *wif)
3880 {
3881 	struct wlan_mac_mac *wmm;
3882 
3883 	while ((wmm = SLIST_FIRST(&wif->mac_maclist)) != NULL) {
3884 		SLIST_REMOVE_HEAD(&wif->mac_maclist, wm);
3885 		free(wmm);
3886 	}
3887 
3888 	SLIST_INIT(&wif->mac_maclist);
3889 }
3890 
3891 static struct wlan_mac_mac *
3892 wlan_mac_find_mac(struct wlan_iface *wif, uint8_t *mac)
3893 {
3894 	struct wlan_mac_mac *wmm;
3895 
3896 	SLIST_FOREACH(wmm, &wif->mac_maclist, wm)
3897 		if (memcmp(wmm->mac, mac, IEEE80211_ADDR_LEN) == 0)
3898 			break;
3899 
3900 	return (wmm);
3901 }
3902 
3903 struct wlan_mac_mac *
3904 wlan_mac_new_mac(const uint8_t *mac)
3905 {
3906 	struct wlan_mac_mac *wmm;
3907 
3908 	if ((wmm = (struct wlan_mac_mac *)malloc(sizeof(*wmm))) == NULL)
3909 		return (NULL);
3910 
3911 	memset(wmm, 0, sizeof(*wmm));
3912 	memcpy(wmm->mac, mac, IEEE80211_ADDR_LEN);
3913 	wmm->mac_status = RowStatus_notReady;
3914 
3915 	return (wmm);
3916 }
3917 
3918 void
3919 wlan_mac_free_mac(struct wlan_mac_mac *wmm)
3920 {
3921 	free(wmm);
3922 }
3923 
3924 int
3925 wlan_mac_add_mac(struct wlan_iface *wif, struct wlan_mac_mac *wmm)
3926 {
3927 	struct wlan_mac_mac *temp, *prev;
3928 
3929 	SLIST_FOREACH(temp, &wif->mac_maclist, wm)
3930 		if (memcmp(temp->mac, wmm->mac, IEEE80211_ADDR_LEN) == 0)
3931 			return (-1);
3932 
3933 	if ((prev = SLIST_FIRST(&wif->mac_maclist)) == NULL ||
3934 	    memcmp(wmm->mac, prev->mac,IEEE80211_ADDR_LEN) < 0) {
3935 	    	SLIST_INSERT_HEAD(&wif->mac_maclist, wmm, wm);
3936 	    	return (0);
3937 	}
3938 
3939 	SLIST_FOREACH(temp, &wif->mac_maclist, wm) {
3940 		if (memcmp(wmm->mac, temp->mac, IEEE80211_ADDR_LEN) < 0)
3941 			break;
3942 		prev = temp;
3943 	}
3944 
3945 	SLIST_INSERT_AFTER(prev, wmm, wm);
3946 	return (0);
3947 }
3948 
3949 static int
3950 wlan_mac_delete_mac(struct wlan_iface *wif, struct wlan_mac_mac *wmm)
3951 {
3952 	if (wmm->mac_status == RowStatus_active &&
3953 	    wlan_del_mac_acl_mac(wif, wmm) < 0)
3954 		return (-1);
3955 
3956 	SLIST_REMOVE(&wif->mac_maclist, wmm, wlan_mac_mac, wm);
3957 	free(wmm);
3958 
3959 	return (0);
3960 }
3961 
3962 static void
3963 wlan_mac_update_aclmacs(void)
3964 {
3965 	struct wlan_iface *wif;
3966 	struct wlan_mac_mac *wmm, *twmm;
3967 
3968 	if ((time(NULL) - wlan_maclist_age) <= WLAN_LIST_MAXAGE)
3969 		return;
3970 
3971 	for (wif = wlan_first_interface(); wif != NULL;
3972 	    wif = wlan_next_interface(wif)) {
3973 		if (wif->status != RowStatus_active)
3974 			continue;
3975 		/*
3976 		 * Nuke old entries - XXX - they are likely not to
3977 		 * change often - reconsider.
3978 		 */
3979 		SLIST_FOREACH_SAFE(wmm, &wif->mac_maclist, wm, twmm)
3980 			if (wmm->mac_status == RowStatus_active) {
3981 				SLIST_REMOVE(&wif->mac_maclist, wmm,
3982 				    wlan_mac_mac, wm);
3983 				wlan_mac_free_mac(wmm);
3984 			}
3985 		(void)wlan_get_mac_acl_macs(wif);
3986 	}
3987 	wlan_maclist_age = time(NULL);
3988 }
3989 
3990 static struct wlan_mac_mac *
3991 wlan_get_acl_mac(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
3992 {
3993 	char wname[IFNAMSIZ];
3994 	char mac[IEEE80211_ADDR_LEN];
3995 
3996 	if (wlan_mac_index_decode(oid, sub, wname, mac) < 0)
3997 		return (NULL);
3998 
3999 	if ((*wif = wlan_find_interface(wname)) == NULL)
4000 		return (NULL);
4001 
4002 	return (wlan_mac_find_mac(*wif, mac));
4003 }
4004 
4005 static struct wlan_mac_mac *
4006 wlan_get_next_acl_mac(const struct asn_oid *oid, uint sub,
4007     struct wlan_iface **wif)
4008 {
4009 	char wname[IFNAMSIZ];
4010 	char mac[IEEE80211_ADDR_LEN];
4011 	struct wlan_mac_mac *wmm;
4012 
4013 	if (oid->len - sub == 0) {
4014 		for (*wif = wlan_first_interface(); *wif != NULL;
4015 		    *wif = wlan_next_interface(*wif)) {
4016 			wmm = SLIST_FIRST(&(*wif)->mac_maclist);
4017 			if (wmm != NULL)
4018 				return (wmm);
4019 		}
4020 		return (NULL);
4021 	}
4022 
4023 	if (wlan_mac_index_decode(oid, sub, wname, mac) < 0 ||
4024 	    (*wif = wlan_find_interface(wname)) == NULL ||
4025 	    (wmm = wlan_mac_find_mac(*wif, mac)) == NULL)
4026 		return (NULL);
4027 
4028 	if ((wmm = SLIST_NEXT(wmm, wm)) != NULL)
4029 		return (wmm);
4030 
4031 	while ((*wif = wlan_next_interface(*wif)) != NULL)
4032 		if ((wmm = SLIST_FIRST(&(*wif)->mac_maclist)) != NULL)
4033 			break;
4034 
4035 	return (wmm);
4036 }
4037 
4038 static int
4039 wlan_acl_mac_set_status(struct snmp_context *ctx, struct snmp_value *val,
4040     uint sub)
4041 {
4042 	char wname[IFNAMSIZ];
4043 	uint8_t mac[IEEE80211_ADDR_LEN];
4044 	struct wlan_iface *wif;
4045 	struct wlan_mac_mac *macl;
4046 
4047 	if (wlan_mac_index_decode(&val->var, sub, wname, mac) < 0)
4048 		return (SNMP_ERR_GENERR);
4049 	macl = wlan_get_acl_mac(&val->var, sub, &wif);
4050 
4051 	switch (val->v.integer) {
4052 	case RowStatus_createAndGo:
4053 		if (macl != NULL)
4054 			return (SNMP_ERR_INCONS_NAME);
4055 		break;
4056 	case RowStatus_destroy:
4057 		if (macl == NULL)
4058 			return (SNMP_ERR_NOSUCHNAME);
4059 		ctx->scratch->int1 = RowStatus_active;
4060 		return (SNMP_ERR_NOERROR);
4061 	default:
4062 		return (SNMP_ERR_INCONS_VALUE);
4063 	}
4064 
4065 
4066 	if (wif == NULL || !wif->macsupported)
4067 		return (SNMP_ERR_INCONS_VALUE);
4068 
4069 	if ((macl = wlan_mac_new_mac((const uint8_t *)mac)) == NULL)
4070 		return (SNMP_ERR_GENERR);
4071 
4072 	ctx->scratch->int1 = RowStatus_destroy;
4073 
4074 	if (wlan_mac_add_mac(wif, macl) < 0) {
4075 		wlan_mac_free_mac(macl);
4076 		return (SNMP_ERR_GENERR);
4077 	}
4078 
4079 	ctx->scratch->int1 = RowStatus_destroy;
4080 	if (wlan_add_mac_acl_mac(wif, macl) < 0) {
4081 		(void)wlan_mac_delete_mac(wif, macl);
4082 		return (SNMP_ERR_GENERR);
4083 	}
4084 
4085 	return (SNMP_ERR_NOERROR);
4086 }
4087 
4088 /*
4089  * Wireless interfaces operating as mesh points.
4090  */
4091 static struct wlan_iface *
4092 wlan_mesh_first_interface(void)
4093 {
4094 	struct wlan_iface *wif;
4095 
4096 	SLIST_FOREACH(wif, &wlan_ifaces, w_if)
4097 		if (wif->mode == WlanIfaceOperatingModeType_meshPoint &&
4098 		    wif->status == RowStatus_active)
4099 			break;
4100 
4101 	return (wif);
4102 }
4103 
4104 static struct wlan_iface *
4105 wlan_mesh_next_interface(struct wlan_iface *wif)
4106 {
4107 	struct wlan_iface *nwif;
4108 
4109 	while ((nwif = wlan_next_interface(wif)) != NULL) {
4110 		if (nwif->mode == WlanIfaceOperatingModeType_meshPoint &&
4111 		    nwif->status == RowStatus_active)
4112 			break;
4113 		wif = nwif;
4114 	}
4115 
4116 	return (nwif);
4117 }
4118 
4119 static struct wlan_iface *
4120 wlan_mesh_get_iface(const struct asn_oid *oid, uint sub)
4121 {
4122 	struct wlan_iface *wif;
4123 
4124 	if ((wif = wlan_get_interface(oid, sub)) == NULL)
4125 		return (NULL);
4126 
4127 	if (wif->mode != WlanIfaceOperatingModeType_meshPoint)
4128 		return (NULL);
4129 
4130 	return (wif);
4131 }
4132 
4133 static struct wlan_iface *
4134 wlan_mesh_get_next_iface(const struct asn_oid *oid, uint sub)
4135 {
4136 	uint32_t i;
4137 	uint8_t wname[IFNAMSIZ];
4138 	struct wlan_iface *wif;
4139 
4140 	if (oid->len - sub == 0)
4141 		return (wlan_mesh_first_interface());
4142 
4143 	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
4144 		return (NULL);
4145 
4146 	memset(wname, 0, IFNAMSIZ);
4147 	for (i = 0; i < oid->subs[sub]; i++)
4148 		wname[i] = oid->subs[sub + i + 1];
4149 	wname[i] = '\0';
4150 
4151 	if ((wif = wlan_find_interface(wname)) == NULL)
4152 		return (NULL);
4153 
4154 	return (wlan_mesh_next_interface(wif));
4155 }
4156 
4157 /*
4158  * The neighbors of wireless interfaces operating as mesh points.
4159  */
4160 static struct wlan_peer *
4161 wlan_mesh_get_peer(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
4162 {
4163 	char wname[IFNAMSIZ];
4164 	uint8_t pmac[IEEE80211_ADDR_LEN];
4165 
4166 	if (wlan_mac_index_decode(oid, sub, wname, pmac) < 0)
4167 		return (NULL);
4168 
4169 	if ((*wif = wlan_find_interface(wname)) == NULL ||
4170 	    (*wif)->mode != WlanIfaceOperatingModeType_meshPoint)
4171 		return (NULL);
4172 
4173 	return (wlan_find_peer(*wif, pmac));
4174 }
4175 
4176 static struct wlan_peer *
4177 wlan_mesh_get_next_peer(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
4178 {
4179 	char wname[IFNAMSIZ];
4180 	char pmac[IEEE80211_ADDR_LEN];
4181 	struct wlan_peer *wip;
4182 
4183 	if (oid->len - sub == 0) {
4184 		for (*wif = wlan_mesh_first_interface(); *wif != NULL;
4185 		    *wif = wlan_mesh_next_interface(*wif)) {
4186 			wip = SLIST_FIRST(&(*wif)->peerlist);
4187 			if (wip != NULL)
4188 				return (wip);
4189 		}
4190 		return (NULL);
4191 	}
4192 
4193 	if (wlan_mac_index_decode(oid, sub, wname, pmac) < 0 ||
4194 	    (*wif = wlan_find_interface(wname)) == NULL ||
4195 	    (*wif)->mode != WlanIfaceOperatingModeType_meshPoint ||
4196 	    (wip = wlan_find_peer(*wif, pmac)) == NULL)
4197 		return (NULL);
4198 
4199 	if ((wip = SLIST_NEXT(wip, wp)) != NULL)
4200 		return (wip);
4201 
4202 	while ((*wif = wlan_mesh_next_interface(*wif)) != NULL)
4203 		if ((wip = SLIST_FIRST(&(*wif)->peerlist)) != NULL)
4204 			break;
4205 
4206 	return (wip);
4207 }
4208 
4209 /*
4210  * Mesh routing table.
4211  */
4212 static void
4213 wlan_mesh_free_routes(struct wlan_iface *wif)
4214 {
4215 	struct wlan_mesh_route *wmr;
4216 
4217 	while ((wmr = SLIST_FIRST(&wif->mesh_routelist)) != NULL) {
4218 		SLIST_REMOVE_HEAD(&wif->mesh_routelist, wr);
4219 		free(wmr);
4220 	}
4221 
4222 	SLIST_INIT(&wif->mesh_routelist);
4223 }
4224 
4225 static struct wlan_mesh_route *
4226 wlan_mesh_find_route(struct wlan_iface *wif, uint8_t *dstmac)
4227 {
4228 	struct wlan_mesh_route *wmr;
4229 
4230 	if (wif->mode != WlanIfaceOperatingModeType_meshPoint)
4231 		return (NULL);
4232 
4233 	SLIST_FOREACH(wmr, &wif->mesh_routelist, wr)
4234 		if (memcmp(wmr->imroute.imr_dest, dstmac,
4235 		    IEEE80211_ADDR_LEN) == 0)
4236 			break;
4237 
4238 	return (wmr);
4239 }
4240 
4241 struct wlan_mesh_route *
4242 wlan_mesh_new_route(const uint8_t *dstmac)
4243 {
4244 	struct wlan_mesh_route *wmr;
4245 
4246 	if ((wmr = (struct wlan_mesh_route *)malloc(sizeof(*wmr))) == NULL)
4247 		return (NULL);
4248 
4249 	memset(wmr, 0, sizeof(*wmr));
4250 	memcpy(wmr->imroute.imr_dest, dstmac, IEEE80211_ADDR_LEN);
4251 	wmr->mroute_status = RowStatus_notReady;
4252 
4253 	return (wmr);
4254 }
4255 
4256 void
4257 wlan_mesh_free_route(struct wlan_mesh_route *wmr)
4258 {
4259 	free(wmr);
4260 }
4261 
4262 int
4263 wlan_mesh_add_rtentry(struct wlan_iface *wif, struct wlan_mesh_route *wmr)
4264 {
4265 	struct wlan_mesh_route *temp, *prev;
4266 
4267 	SLIST_FOREACH(temp, &wif->mesh_routelist, wr)
4268 		if (memcmp(temp->imroute.imr_dest, wmr->imroute.imr_dest,
4269 		    IEEE80211_ADDR_LEN) == 0)
4270 			return (-1);
4271 
4272 	if ((prev = SLIST_FIRST(&wif->mesh_routelist)) == NULL ||
4273 	    memcmp(wmr->imroute.imr_dest, prev->imroute.imr_dest,
4274 	    IEEE80211_ADDR_LEN) < 0) {
4275 	    	SLIST_INSERT_HEAD(&wif->mesh_routelist, wmr, wr);
4276 	    	return (0);
4277 	}
4278 
4279 	SLIST_FOREACH(temp, &wif->mesh_routelist, wr) {
4280 		if (memcmp(wmr->imroute.imr_dest, temp->imroute.imr_dest,
4281 		    IEEE80211_ADDR_LEN) < 0)
4282 			break;
4283 		prev = temp;
4284 	}
4285 
4286 	SLIST_INSERT_AFTER(prev, wmr, wr);
4287 	return (0);
4288 }
4289 
4290 static int
4291 wlan_mesh_delete_route(struct wlan_iface *wif, struct wlan_mesh_route *wmr)
4292 {
4293 	if (wmr->mroute_status == RowStatus_active &&
4294 	    wlan_mesh_del_route(wif, wmr) < 0)
4295 		return (-1);
4296 
4297 	SLIST_REMOVE(&wif->mesh_routelist, wmr, wlan_mesh_route, wr);
4298 	free(wmr);
4299 
4300 	return (0);
4301 }
4302 
4303 static void
4304 wlan_mesh_update_routes(void)
4305 {
4306 	struct wlan_iface *wif;
4307 	struct wlan_mesh_route *wmr, *twmr;
4308 
4309 	if ((time(NULL) - wlan_mrlist_age) <= WLAN_LIST_MAXAGE)
4310 		return;
4311 
4312 	for (wif = wlan_mesh_first_interface(); wif != NULL;
4313 	    wif = wlan_mesh_next_interface(wif)) {
4314 		/*
4315 		 * Nuke old entries - XXX - they are likely not to
4316 		 * change often - reconsider.
4317 		 */
4318 		SLIST_FOREACH_SAFE(wmr, &wif->mesh_routelist, wr, twmr)
4319 			if (wmr->mroute_status == RowStatus_active) {
4320 				SLIST_REMOVE(&wif->mesh_routelist, wmr,
4321 				    wlan_mesh_route, wr);
4322 				wlan_mesh_free_route(wmr);
4323 			}
4324 		(void)wlan_mesh_get_routelist(wif);
4325 	}
4326 	wlan_mrlist_age = time(NULL);
4327 }
4328 
4329 static struct wlan_mesh_route *
4330 wlan_mesh_get_route(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
4331 {
4332 	char wname[IFNAMSIZ];
4333 	char dstmac[IEEE80211_ADDR_LEN];
4334 
4335 	if (wlan_mac_index_decode(oid, sub, wname, dstmac) < 0)
4336 		return (NULL);
4337 
4338 	if ((*wif = wlan_find_interface(wname)) == NULL)
4339 		return (NULL);
4340 
4341 	return (wlan_mesh_find_route(*wif, dstmac));
4342 }
4343 
4344 static struct wlan_mesh_route *
4345 wlan_mesh_get_next_route(const struct asn_oid *oid, uint sub,
4346     struct wlan_iface **wif)
4347 {
4348 	char wname[IFNAMSIZ];
4349 	char dstmac[IEEE80211_ADDR_LEN];
4350 	struct wlan_mesh_route *wmr;
4351 
4352 	if (oid->len - sub == 0) {
4353 		for (*wif = wlan_mesh_first_interface(); *wif != NULL;
4354 		    *wif = wlan_mesh_next_interface(*wif)) {
4355 			wmr = SLIST_FIRST(&(*wif)->mesh_routelist);
4356 			if (wmr != NULL)
4357 				return (wmr);
4358 		}
4359 		return (NULL);
4360 	}
4361 
4362 	if (wlan_mac_index_decode(oid, sub, wname, dstmac) < 0 ||
4363 	    (*wif = wlan_find_interface(wname)) == NULL ||
4364 	    (wmr = wlan_mesh_find_route(*wif, dstmac)) == NULL)
4365 		return (NULL);
4366 
4367 	if ((wmr = SLIST_NEXT(wmr, wr)) != NULL)
4368 		return (wmr);
4369 
4370 	while ((*wif = wlan_mesh_next_interface(*wif)) != NULL)
4371 		if ((wmr = SLIST_FIRST(&(*wif)->mesh_routelist)) != NULL)
4372 			break;
4373 
4374 	return (wmr);
4375 }
4376 
4377 static int
4378 wlan_mesh_route_set_status(struct snmp_context *ctx, struct snmp_value *val,
4379     uint sub)
4380 {
4381 	char wname[IFNAMSIZ];
4382 	char mac[IEEE80211_ADDR_LEN];
4383 	struct wlan_mesh_route *wmr;
4384 	struct wlan_iface *wif;
4385 
4386 	if (wlan_mac_index_decode(&val->var, sub, wname, mac) < 0)
4387 		return (SNMP_ERR_GENERR);
4388 	wmr = wlan_mesh_get_route(&val->var, sub, &wif);
4389 
4390 	switch (val->v.integer) {
4391 	case RowStatus_createAndGo:
4392 		if (wmr != NULL)
4393 			return (SNMP_ERR_INCONS_NAME);
4394 		break;
4395 	case RowStatus_destroy:
4396 		if (wmr == NULL)
4397 			return (SNMP_ERR_NOSUCHNAME);
4398 		ctx->scratch->int1 = RowStatus_active;
4399 		return (SNMP_ERR_NOERROR);
4400 	default:
4401 		return (SNMP_ERR_INCONS_VALUE);
4402 	}
4403 
4404 	if ((wif = wlan_find_interface(wname)) == NULL)
4405 		return (SNMP_ERR_INCONS_NAME);
4406 
4407 	if ((wmr = wlan_mesh_new_route(mac)) == NULL)
4408 		return (SNMP_ERR_GENERR);
4409 
4410 	if (wlan_mesh_add_rtentry(wif, wmr) < 0) {
4411 		wlan_mesh_free_route(wmr);
4412 		return (SNMP_ERR_GENERR);
4413 	}
4414 
4415 	ctx->scratch->int1 = RowStatus_destroy;
4416 	if (wlan_mesh_add_route(wif, wmr) < 0) {
4417 		(void)wlan_mesh_delete_route(wif, wmr);
4418 		return (SNMP_ERR_GENERR);
4419 	}
4420 
4421 	return (SNMP_ERR_NOERROR);
4422 }
4423 
4424 /*
4425  * Wlan snmp module initialization hook.
4426  * Returns 0 on success, < 0 on error.
4427  */
4428 static int
4429 wlan_init(struct lmodule * mod __unused, int argc __unused,
4430      char *argv[] __unused)
4431 {
4432 	if (wlan_kmodules_load() < 0)
4433 		return (-1);
4434 
4435 	if (wlan_ioctl_init() < 0)
4436 		return (-1);
4437 
4438 	/* Register for new interface creation notifications. */
4439 	if (mib_register_newif(wlan_attach_newif, wlan_module)) {
4440 		syslog(LOG_ERR, "Cannot register newif function: %s",
4441 		    strerror(errno));
4442 		return (-1);
4443 	}
4444 
4445 	return (0);
4446 }
4447 
4448 /*
4449  * Wlan snmp module finalization hook.
4450  */
4451 static int
4452 wlan_fini(void)
4453 {
4454 	mib_unregister_newif(wlan_module);
4455 	or_unregister(reg_wlan);
4456 
4457 	/* XXX: Cleanup! */
4458 	wlan_free_iflist();
4459 
4460 	return (0);
4461 }
4462 
4463 /*
4464  * Refetch all available data from the kernel.
4465  */
4466 static void
4467 wlan_update_data(void *arg __unused)
4468 {
4469 }
4470 
4471 /*
4472  * Wlan snmp module start operation.
4473  */
4474 static void
4475 wlan_start(void)
4476 {
4477 	struct mibif *ifp;
4478 
4479 	reg_wlan = or_register(&oid_wlan,
4480 	    "The MIB module for managing wireless networking.", wlan_module);
4481 
4482 	 /* Add the existing wlan interfaces. */
4483 	 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
4484 		wlan_attach_newif(ifp);
4485 
4486 	wlan_data_timer = timer_start_repeat(wlan_poll_ticks,
4487 	    wlan_poll_ticks, wlan_update_data, NULL, wlan_module);
4488 }
4489 
4490 /*
4491  * Dump the Wlan snmp module data on SIGUSR1.
4492  */
4493 static void
4494 wlan_dump(void)
4495 {
4496 	/* XXX: Print some debug info to syslog. */
4497 	struct wlan_iface *wif;
4498 
4499 	for (wif = wlan_first_interface(); wif != NULL;
4500 	    wif = wlan_next_interface(wif))
4501 		syslog(LOG_ERR, "wlan iface %s", wif->wname);
4502 }
4503 
4504 const char wlan_comment[] = \
4505 "This module implements the BEGEMOT MIB for wireless networking.";
4506 
4507 const struct snmp_module config = {
4508 	.comment =	wlan_comment,
4509 	.init =		wlan_init,
4510 	.fini =		wlan_fini,
4511 	.start =	wlan_start,
4512 	.tree =		wlan_ctree,
4513 	.dump =		wlan_dump,
4514 	.tree_size =	wlan_CTREE_SIZE,
4515 };
4516