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