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
57static struct lmodule *wlan_module;
58
59/* For the registration. */
60static const struct asn_oid oid_wlan = OIDX_begemotWlan;
61/* The registration. */
62static uint reg_wlan;
63
64/* Periodic timer for polling the module's data. */
65static 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 */
72static int wlan_poll_ticks = (15 * 60) * 100;
73
74/* The age of each table. */
75#define	WLAN_LIST_MAXAGE	5
76
77static time_t wlan_iflist_age;
78static time_t wlan_peerlist_age;
79static time_t wlan_chanlist_age;
80static time_t wlan_roamlist_age;
81static time_t wlan_tx_paramlist_age;
82static time_t wlan_scanlist_age;
83static time_t wlan_maclist_age;
84static time_t wlan_mrlist_age;
85
86/*
87 * The list of all virtual wireless interfaces - sorted by name.
88 */
89SLIST_HEAD(wlan_ifaces, wlan_iface);
90static struct wlan_ifaces wlan_ifaces = SLIST_HEAD_INITIALIZER(wlan_ifaces);
91
92static struct wlan_config wlan_config;
93
94/* Forward declarations */
95static int	bits_get(struct snmp_value *, const u_char *, ssize_t);
96
97static int	wlan_add_wif(struct wlan_iface *);
98static void	wlan_delete_wif(struct wlan_iface *);
99static int	wlan_attach_newif(struct mibif *);
100static int	wlan_iface_create(struct wlan_iface *);
101static int	wlan_iface_destroy(struct wlan_iface *);
102static struct wlan_iface *	wlan_new_wif(char *);
103
104static void	wlan_free_interface(struct wlan_iface *);
105static void	wlan_free_iflist(void);
106static void	wlan_free_peerlist(struct wlan_iface *);
107static void	wlan_scan_free_results(struct wlan_iface *);
108static void	wlan_mac_free_maclist(struct wlan_iface *);
109static void	wlan_mesh_free_routes(struct wlan_iface *);
110
111static int	wlan_update_interface(struct wlan_iface *);
112static void	wlan_update_interface_list(void);
113static void	wlan_update_peers(void);
114static void	wlan_update_channels(void);
115static void	wlan_update_roam_params(void);
116static void	wlan_update_tx_params(void);
117static void	wlan_scan_update_results(void);
118static void	wlan_mac_update_aclmacs(void);
119static void	wlan_mesh_update_routes(void);
120
121static struct wlan_iface *	wlan_find_interface(const char *);
122static struct wlan_peer *	wlan_find_peer(struct wlan_iface *, uint8_t *);
123static struct ieee80211_channel*	wlan_find_channel(struct wlan_iface *,
124    uint32_t);
125static struct wlan_scan_result *	wlan_scan_find_result(struct wlan_iface *,
126    uint8_t *, uint8_t *);
127static struct wlan_mac_mac *		wlan_mac_find_mac(struct wlan_iface *,
128    uint8_t *);
129static struct wlan_mesh_route *		wlan_mesh_find_route(struct wlan_iface *,
130    uint8_t *);
131
132static struct wlan_iface *	wlan_first_interface(void);
133static struct wlan_iface *	wlan_next_interface(struct wlan_iface *);
134static struct wlan_iface *	wlan_mesh_first_interface(void);
135static struct wlan_iface *	wlan_mesh_next_interface(struct wlan_iface *);
136
137static struct wlan_iface *	wlan_get_interface(const struct asn_oid *, uint);
138static struct wlan_iface *	wlan_get_snmp_interface(const struct asn_oid *,
139    uint);
140static struct wlan_peer *	wlan_get_peer(const struct asn_oid *, uint,
141    struct wlan_iface **);
142static struct ieee80211_channel *wlan_get_channel(const struct asn_oid *, uint,
143    struct wlan_iface **);
144static struct ieee80211_roamparam *wlan_get_roam_param(const struct asn_oid *,
145    uint, struct wlan_iface **);
146static struct ieee80211_txparam *wlan_get_tx_param(const struct asn_oid *,
147    uint, struct wlan_iface **, uint32_t *);
148static struct wlan_scan_result *wlan_get_scanr(const struct asn_oid *, uint,
149    struct wlan_iface **);
150static struct wlan_mac_mac *	wlan_get_acl_mac(const struct asn_oid *,
151    uint, struct wlan_iface **);
152static struct wlan_iface *	wlan_mesh_get_iface(const struct asn_oid *, uint);
153static struct wlan_peer *	wlan_mesh_get_peer(const struct asn_oid *, uint,
154    struct wlan_iface **);
155static struct wlan_mesh_route *	wlan_mesh_get_route(const struct asn_oid *,
156    uint, struct wlan_iface **);
157
158static struct wlan_iface *	wlan_get_next_interface(const struct asn_oid *,
159    uint);
160static struct wlan_iface *	wlan_get_next_snmp_interface(const struct
161    asn_oid *, uint);
162static struct wlan_peer *	wlan_get_next_peer(const struct asn_oid *, uint,
163    struct wlan_iface **);
164static struct ieee80211_channel *wlan_get_next_channel(const struct asn_oid *,
165    uint, struct wlan_iface **);
166static struct ieee80211_roamparam *wlan_get_next_roam_param(const struct
167    asn_oid *, uint sub, struct wlan_iface **, uint32_t *);
168static struct ieee80211_txparam *wlan_get_next_tx_param(const struct asn_oid *,
169    uint, struct wlan_iface **, uint32_t *);
170static struct wlan_scan_result *wlan_get_next_scanr(const struct asn_oid *,
171    uint , struct wlan_iface **);
172static struct wlan_mac_mac *	wlan_get_next_acl_mac(const struct asn_oid *,
173    uint, struct wlan_iface **);
174static struct wlan_iface *	wlan_mesh_get_next_iface(const struct asn_oid *,
175    uint);
176static struct wlan_peer *	wlan_mesh_get_next_peer(const struct asn_oid *,
177    uint, struct wlan_iface **);
178static struct wlan_mesh_route *	wlan_mesh_get_next_route(const struct asn_oid *,
179    uint sub, struct wlan_iface **);
180
181static uint8_t *wlan_get_ifname(const struct asn_oid *, uint, uint8_t *);
182static int	wlan_mac_index_decode(const struct asn_oid *, uint, char *,
183    uint8_t *);
184static int	wlan_channel_index_decode(const struct asn_oid *, uint,
185    char *, uint32_t *);
186static int	wlan_phy_index_decode(const struct asn_oid *, uint, char *,
187    uint32_t *);
188static int wlan_scanr_index_decode(const struct asn_oid *oid, uint sub,
189    char *wname, uint8_t *ssid, uint8_t *bssid);
190
191static void	wlan_append_ifindex(struct asn_oid *, uint,
192    const struct wlan_iface *);
193static void	wlan_append_mac_index(struct asn_oid *, uint, char *, uint8_t *);
194static void	wlan_append_channel_index(struct asn_oid *, uint,
195    const struct wlan_iface *, const struct ieee80211_channel *);
196static void	wlan_append_phy_index(struct asn_oid *, uint, char *, uint32_t);
197static void	wlan_append_scanr_index(struct asn_oid *, uint, char *,
198    uint8_t *, uint8_t *);
199
200static int	wlan_acl_mac_set_status(struct snmp_context *,
201    struct snmp_value *, uint);
202static int	wlan_mesh_route_set_status(struct snmp_context *,
203    struct snmp_value *, uint);
204
205static int32_t	wlan_get_channel_type(struct ieee80211_channel *);
206static int	wlan_scan_compare_result(struct wlan_scan_result *,
207    struct wlan_scan_result *);
208static int	wlan_mac_delete_mac(struct wlan_iface *, struct wlan_mac_mac *);
209static 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 */
216int
217op_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
443int
444op_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
486int
487op_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
709get_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
853set_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
875int
876op_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
961int
962op_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
1029int
1030op_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
1076int
1077op_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
1159get_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
1180int
1181op_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
1288int
1289op_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
1347int
1348op_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
1750int
1751op_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
1848int
1849op_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
1856int
1857op_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
1946int
1947op_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
2012int
2013op_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
2111int
2112op_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
2272int
2273op_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
2341int
2342op_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
2433int
2434op_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
2505int
2506op_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
2643int
2644op_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
2723int
2724op_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 */
2777static int
2778bits_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 */
2805static void
2806wlan_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
2816static void
2817wlan_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
2827static struct wlan_iface *
2828wlan_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
2842static struct wlan_iface *
2843wlan_first_interface(void)
2844{
2845	return (SLIST_FIRST(&wlan_ifaces));
2846}
2847
2848static struct wlan_iface *
2849wlan_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 */
2860static int
2861wlan_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
2890static struct wlan_iface *
2891wlan_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
2920static void
2921wlan_delete_wif(struct wlan_iface *wif)
2922{
2923	SLIST_REMOVE(&wlan_ifaces, wif, wlan_iface, w_if);
2924	wlan_free_interface(wif);
2925}
2926
2927static int
2928wlan_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
2947static int
2948wlan_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
2965static int
2966wlan_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
2979static int
2980wlan_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
3015static void
3016wlan_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
3034static void
3035wlan_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
3045static uint8_t *
3046wlan_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
3062static struct wlan_iface *
3063wlan_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
3073static struct wlan_iface *
3074wlan_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
3105static struct wlan_iface *
3106wlan_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
3122static struct wlan_iface *
3123wlan_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 */
3152static int
3153wlan_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
3176static void
3177wlan_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 */
3196static int
3197wlan_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
3213static void
3214wlan_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 */
3228static void
3229wlan_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
3241static struct wlan_peer *
3242wlan_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
3253struct wlan_peer *
3254wlan_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
3267void
3268wlan_free_peer(struct wlan_peer *wip)
3269{
3270	free(wip);
3271}
3272
3273int
3274wlan_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
3298static void
3299wlan_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
3316static struct wlan_peer *
3317wlan_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
3331static struct wlan_peer *
3332wlan_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 */
3372static void
3373wlan_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
3389static int
3390wlan_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
3406static void
3407wlan_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
3419static int32_t
3420wlan_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
3442static struct ieee80211_channel *
3443wlan_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
3451static struct ieee80211_channel *
3452wlan_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
3466static struct ieee80211_channel *
3467wlan_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 */
3504static void
3505wlan_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
3521static struct ieee80211_roamparam *
3522wlan_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
3539static struct ieee80211_roamparam *
3540wlan_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 */
3576static void
3577wlan_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
3594static struct ieee80211_txparam *
3595wlan_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
3612static struct ieee80211_txparam *
3613wlan_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 */
3649static void
3650wlan_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
3662static struct wlan_scan_result *
3663wlan_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
3676struct wlan_scan_result *
3677wlan_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
3693void
3694wlan_scan_free_result(struct wlan_scan_result *sr)
3695{
3696	free(sr);
3697}
3698
3699static int
3700wlan_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
3727int
3728wlan_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
3754static void
3755wlan_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
3772static int
3773wlan_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
3801static void
3802wlan_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
3823static struct wlan_scan_result *
3824wlan_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
3839static struct wlan_scan_result *
3840wlan_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 */
3876static void
3877wlan_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
3889static struct wlan_mac_mac *
3890wlan_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
3901struct wlan_mac_mac *
3902wlan_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
3916void
3917wlan_mac_free_mac(struct wlan_mac_mac *wmm)
3918{
3919	free(wmm);
3920}
3921
3922int
3923wlan_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
3947static int
3948wlan_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
3960static void
3961wlan_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
3988static struct wlan_mac_mac *
3989wlan_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
4003static struct wlan_mac_mac *
4004wlan_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
4036static int
4037wlan_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 */
4089static struct wlan_iface *
4090wlan_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
4102static struct wlan_iface *
4103wlan_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
4117static struct wlan_iface *
4118wlan_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
4131static struct wlan_iface *
4132wlan_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 */
4158static struct wlan_peer *
4159wlan_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
4174static struct wlan_peer *
4175wlan_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 */
4210static void
4211wlan_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
4223static struct wlan_mesh_route *
4224wlan_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
4239struct wlan_mesh_route *
4240wlan_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
4254void
4255wlan_mesh_free_route(struct wlan_mesh_route *wmr)
4256{
4257	free(wmr);
4258}
4259
4260int
4261wlan_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
4288static int
4289wlan_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
4301static void
4302wlan_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
4327static struct wlan_mesh_route *
4328wlan_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
4342static struct wlan_mesh_route *
4343wlan_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
4375static int
4376wlan_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 */
4426static int
4427wlan_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 */
4449static int
4450wlan_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 */
4464static void
4465wlan_update_data(void *arg __unused)
4466{
4467}
4468
4469/*
4470 * Wlan snmp module start operation.
4471 */
4472static void
4473wlan_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 */
4491static void
4492wlan_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
4502const char wlan_comment[] = \
4503"This module implements the BEGEMOT MIB for wireless networking.";
4504
4505const 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