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