text: /*-
   * Copyright (c) 2010 The FreeBSD Foundation
   * All rights reserved.
   *
   * This software was developed by Shteryana Sotirova Shopova under
   * sponsorship from the FreeBSD Foundation.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   *
   * $FreeBSD: soc2013/dpl/head/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.c 210545 2010-07-26 16:16:39Z syrinx $
   */
  
  #include <sys/queue.h>
  #include <sys/socket.h>
  #include <sys/types.h>
  
  #include <net/if.h>
  #include <net/if_media.h>
  #include <net/if_mib.h>
  #include <net/if_types.h>
  #include <net80211/ieee80211.h>
  #include <net80211/ieee80211_ioctl.h>
  
  #include <errno.h>
  #include <stdarg.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <string.h>
  #include <syslog.h>
  
  #include <bsnmp/snmpmod.h>
  #include <bsnmp/snmp_mibII.h>
  
  #include "wlan_tree.h"
  #include "wlan_snmp.h"
  #include "wlan_oid.h"
  
  static struct lmodule *wlan_module;
  
  /* For the registration. */
  static const struct asn_oid oid_wlan = OIDX_begemotWlan;
  /* The registration. */
  static uint reg_wlan;
  
  /* Periodic timer for polling the module's data. */
  static void *wlan_data_timer;
  
  /*
   * Poll data from kernel every 15 minutes unless explicitly requested by an
   * SNMP client.
   * XXX: make that configurable.
   */
  static int wlan_poll_ticks = (15 * 60) * 100;
  
  /* The age of each table. */
  #define	WLAN_LIST_MAXAGE	5
  
  static time_t wlan_iflist_age;
  static time_t wlan_peerlist_age;
  static time_t wlan_chanlist_age;
  static time_t wlan_roamlist_age;
  static time_t wlan_tx_paramlist_age;
  static time_t wlan_scanlist_age;
  static time_t wlan_maclist_age;
  static time_t wlan_mrlist_age;
  
  /*
   * The list of all virtual wireless interfaces - sorted by name.
   */
  SLIST_HEAD(wlan_ifaces, wlan_iface);
  static struct wlan_ifaces wlan_ifaces = SLIST_HEAD_INITIALIZER(wlan_ifaces);
  
  static struct wlan_config wlan_config;
  
  /* Forward declarations */
  static int	bits_get(struct snmp_value *, const u_char *, ssize_t);
  
  static int	wlan_add_wif(struct wlan_iface *);
  static void	wlan_delete_wif(struct wlan_iface *);
  static int	wlan_attach_newif(struct mibif *);
  static int	wlan_iface_create(struct wlan_iface *);
  static int	wlan_iface_destroy(struct wlan_iface *);
  static struct wlan_iface *	wlan_new_wif(char *);
  
  static void	wlan_free_interface(struct wlan_iface *);
  static void	wlan_free_iflist(void);
  static void	wlan_free_peerlist(struct wlan_iface *);
  static void	wlan_scan_free_results(struct wlan_iface *);
  static void	wlan_mac_free_maclist(struct wlan_iface *);
  static void	wlan_mesh_free_routes(struct wlan_iface *);
  
  static int	wlan_update_interface(struct wlan_iface *);
  static void	wlan_update_interface_list(void);
  static void	wlan_update_peers(void);
  static void	wlan_update_channels(void);
  static void	wlan_update_roam_params(void);
  static void	wlan_update_tx_params(void);
  static void	wlan_scan_update_results(void);
  static void	wlan_mac_update_aclmacs(void);
  static void	wlan_mesh_update_routes(void);
  
  static struct wlan_iface *	wlan_find_interface(const char *);
  static struct wlan_peer *	wlan_find_peer(struct wlan_iface *, uint8_t *);
  static struct ieee80211_channel*	wlan_find_channel(struct wlan_iface *,
      uint32_t);
  static struct wlan_scan_result *	wlan_scan_find_result(struct wlan_iface *,
      uint8_t *, uint8_t *);
  static struct wlan_mac_mac *		wlan_mac_find_mac(struct wlan_iface *,
      uint8_t *);
  static struct wlan_mesh_route *		wlan_mesh_find_route(struct wlan_iface *,
      uint8_t *);
  
  static struct wlan_iface *	wlan_first_interface(void);
  static struct wlan_iface *	wlan_next_interface(struct wlan_iface *);
  static struct wlan_iface *	wlan_mesh_first_interface(void);
  static struct wlan_iface *	wlan_mesh_next_interface(struct wlan_iface *);
  
  static struct wlan_iface *	wlan_get_interface(const struct asn_oid *, uint);
  static struct wlan_iface *	wlan_get_snmp_interface(const struct asn_oid *,
      uint);
  static struct wlan_peer *	wlan_get_peer(const struct asn_oid *, uint,
      struct wlan_iface **);
  static struct ieee80211_channel *wlan_get_channel(const struct asn_oid *, uint,
      struct wlan_iface **);
  static struct ieee80211_roamparam *wlan_get_roam_param(const struct asn_oid *,
      uint, struct wlan_iface **);
  static struct ieee80211_txparam *wlan_get_tx_param(const struct asn_oid *,
      uint, struct wlan_iface **, uint32_t *);
  static struct wlan_scan_result *wlan_get_scanr(const struct asn_oid *, uint,
      struct wlan_iface **);
  static struct wlan_mac_mac *	wlan_get_acl_mac(const struct asn_oid *,
      uint, struct wlan_iface **);
  static struct wlan_iface *	wlan_mesh_get_iface(const struct asn_oid *, uint);
  static struct wlan_peer *	wlan_mesh_get_peer(const struct asn_oid *, uint,
      struct wlan_iface **);
  static struct wlan_mesh_route *	wlan_mesh_get_route(const struct asn_oid *,
      uint, struct wlan_iface **);
  
  static struct wlan_iface *	wlan_get_next_interface(const struct asn_oid *,
      uint);
  static struct wlan_iface *	wlan_get_next_snmp_interface(const struct
      asn_oid *, uint);
  static struct wlan_peer *	wlan_get_next_peer(const struct asn_oid *, uint,
      struct wlan_iface **);
  static struct ieee80211_channel *wlan_get_next_channel(const struct asn_oid *,
      uint, struct wlan_iface **);
  static struct ieee80211_roamparam *wlan_get_next_roam_param(const struct
      asn_oid *, uint sub, struct wlan_iface **, uint32_t *);
  static struct ieee80211_txparam *wlan_get_next_tx_param(const struct asn_oid *,
      uint, struct wlan_iface **, uint32_t *);
  static struct wlan_scan_result *wlan_get_next_scanr(const struct asn_oid *,
      uint , struct wlan_iface **);
  static struct wlan_mac_mac *	wlan_get_next_acl_mac(const struct asn_oid *,
      uint, struct wlan_iface **);
  static struct wlan_iface *	wlan_mesh_get_next_iface(const struct asn_oid *,
      uint);
  static struct wlan_peer *	wlan_mesh_get_next_peer(const struct asn_oid *,
      uint, struct wlan_iface **);
  static struct wlan_mesh_route *	wlan_mesh_get_next_route(const struct asn_oid *,
      uint sub, struct wlan_iface **);
  
  static uint8_t *wlan_get_ifname(const struct asn_oid *, uint, uint8_t *);
  static int	wlan_mac_index_decode(const struct asn_oid *, uint, char *,
      uint8_t *);
  static int	wlan_channel_index_decode(const struct asn_oid *, uint,
      char *, uint32_t *);
  static int	wlan_phy_index_decode(const struct asn_oid *, uint, char *,
      uint32_t *);
  static int wlan_scanr_index_decode(const struct asn_oid *oid, uint sub,
      char *wname, uint8_t *ssid, uint8_t *bssid);
  
  static void	wlan_append_ifindex(struct asn_oid *, uint,
      const struct wlan_iface *);
  static void	wlan_append_mac_index(struct asn_oid *, uint, char *, uint8_t *);
  static void	wlan_append_channel_index(struct asn_oid *, uint,
      const struct wlan_iface *, const struct ieee80211_channel *);
  static void	wlan_append_phy_index(struct asn_oid *, uint, char *, uint32_t);
  static void	wlan_append_scanr_index(struct asn_oid *, uint, char *,
      uint8_t *, uint8_t *);
  
  static int	wlan_acl_mac_set_status(struct snmp_context *,
      struct snmp_value *, uint);
  static int	wlan_mesh_route_set_status(struct snmp_context *,
      struct snmp_value *, uint);
  
  static int32_t	wlan_get_channel_type(struct ieee80211_channel *);
  static int	wlan_scan_compare_result(struct wlan_scan_result *,
      struct wlan_scan_result *);
  static int	wlan_mac_delete_mac(struct wlan_iface *, struct wlan_mac_mac *);
  static int	wlan_mesh_delete_route(struct wlan_iface *,
      struct wlan_mesh_route *);
  
  /*
   * The module's GET/SET data hooks per each table or group of objects as
   * required by bsnmpd(1).
   */
  int
  op_wlan_iface(struct snmp_context *ctx, struct snmp_value *val, uint32_t sub,
      uint32_t iidx __unused, enum snmp_op op)
  {
  	int rc;
  	char wname[IFNAMSIZ];
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((wif = wlan_get_snmp_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  
  	case SNMP_OP_GETNEXT:
  		if ((wif = wlan_get_next_snmp_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_ifindex(&val->var, sub, wif);
  		break;
  
  	case SNMP_OP_SET:
  		if ((wif = wlan_get_snmp_interface(&val->var, sub)) == NULL) {
  			if (val->var.subs[sub - 1] != LEAF_wlanIfaceName)
  				return (SNMP_ERR_NOSUCHNAME);
  			if (wlan_get_ifname(&val->var, sub, wname) == NULL)
  				return (SNMP_ERR_INCONS_VALUE);
  			if ((wif = wlan_new_wif(wname)) == NULL)
  				return (SNMP_ERR_GENERR);
  			wif->internal = 1;
  		}
  		if (wif->status == RowStatus_active &&
  		    val->var.subs[sub - 1] != LEAF_wlanIfaceStatus &&
  		    val->var.subs[sub - 1] != LEAF_wlanIfaceState)
  			return (SNMP_ERR_INCONS_VALUE);
  
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanIfaceIndex:
  			return (SNMP_ERR_NOT_WRITEABLE);
  
  		case LEAF_wlanIfaceName:
  			if (val->v.octetstring.len >= IFNAMSIZ)
  				return (SNMP_ERR_INCONS_VALUE);
  			if ((ctx->scratch->ptr1 = malloc(IFNAMSIZ)) == NULL)
  				return (SNMP_ERR_GENERR);
  			strlcpy(ctx->scratch->ptr1, wif->wname, IFNAMSIZ);
  			memcpy(wif->wname, val->v.octetstring.octets,
  			    val->v.octetstring.len);
  			wif->wname[val->v.octetstring.len] = '\0';
  			return (SNMP_ERR_NOERROR);
  
  		case LEAF_wlanParentIfName:
  			if (val->v.octetstring.len >= IFNAMSIZ)
  				return (SNMP_ERR_INCONS_VALUE);
  			if ((ctx->scratch->ptr1 = malloc(IFNAMSIZ)) == NULL)
  				return (SNMP_ERR_GENERR);
  			strlcpy(ctx->scratch->ptr1, wif->pname, IFNAMSIZ);
  			memcpy(wif->pname, val->v.octetstring.octets,
  			    val->v.octetstring.len);
  			wif->pname[val->v.octetstring.len] = '\0';
  			return (SNMP_ERR_NOERROR);
  
  		case LEAF_wlanIfaceOperatingMode:
  			ctx->scratch->int1 = wif->mode;
  			wif->mode = val->v.integer;
  			return (SNMP_ERR_NOERROR);
  
  		case LEAF_wlanIfaceFlags:
  			if (val->v.octetstring.len > sizeof(wif->flags))
  				return (SNMP_ERR_INCONS_VALUE);
  			ctx->scratch->ptr1 = malloc(sizeof(wif->flags));
  			if (ctx->scratch->ptr1 == NULL)
  				return (SNMP_ERR_GENERR);
  			memcpy(ctx->scratch->ptr1, (uint8_t *)&wif->flags,
  			    sizeof(wif->flags));
  			memcpy((uint8_t *)&wif->flags, val->v.octetstring.octets,
  			    sizeof(wif->flags));
  			return (SNMP_ERR_NOERROR);
  
  		case LEAF_wlanIfaceBssid:
  			if (val->v.octetstring.len != IEEE80211_ADDR_LEN)
  				return (SNMP_ERR_INCONS_VALUE);
  			ctx->scratch->ptr1 = malloc(IEEE80211_ADDR_LEN);
  			if (ctx->scratch->ptr1 == NULL)
  				return (SNMP_ERR_GENERR);
  			memcpy(ctx->scratch->ptr1, wif->dbssid,
  			    IEEE80211_ADDR_LEN);
  			memcpy(wif->dbssid, val->v.octetstring.octets,
  			    IEEE80211_ADDR_LEN);
  			return (SNMP_ERR_NOERROR);
  
  		case LEAF_wlanIfaceLocalAddress:
  			if (val->v.octetstring.len != IEEE80211_ADDR_LEN)
  				return (SNMP_ERR_INCONS_VALUE);
  			ctx->scratch->ptr1 = malloc(IEEE80211_ADDR_LEN);
  			if (ctx->scratch->ptr1 == NULL)
  				return (SNMP_ERR_GENERR);
  			memcpy(ctx->scratch->ptr1, wif->dlmac,
  			    IEEE80211_ADDR_LEN);
  			memcpy(wif->dlmac, val->v.octetstring.octets,
  			    IEEE80211_ADDR_LEN);
  			return (SNMP_ERR_NOERROR);
  
  		case LEAF_wlanIfaceStatus:
  			ctx->scratch->int1 = wif->status;
  			wif->status = val->v.integer;
  			if (wif->status == RowStatus_active) {
  				rc = wlan_iface_create(wif); /* XXX */
  				if (rc != SNMP_ERR_NOERROR) {
  					wif->status = ctx->scratch->int1;
  					return (rc);
  				}
  			} else if (wif->status == RowStatus_destroy)
  				return (wlan_iface_destroy(wif));
  			else
  				wif->status = RowStatus_notReady;
  			return (SNMP_ERR_NOERROR);
  
  		case LEAF_wlanIfaceState:
  			ctx->scratch->int1 = wif->state;
  			wif->state = val->v.integer;
  			if (wif->status == RowStatus_active)
  				if (wlan_config_state(wif, 1) < 0)
  					return (SNMP_ERR_GENERR);
  			return (SNMP_ERR_NOERROR);
  		}
  		abort();
  
  	case SNMP_OP_ROLLBACK:
  		if ((wif = wlan_get_snmp_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanIfaceName:
  			strlcpy(wif->wname, ctx->scratch->ptr1, IFNAMSIZ);
  			free(ctx->scratch->ptr1);
  			break;
  
  		case LEAF_wlanParentIfName:
  			strlcpy(wif->pname, ctx->scratch->ptr1, IFNAMSIZ);
  			free(ctx->scratch->ptr1);
  			break;
  
  		case LEAF_wlanIfaceOperatingMode:
  			wif->mode = ctx->scratch->int1;
  			break;
  
  		case LEAF_wlanIfaceFlags:
  			memcpy((uint8_t *)&wif->flags, ctx->scratch->ptr1,
  			    sizeof(wif->flags));
  			free(ctx->scratch->ptr1);
  			break;
  
  		case LEAF_wlanIfaceBssid:
  			memcpy(wif->dbssid, ctx->scratch->ptr1,
  			    IEEE80211_ADDR_LEN);
  			free(ctx->scratch->ptr1);
  			break;
  
  		case LEAF_wlanIfaceLocalAddress:
  			memcpy(wif->dlmac, ctx->scratch->ptr1,
  			    IEEE80211_ADDR_LEN);
  			free(ctx->scratch->ptr1);
  			break;
  
  		case LEAF_wlanIfaceStatus:
  			wif->status = ctx->scratch->int1;
  			if (ctx->scratch->int1 == RowStatus_active)
  				return (SNMP_ERR_GENERR); /* XXX: FIXME */
  			else if (wif->internal != 0)
  				return (wlan_iface_destroy(wif));
  			break;
  
  		case LEAF_wlanIfaceState:
  			wif->state = ctx->scratch->int1;
  			if (wif->status == RowStatus_active)
  				if (wlan_config_state(wif, 1) < 0)
  					return (SNMP_ERR_GENERR);
  			break;
  		}
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_COMMIT:
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanIfaceName:
  		case LEAF_wlanParentIfName:
  		case LEAF_wlanIfaceFlags:
  		case LEAF_wlanIfaceBssid:
  		case LEAF_wlanIfaceLocalAddress:
  			free(ctx->scratch->ptr1);
  			/* FALLTHROUGH */
  		default:
  			return (SNMP_ERR_NOERROR);
  		}
  	default:
  		abort();
  	}
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanIfaceIndex:
  		val->v.integer = wif->index;
  		return (SNMP_ERR_NOERROR);
  	case LEAF_wlanIfaceName:
  		return (string_get(val, wif->wname, -1));
  	case LEAF_wlanParentIfName:
  		return (string_get(val, wif->pname, -1));
  	case LEAF_wlanIfaceOperatingMode:
  		val->v.integer = wif->mode;
  		return (SNMP_ERR_NOERROR);
  	case LEAF_wlanIfaceFlags:
  		return (bits_get(val, (uint8_t *)&wif->flags,
  		    sizeof(wif->flags)));
  	case LEAF_wlanIfaceBssid:
  		return (string_get(val, wif->dbssid, IEEE80211_ADDR_LEN));
  	case LEAF_wlanIfaceLocalAddress:
  		return (string_get(val, wif->dlmac, IEEE80211_ADDR_LEN));
  	case LEAF_wlanIfaceStatus:
  		val->v.integer = wif->status;
  		return (SNMP_ERR_NOERROR);
  	case LEAF_wlanIfaceState:
  		val->v.integer = wif->state;
  		return (SNMP_ERR_NOERROR);
  	}
  
  	abort();
  }
  
  int
  op_wlan_if_parent(struct snmp_context *ctx __unused, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  	case SNMP_OP_GETNEXT:
  		if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_ifindex(&val->var, sub, wif);
  		break;
  	case SNMP_OP_SET:
  		return (SNMP_ERR_NOT_WRITEABLE);
  	case SNMP_OP_COMMIT:
  		/* FALLTHROUGH */
  	case SNMP_OP_ROLLBACK:
  		/* FALLTHROUGH */
  	default:
  		abort();
  	}
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanIfParentDriverCapabilities:
  		return (bits_get(val, (uint8_t *)&wif->drivercaps,
  		    sizeof(wif->drivercaps)));
  	case LEAF_wlanIfParentCryptoCapabilities:
  		return (bits_get(val, (uint8_t *)&wif->cryptocaps,
  		    sizeof(wif->cryptocaps)));
  	case LEAF_wlanIfParentHTCapabilities:
  		return (bits_get(val, (uint8_t *)&wif->htcaps,
  		    sizeof(wif->htcaps)));
  	}
  
  	abort();
  }
  
  int
  op_wlan_iface_config(struct snmp_context *ctx, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	int intval, vlen, rc;
  	char *strval;
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		goto get_config;
  
  	case SNMP_OP_GETNEXT:
  		if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_ifindex(&val->var, sub, wif);
  		goto get_config;
  
  	case SNMP_OP_SET:
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  
  		intval = val->v.integer;
  		strval = NULL;
  		vlen = 0;
  
  		/* Simple sanity checks & save old data. */
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanIfaceCountryCode:
  			if (val->v.octetstring.len != WLAN_COUNTRY_CODE_SIZE)
  				return (SNMP_ERR_INCONS_VALUE);
  			break;
  		case LEAF_wlanIfaceDesiredSsid:
  			if (val->v.octetstring.len > IEEE80211_NWID_LEN)
  				return (SNMP_ERR_INCONS_VALUE);
  			break;
  		case LEAF_wlanIfaceDesiredBssid:
  			if (val->v.octetstring.len != IEEE80211_ADDR_LEN)
  				return (SNMP_ERR_INCONS_VALUE);
  			break;
  		case LEAF_wlanIfacePacketBurst:
  			ctx->scratch->int1 = wif->packet_burst;
  			break;
  		case LEAF_wlanIfaceRegDomain:
  			ctx->scratch->int1 = wif->reg_domain;
  			break;
  		case LEAF_wlanIfaceDesiredChannel:
  			ctx->scratch->int1 = wif->desired_channel;
  			break;
  		case LEAF_wlanIfaceDynamicFreqSelection:
  			ctx->scratch->int1 = wif->dyn_frequency;
  			break;
  		case LEAF_wlanIfaceFastFrames:
  			ctx->scratch->int1 = wif->fast_frames;
  			break;
  		case LEAF_wlanIfaceDturbo:
  			ctx->scratch->int1 = wif->dturbo;
  			break;
  		case LEAF_wlanIfaceTxPower:
  			ctx->scratch->int1 = wif->tx_power;
  			break;
  		case LEAF_wlanIfaceFragmentThreshold:
  			ctx->scratch->int1 = wif->frag_threshold;
  			break;
  		case LEAF_wlanIfaceRTSThreshold:
  			ctx->scratch->int1 = wif->rts_threshold;
  			break;
  		case LEAF_wlanIfaceWlanPrivacySubscribe:
  			ctx->scratch->int1 = wif->priv_subscribe;
  			break;
  		case LEAF_wlanIfaceBgScan:
  			ctx->scratch->int1 = wif->bg_scan;
  			break;
  		case LEAF_wlanIfaceBgScanIdle:
  			ctx->scratch->int1 = wif->bg_scan_idle;
  			break;
  		case LEAF_wlanIfaceBgScanInterval:
  			ctx->scratch->int1 = wif->bg_scan_interval;
  			break;
  		case LEAF_wlanIfaceBeaconMissedThreshold:
  			ctx->scratch->int1 = wif->beacons_missed;
  			break;
  		case LEAF_wlanIfaceRoamingMode:
  			ctx->scratch->int1 = wif->roam_mode;
  			break;
  		case LEAF_wlanIfaceDot11d:
  			ctx->scratch->int1 = wif->dot11d;
  			break;
  		case LEAF_wlanIfaceDot11h:
  			ctx->scratch->int1 = wif->dot11h;
  			break;
  		case LEAF_wlanIfaceDynamicWds:
  			ctx->scratch->int1 = wif->dynamic_wds;
  			break;
  		case LEAF_wlanIfacePowerSave:
  			ctx->scratch->int1 = wif->power_save;
  			break;
  		case LEAF_wlanIfaceApBridge:
  			ctx->scratch->int1 = wif->ap_bridge;
  			break;
  		case LEAF_wlanIfaceBeaconInterval:
  			ctx->scratch->int1 = wif->beacon_interval;
  			break;
  		case LEAF_wlanIfaceDtimPeriod:
  			ctx->scratch->int1 = wif->dtim_period;
  			break;
  		case LEAF_wlanIfaceHideSsid:
  			ctx->scratch->int1 = wif->hide_ssid;
  			break;
  		case LEAF_wlanIfaceInactivityProccess:
  			ctx->scratch->int1 = wif->inact_process;
  			break;
  		case LEAF_wlanIfaceDot11gProtMode:
  			ctx->scratch->int1 = wif->do11g_protect;
  			break;
  		case LEAF_wlanIfaceDot11gPureMode:
  			ctx->scratch->int1 = wif->dot11g_pure;
  			break;
  		case LEAF_wlanIfaceDot11nPureMode:
  			ctx->scratch->int1 = wif->dot11n_pure;
  			break;
  		case LEAF_wlanIfaceDot11nAmpdu:
  			ctx->scratch->int1 = wif->ampdu;
  			break;
  		case LEAF_wlanIfaceDot11nAmpduDensity:
  			ctx->scratch->int1 = wif->ampdu_density;
  			break;
  		case LEAF_wlanIfaceDot11nAmpduLimit:
  			ctx->scratch->int1 = wif->ampdu_limit;
  			break;
  		case LEAF_wlanIfaceDot11nAmsdu:
  			ctx->scratch->int1 = wif->amsdu;
  			break;
  		case LEAF_wlanIfaceDot11nAmsduLimit:
  			ctx->scratch->int1 = wif->amsdu_limit;
  			break;
  		case LEAF_wlanIfaceDot11nHighThroughput:
  			ctx->scratch->int1 = wif->ht_enabled;
  			break;
  		case LEAF_wlanIfaceDot11nHTCompatible:
  			ctx->scratch->int1 = wif->ht_compatible;
  			break;
  		case LEAF_wlanIfaceDot11nHTProtMode:
  			ctx->scratch->int1 = wif->ht_prot_mode;
  			break;
  		case LEAF_wlanIfaceDot11nRIFS:
  			ctx->scratch->int1 = wif->rifs;
  			break;
  		case LEAF_wlanIfaceDot11nShortGI:
  			ctx->scratch->int1 = wif->short_gi;
  			break;
  		case LEAF_wlanIfaceDot11nSMPSMode:
  			ctx->scratch->int1 = wif->smps_mode;
  			break;
  		case LEAF_wlanIfaceTdmaSlot:
  			ctx->scratch->int1 = wif->tdma_slot;
  			break;
  		case LEAF_wlanIfaceTdmaSlotCount:
  			ctx->scratch->int1 = wif->tdma_slot_count;
  			break;
  		case LEAF_wlanIfaceTdmaSlotLength:
  			ctx->scratch->int1 = wif->tdma_slot_length;
  			break;
  		case LEAF_wlanIfaceTdmaBeaconInterval:
  			ctx->scratch->int1 = wif->tdma_binterval;
  			break;
  		default:
  			abort();
  		}
  
  		if (val->syntax != SNMP_SYNTAX_OCTETSTRING)
  			goto set_config;
  
  		ctx->scratch->int1 = val->v.octetstring.len;
  		ctx->scratch->ptr1 = malloc(val->v.octetstring.len + 1);
  		if (ctx->scratch->ptr1 == NULL)
  			return (SNMP_ERR_GENERR); /* XXX */
  		if (val->var.subs[sub - 1] == LEAF_wlanIfaceDesiredSsid)
  			strlcpy(ctx->scratch->ptr1, val->v.octetstring.octets,
  			    val->v.octetstring.len + 1);
  		else
  			memcpy(ctx->scratch->ptr1, val->v.octetstring.octets,
  			    val->v.octetstring.len);
  		strval = val->v.octetstring.octets;
  		vlen = val->v.octetstring.len;
  		goto set_config;
  
  	case SNMP_OP_ROLLBACK:
  		intval = ctx->scratch->int1;
  		strval = NULL;
  		vlen = 0;
  
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanIfaceCountryCode:
  		case LEAF_wlanIfaceDesiredSsid:
  		case LEAF_wlanIfaceDesiredBssid:
  			strval = ctx->scratch->ptr1;
  			vlen = ctx->scratch->int1;
  			break;
  		default:
  			break;
  		}
  		goto set_config;
  
  	case SNMP_OP_COMMIT:
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanIfaceCountryCode:
  		case LEAF_wlanIfaceDesiredSsid:
  		case LEAF_wlanIfaceDesiredBssid:
  			free(ctx->scratch->ptr1);
  			/* FALLTHROUGH */
  		default:
  			return (SNMP_ERR_NOERROR);
  		}
  	}
  	abort();
  
  get_config:
  
  	if (wlan_config_get_ioctl(wif, val->var.subs[sub - 1]) < 0)
  		return (SNMP_ERR_GENERR);
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanIfacePacketBurst:
  		val->v.integer = wif->packet_burst;
  		break;
  	case LEAF_wlanIfaceCountryCode:
  		return (string_get(val, wif->country_code,
  		    WLAN_COUNTRY_CODE_SIZE));
  	case LEAF_wlanIfaceRegDomain:
  		val->v.integer = wif->reg_domain;
  		break;
  	case LEAF_wlanIfaceDesiredSsid:
  		return (string_get(val, wif->desired_ssid, -1));
  	case LEAF_wlanIfaceDesiredChannel:
  		val->v.integer = wif->desired_channel;
  		break;
  	case LEAF_wlanIfaceDynamicFreqSelection:
  		val->v.integer = wif->dyn_frequency;
  		break;
  	case LEAF_wlanIfaceFastFrames:
  		val->v.integer = wif->fast_frames;
  		break;
  	case LEAF_wlanIfaceDturbo:
  		val->v.integer = wif->dturbo;
  		break;
  	case LEAF_wlanIfaceTxPower:
  		val->v.integer = wif->tx_power;
  		break;
  	case LEAF_wlanIfaceFragmentThreshold:
  		val->v.integer = wif->frag_threshold;
  		break;
  	case LEAF_wlanIfaceRTSThreshold:
  		val->v.integer = wif->rts_threshold;
  		break;
  	case LEAF_wlanIfaceWlanPrivacySubscribe:
  		val->v.integer = wif->priv_subscribe;
  		break;
  	case LEAF_wlanIfaceBgScan:
  		val->v.integer = wif->bg_scan;
  		break;
  	case LEAF_wlanIfaceBgScanIdle:
  		val->v.integer = wif->bg_scan_idle;
  		break;
  	case LEAF_wlanIfaceBgScanInterval:
  		val->v.integer = wif->bg_scan_interval;
  		break;
  	case LEAF_wlanIfaceBeaconMissedThreshold:
  		val->v.integer = wif->beacons_missed;
  		break;
  	case LEAF_wlanIfaceDesiredBssid:
  		return (string_get(val, wif->desired_bssid,
  		    IEEE80211_ADDR_LEN));
  	case LEAF_wlanIfaceRoamingMode:
  		val->v.integer = wif->roam_mode;
  		break;
  	case LEAF_wlanIfaceDot11d:
  		val->v.integer = wif->dot11d;
  		break;
  	case LEAF_wlanIfaceDot11h:
  		val->v.integer = wif->dot11h;
  		break;
  	case LEAF_wlanIfaceDynamicWds:
  		val->v.integer = wif->dynamic_wds;
  		break;
  	case LEAF_wlanIfacePowerSave:
  		val->v.integer = wif->power_save;
  		break;
  	case LEAF_wlanIfaceApBridge:
  		val->v.integer = wif->ap_bridge;
  		break;
  	case LEAF_wlanIfaceBeaconInterval:
  		val->v.integer = wif->beacon_interval;
  		break;
  	case LEAF_wlanIfaceDtimPeriod:
  		val->v.integer = wif->dtim_period;
  		break;
  	case LEAF_wlanIfaceHideSsid:
  		val->v.integer = wif->hide_ssid;
  		break;
  	case LEAF_wlanIfaceInactivityProccess:
  		val->v.integer = wif->inact_process;
  		break;
  	case LEAF_wlanIfaceDot11gProtMode:
  		val->v.integer = wif->do11g_protect;
  		break;
  	case LEAF_wlanIfaceDot11gPureMode:
  		val->v.integer = wif->dot11g_pure;
  		break;
  	case LEAF_wlanIfaceDot11nPureMode:
  		val->v.integer = wif->dot11n_pure;
  		break;
  	case LEAF_wlanIfaceDot11nAmpdu:
  		val->v.integer = wif->ampdu;
  		break;
  	case LEAF_wlanIfaceDot11nAmpduDensity:
  		val->v.integer = wif->ampdu_density;
  		break;
  	case LEAF_wlanIfaceDot11nAmpduLimit:
  		val->v.integer = wif->ampdu_limit;
  		break;
  	case LEAF_wlanIfaceDot11nAmsdu:
  		val->v.integer = wif->amsdu;
  		break;
  	case LEAF_wlanIfaceDot11nAmsduLimit:
  		val->v.integer = wif->amsdu_limit;
  		break;
  	case LEAF_wlanIfaceDot11nHighThroughput:
  		val->v.integer = wif->ht_enabled;
  		break;
  	case LEAF_wlanIfaceDot11nHTCompatible:
  		val->v.integer = wif->ht_compatible;
  		break;
  	case LEAF_wlanIfaceDot11nHTProtMode:
  		val->v.integer = wif->ht_prot_mode;
  		break;
  	case LEAF_wlanIfaceDot11nRIFS:
  		val->v.integer = wif->rifs;
  		break;
  	case LEAF_wlanIfaceDot11nShortGI:
  		val->v.integer = wif->short_gi;
  		break;
  	case LEAF_wlanIfaceDot11nSMPSMode:
  		val->v.integer = wif->smps_mode;
  		break;
  	case LEAF_wlanIfaceTdmaSlot:
  		val->v.integer = wif->tdma_slot;
  		break;
  	case LEAF_wlanIfaceTdmaSlotCount:
  		val->v.integer = wif->tdma_slot_count;
  		break;
  	case LEAF_wlanIfaceTdmaSlotLength:
  		val->v.integer = wif->tdma_slot_length;
  		break;
  	case LEAF_wlanIfaceTdmaBeaconInterval:
  		val->v.integer = wif->tdma_binterval;
  		break;
  	}
  
  	return (SNMP_ERR_NOERROR);
  
  set_config:
  	rc = wlan_config_set_ioctl(wif, val->var.subs[sub - 1], intval,
  	    strval, vlen);
  
  	if (op == SNMP_OP_ROLLBACK) {
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanIfaceCountryCode:
  		case LEAF_wlanIfaceDesiredSsid:
  		case LEAF_wlanIfaceDesiredBssid:
  			free(ctx->scratch->ptr1);
  			/* FALLTHROUGH */
  		default:
  			break;
  		}
  	}
  
  	if (rc < 0)
  		return (SNMP_ERR_GENERR);
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_if_peer(struct snmp_context *ctx, struct snmp_value *val, uint32_t sub,
      uint32_t iidx __unused, enum snmp_op op)
  {
  	struct wlan_peer *wip;
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  	wlan_update_peers();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((wip = wlan_get_peer(&val->var, sub, &wif)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  	case SNMP_OP_GETNEXT:
  		if ((wip = wlan_get_next_peer(&val->var, sub, &wif)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_mac_index(&val->var, sub, wif->wname, wip->pmac);
  		break;
  	case SNMP_OP_SET:
  		if ((wip = wlan_get_peer(&val->var, sub, &wif)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		if (val->var.subs[sub - 1] != LEAF_wlanIfacePeerVlanTag)
  			return (SNMP_ERR_GENERR);
  		ctx->scratch->int1 = wip->vlan;
  		if (wlan_peer_set_vlan(wif, wip, val->v.integer) < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  	case SNMP_OP_COMMIT:
  		return (SNMP_ERR_NOERROR);
  	case SNMP_OP_ROLLBACK:
  		if ((wip = wlan_get_peer(&val->var, sub, &wif)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		if (val->var.subs[sub - 1] != LEAF_wlanIfacePeerVlanTag)
  			return (SNMP_ERR_GENERR);
  		if (wlan_peer_set_vlan(wif, wip, ctx->scratch->int1) < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  	default:
  		abort();
  	}
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanIfacePeerAddress:
  		return (string_get(val, wip->pmac, IEEE80211_ADDR_LEN));
  	case LEAF_wlanIfacePeerAssociationId:
  		val->v.integer = wip->associd;
  		break;
  	case LEAF_wlanIfacePeerVlanTag:
  		val->v.integer = wip->vlan;
  		break;
  	case LEAF_wlanIfacePeerFrequency:
  		val->v.integer = wip->frequency;
  		break;
  	case LEAF_wlanIfacePeerCurrentTXRate:
  		val->v.integer = wip->txrate;
  		break;
  	case LEAF_wlanIfacePeerRxSignalStrength:
  		val->v.integer = wip->rssi;
  		break;
  	case LEAF_wlanIfacePeerIdleTimer:
  		val->v.integer = wip->idle;
  		break;
  	case LEAF_wlanIfacePeerTxSequenceNo:
  		val->v.integer = wip->txseqs;
  		break;
  	case LEAF_wlanIfacePeerRxSequenceNo:
  		val->v.integer = wip->rxseqs;
  		break;
  	case LEAF_wlanIfacePeerTxPower:
  		val->v.integer = wip->txpower;
  		break;
  	case LEAF_wlanIfacePeerCapabilities:
  		return (bits_get(val, (uint8_t *)&wip->capinfo,
  		    sizeof(wip->capinfo)));
  	case LEAF_wlanIfacePeerFlags:
  		return (bits_get(val, (uint8_t *)&wip->state,
  		    sizeof(wip->state)));
  	default:
  		abort();
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_channels(struct snmp_context *ctx __unused, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	int32_t bits;
  	struct ieee80211_channel *channel;
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  	wlan_update_channels();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((channel = wlan_get_channel(&val->var, sub, &wif)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  	case SNMP_OP_GETNEXT:
  		channel = wlan_get_next_channel(&val->var, sub, &wif);
  		if (channel == NULL || wif == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_channel_index(&val->var, sub, wif, channel);
  		break;
  	case SNMP_OP_SET:
  		return (SNMP_ERR_NOT_WRITEABLE);
  	case SNMP_OP_COMMIT:
  		/* FALLTHROUGH */
  	case SNMP_OP_ROLLBACK:
  		/* FALLTHROUGH */
  	default:
  		abort();
  	}
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanIfaceChannelIeeeId:
  		val->v.integer = channel->ic_ieee;
  		break;
  	case LEAF_wlanIfaceChannelType:
  		val->v.integer = wlan_get_channel_type(channel);
  		break;
  	case LEAF_wlanIfaceChannelFlags:
  		bits = wlan_channel_flags_to_snmp(channel->ic_flags);
  		return (bits_get(val, (uint8_t *)&bits, sizeof(bits)));
  	case LEAF_wlanIfaceChannelFrequency:
  		val->v.integer = channel->ic_freq;
  		break;
  	case LEAF_wlanIfaceChannelMaxRegPower:
  		val->v.integer = channel->ic_maxregpower;
  		break;
  	case LEAF_wlanIfaceChannelMaxTxPower:
  		val->v.integer = channel->ic_maxpower;
  		break;
  	case LEAF_wlanIfaceChannelMinTxPower:
  		val->v.integer = channel->ic_minpower;
  		break;
  	case LEAF_wlanIfaceChannelState:
  		bits = wlan_channel_state_to_snmp(channel->ic_state);
  		return (bits_get(val, (uint8_t *)&bits, sizeof(bits)));
  	case LEAF_wlanIfaceChannelHTExtension:
  		val->v.integer = channel->ic_extieee;
  		break;
  	case LEAF_wlanIfaceChannelMaxAntennaGain:
  		val->v.integer = channel->ic_maxantgain;
  		break;
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_roam_params(struct snmp_context *ctx __unused, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	uint32_t phy;
  	struct ieee80211_roamparam *rparam;
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  	wlan_update_roam_params();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		rparam = wlan_get_roam_param(&val->var, sub, &wif);
  		if (rparam == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  	case SNMP_OP_GETNEXT:
  		rparam = wlan_get_next_roam_param(&val->var, sub, &wif, &phy);
  		if (rparam == NULL || wif == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_phy_index(&val->var, sub, wif->wname, phy);
  		break;
  	case SNMP_OP_SET:
  		return (SNMP_ERR_NOT_WRITEABLE);
  	case SNMP_OP_COMMIT:
  		/* FALLTHROUGH */
  	case SNMP_OP_ROLLBACK:
  		/* FALLTHROUGH */
  	default:
  		abort();
  	}
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanIfRoamRxSignalStrength:
  		val->v.integer = rparam->rssi/2;
  		break;
  	case LEAF_wlanIfRoamTxRateThreshold:
  		val->v.integer = rparam->rate/2;
  		break;
  	default:
  		abort();
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_tx_params(struct snmp_context *ctx, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	uint32_t phy;
  	struct ieee80211_txparam *txparam;
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  	wlan_update_tx_params();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		txparam = wlan_get_tx_param(&val->var, sub, &wif, &phy);
  		if (txparam == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		goto get_txparams;
  
  	case SNMP_OP_GETNEXT:
  		txparam = wlan_get_next_tx_param(&val->var, sub, &wif, &phy);
  		if (txparam == NULL || wif == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_phy_index(&val->var, sub, wif->wname, phy);
  		goto get_txparams;
  
  	case SNMP_OP_SET:
  		txparam = wlan_get_tx_param(&val->var, sub, &wif, &phy);
  		if (txparam == NULL || wif == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanIfTxUnicastRate:
  			ctx->scratch->int1 = txparam->ucastrate;
  			txparam->ucastrate = val->v.integer * 2;
  			break;
  		case LEAF_wlanIfTxMcastRate:
  			ctx->scratch->int1 = txparam->mcastrate;
  			txparam->mcastrate = val->v.integer * 2;
  			break;
  		case LEAF_wlanIfTxMgmtRate:
  			ctx->scratch->int1 = txparam->mgmtrate;
  			txparam->mgmtrate = val->v.integer * 2;
  			break;
  		case LEAF_wlanIfTxMaxRetryCount:
  			ctx->scratch->int1 = txparam->maxretry;
  			txparam->maxretry = val->v.integer;
  			break;
  		default:
  			abort();
  		}
  		if (wlan_set_tx_params(wif, phy) < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_COMMIT:
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_ROLLBACK:
  		txparam = wlan_get_tx_param(&val->var, sub, &wif, &phy);
  		if (txparam == NULL || wif == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanIfTxUnicastRate:
  			txparam->ucastrate = ctx->scratch->int1;
  			break;
  		case LEAF_wlanIfTxMcastRate:
  			txparam->mcastrate = ctx->scratch->int1;
  			break;
  		case LEAF_wlanIfTxMgmtRate:
  			txparam->mgmtrate = ctx->scratch->int1;
  			break;
  		case LEAF_wlanIfTxMaxRetryCount:
  			txparam->maxretry = ctx->scratch->int1;
  			break;
  		default:
  			abort();
  		}
  		if (wlan_set_tx_params(wif, phy) < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  	default:
  		abort();
  	}
  
  get_txparams:
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanIfTxUnicastRate:
  		val->v.integer = txparam->ucastrate / 2;
  		break;
  	case LEAF_wlanIfTxMcastRate:
  		val->v.integer = txparam->mcastrate / 2;
  		break;
  	case LEAF_wlanIfTxMgmtRate:
  		val->v.integer = txparam->mgmtrate / 2;
  		break;
  	case LEAF_wlanIfTxMaxRetryCount:
  		val->v.integer = txparam->maxretry;
  		break;
  	default:
  		abort();
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_scan_config(struct snmp_context *ctx, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  
  	case SNMP_OP_GETNEXT:
  		if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_ifindex(&val->var, sub, wif);
  		break;
  
  	case SNMP_OP_SET:
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		if (wif->scan_status ==  wlanScanConfigStatus_running
  		    && val->var.subs[sub - 1] != LEAF_wlanScanConfigStatus)
  			return (SNMP_ERR_INCONS_VALUE);
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanScanFlags:
  			ctx->scratch->int1 = wif->scan_flags;
  			wif->scan_flags = val->v.integer;
  			break;
  		case LEAF_wlanScanDuration:
  			ctx->scratch->int1 = wif->scan_duration;
  			wif->scan_duration = val->v.integer;
  			break;
  		case LEAF_wlanScanMinChannelDwellTime:
  			ctx->scratch->int1 = wif->scan_mindwell;
  			wif->scan_mindwell = val->v.integer;
  			break;
  		case LEAF_wlanScanMaxChannelDwellTime:
  			ctx->scratch->int1 = wif->scan_maxdwell;
  			wif->scan_maxdwell = val->v.integer;
  			break;
  		case LEAF_wlanScanConfigStatus:
  			if (val->v.integer == wlanScanConfigStatus_running ||
  			    val->v.integer == wlanScanConfigStatus_cancel) {
  				ctx->scratch->int1 = wif->scan_status;
  				wif->scan_status = val->v.integer;
  				break;
  			}
  			return (SNMP_ERR_INCONS_VALUE);
  		}
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_COMMIT:
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		if (val->var.subs[sub - 1] == LEAF_wlanScanConfigStatus)
  			if (wif->scan_status == wlanScanConfigStatus_running)
  				(void)wlan_set_scan_config(wif); /* XXX */
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_ROLLBACK:
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanScanFlags:
  			wif->scan_flags = ctx->scratch->int1;
  			break;
  		case LEAF_wlanScanDuration:
  			wif->scan_duration = ctx->scratch->int1;
  			break;
  		case LEAF_wlanScanMinChannelDwellTime:
  			wif->scan_mindwell = ctx->scratch->int1;
  			break;
  		case LEAF_wlanScanMaxChannelDwellTime:
  			wif->scan_maxdwell = ctx->scratch->int1;
  			break;
  		case LEAF_wlanScanConfigStatus:
  			wif->scan_status = ctx->scratch->int1;
  			break;
  		}
  		return (SNMP_ERR_NOERROR);
  	default:
  		abort();
  	}
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanScanFlags:
  		val->v.integer = wif->scan_flags;
  		break;
  	case LEAF_wlanScanDuration:
  		val->v.integer = wif->scan_duration;
  		break;
  	case LEAF_wlanScanMinChannelDwellTime:
  		val->v.integer = wif->scan_mindwell;
  		break;
  	case LEAF_wlanScanMaxChannelDwellTime:
  		val->v.integer = wif->scan_maxdwell;
  		break;
  	case LEAF_wlanScanConfigStatus:
  		val->v.integer = wif->scan_status;
  		break;
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_scan_results(struct snmp_context *ctx __unused, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	struct wlan_scan_result *sr;
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  	wlan_scan_update_results();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((sr = wlan_get_scanr(&val->var, sub, &wif)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  
  	case SNMP_OP_GETNEXT:
  		if ((sr = wlan_get_next_scanr(&val->var, sub, &wif)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_scanr_index(&val->var, sub, wif->wname, sr->ssid,
  		    sr->bssid);
  		break;
  
  	case SNMP_OP_SET:
  		return (SNMP_ERR_NOT_WRITEABLE);
  	case SNMP_OP_COMMIT:
  		/* FALLTHROUGH */
  	case SNMP_OP_ROLLBACK:
  		/* FALLTHROUGH */
  	default:
  		abort();
  	}
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanScanResultID:
  		return (string_get(val, sr->ssid, -1));
  	case LEAF_wlanScanResultBssid:
  		return (string_get(val, sr->bssid, IEEE80211_ADDR_LEN));
  	case LEAF_wlanScanResultChannel:
  		val->v.integer = sr->opchannel; /* XXX */
  		break;
  	case LEAF_wlanScanResultRate:
  		val->v.integer = sr->rssi;
  		break;
  	case LEAF_wlanScanResultNoise:
  		val->v.integer = sr->noise;
  		break;
  	case LEAF_wlanScanResultBeaconInterval:
  		val->v.integer = sr->bintval;
  		break;
  	case LEAF_wlanScanResultCapabilities:
  		return (bits_get(val, &sr->capinfo, sizeof(sr->capinfo)));
  	default:
  		abort();
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_iface_stats(struct snmp_context *ctx __unused, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  	case SNMP_OP_GETNEXT:
  		if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_ifindex(&val->var, sub, wif);
  		break;
  	case SNMP_OP_SET:
  		/* XXX: LEAF_wlanStatsReset */
  		return (SNMP_ERR_NOT_WRITEABLE);
  	case SNMP_OP_COMMIT:
  		/* FALLTHROUGH */
  	case SNMP_OP_ROLLBACK:
  		/* FALLTHROUGH */
  	default:
  		abort();
  	}
  
  	if (wlan_get_stats(wif) < 0)
  		return (SNMP_ERR_GENERR);
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanStatsRxBadVersion:
  		val->v.uint32 = wif->stats.is_rx_badversion;
  		break;
  	case LEAF_wlanStatsRxTooShort:
  		val->v.uint32 = wif->stats.is_rx_tooshort;
  		break;
  	case LEAF_wlanStatsRxWrongBssid:
  		val->v.uint32 = wif->stats.is_rx_wrongbss;
  		break;
  	case LEAF_wlanStatsRxDiscardedDups:
  		val->v.uint32 = wif->stats.is_rx_dup;
  		break;
  	case LEAF_wlanStatsRxWrongDir:
  		val->v.uint32 = wif->stats.is_rx_wrongdir;
  		break;
  	case LEAF_wlanStatsRxDiscardMcastEcho:
  		val->v.uint32 = wif->stats.is_rx_mcastecho;
  		break;
  	case LEAF_wlanStatsRxDiscardNoAssoc:
  		val->v.uint32 = wif->stats.is_rx_notassoc;
  		break;
  	case LEAF_wlanStatsRxWepNoPrivacy:
  		val->v.uint32 = wif->stats.is_rx_noprivacy;
  		break;
  	case LEAF_wlanStatsRxWepUnencrypted:
  		val->v.uint32 = wif->stats.is_rx_unencrypted;
  		break;
  	case LEAF_wlanStatsRxWepFailed:
  		val->v.uint32 = wif->stats.is_rx_wepfail;
  		break;
  	case LEAF_wlanStatsRxDecapsulationFailed:
  		val->v.uint32 = wif->stats.is_rx_decap;
  		break;
  	case LEAF_wlanStatsRxDiscardMgmt:
  		val->v.uint32 = wif->stats.is_rx_mgtdiscard;
  		break;
  	case LEAF_wlanStatsRxControl:
  		val->v.uint32 = wif->stats.is_rx_ctl;
  		break;
  	case LEAF_wlanStatsRxBeacon:
  		val->v.uint32 = wif->stats.is_rx_beacon;
  		break;
  	case LEAF_wlanStatsRxRateSetTooBig:
  		val->v.uint32 = wif->stats.is_rx_rstoobig;
  		break;
  	case LEAF_wlanStatsRxElemMissing:
  		val->v.uint32 = wif->stats.is_rx_elem_missing;
  		break;
  	case LEAF_wlanStatsRxElemTooBig:
  		val->v.uint32 = wif->stats.is_rx_elem_toobig;
  		break;
  	case LEAF_wlanStatsRxElemTooSmall:
  		val->v.uint32 = wif->stats.is_rx_elem_toosmall;
  		break;
  	case LEAF_wlanStatsRxElemUnknown:
  		val->v.uint32 = wif->stats.is_rx_elem_unknown;
  		break;
  	case LEAF_wlanStatsRxChannelMismatch:
  		val->v.uint32 = wif->stats.is_rx_chanmismatch;
  		break;
  	case LEAF_wlanStatsRxDropped:
  		val->v.uint32 = wif->stats.is_rx_nodealloc;
  		break;
  	case LEAF_wlanStatsRxSsidMismatch:
  		val->v.uint32 = wif->stats.is_rx_ssidmismatch;
  		break;
  	case LEAF_wlanStatsRxAuthNotSupported:
  		val->v.uint32 = wif->stats.is_rx_auth_unsupported;
  		break;
  	case LEAF_wlanStatsRxAuthFailed:
  		val->v.uint32 = wif->stats.is_rx_auth_fail;
  		break;
  	case LEAF_wlanStatsRxAuthCM:
  		val->v.uint32 = wif->stats.is_rx_auth_countermeasures;
  		break;
  	case LEAF_wlanStatsRxAssocWrongBssid:
  		val->v.uint32 = wif->stats.is_rx_assoc_bss;
  		break;
  	case LEAF_wlanStatsRxAssocNoAuth:
  		val->v.uint32 = wif->stats.is_rx_assoc_notauth;
  		break;
  	case LEAF_wlanStatsRxAssocCapMismatch:
  		val->v.uint32 = wif->stats.is_rx_assoc_capmismatch;
  		break;
  	case LEAF_wlanStatsRxAssocNoRateMatch:
  		val->v.uint32 = wif->stats.is_rx_assoc_norate;
  		break;
  	case LEAF_wlanStatsRxBadWpaIE:
  		val->v.uint32 = wif->stats.is_rx_assoc_badwpaie;
  		break;
  	case LEAF_wlanStatsRxDeauthenticate:
  		val->v.uint32 = wif->stats.is_rx_deauth;
  		break;
  	case LEAF_wlanStatsRxDisassociate:
  		val->v.uint32 = wif->stats.is_rx_disassoc;
  		break;
  	case LEAF_wlanStatsRxUnknownSubtype:
  		val->v.uint32 = wif->stats.is_rx_badsubtype;
  		break;
  	case LEAF_wlanStatsRxFailedNoBuf:
  		val->v.uint32 = wif->stats.is_rx_nobuf;
  		break;
  	case LEAF_wlanStatsRxBadAuthRequest:
  		val->v.uint32 = wif->stats.is_rx_bad_auth;
  		break;
  	case LEAF_wlanStatsRxUnAuthorized:
  		val->v.uint32 = wif->stats.is_rx_unauth;
  		break;
  	case LEAF_wlanStatsRxBadKeyId:
  		val->v.uint32 = wif->stats.is_rx_badkeyid;
  		break;
  	case LEAF_wlanStatsRxCCMPSeqViolation:
  		val->v.uint32 = wif->stats.is_rx_ccmpreplay;
  		break;
  	case LEAF_wlanStatsRxCCMPBadFormat:
  		val->v.uint32 = wif->stats.is_rx_ccmpformat;
  		break;
  	case LEAF_wlanStatsRxCCMPFailedMIC:
  		val->v.uint32 = wif->stats.is_rx_ccmpmic;
  		break;
  	case LEAF_wlanStatsRxTKIPSeqViolation:
  		val->v.uint32 = wif->stats.is_rx_tkipreplay;
  		break;
  	case LEAF_wlanStatsRxTKIPBadFormat:
  		val->v.uint32 = wif->stats.is_rx_tkipformat;
  		break;
  	case LEAF_wlanStatsRxTKIPFailedMIC:
  		val->v.uint32 = wif->stats.is_rx_tkipmic;
  		break;
  	case LEAF_wlanStatsRxTKIPFailedICV:
  		val->v.uint32 = wif->stats.is_rx_tkipicv;
  		break;
  	case LEAF_wlanStatsRxDiscardACL:
  		val->v.uint32 = wif->stats.is_rx_acl;
  		break;
  	case LEAF_wlanStatsTxFailedNoBuf:
  		val->v.uint32 = wif->stats.is_tx_nobuf;
  		break;
  	case LEAF_wlanStatsTxFailedNoNode:
  		val->v.uint32 = wif->stats.is_tx_nonode;
  		break;
  	case LEAF_wlanStatsTxUnknownMgmt:
  		val->v.uint32 = wif->stats.is_tx_unknownmgt;
  		break;
  	case LEAF_wlanStatsTxBadCipher:
  		val->v.uint32 = wif->stats.is_tx_badcipher;
  		break;
  	case LEAF_wlanStatsTxNoDefKey:
  		val->v.uint32 = wif->stats.is_tx_nodefkey;
  		break;
  	case LEAF_wlanStatsTxFragmented:
  		val->v.uint32 = wif->stats.is_tx_fragframes;
  		break;
  	case LEAF_wlanStatsTxFragmentsCreated:
  		val->v.uint32 = wif->stats.is_tx_frags;
  		break;
  	case LEAF_wlanStatsActiveScans:
  		val->v.uint32 = wif->stats.is_scan_active;
  		break;
  	case LEAF_wlanStatsPassiveScans:
  		val->v.uint32 = wif->stats.is_scan_passive;
  		break;
  	case LEAF_wlanStatsTimeoutInactivity:
  		val->v.uint32 = wif->stats.is_node_timeout;
  		break;
  	case LEAF_wlanStatsCryptoNoMem:
  		val->v.uint32 = wif->stats.is_crypto_nomem;
  		break;
  	case LEAF_wlanStatsSwCryptoTKIP:
  		val->v.uint32 = wif->stats.is_crypto_tkip;
  		break;
  	case LEAF_wlanStatsSwCryptoTKIPEnMIC:
  		val->v.uint32 = wif->stats.is_crypto_tkipenmic;
  		break;
  	case LEAF_wlanStatsSwCryptoTKIPDeMIC:
  		val->v.uint32 = wif->stats.is_crypto_tkipdemic;
  		break;
  	case LEAF_wlanStatsCryptoTKIPCM:
  		val->v.uint32 = wif->stats.is_crypto_tkipcm;
  		break;
  	case LEAF_wlanStatsSwCryptoCCMP:
  		val->v.uint32 = wif->stats.is_crypto_ccmp;
  		break;
  	case LEAF_wlanStatsSwCryptoWEP:
  		val->v.uint32 = wif->stats.is_crypto_wep;
  		break;
  	case LEAF_wlanStatsCryptoCipherKeyRejected:
  		val->v.uint32 = wif->stats.is_crypto_setkey_cipher;
  		break;
  	case LEAF_wlanStatsCryptoNoKey:
  		val->v.uint32 = wif->stats.is_crypto_setkey_nokey;
  		break;
  	case LEAF_wlanStatsCryptoDeleteKeyFailed:
  		val->v.uint32 = wif->stats.is_crypto_delkey;
  		break;
  	case LEAF_wlanStatsCryptoUnknownCipher:
  		val->v.uint32 = wif->stats.is_crypto_badcipher;
  		break;
  	case LEAF_wlanStatsCryptoAttachFailed:
  		val->v.uint32 = wif->stats.is_crypto_attachfail;
  		break;
  	case LEAF_wlanStatsCryptoKeyFailed:
  		val->v.uint32 = wif->stats.is_crypto_keyfail;
  		break;
  	case LEAF_wlanStatsCryptoEnMICFailed:
  		val->v.uint32 = wif->stats.is_crypto_enmicfail;
  		break;
  	case LEAF_wlanStatsIBSSCapMismatch:
  		val->v.uint32 = wif->stats.is_ibss_capmismatch;
  		break;
  	case LEAF_wlanStatsUnassocStaPSPoll:
  		val->v.uint32 = wif->stats.is_ps_unassoc;
  		break;
  	case LEAF_wlanStatsBadAidPSPoll:
  		val->v.uint32 = wif->stats.is_ps_badaid;
  		break;
  	case LEAF_wlanStatsEmptyPSPoll:
  		val->v.uint32 = wif->stats.is_ps_qempty;
  		break;
  	case LEAF_wlanStatsRxFFBadHdr:
  		val->v.uint32 = wif->stats.is_ff_badhdr;
  		break;
  	case LEAF_wlanStatsRxFFTooShort:
  		val->v.uint32 = wif->stats.is_ff_tooshort;
  		break;
  	case LEAF_wlanStatsRxFFSplitError:
  		val->v.uint32 = wif->stats.is_ff_split;
  		break;
  	case LEAF_wlanStatsRxFFDecap:
  		val->v.uint32 = wif->stats.is_ff_decap;
  		break;
  	case LEAF_wlanStatsTxFFEncap:
  		val->v.uint32 = wif->stats.is_ff_encap;
  		break;
  	case LEAF_wlanStatsRxBadBintval:
  		val->v.uint32 = wif->stats.is_rx_badbintval;
  		break;
  	case LEAF_wlanStatsRxDemicFailed:
  		val->v.uint32 = wif->stats.is_rx_demicfail;
  		break;
  	case LEAF_wlanStatsRxDefragFailed:
  		val->v.uint32 = wif->stats.is_rx_defrag;
  		break;
  	case LEAF_wlanStatsRxMgmt:
  		val->v.uint32 = wif->stats.is_rx_mgmt;
  		break;
  	case LEAF_wlanStatsRxActionMgmt:
  		val->v.uint32 = wif->stats.is_rx_action;
  		break;
  	case LEAF_wlanStatsRxAMSDUTooShort:
  		val->v.uint32 = wif->stats.is_amsdu_tooshort;
  		break;
  	case LEAF_wlanStatsRxAMSDUSplitError:
  		val->v.uint32 = wif->stats.is_amsdu_split;
  		break;
  	case LEAF_wlanStatsRxAMSDUDecap:
  		val->v.uint32 = wif->stats.is_amsdu_decap;
  		break;
  	case LEAF_wlanStatsTxAMSDUEncap:
  		val->v.uint32 = wif->stats.is_amsdu_encap;
  		break;
  	case LEAF_wlanStatsAMPDUBadBAR:
  		val->v.uint32 = wif->stats.is_ampdu_bar_bad;
  		break;
  	case LEAF_wlanStatsAMPDUOowBar:
  		val->v.uint32 = wif->stats.is_ampdu_bar_oow;
  		break;
  	case LEAF_wlanStatsAMPDUMovedBAR:
  		val->v.uint32 = wif->stats.is_ampdu_bar_move;
  		break;
  	case LEAF_wlanStatsAMPDURxBAR:
  		val->v.uint32 = wif->stats.is_ampdu_bar_rx;
  		break;
  	case LEAF_wlanStatsAMPDURxOor:
  		val->v.uint32 = wif->stats.is_ampdu_rx_oor;
  		break;
  	case LEAF_wlanStatsAMPDURxCopied:
  		val->v.uint32 = wif->stats.is_ampdu_rx_copy;
  		break;
  	case LEAF_wlanStatsAMPDURxDropped:
  		val->v.uint32 = wif->stats.is_ampdu_rx_drop;
  		break;
  	case LEAF_wlanStatsTxDiscardBadState:
  		val->v.uint32 = wif->stats.is_tx_badstate;
  		break;
  	case LEAF_wlanStatsTxFailedNoAssoc:
  		val->v.uint32 = wif->stats.is_tx_notassoc;
  		break;
  	case LEAF_wlanStatsTxClassifyFailed:
  		val->v.uint32 = wif->stats.is_tx_classify;
  		break;
  	case LEAF_wlanStatsDwdsMcastDiscard:
  		val->v.uint32 = wif->stats.is_dwds_mcast;
  		break;
  	case LEAF_wlanStatsHTAssocRejectNoHT:
  		val->v.uint32 = wif->stats.is_ht_assoc_nohtcap;
  		break;
  	case LEAF_wlanStatsHTAssocDowngrade:
  		val->v.uint32 = wif->stats.is_ht_assoc_downgrade;
  		break;
  	case LEAF_wlanStatsHTAssocRateMismatch:
  		val->v.uint32 = wif->stats.is_ht_assoc_norate;
  		break;
  	case LEAF_wlanStatsAMPDURxAge:
  		val->v.uint32 = wif->stats.is_ampdu_rx_age;
  		break;
  	case LEAF_wlanStatsAMPDUMoved:
  		val->v.uint32 = wif->stats.is_ampdu_rx_move;
  		break;
  	case LEAF_wlanStatsADDBADisabledReject:
  		val->v.uint32 = wif->stats.is_addba_reject;
  		break;
  	case LEAF_wlanStatsADDBANoRequest:
  		val->v.uint32 = wif->stats.is_addba_norequest;
  		break;
  	case LEAF_wlanStatsADDBABadToken:
  		val->v.uint32 = wif->stats.is_addba_badtoken;
  		break;
  	case LEAF_wlanStatsADDBABadPolicy:
  		val->v.uint32 = wif->stats.is_addba_badpolicy;
  		break;
  	case LEAF_wlanStatsAMPDUStopped:
  		val->v.uint32 = wif->stats.is_ampdu_stop;
  		break;
  	case LEAF_wlanStatsAMPDUStopFailed:
  		val->v.uint32 = wif->stats.is_ampdu_stop_failed;
  		break;
  	case LEAF_wlanStatsAMPDURxReorder:
  		val->v.uint32 = wif->stats.is_ampdu_rx_reorder;
  		break;
  	case LEAF_wlanStatsScansBackground:
  		val->v.uint32 = wif->stats.is_scan_bg;
  		break;
  	case LEAF_wlanLastDeauthReason:
  		val->v.uint32 = wif->stats.is_rx_deauth_code;
  		break;
  	case LEAF_wlanLastDissasocReason:
  		val->v.uint32 = wif->stats.is_rx_disassoc_code;
  		break;
  	case LEAF_wlanLastAuthFailReason:
  		val->v.uint32 = wif->stats.is_rx_authfail_code;
  		break;
  	case LEAF_wlanStatsBeaconMissedEvents:
  		val->v.uint32 = wif->stats.is_beacon_miss;
  		break;
  	case LEAF_wlanStatsRxDiscardBadStates:
  		val->v.uint32 = wif->stats.is_rx_badstate;
  		break;
  	case LEAF_wlanStatsFFFlushed:
  		val->v.uint32 = wif->stats.is_ff_flush;
  		break;
  	case LEAF_wlanStatsTxControlFrames:
  		val->v.uint32 = wif->stats.is_tx_ctl;
  		break;
  	case LEAF_wlanStatsAMPDURexmt:
  		val->v.uint32 = wif->stats.is_ampdu_rexmt;
  		break;
  	case LEAF_wlanStatsAMPDURexmtFailed:
  		val->v.uint32 = wif->stats.is_ampdu_rexmt_fail;
  		break;
  	case LEAF_wlanStatsReset:
  		val->v.uint32 = wlanStatsReset_no_op;
  		break;
  	default:
  		abort();
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_wep_iface(struct snmp_context *ctx, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL ||
  		    !wif->wepsupported)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  
  	case SNMP_OP_GETNEXT:
  		/* XXX: filter wif->wepsupported */
  		if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_ifindex(&val->var, sub, wif);
  		break;
  
  	case SNMP_OP_SET:
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL ||
  		    !wif->wepsupported)
  			return (SNMP_ERR_NOSUCHNAME);
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanWepMode:
  			if (val->v.integer < wlanWepMode_off ||
  			    val->v.integer > wlanWepMode_mixed)
  				return (SNMP_ERR_INCONS_VALUE);
  			ctx->scratch->int1 = wif->wepmode;
  			wif->wepmode = val->v.integer;
  			if (wlan_set_wepmode(wif) < 0) {
  				wif->wepmode = ctx->scratch->int1;
  				return (SNMP_ERR_GENERR);
  			}
  			break;
  		case LEAF_wlanWepDefTxKey:
  			if (val->v.integer < 0 ||
  			    val->v.integer > IEEE80211_WEP_NKID)
  				return (SNMP_ERR_INCONS_VALUE);
  			ctx->scratch->int1 = wif->weptxkey;
  			wif->weptxkey = val->v.integer;
  			if (wlan_set_weptxkey(wif) < 0) {
  				wif->weptxkey = ctx->scratch->int1;
  				return (SNMP_ERR_GENERR);
  			}
  			break;
  		default:
  			abort();
  		}
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_COMMIT:
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_ROLLBACK:
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanWepMode:
  			wif->wepmode = ctx->scratch->int1;
  			if (wlan_set_wepmode(wif) < 0)
  				return (SNMP_ERR_GENERR);
  			break;
  		case LEAF_wlanWepDefTxKey:
  			wif->weptxkey = ctx->scratch->int1;
  			if (wlan_set_weptxkey(wif) < 0)
  				return (SNMP_ERR_GENERR);
  			break;
  		default:
  			abort();
  		}
  		return (SNMP_ERR_NOERROR);
  
  	default:
  		abort();
  	}
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanWepMode:
  		if (wlan_get_wepmode(wif) < 0)
  			return (SNMP_ERR_GENERR);
  		val->v.integer = wif->wepmode;
  		break;
  	case LEAF_wlanWepDefTxKey:
  		if (wlan_get_weptxkey(wif) < 0)
  			return (SNMP_ERR_GENERR);
  		val->v.integer = wif->weptxkey;
  		break;
  	default:
  		abort();
  	}
  	
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_wep_key(struct snmp_context *ctx __unused,
      struct snmp_value *val __unused, uint32_t sub __unused,
      uint32_t iidx __unused, enum snmp_op op __unused)
  {
  	return (SNMP_ERR_NOSUCHNAME);
  }
  
  int
  op_wlan_mac_access_control(struct snmp_context *ctx, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL ||
  		    !wif->macsupported)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  
  	case SNMP_OP_GETNEXT:
  		/* XXX: filter wif->macsupported */
  		if ((wif = wlan_get_next_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_ifindex(&val->var, sub, wif);
  		break;
  
  	case SNMP_OP_SET:
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL ||
  		    !wif->macsupported)
  			return (SNMP_ERR_NOSUCHNAME);
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanMACAccessControlPolicy:
  			ctx->scratch->int1 = wif->mac_policy;
  			wif->mac_policy = val->v.integer;
  			break;
  		case LEAF_wlanMACAccessControlNacl:
  			return (SNMP_ERR_NOT_WRITEABLE);
  		case LEAF_wlanMACAccessControlFlush:
  			break;
  		default:
  			abort();
  		}
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_COMMIT:
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanMACAccessControlPolicy:
  			if (wlan_set_mac_policy(wif) < 0) {
  				wif->mac_policy = ctx->scratch->int1;
  				return (SNMP_ERR_GENERR);
  			}
  			break;
  		case LEAF_wlanMACAccessControlFlush:
  			if (wlan_flush_mac_mac(wif) < 0)
  				return (SNMP_ERR_GENERR);
  			break;
  		default:
  			abort();
  		}
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_ROLLBACK:
  		if ((wif = wlan_get_interface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		if (val->var.subs[sub - 1] == LEAF_wlanMACAccessControlPolicy)
  			wif->mac_policy = ctx->scratch->int1;
  		return (SNMP_ERR_NOERROR);
  
  	default:
  		abort();
  	}
  
  	if (wlan_get_mac_policy(wif) < 0)
  		return (SNMP_ERR_GENERR);
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanMACAccessControlPolicy:
  		val->v.integer = wif->mac_policy;
  		break;
  	case LEAF_wlanMACAccessControlNacl:
  		val->v.integer = wif->mac_nacls;
  		break;
  	case LEAF_wlanMACAccessControlFlush:
  		val->v.integer = wlanMACAccessControlFlush_no_op;
  		break;
  	default:
  		abort();
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_mac_acl_mac(struct snmp_context *ctx, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	struct wlan_iface *wif;
  	struct wlan_mac_mac *macl;
  
  	wlan_update_interface_list();
  	wlan_mac_update_aclmacs();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((macl = wlan_get_acl_mac(&val->var, sub, &wif)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  
  	case SNMP_OP_GETNEXT:
  		if ((macl = wlan_get_next_acl_mac(&val->var, sub, &wif))
  		    == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_mac_index(&val->var, sub, wif->wname, macl->mac);
  		break;
  
  	case SNMP_OP_SET:
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanMACAccessControlMAC:
  			return (SNMP_ERR_INCONS_NAME);
  		case LEAF_wlanMACAccessControlMACStatus:
  			return(wlan_acl_mac_set_status(ctx, val, sub));
  		default:
  			abort();
  		}
  
  	case SNMP_OP_COMMIT:
  		if ((macl = wlan_get_acl_mac(&val->var, sub, &wif)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		if (val->v.integer == RowStatus_destroy &&
  		    wlan_mac_delete_mac(wif, macl) < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_ROLLBACK:
  		if ((macl = wlan_get_acl_mac(&val->var, sub, &wif)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		if (ctx->scratch->int1 == RowStatus_destroy &&
  		    wlan_mac_delete_mac(wif, macl) < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  
  	default:
  		abort();
  	}
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanMACAccessControlMAC:
  		return (string_get(val, macl->mac, IEEE80211_ADDR_LEN));
  	case LEAF_wlanMACAccessControlMACStatus:
  		val->v.integer = macl->mac_status;
  		break;
  	default:
  		abort();
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_mesh_config(struct snmp_context *ctx, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	int which;
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanMeshMaxRetries:
  		which = WLAN_MESH_MAX_RETRIES;
  		break;
  	case LEAF_wlanMeshHoldingTimeout:
  		which = WLAN_MESH_HOLDING_TO;
  		break;
  	case LEAF_wlanMeshConfirmTimeout:
  		which = WLAN_MESH_CONFIRM_TO;
  		break;
  	case LEAF_wlanMeshRetryTimeout:
  		which = WLAN_MESH_RETRY_TO;
  		break;
  	default:
  		abort();
  	}
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if (wlan_do_sysctl(&wlan_config, which, 0) < 0)
  			return (SNMP_ERR_GENERR);
  		break;
  
  	case SNMP_OP_GETNEXT:
  		abort();
  
  	case SNMP_OP_SET:
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanMeshRetryTimeout :
  			ctx->scratch->int1 = wlan_config.mesh_retryto;
  			wlan_config.mesh_retryto = val->v.integer;
  			break;
  		case LEAF_wlanMeshHoldingTimeout:
  			ctx->scratch->int1 = wlan_config.mesh_holdingto;
  			wlan_config.mesh_holdingto = val->v.integer;
  			break;
  		case LEAF_wlanMeshConfirmTimeout:
  			ctx->scratch->int1 = wlan_config.mesh_confirmto;
  			wlan_config.mesh_confirmto = val->v.integer;
  			break;
  		case LEAF_wlanMeshMaxRetries:
  			ctx->scratch->int1 = wlan_config.mesh_maxretries;
  			wlan_config.mesh_maxretries = val->v.integer;
  			break;
  		}
  		if (wlan_do_sysctl(&wlan_config, which, 1) < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_COMMIT:
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_ROLLBACK:
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanMeshRetryTimeout:
  			wlan_config.mesh_retryto = ctx->scratch->int1;
  			break;
  		case LEAF_wlanMeshConfirmTimeout:
  			wlan_config.mesh_confirmto = ctx->scratch->int1;
  			break;
  		case LEAF_wlanMeshHoldingTimeout:
  			wlan_config.mesh_holdingto= ctx->scratch->int1;
  			break;
  		case LEAF_wlanMeshMaxRetries:
  			wlan_config.mesh_maxretries = ctx->scratch->int1;
  			break;
  		}
  		if (wlan_do_sysctl(&wlan_config, which, 1) < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  
  	default:
  		abort();
  	}
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanMeshRetryTimeout:
  		val->v.integer = wlan_config.mesh_retryto;
  		break;
  	case LEAF_wlanMeshHoldingTimeout:
  		val->v.integer = wlan_config.mesh_holdingto;
  		break;
  	case LEAF_wlanMeshConfirmTimeout:
  		val->v.integer = wlan_config.mesh_confirmto;
  		break;
  	case LEAF_wlanMeshMaxRetries:
  		val->v.integer = wlan_config.mesh_maxretries;
  		break;
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_mesh_iface(struct snmp_context *ctx, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	int rc;
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  
  	case SNMP_OP_GETNEXT:
  		if ((wif = wlan_mesh_get_next_iface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_ifindex(&val->var, sub, wif);
  		break;
  
  	case SNMP_OP_SET:
  		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanMeshId:
  			if (val->v.octetstring.len > IEEE80211_NWID_LEN)
  				return (SNMP_ERR_INCONS_VALUE);
  			ctx->scratch->ptr1 = malloc(val->v.octetstring.len + 1);
  			if (ctx->scratch->ptr1 == NULL)
  				return (SNMP_ERR_GENERR);
  			strlcpy(ctx->scratch->ptr1, wif->desired_ssid,
  			    val->v.octetstring.len + 1);
  			ctx->scratch->int1 = strlen(wif->desired_ssid);
  			memcpy(wif->desired_ssid, val->v.octetstring.octets,
  			    val->v.octetstring.len);
  			wif->desired_ssid[val->v.octetstring.len] = '\0';
  			break;
  		case LEAF_wlanMeshTTL:
  			ctx->scratch->int1 = wif->mesh_ttl;
  			wif->mesh_ttl = val->v.integer;
  			break;
  		case LEAF_wlanMeshPeeringEnabled:
  			ctx->scratch->int1 = wif->mesh_peering;
  			wif->mesh_peering = val->v.integer;
  			break;
  		case LEAF_wlanMeshForwardingEnabled:
  			ctx->scratch->int1 = wif->mesh_forwarding;
  			wif->mesh_forwarding = val->v.integer;
  			break;
  		case LEAF_wlanMeshMetric:
  			ctx->scratch->int1 = wif->mesh_metric;
  			wif->mesh_metric = val->v.integer;
  			break;
  		case LEAF_wlanMeshPath:
  			ctx->scratch->int1 = wif->mesh_path;
  			wif->mesh_path = val->v.integer;
  			break;
  		case LEAF_wlanMeshRoutesFlush:
  			if (val->v.integer != wlanMeshRoutesFlush_flush)
  				return (SNMP_ERR_INCONS_VALUE);
  			return (SNMP_ERR_NOERROR);
  		default:
  			abort();
  		}
  		if (val->var.subs[sub - 1] == LEAF_wlanMeshId)
  			rc = wlan_config_set_dssid(wif,
  			    val->v.octetstring.octets, val->v.octetstring.len);
  		else
  			rc = wlan_mesh_config_set(wif, val->var.subs[sub - 1]);
  		if (rc < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_COMMIT:
  		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		if (val->var.subs[sub - 1] == LEAF_wlanMeshRoutesFlush &&
  		    wlan_mesh_flush_routes(wif) < 0)
  			return (SNMP_ERR_GENERR);
  		if (val->var.subs[sub - 1] == LEAF_wlanMeshId)
  			free(ctx->scratch->ptr1);
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_ROLLBACK:
  		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanMeshId:
  			strlcpy(wif->desired_ssid, ctx->scratch->ptr1,
  			    IEEE80211_NWID_LEN);
  			free(ctx->scratch->ptr1);
  			break;
  		case LEAF_wlanMeshTTL:
  			wif->mesh_ttl = ctx->scratch->int1;
  			break;
  		case LEAF_wlanMeshPeeringEnabled:
  			wif->mesh_peering = ctx->scratch->int1;
  			break;
  		case LEAF_wlanMeshForwardingEnabled:
  			wif->mesh_forwarding = ctx->scratch->int1;
  			break;
  		case LEAF_wlanMeshMetric:
  			wif->mesh_metric = ctx->scratch->int1;
  			break;
  		case LEAF_wlanMeshPath:
  			wif->mesh_path = ctx->scratch->int1;
  			break;
  		case LEAF_wlanMeshRoutesFlush:
  			return (SNMP_ERR_NOERROR);
  		default:
  			abort();
  		}
  		if (val->var.subs[sub - 1] == LEAF_wlanMeshId)
  			rc = wlan_config_set_dssid(wif, wif->desired_ssid,
  			    strlen(wif->desired_ssid));
  		else
  			rc = wlan_mesh_config_set(wif, val->var.subs[sub - 1]);
  		if (rc < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  
  	default:
  		abort();
  	}
  
  	if (val->var.subs[sub - 1] == LEAF_wlanMeshId)
  		rc = wlan_config_get_dssid(wif);
  	else
  		rc = wlan_mesh_config_get(wif, val->var.subs[sub - 1]);
  	if (rc < 0)
  		return (SNMP_ERR_GENERR);
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanMeshId:
  		return (string_get(val, wif->desired_ssid, -1));
  	case LEAF_wlanMeshTTL:
  		val->v.integer = wif->mesh_ttl;
  		break;
  	case LEAF_wlanMeshPeeringEnabled:
  		val->v.integer = wif->mesh_peering;
  		break;
  	case LEAF_wlanMeshForwardingEnabled:
  		val->v.integer = wif->mesh_forwarding;
  		break;
  	case LEAF_wlanMeshMetric:
  		val->v.integer = wif->mesh_metric;
  		break;
  	case LEAF_wlanMeshPath:
  		val->v.integer = wif->mesh_path;
  		break;
  	case LEAF_wlanMeshRoutesFlush:
  		val->v.integer = wlanMeshRoutesFlush_no_op;
  		break;
  	default:
  		abort();
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_mesh_neighbor(struct snmp_context *ctx __unused, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	struct wlan_peer *wip;
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  	wlan_update_peers();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((wip = wlan_mesh_get_peer(&val->var, sub, &wif)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  	case SNMP_OP_GETNEXT:
  		wip = wlan_mesh_get_next_peer(&val->var, sub, &wif);
  		if (wip == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_mac_index(&val->var, sub, wif->wname,
  		    wip->pmac);
  		break;
  	case SNMP_OP_SET:
  		return (SNMP_ERR_NOT_WRITEABLE);
  	case SNMP_OP_COMMIT:
  		/* FALLTHROUGH */
  	case SNMP_OP_ROLLBACK:
  		/* FALLTHROUGH */
  	default:
  		abort();
  	}
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanMeshNeighborAddress:
  		return (string_get(val, wip->pmac, IEEE80211_ADDR_LEN));
  	case LEAF_wlanMeshNeighborFrequency:
  		val->v.integer = wip->frequency;
  		break;
  	case LEAF_wlanMeshNeighborLocalId:
  		val->v.integer = wip->local_id;
  		break;
  	case LEAF_wlanMeshNeighborPeerId:
  		val->v.integer = wip->peer_id;
  		break;
  	case LEAF_wlanMeshNeighborPeerState:
  		return (bits_get(val, (uint8_t *)&wip->state,
  		    sizeof(wip->state)));
  	case LEAF_wlanMeshNeighborCurrentTXRate:
  		val->v.integer = wip->txrate;
  		break;
  	case LEAF_wlanMeshNeighborRxSignalStrength:
  		val->v.integer = wip->rssi;
  		break;
  	case LEAF_wlanMeshNeighborIdleTimer:
  		val->v.integer = wip->idle;
  		break;
  	case LEAF_wlanMeshNeighborTxSequenceNo:
  		val->v.integer = wip->txseqs;
  		break;
  	case LEAF_wlanMeshNeighborRxSequenceNo:
  		val->v.integer = wip->rxseqs;
  		break;
  	default:
  		abort();
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_mesh_route(struct snmp_context *ctx, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	struct wlan_mesh_route *wmr;
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  	wlan_mesh_update_routes();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((wmr = wlan_mesh_get_route(&val->var, sub, &wif)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  
  	case SNMP_OP_GETNEXT:
  		wmr = wlan_mesh_get_next_route(&val->var, sub, &wif);
  		if (wmr == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_mac_index(&val->var, sub, wif->wname,
  		    wmr->imroute.imr_dest);
  		break;
  
  	case SNMP_OP_SET:
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanMeshRouteDestination:
  			return (SNMP_ERR_INCONS_NAME);
  		case LEAF_wlanMeshRouteStatus:
  			return(wlan_mesh_route_set_status(ctx, val, sub));
  		default:
  			return (SNMP_ERR_NOT_WRITEABLE);
  		}
  		abort();
  
  	case SNMP_OP_COMMIT:
  		if ((wmr = wlan_mesh_get_route(&val->var, sub, &wif)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		if (val->v.integer == RowStatus_destroy &&
  		    wlan_mesh_delete_route(wif, wmr) < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_ROLLBACK:
  		if ((wmr = wlan_mesh_get_route(&val->var, sub, &wif)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		if (ctx->scratch->int1 == RowStatus_destroy &&
  		    wlan_mesh_delete_route(wif, wmr) < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  
  	default:
  		abort();
  	}
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanMeshRouteDestination:
  		return (string_get(val, wmr->imroute.imr_dest,
  		    IEEE80211_ADDR_LEN));
  	case LEAF_wlanMeshRouteNextHop:
  		return (string_get(val, wmr->imroute.imr_nexthop,
  		    IEEE80211_ADDR_LEN));
  	case LEAF_wlanMeshRouteHops:
  		val->v.integer = wmr->imroute.imr_nhops;
  		break;
  	case LEAF_wlanMeshRouteMetric:
  		val->v.integer = wmr->imroute.imr_metric;
  		break;
  	case LEAF_wlanMeshRouteLifeTime:
  		val->v.integer = wmr->imroute.imr_lifetime;
  		break;
  	case LEAF_wlanMeshRouteLastMseq:
  		val->v.integer = wmr->imroute.imr_lastmseq;
  		break;
  	case LEAF_wlanMeshRouteFlags:
  		val->v.integer = 0;
  		if ((wmr->imroute.imr_flags &
  		    IEEE80211_MESHRT_FLAGS_VALID) != 0)
  			val->v.integer |= (0x1 << wlanMeshRouteFlags_valid);
  		if ((wmr->imroute.imr_flags &
  		    IEEE80211_MESHRT_FLAGS_PROXY) != 0)
  			val->v.integer |= (0x1 << wlanMeshRouteFlags_proxy);
  		return (bits_get(val, (uint8_t *)&val->v.integer,
  		    sizeof(val->v.integer)));
  	case LEAF_wlanMeshRouteStatus:
  		val->v.integer = wmr->mroute_status;
  		break;
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_mesh_stats(struct snmp_context *ctx __unused, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  	case SNMP_OP_GETNEXT:
  		if ((wif = wlan_mesh_get_next_iface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_ifindex(&val->var, sub, wif);
  		break;
  	case SNMP_OP_SET:
  		return (SNMP_ERR_NOT_WRITEABLE);
  	case SNMP_OP_COMMIT:
  		/* FALLTHROUGH */
  	case SNMP_OP_ROLLBACK:
  		/* FALLTHROUGH */
  	default:
  		abort();
  	}
  
  	if (wlan_get_stats(wif) < 0)
  		return (SNMP_ERR_GENERR);
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanMeshDroppedBadSta:
  		val->v.uint32 = wif->stats.is_mesh_wrongmesh;
  		break;
  	case LEAF_wlanMeshDroppedNoLink:
  		val->v.uint32 = wif->stats.is_mesh_nolink;
  		break;
  	case LEAF_wlanMeshNoFwdTtl:
  		val->v.uint32 = wif->stats.is_mesh_fwd_ttl;
  		break;
  	case LEAF_wlanMeshNoFwdBuf:
  		val->v.uint32 = wif->stats.is_mesh_fwd_nobuf;
  		break;
  	case LEAF_wlanMeshNoFwdTooShort:
  		val->v.uint32 = wif->stats.is_mesh_fwd_tooshort;
  		break;
  	case LEAF_wlanMeshNoFwdDisabled:
  		val->v.uint32 = wif->stats.is_mesh_fwd_disabled;
  		break;
  	case LEAF_wlanMeshNoFwdPathUnknown:
  		val->v.uint32 = wif->stats.is_mesh_fwd_nopath;
  		break;
  	case LEAF_wlanMeshDroppedBadAE:
  		val->v.uint32 = wif->stats.is_mesh_badae;
  		break;
  	case LEAF_wlanMeshRouteAddFailed:
  		val->v.uint32 = wif->stats.is_mesh_rtaddfailed;
  		break;
  	case LEAF_wlanMeshDroppedNoProxy:
  		val->v.uint32 = wif->stats.is_mesh_notproxy;
  		break;
  	case LEAF_wlanMeshDroppedMisaligned:
  		val->v.uint32 = wif->stats.is_rx_badalign;
  		break;
  	default:
  		abort();
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_hwmp_config(struct snmp_context *ctx, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	int which;
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanHWMPRouteInactiveTimeout:
  		which = WLAN_HWMP_INACTIVITY_TO;
  		break;
  	case LEAF_wlanHWMPRootAnnounceInterval:
  		which = WLAN_HWMP_RANN_INT;
  		break;
  	case LEAF_wlanHWMPRootInterval:
  		which = WLAN_HWMP_ROOT_INT;
  		break;
  	case LEAF_wlanHWMPRootTimeout:
  		which = WLAN_HWMP_ROOT_TO;
  		break;
  	case LEAF_wlanHWMPPathLifetime:
  		which = WLAN_HWMP_PATH_LIFETIME;
  		break;
  	case LEAF_wlanHWMPReplyForwardBit:
  		which = WLAN_HWMP_REPLY_FORWARD;
  		break;
  	case LEAF_wlanHWMPTargetOnlyBit:
  		which = WLAN_HWMP_TARGET_ONLY;
  		break;
  	default:
  		abort();
  	}
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if (wlan_do_sysctl(&wlan_config, which, 0) < 0)
  			return (SNMP_ERR_GENERR);
  		break;
  
  	case SNMP_OP_GETNEXT:
  		abort();
  
  	case SNMP_OP_SET:
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanHWMPRouteInactiveTimeout:
  			ctx->scratch->int1 = wlan_config.hwmp_inact;
  			wlan_config.hwmp_inact = val->v.integer;
  			break;
  		case LEAF_wlanHWMPRootAnnounceInterval:
  			ctx->scratch->int1 = wlan_config.hwmp_rannint;
  			wlan_config.hwmp_rannint = val->v.integer;
  			break;
  		case LEAF_wlanHWMPRootInterval:
  			ctx->scratch->int1 = wlan_config.hwmp_rootint;
  			wlan_config.hwmp_rootint = val->v.integer;
  			break;
  		case LEAF_wlanHWMPRootTimeout:
  			ctx->scratch->int1 = wlan_config.hwmp_roottimeout;
  			wlan_config.hwmp_roottimeout = val->v.integer;
  			break;
  		case LEAF_wlanHWMPPathLifetime:
  			ctx->scratch->int1 = wlan_config.hwmp_pathlifetime;
  			wlan_config.hwmp_pathlifetime = val->v.integer;
  			break;
  		case LEAF_wlanHWMPReplyForwardBit:
  			ctx->scratch->int1 = wlan_config.hwmp_replyforward;
  			wlan_config.hwmp_replyforward = val->v.integer;
  			break;
  		case LEAF_wlanHWMPTargetOnlyBit:
  			ctx->scratch->int1 = wlan_config.hwmp_targetonly;
  			wlan_config.hwmp_targetonly = val->v.integer;
  			break;
  		}
  		if (wlan_do_sysctl(&wlan_config, which, 1) < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_COMMIT:
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_ROLLBACK:
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanHWMPRouteInactiveTimeout:
  			wlan_config.hwmp_inact = ctx->scratch->int1;
  			break;
  		case LEAF_wlanHWMPRootAnnounceInterval:
  			wlan_config.hwmp_rannint = ctx->scratch->int1;
  			break;
  		case LEAF_wlanHWMPRootInterval:
  			wlan_config.hwmp_rootint = ctx->scratch->int1;
  			break;
  		case LEAF_wlanHWMPRootTimeout:
  			wlan_config.hwmp_roottimeout = ctx->scratch->int1;
  			break;
  		case LEAF_wlanHWMPPathLifetime:
  			wlan_config.hwmp_pathlifetime = ctx->scratch->int1;
  			break;
  		case LEAF_wlanHWMPReplyForwardBit:
  			wlan_config.hwmp_replyforward = ctx->scratch->int1;
  			break;
  		case LEAF_wlanHWMPTargetOnlyBit:
  			wlan_config.hwmp_targetonly = ctx->scratch->int1;
  			break;
  		}
  		if (wlan_do_sysctl(&wlan_config, which, 1) < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  
  	default:
  		abort();
  	}
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanHWMPRouteInactiveTimeout:
  		val->v.integer = wlan_config.hwmp_inact;
  		break;
  	case LEAF_wlanHWMPRootAnnounceInterval:
  		val->v.integer = wlan_config.hwmp_rannint;
  		break;
  	case LEAF_wlanHWMPRootInterval:
  		val->v.integer = wlan_config.hwmp_rootint;
  		break;
  	case LEAF_wlanHWMPRootTimeout:
  		val->v.integer = wlan_config.hwmp_roottimeout;
  		break;
  	case LEAF_wlanHWMPPathLifetime:
  		val->v.integer = wlan_config.hwmp_pathlifetime;
  		break;
  	case LEAF_wlanHWMPReplyForwardBit:
  		val->v.integer = wlan_config.hwmp_replyforward;
  		break;
  	case LEAF_wlanHWMPTargetOnlyBit:
  		val->v.integer = wlan_config.hwmp_targetonly;
  		break;
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_hwmp_iface(struct snmp_context *ctx, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  
  	case SNMP_OP_GETNEXT:
  		if ((wif = wlan_mesh_get_next_iface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_ifindex(&val->var, sub, wif);
  		break;
  
  	case SNMP_OP_SET:
  		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanHWMPRootMode:
  			ctx->scratch->int1 = wif->hwmp_root_mode;
  			wif->hwmp_root_mode = val->v.integer;
  			break;
  		case LEAF_wlanHWMPMaxHops:
  			ctx->scratch->int1 = wif->hwmp_max_hops;
  			wif->hwmp_max_hops = val->v.integer;
  			break;
  		default:
  			abort();
  		}
  		if (wlan_hwmp_config_set(wif, val->var.subs[sub - 1]) < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_COMMIT:
  		return (SNMP_ERR_NOERROR);
  
  	case SNMP_OP_ROLLBACK:
  		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		switch (val->var.subs[sub - 1]) {
  		case LEAF_wlanHWMPRootMode:
  			wif->hwmp_root_mode = ctx->scratch->int1;
  			break;
  		case LEAF_wlanHWMPMaxHops:
  			wif->hwmp_max_hops = ctx->scratch->int1;
  			break;
  		default:
  			abort();
  		}
  		if (wlan_hwmp_config_set(wif, val->var.subs[sub - 1]) < 0)
  			return (SNMP_ERR_GENERR);
  		return (SNMP_ERR_NOERROR);
  
  	default:
  		abort();
  	}
  
  	if (wlan_hwmp_config_get(wif, val->var.subs[sub - 1]) < 0)
  		return (SNMP_ERR_GENERR);
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanHWMPRootMode:
  		val->v.integer = wif->hwmp_root_mode;
  		break;
  	case LEAF_wlanHWMPMaxHops:
  		val->v.integer = wif->hwmp_max_hops;
  		break;
  	default:
  		abort();
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  int
  op_wlan_hwmp_stats(struct snmp_context *ctx __unused, struct snmp_value *val,
      uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  {
  	struct wlan_iface *wif;
  
  	wlan_update_interface_list();
  
  	switch (op) {
  	case SNMP_OP_GET:
  		if ((wif = wlan_mesh_get_iface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		break;
  	case SNMP_OP_GETNEXT:
  		if ((wif = wlan_mesh_get_next_iface(&val->var, sub)) == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		wlan_append_ifindex(&val->var, sub, wif);
  		break;
  	case SNMP_OP_SET:
  		return (SNMP_ERR_NOT_WRITEABLE);
  	case SNMP_OP_COMMIT:
  		/* FALLTHROUGH */
  	case SNMP_OP_ROLLBACK:
  		/* FALLTHROUGH */
  	default:
  		abort();
  	}
  
  	if (wlan_get_stats(wif) < 0)
  		return (SNMP_ERR_GENERR);
  
  	switch (val->var.subs[sub - 1]) {
  	case LEAF_wlanMeshHWMPWrongSeqNo:
  		val->v.uint32 = wif->stats.is_hwmp_wrongseq;
  		break;
  	case LEAF_wlanMeshHWMPTxRootPREQ:
  		val->v.uint32 = wif->stats.is_hwmp_rootreqs;
  		break;
  	case LEAF_wlanMeshHWMPTxRootRANN:
  		val->v.uint32 = wif->stats.is_hwmp_rootrann;
  		break;
  	case LEAF_wlanMeshHWMPProxy:
  		val->v.uint32 = wif->stats.is_hwmp_proxy;
  		break;
  	default:
  		abort();
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  /*
   * Encode BITS type for a response packet - XXX: this belongs to the snmp lib.
   */
  static int
  bits_get(struct snmp_value *value, const u_char *ptr, ssize_t len)
  {
  	int size;
  
  	if (ptr == NULL) {
  		value->v.octetstring.len = 0;
  		value->v.octetstring.octets = NULL;
  		return (SNMP_ERR_NOERROR);
  	}
  
  	/* Determine length - up to 8 octets supported so far. */
  	for (size = len; size > 0; size--)
  		if (ptr[size - 1] != 0)
  			break;
  	if (size == 0)
  		size = 1;
  
  	value->v.octetstring.len = (u_long)size;
  	if ((value->v.octetstring.octets = malloc((size_t)size)) == NULL)
  		return (SNMP_ERR_RES_UNAVAIL);
  	memcpy(value->v.octetstring.octets, ptr, (size_t)size);
  	return (SNMP_ERR_NOERROR);
  }
  
  /*
   * Calls for adding/updating/freeing/etc of wireless interfaces.
   */
  static void
  wlan_free_interface(struct wlan_iface *wif)
  {
  	wlan_free_peerlist(wif);
  	free(wif->chanlist);
  	wlan_scan_free_results(wif);
  	wlan_mac_free_maclist(wif);
  	wlan_mesh_free_routes(wif);
  	free(wif);
  }
  
  static void
  wlan_free_iflist(void)
  {
  	struct wlan_iface *w;
  
  	while ((w = SLIST_FIRST(&wlan_ifaces)) != NULL) {
  		SLIST_REMOVE_HEAD(&wlan_ifaces, w_if);
  		wlan_free_interface(w);
  	}
  }
  
  static struct wlan_iface *
  wlan_find_interface(const char *wname)
  {
  	struct wlan_iface *wif;
  
  	SLIST_FOREACH(wif, &wlan_ifaces, w_if)
  		if (strcmp(wif->wname, wname) == 0) {
  			if (wif->status != RowStatus_active)
  				return (NULL);
  			break;
  		}
  
  	return (wif);
  }
  
  static struct wlan_iface *
  wlan_first_interface(void)
  {
  	return (SLIST_FIRST(&wlan_ifaces));
  }
  
  static struct wlan_iface *
  wlan_next_interface(struct wlan_iface *wif)
  {
  	if (wif == NULL)
  		return (NULL);
  
  	return (SLIST_NEXT(wif, w_if));
  }
  
  /*
   * Add a new interface to the list - sorted by name.
   */
  static int
  wlan_add_wif(struct wlan_iface *wif)
  {
  	int cmp;
  	struct wlan_iface *temp, *prev;
  
  	if ((prev = SLIST_FIRST(&wlan_ifaces)) == NULL ||
  	    strcmp(wif->wname, prev->wname) < 0) {
  		SLIST_INSERT_HEAD(&wlan_ifaces, wif, w_if);
  		return (0);
  	}
  
  	SLIST_FOREACH(temp, &wlan_ifaces, w_if) {
  		if ((cmp = strcmp(wif->wname, temp->wname)) <= 0)
  			break;
  		prev = temp;
  	}
  
  	if (temp == NULL)
  		SLIST_INSERT_AFTER(prev, wif, w_if);
  	else if (cmp > 0)
  		SLIST_INSERT_AFTER(temp, wif, w_if);
  	else {
  		syslog(LOG_ERR, "Wlan iface %s already in list", wif->wname);
  		return (-1);
  	}
  
  	return (0);
  }
  
  static struct wlan_iface *
  wlan_new_wif(char *wname)
  {
  	struct wlan_iface *wif;
  
  	/* Make sure it's not in the list. */
  	for (wif = wlan_first_interface(); wif != NULL;
  	    wif = wlan_next_interface(wif))
  		if (strcmp(wname, wif->wname) == 0) {
  			wif->internal = 0;
  			return (wif);
  		}
  
  	if ((wif = (struct wlan_iface *)malloc(sizeof(*wif))) == NULL)
  		return (NULL);
  
  	memset(wif, 0, sizeof(struct wlan_iface));
  	strlcpy(wif->wname, wname, IFNAMSIZ);
  	wif->status = RowStatus_notReady;
  	wif->state = wlanIfaceState_down;
  	wif->mode = WlanIfaceOperatingModeType_station;
  
  	if (wlan_add_wif(wif) < 0) {
  		free(wif);
  		return (NULL);
  	}
  
  	return (wif);
  }
  
  static void
  wlan_delete_wif(struct wlan_iface *wif)
  {
  	SLIST_REMOVE(&wlan_ifaces, wif, wlan_iface, w_if);
  	wlan_free_interface(wif);
  }
  
  static int
  wlan_attach_newif(struct mibif *mif)
  {
  	struct wlan_iface *wif;
  
  	if (mif->mib.ifmd_data.ifi_type != IFT_ETHER ||
  	    wlan_check_media(mif->name) != IFM_IEEE80211)
  		return (0);
  
  	if ((wif = wlan_new_wif(mif->name)) == NULL)
  		return (-1);
  
  	(void)wlan_get_opmode(wif);
  	wif->index = mif->index;
  	wif->status = RowStatus_active;
  	(void)wlan_update_interface(wif);
  
  	return (0);
  }
  
  static int
  wlan_iface_create(struct wlan_iface *wif)
  {
  	int rc;
  
  	if ((rc = wlan_clone_create(wif)) == SNMP_ERR_NOERROR) {
  		/*
  		 * The rest of the info will be updated once the
  		 * snmp_mibII module notifies us of the interface.
  		 */
  		wif->status = RowStatus_active;
  		if (wif->state == wlanIfaceState_up)
  			(void)wlan_config_state(wif, 1);
  	}
  
  	return (rc);
  }
  
  static int
  wlan_iface_destroy(struct wlan_iface *wif)
  {
  	int rc = SNMP_ERR_NOERROR;
  
  	if (wif->internal == 0)
  		rc = wlan_clone_destroy(wif);
  
  	if (rc == SNMP_ERR_NOERROR)
  		wlan_delete_wif(wif);
  
  	return (rc);
  }
  
  static int
  wlan_update_interface(struct wlan_iface *wif)
  {
  	int i;
  
  	(void)wlan_config_state(wif, 0);
  	(void)wlan_get_driver_caps(wif);
  	for (i = LEAF_wlanIfacePacketBurst;
  	    i <= LEAF_wlanIfaceTdmaBeaconInterval; i++)
  		(void)wlan_config_get_ioctl(wif, i);
  	(void)wlan_get_stats(wif);
  	/*
  	 * XXX: wlan_get_channel_list() not needed -
  	 * fetched with wlan_get_driver_caps()
  	 */
  	(void)wlan_get_channel_list(wif);
  	(void)wlan_get_roam_params(wif);
  	(void)wlan_get_tx_params(wif);
  	(void)wlan_get_scan_results(wif);
  	(void)wlan_get_wepmode(wif);
  	(void)wlan_get_weptxkey(wif);
  	(void)wlan_get_mac_policy(wif);
  	(void)wlan_get_mac_acl_macs(wif);
  	(void)wlan_get_peerinfo(wif);
  
  	if (wif->mode == WlanIfaceOperatingModeType_meshPoint) {
  		for (i = LEAF_wlanMeshTTL; i <= LEAF_wlanMeshPath; i++)
  			(void)wlan_mesh_config_get(wif, i);
  		(void)wlan_mesh_get_routelist(wif);
  		for (i = LEAF_wlanHWMPRootMode; i <= LEAF_wlanHWMPMaxHops; i++)
  			(void)wlan_hwmp_config_get(wif, i);
  	}
  
  	return (0);
  }
  
  static void
  wlan_update_interface_list(void)
  {
  	struct wlan_iface *wif, *twif;
  
  	if ((time(NULL) - wlan_iflist_age) <= WLAN_LIST_MAXAGE)
  		return;
  
  	/*
  	 * The snmp_mibII module would have notified us for new interfaces,
  	 * so only check if any have been deleted.
  	 */
  	SLIST_FOREACH_SAFE(wif, &wlan_ifaces, w_if, twif)
  		if (wif->status == RowStatus_active && wlan_get_opmode(wif) < 0)
  			wlan_delete_wif(wif);
  
  	wlan_iflist_age = time(NULL);
  }
  
  static void
  wlan_append_ifindex(struct asn_oid *oid, uint sub, const struct wlan_iface *w)
  {
  	uint32_t i;
  
  	oid->len = sub + strlen(w->wname) + 1;
  	oid->subs[sub] = strlen(w->wname);
  	for (i = 1; i <= strlen(w->wname); i++)
  		oid->subs[sub + i] = w->wname[i - 1];
  }
  
  static uint8_t *
  wlan_get_ifname(const struct asn_oid *oid, uint sub, uint8_t *wname)
  {
  	uint32_t i;
  
  	memset(wname, 0, IFNAMSIZ);
  
  	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
  		return (NULL);
  
  	for (i = 0; i < oid->subs[sub]; i++)
  		wname[i] = oid->subs[sub + i + 1];
  	wname[i] = '\0';
  
  	return (wname);
  }
  
  static struct wlan_iface *
  wlan_get_interface(const struct asn_oid *oid, uint sub)
  {
  	uint8_t wname[IFNAMSIZ];
  
  	if (wlan_get_ifname(oid, sub, wname) == NULL)
  		return (NULL);
  
  	return (wlan_find_interface(wname));
  }
  
  static struct wlan_iface *
  wlan_get_next_interface(const struct asn_oid *oid, uint sub)
  {
  	uint32_t i;
  	uint8_t wname[IFNAMSIZ];
  	struct wlan_iface *wif;
  
  	if (oid->len - sub == 0) {
  		for (wif = wlan_first_interface(); wif != NULL;
  		    wif = wlan_next_interface(wif))
  			if (wif->status == RowStatus_active)
  				break;
  		return (wif);
  	}
  
  	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
  		return (NULL);
  
  	memset(wname, 0, IFNAMSIZ);
  	for (i = 0; i < oid->subs[sub]; i++)
  		wname[i] = oid->subs[sub + i + 1];
  	wname[i] = '\0';
  	if ((wif = wlan_find_interface(wname)) == NULL)
  		return (NULL);
  
  	while ((wif = wlan_next_interface(wif)) != NULL)
  		if (wif->status == RowStatus_active)
  			break;
  
  	return (wif);
  }
  
  static struct wlan_iface *
  wlan_get_snmp_interface(const struct asn_oid *oid, uint sub)
  {
  	uint8_t wname[IFNAMSIZ];
  	struct wlan_iface *wif;
  
  	if (wlan_get_ifname(oid, sub, wname) == NULL)
  		return (NULL);
  
  	for (wif = wlan_first_interface(); wif != NULL;
  	    wif = wlan_next_interface(wif))
  		if (strcmp(wif->wname, wname) == 0)
  			break;
  
  	return (wif);
  }
  
  static struct wlan_iface *
  wlan_get_next_snmp_interface(const struct asn_oid *oid, uint sub)
  {
  	uint32_t i;
  	uint8_t wname[IFNAMSIZ];
  	struct wlan_iface *wif;
  
  	if (oid->len - sub == 0)
  		return (wlan_first_interface());
  
  	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
  		return (NULL);
  
  	memset(wname, 0, IFNAMSIZ);
  	for (i = 0; i < oid->subs[sub]; i++)
  		wname[i] = oid->subs[sub + i + 1];
  	wname[i] = '\0';
  
  	for (wif = wlan_first_interface(); wif != NULL;
  	    wif = wlan_next_interface(wif))
  		if (strcmp(wif->wname, wname) == 0)
  			break;
  
  	return (wlan_next_interface(wif));
  }
  
  /*
   * Decode/Append an index for tables indexed by the wireless interface
   * name and a MAC address - ACL MACs and Mesh Routes.
   */
  static int
  wlan_mac_index_decode(const struct asn_oid *oid, uint sub,
      char *wname, uint8_t *mac)
  {
  	uint32_t i;
  	int mac_off;
  
  	if (oid->len - sub != oid->subs[sub] + 2 + IEEE80211_ADDR_LEN
  	    || oid->subs[sub] >= IFNAMSIZ)
  		return (-1);
  
  	for (i = 0; i < oid->subs[sub]; i++)
  		wname[i] = oid->subs[sub + i + 1];
  	wname[i] = '\0';
  
  	mac_off = sub + oid->subs[sub] + 1;
  	if (oid->subs[mac_off] != IEEE80211_ADDR_LEN)
  		return (-1);
  	for (i = 0; i < IEEE80211_ADDR_LEN; i++)
  		mac[i] = oid->subs[mac_off + i + 1];
  
  	return (0);
  }
  
  static void
  wlan_append_mac_index(struct asn_oid *oid, uint sub, char *wname, uint8_t *mac)
  {
  	uint32_t i;
  
  	oid->len = sub + strlen(wname) + IEEE80211_ADDR_LEN + 2;
  	oid->subs[sub] = strlen(wname);
  	for (i = 1; i <= strlen(wname); i++)
  		oid->subs[sub + i] = wname[i - 1];
  
  	sub += strlen(wname) + 1;
  	oid->subs[sub] = IEEE80211_ADDR_LEN;
  	for (i = 1; i <= IEEE80211_ADDR_LEN; i++)
  		oid->subs[sub + i] = mac[i - 1];
  }
  
  /*
   * Decode/Append an index for tables indexed by the wireless interface
   * name and the PHY mode - Roam and TX params.
   */
  static int
  wlan_phy_index_decode(const struct asn_oid *oid, uint sub, char *wname,
      uint32_t *phy)
  {
  	uint32_t i;
  
  	if (oid->len - sub != oid->subs[sub] + 2 || oid->subs[sub] >= IFNAMSIZ)
  		return (-1);
  
  	for (i = 0; i < oid->subs[sub]; i++)
  		wname[i] = oid->subs[sub + i + 1];
  	wname[i] = '\0';
  
  	*phy = oid->subs[sub + oid->subs[sub] + 1];
  	return (0);
  }
  
  static void
  wlan_append_phy_index(struct asn_oid *oid, uint sub, char *wname, uint32_t phy)
  {
  	uint32_t i;
  
  	oid->len = sub + strlen(wname) + 2;
  	oid->subs[sub] = strlen(wname);
  	for (i = 1; i <= strlen(wname); i++)
  		oid->subs[sub + i] = wname[i - 1];
  	oid->subs[sub + strlen(wname) + 1] = phy;
  }
  
  /*
   * Calls for manipulating the peerlist of a wireless interface.
   */
  static void
  wlan_free_peerlist(struct wlan_iface *wif)
  {
  	struct wlan_peer *wip;
  
  	while ((wip = SLIST_FIRST(&wif->peerlist)) != NULL) {
  		SLIST_REMOVE_HEAD(&wif->peerlist, wp);
  		free(wip);
  	}
  
  	SLIST_INIT(&wif->peerlist);
  }
  
  static struct wlan_peer *
  wlan_find_peer(struct wlan_iface *wif, uint8_t *peermac)
  {
  	struct wlan_peer *wip;
  
  	SLIST_FOREACH(wip, &wif->peerlist, wp)
  		if (memcmp(wip->pmac, peermac, IEEE80211_ADDR_LEN) == 0)
  			break;
  
  	return (wip);
  }
  
  struct wlan_peer *
  wlan_new_peer(const uint8_t *pmac)
  {
  	struct wlan_peer *wip;
  
  	if ((wip = (struct wlan_peer *)malloc(sizeof(*wip))) == NULL)
  		return (NULL);
  
  	memset(wip, 0, sizeof(struct wlan_peer));
  	memcpy(wip->pmac, pmac, IEEE80211_ADDR_LEN);
  
  	return (wip);
  }
  
  void
  wlan_free_peer(struct wlan_peer *wip)
  {
  	free(wip);
  }
  
  int
  wlan_add_peer(struct wlan_iface *wif, struct wlan_peer *wip)
  {
  	struct wlan_peer *temp, *prev;
  
  	SLIST_FOREACH(temp, &wif->peerlist, wp)
  		if (memcmp(temp->pmac, wip->pmac, IEEE80211_ADDR_LEN) == 0)
  			return (-1);
  
  	if ((prev = SLIST_FIRST(&wif->peerlist)) == NULL ||
  	    memcmp(wip->pmac, prev->pmac, IEEE80211_ADDR_LEN) < 0) {
  	    	SLIST_INSERT_HEAD(&wif->peerlist, wip, wp);
  	    	return (0);
  	}
  
  	SLIST_FOREACH(temp, &wif->peerlist, wp) {
  		if (memcmp(wip->pmac, temp->pmac, IEEE80211_ADDR_LEN) < 0)
  			break;
  		prev = temp;
  	}
  
  	SLIST_INSERT_AFTER(prev, wip, wp);
  	return (0);
  }
  
  static void
  wlan_update_peers(void)
  {
  	struct wlan_iface *wif;
  
  	if ((time(NULL) - wlan_peerlist_age) <= WLAN_LIST_MAXAGE)
  		return;
  
  	for (wif = wlan_first_interface(); wif != NULL;
  	    wif = wlan_next_interface(wif)) {
  		if (wif->status != RowStatus_active)
  			continue;
  		wlan_free_peerlist(wif);
  		(void)wlan_get_peerinfo(wif);
  	}
  	wlan_peerlist_age = time(NULL);
  }
  
  static struct wlan_peer *
  wlan_get_peer(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
  {
  	char wname[IFNAMSIZ];
  	uint8_t pmac[IEEE80211_ADDR_LEN];
  
  	if (wlan_mac_index_decode(oid, sub, wname, pmac) < 0)
  		return (NULL);
  
  	if ((*wif = wlan_find_interface(wname)) == NULL)
  		return (NULL);
  
  	return (wlan_find_peer(*wif, pmac));
  }
  
  static struct wlan_peer *
  wlan_get_next_peer(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
  {
  	char wname[IFNAMSIZ];
  	char pmac[IEEE80211_ADDR_LEN];
  	struct wlan_peer *wip;
  
  	if (oid->len - sub == 0) {
  		for (*wif = wlan_first_interface(); *wif != NULL;
  		    *wif = wlan_next_interface(*wif)) {
  			if ((*wif)->mode ==
  			    WlanIfaceOperatingModeType_meshPoint)
  				continue;
  			wip = SLIST_FIRST(&(*wif)->peerlist);
  			if (wip != NULL)
  				return (wip);
  		}
  		return (NULL);
  	}
  
  	if (wlan_mac_index_decode(oid, sub, wname, pmac) < 0 ||
  	    (*wif = wlan_find_interface(wname)) == NULL ||
  	    (wip = wlan_find_peer(*wif, pmac)) == NULL)
  		return (NULL);
  
  	if ((wip = SLIST_NEXT(wip, wp)) != NULL)
  		return (wip);
  
  	while ((*wif = wlan_next_interface(*wif)) != NULL) {
  		if ((*wif)->mode == WlanIfaceOperatingModeType_meshPoint)
  			continue;
  		if ((wip = SLIST_FIRST(&(*wif)->peerlist)) != NULL)
  			break;
  	}
  
  	return (wip);
  }
  
  /*
   * Calls for manipulating the active channel list of a wireless interface.
   */
  static void
  wlan_update_channels(void)
  {
  	struct wlan_iface *wif;
  
  	if ((time(NULL) - wlan_chanlist_age) <= WLAN_LIST_MAXAGE)
  		return;
  
  	for (wif = wlan_first_interface(); wif != NULL;
  	    wif = wlan_next_interface(wif)) {
  		if (wif->status != RowStatus_active)
  			continue;
  		(void)wlan_get_channel_list(wif);
  	}
  	wlan_chanlist_age = time(NULL);
  }
  
  static int
  wlan_channel_index_decode(const struct asn_oid *oid, uint sub, char *wname,
      uint32_t *cindex)
  {
  	uint32_t i;
  	if (oid->len - sub != oid->subs[sub] + 2 || oid->subs[sub] >= IFNAMSIZ)
  		return (-1);
  
  	for (i = 0; i < oid->subs[sub]; i++)
  		wname[i] = oid->subs[sub + i + 1];
  	wname[i] = '\0';
  
  	*cindex = oid->subs[sub + oid->subs[sub] + 1];
  
  	return (0);
  }
  
  static void
  wlan_append_channel_index(struct asn_oid *oid, uint sub,
      const struct wlan_iface *wif, const struct ieee80211_channel *channel)
  {
  	uint32_t i;
  
  	oid->len = sub + strlen(wif->wname) + 2;
  	oid->subs[sub] = strlen(wif->wname);
  	for (i = 1; i <= strlen(wif->wname); i++)
  		oid->subs[sub + i] = wif->wname[i - 1];
  	oid->subs[sub + strlen(wif->wname) + 1] = (channel - wif->chanlist) + 1;
  }
  
  static int32_t
  wlan_get_channel_type(struct ieee80211_channel *c)
  {
  	if (IEEE80211_IS_CHAN_FHSS(c))
  		return (WlanChannelType_fhss);
  	if (IEEE80211_IS_CHAN_A(c))
  		return (WlanChannelType_dot11a);
  	if (IEEE80211_IS_CHAN_B(c))
  		return (WlanChannelType_dot11b);
  	if (IEEE80211_IS_CHAN_ANYG(c))
  		return (WlanChannelType_dot11g);
  	if (IEEE80211_IS_CHAN_HALF(c))
  		return (WlanChannelType_tenMHz);
  	if (IEEE80211_IS_CHAN_QUARTER(c))
  		return (WlanChannelType_fiveMHz);
  	if (IEEE80211_IS_CHAN_TURBO(c))
  		return (WlanChannelType_turbo);
  	if (IEEE80211_IS_CHAN_HT(c))
  		return (WlanChannelType_ht);
  		
  	return (-1);
  }
  
  static struct ieee80211_channel *
  wlan_find_channel(struct wlan_iface *wif, uint32_t cindex)
  {
  	if (wif->chanlist == NULL || cindex > wif->nchannels)
  		return (NULL);
  
  	return (wif->chanlist + cindex - 1);
  }
  
  static struct ieee80211_channel *
  wlan_get_channel(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
  {
  	uint32_t cindex;
  	char wname[IFNAMSIZ];
  
  	if (wlan_channel_index_decode(oid, sub, wname, &cindex) < 0)
  		return (NULL);
  
  	if ((*wif = wlan_find_interface(wname)) == NULL)
  		return (NULL);
  
  	return (wlan_find_channel(*wif, cindex));
  }
  
  static struct ieee80211_channel *
  wlan_get_next_channel(const struct asn_oid *oid, uint sub,
      struct wlan_iface **wif)
  {
  	uint32_t cindex;
  	char wname[IFNAMSIZ];
  
  	if (oid->len - sub == 0) {
  		for (*wif = wlan_first_interface(); *wif != NULL;
  		    *wif = wlan_next_interface(*wif)) {
  			if ((*wif)->status != RowStatus_active)
  				continue;
  			if ((*wif)->nchannels != 0 && (*wif)->chanlist != NULL)
  				return ((*wif)->chanlist);
  		}
  		return (NULL);
  	}
  
  	if (wlan_channel_index_decode(oid, sub, wname, &cindex) < 0)
  		return (NULL);
  
  	if ((*wif = wlan_find_interface(wname)) == NULL)
  		return (NULL);
  
  	if (cindex < (*wif)->nchannels)
  		return ((*wif)->chanlist + cindex);
  
  	while ((*wif = wlan_next_interface(*wif)) != NULL)
  		if ((*wif)->status == RowStatus_active)
  			if ((*wif)->nchannels != 0 && (*wif)->chanlist != NULL)
  				return ((*wif)->chanlist);
  
  	return (NULL);
  }
  
  /*
   * Calls for manipulating the roam params of a wireless interface.
   */
  static void
  wlan_update_roam_params(void)
  {
  	struct wlan_iface *wif;
  
  	if ((time(NULL) - wlan_roamlist_age) <= WLAN_LIST_MAXAGE)
  		return;
  
  	for (wif = wlan_first_interface(); wif != NULL;
  	    wif = wlan_next_interface(wif)) {
  		if (wif->status != RowStatus_active)
  			continue;
  		(void)wlan_get_roam_params(wif);
  	}
  	wlan_roamlist_age = time(NULL);
  }
  
  static struct ieee80211_roamparam *
  wlan_get_roam_param(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
  {
  	uint32_t phy;
  	char wname[IFNAMSIZ];
  
  	if (wlan_phy_index_decode(oid, sub, wname, &phy) < 0)
  		return (NULL);
  
  	if ((*wif = wlan_find_interface(wname)) == NULL)
  		return (NULL);
  
  	if (phy == 0 || phy > IEEE80211_MODE_MAX)
  		return (NULL);
  
  	return ((*wif)->roamparams.params + phy - 1);
  }
  
  static struct ieee80211_roamparam *
  wlan_get_next_roam_param(const struct asn_oid *oid, uint sub,
      struct wlan_iface **wif, uint32_t *phy)
  {
  	char wname[IFNAMSIZ];
  
  	if (oid->len - sub == 0) {
  		for (*wif = wlan_first_interface(); *wif != NULL;
  		    *wif = wlan_next_interface(*wif)) {
  			if ((*wif)->status != RowStatus_active)
  				continue;
  			*phy = 1;
  			return ((*wif)->roamparams.params);
  		}
  		return (NULL);
  	}
  
  	if (wlan_phy_index_decode(oid, sub, wname, phy) < 0)
  		return (NULL);
  
  	if (*phy == 0  || (*wif = wlan_find_interface(wname)) == NULL)
  		return (NULL);
  
  	if (++(*phy) <= IEEE80211_MODE_MAX)
  		return ((*wif)->roamparams.params + *phy - 1);
  
  	*phy = 1;
  	while ((*wif = wlan_next_interface(*wif)) != NULL)
  		if ((*wif)->status == RowStatus_active)
  			return ((*wif)->roamparams.params);
  
  	return (NULL);
  }
  
  /*
   * Calls for manipulating the tx params of a wireless interface.
   */
  static void
  wlan_update_tx_params(void)
  {
  	struct wlan_iface *wif;
  
  	if ((time(NULL) - wlan_tx_paramlist_age) <= WLAN_LIST_MAXAGE)
  		return;
  
  	for (wif = wlan_first_interface(); wif != NULL;
  	    wif = wlan_next_interface(wif)) {
  		if (wif->status != RowStatus_active)
  			continue;
  		(void)wlan_get_tx_params(wif);
  	}
  
  	wlan_tx_paramlist_age = time(NULL);
  }
  
  static struct ieee80211_txparam *
  wlan_get_tx_param(const struct asn_oid *oid, uint sub, struct wlan_iface **wif,
      uint32_t *phy)
  {
  	char wname[IFNAMSIZ];
  
  	if (wlan_phy_index_decode(oid, sub, wname, phy) < 0)
  		return (NULL);
  
  	if ((*wif = wlan_find_interface(wname)) == NULL)
  		return (NULL);
  
  	if (*phy == 0 || *phy > IEEE80211_MODE_MAX)
  		return (NULL);
  
  	return ((*wif)->txparams.params + *phy - 1);
  }
  
  static struct ieee80211_txparam *
  wlan_get_next_tx_param(const struct asn_oid *oid, uint sub,
      struct wlan_iface **wif, uint32_t *phy)
  {
  	char wname[IFNAMSIZ];
  
  	if (oid->len - sub == 0) {
  		for (*wif = wlan_first_interface(); *wif != NULL;
  		    *wif = wlan_next_interface(*wif)) {
  			if ((*wif)->status != RowStatus_active)
  				continue;
  			*phy = 1;
  			return ((*wif)->txparams.params);
  		}
  		return (NULL);
  	}
  
  	if (wlan_phy_index_decode(oid, sub, wname, phy) < 0)
  		return (NULL);
  
  	if (*phy == 0 || (*wif = wlan_find_interface(wname)) == NULL)
  		return (NULL);
  
  	if (++(*phy) <= IEEE80211_MODE_MAX)
  		return ((*wif)->txparams.params + *phy - 1);
  
  	*phy = 1;
  	while ((*wif = wlan_next_interface(*wif)) != NULL)
  		if ((*wif)->status == RowStatus_active)
  			return ((*wif)->txparams.params);
  
  	return (NULL);
  }
  
  /*
   * Calls for manipulating the scan results for a wireless interface.
   */
  static void
  wlan_scan_free_results(struct wlan_iface *wif)
  {
  	struct wlan_scan_result *sr;
  
  	while ((sr = SLIST_FIRST(&wif->scanlist)) != NULL) {
  		SLIST_REMOVE_HEAD(&wif->scanlist, wsr);
  		free(sr);
  	}
  
  	SLIST_INIT(&wif->scanlist);
  }
  
  static struct wlan_scan_result *
  wlan_scan_find_result(struct wlan_iface *wif, uint8_t *ssid, uint8_t *bssid)
  {
  	struct wlan_scan_result *sr;
  
  	SLIST_FOREACH(sr, &wif->scanlist, wsr)
  		if (strlen(ssid) == strlen(sr->ssid) &&
  		    strcmp(sr->ssid, ssid) == 0 &&
  		    memcmp(sr->bssid, bssid, IEEE80211_ADDR_LEN) == 0)
  			break;
  
  	return (sr);
  }
  
  struct wlan_scan_result *
  wlan_scan_new_result(const uint8_t *ssid, const uint8_t *bssid)
  {
  	struct wlan_scan_result *sr;
  
  	sr = (struct wlan_scan_result *)malloc(sizeof(*sr));
  	if (sr == NULL)
  		return (NULL);
  
  	memset(sr, 0, sizeof(*sr));
  	if (ssid[0] != '\0')
  		strlcpy(sr->ssid, ssid, IEEE80211_NWID_LEN + 1);
  	memcpy(sr->bssid, bssid, IEEE80211_ADDR_LEN);
  
  	return (sr);
  }
  
  void
  wlan_scan_free_result(struct wlan_scan_result *sr)
  {
  	free(sr);
  }
  
  static int
  wlan_scan_compare_result(struct wlan_scan_result *sr1,
      struct wlan_scan_result *sr2)
  {
  	uint32_t i;
  
  	if (strlen(sr1->ssid) < strlen(sr2->ssid))
  		return (-1);
  	if (strlen(sr1->ssid) > strlen(sr2->ssid))
  		return (1);
  
  	for (i = 0; i < strlen(sr1->ssid) && i < strlen(sr2->ssid); i++) {
  		if (sr1->ssid[i] < sr2->ssid[i])
  			return (-1);
  		if (sr1->ssid[i] > sr2->ssid[i])
  			return (1);
  	}
  
  	for (i = 0; i < IEEE80211_ADDR_LEN; i++) {
  		if (sr1->bssid[i] < sr2->bssid[i])
  			return (-1);
  		if (sr1->bssid[i] > sr2->bssid[i])
  			return (1);
  	}
  
  	return (0);
  }
  
  int
  wlan_scan_add_result(struct wlan_iface *wif, struct wlan_scan_result *sr)
  {
  	struct wlan_scan_result *prev, *temp;
  
  	SLIST_FOREACH(temp, &wif->scanlist, wsr)
  		if (strlen(temp->ssid) == strlen(sr->ssid) &&
  		    strcmp(sr->ssid, temp->ssid) == 0 &&
  		    memcmp(sr->bssid, temp->bssid, IEEE80211_ADDR_LEN) == 0)
  			return (-1);
  
  	if ((prev = SLIST_FIRST(&wif->scanlist)) == NULL ||
  	    wlan_scan_compare_result(sr, prev) < 0) {
  	    	SLIST_INSERT_HEAD(&wif->scanlist, sr, wsr);
  	    	return (0);
  	}
  	
  	SLIST_FOREACH(temp, &wif->scanlist, wsr) {
  		if (wlan_scan_compare_result(sr, temp) < 0)
  			break;
  		prev = temp;
  	}
  
  	SLIST_INSERT_AFTER(prev, sr, wsr);
  	return (0);
  }
  
  static void
  wlan_scan_update_results(void)
  {
  	struct wlan_iface *wif;
  
  	if ((time(NULL) - wlan_scanlist_age) <= WLAN_LIST_MAXAGE)
  		return;
  
  	for (wif = wlan_first_interface(); wif != NULL;
  	    wif = wlan_next_interface(wif)) {
  		if (wif->status != RowStatus_active)
  			continue;
  		wlan_scan_free_results(wif);
  		(void)wlan_get_scan_results(wif);
  	}
  	wlan_scanlist_age = time(NULL);
  }
  
  static int
  wlan_scanr_index_decode(const struct asn_oid *oid, uint sub,
      char *wname, uint8_t *ssid, uint8_t *bssid)
  {
  	uint32_t i;
  	int offset;
  
  	if (oid->subs[sub] >= IFNAMSIZ)
  		return (-1);
  	for (i = 0; i < oid->subs[sub]; i++)
  		wname[i] = oid->subs[sub + i + 1];
  	wname[oid->subs[sub]] = '\0';
  
  	offset = sub + oid->subs[sub] + 1;
  	if (oid->subs[offset] > IEEE80211_NWID_LEN)
  		return (-1);
  	for (i = 0; i < oid->subs[offset]; i++)
  		ssid[i] = oid->subs[offset + i + 1];
  	ssid[i] = '\0';
  
  	offset = sub + oid->subs[sub] + oid->subs[offset] + 2;
  	if (oid->subs[offset] != IEEE80211_ADDR_LEN)
  		return (-1);
  	for (i = 0; i < IEEE80211_ADDR_LEN; i++)
  		bssid[i] = oid->subs[offset + i + 1];
  
  	return (0);
  }
  
  static void
  wlan_append_scanr_index(struct asn_oid *oid, uint sub, char *wname,
      uint8_t *ssid, uint8_t *bssid)
  {
  	uint32_t i;
  
  	oid->len = sub + strlen(wname) + strlen(ssid) + IEEE80211_ADDR_LEN + 3;
  	oid->subs[sub] = strlen(wname);
  	for (i = 1; i <= strlen(wname); i++)
  		oid->subs[sub + i] = wname[i - 1];
  
  	sub += strlen(wname) + 1;
  	oid->subs[sub] = strlen(ssid);
  	for (i = 1; i <= strlen(ssid); i++)
  		oid->subs[sub + i] = ssid[i - 1];
  
  	sub += strlen(ssid) + 1;
  	oid->subs[sub] = IEEE80211_ADDR_LEN;
  	for (i = 1; i <= IEEE80211_ADDR_LEN; i++)
  		oid->subs[sub + i] = bssid[i - 1];
  }
  
  static struct wlan_scan_result *
  wlan_get_scanr(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
  {
  	char wname[IFNAMSIZ];
  	uint8_t ssid[IEEE80211_NWID_LEN + 1];
  	uint8_t bssid[IEEE80211_ADDR_LEN];
  
  	if (wlan_scanr_index_decode(oid, sub, wname, ssid, bssid) < 0)
  		return (NULL);
  
  	if ((*wif = wlan_find_interface(wname)) == NULL)
  		return (NULL);
  
  	return (wlan_scan_find_result(*wif, ssid, bssid));
  }
  
  static struct wlan_scan_result *
  wlan_get_next_scanr(const struct asn_oid *oid, uint sub,
      struct wlan_iface **wif)
  {
  	char wname[IFNAMSIZ];
  	uint8_t ssid[IEEE80211_NWID_LEN + 1];
  	uint8_t bssid[IEEE80211_ADDR_LEN];
  	struct wlan_scan_result *sr;
  
  	if (oid->len - sub == 0) {
  		for (*wif = wlan_first_interface(); *wif != NULL;
  		    *wif = wlan_next_interface(*wif)) {
  			sr = SLIST_FIRST(&(*wif)->scanlist);
  			if (sr != NULL)
  				return (sr);
  		}
  		return (NULL);
  	}
  
  	if (wlan_scanr_index_decode(oid, sub, wname, ssid, bssid) < 0 ||
  	    (*wif = wlan_find_interface(wname)) == NULL ||
  	    (sr = wlan_scan_find_result(*wif, ssid, bssid)) == NULL)
  		return (NULL);
  
  	if ((sr = SLIST_NEXT(sr, wsr)) != NULL)
  		return (sr);
  
  	while ((*wif = wlan_next_interface(*wif)) != NULL)
  		if ((sr = SLIST_FIRST(&(*wif)->scanlist)) != NULL)
  			break;
  
  	return (sr);
  }
  
  /*
   * MAC Access Control.
   */
  static void
  wlan_mac_free_maclist(struct wlan_iface *wif)
  {
  	struct wlan_mac_mac *wmm;
  
  	while ((wmm = SLIST_FIRST(&wif->mac_maclist)) != NULL) {
  		SLIST_REMOVE_HEAD(&wif->mac_maclist, wm);
  		free(wmm);
  	}
  
  	SLIST_INIT(&wif->mac_maclist);
  }
  
  static struct wlan_mac_mac *
  wlan_mac_find_mac(struct wlan_iface *wif, uint8_t *mac)
  {
  	struct wlan_mac_mac *wmm;
  
  	SLIST_FOREACH(wmm, &wif->mac_maclist, wm)
  		if (memcmp(wmm->mac, mac, IEEE80211_ADDR_LEN) == 0)
  			break;
  
  	return (wmm);
  }
  
  struct wlan_mac_mac *
  wlan_mac_new_mac(const uint8_t *mac)
  {
  	struct wlan_mac_mac *wmm;
  
  	if ((wmm = (struct wlan_mac_mac *)malloc(sizeof(*wmm))) == NULL)
  		return (NULL);
  
  	memset(wmm, 0, sizeof(*wmm));
  	memcpy(wmm->mac, mac, IEEE80211_ADDR_LEN);
  	wmm->mac_status = RowStatus_notReady;
  
  	return (wmm);
  }
  
  void
  wlan_mac_free_mac(struct wlan_mac_mac *wmm)
  {
  	free(wmm);
  }
  
  int
  wlan_mac_add_mac(struct wlan_iface *wif, struct wlan_mac_mac *wmm)
  {
  	struct wlan_mac_mac *temp, *prev;
  
  	SLIST_FOREACH(temp, &wif->mac_maclist, wm)
  		if (memcmp(temp->mac, wmm->mac, IEEE80211_ADDR_LEN) == 0)
  			return (-1);
  
  	if ((prev = SLIST_FIRST(&wif->mac_maclist)) == NULL ||
  	    memcmp(wmm->mac, prev->mac,IEEE80211_ADDR_LEN) < 0) {
  	    	SLIST_INSERT_HEAD(&wif->mac_maclist, wmm, wm);
  	    	return (0);
  	}
  
  	SLIST_FOREACH(temp, &wif->mac_maclist, wm) {
  		if (memcmp(wmm->mac, temp->mac, IEEE80211_ADDR_LEN) < 0)
  			break;
  		prev = temp;
  	}
  
  	SLIST_INSERT_AFTER(prev, wmm, wm);
  	return (0);
  }
  
  static int
  wlan_mac_delete_mac(struct wlan_iface *wif, struct wlan_mac_mac *wmm)
  {
  	if (wmm->mac_status == RowStatus_active &&
  	    wlan_del_mac_acl_mac(wif, wmm) < 0)
  		return (-1);
  
  	SLIST_REMOVE(&wif->mac_maclist, wmm, wlan_mac_mac, wm);
  	free(wmm);
  
  	return (0);
  }
  
  static void
  wlan_mac_update_aclmacs(void)
  {
  	struct wlan_iface *wif;
  	struct wlan_mac_mac *wmm, *twmm;
  
  	if ((time(NULL) - wlan_maclist_age) <= WLAN_LIST_MAXAGE)
  		return;
  
  	for (wif = wlan_first_interface(); wif != NULL;
  	    wif = wlan_next_interface(wif)) {
  		if (wif->status != RowStatus_active)
  			continue;
  		/*
  		 * Nuke old entries - XXX - they are likely not to
  		 * change often - reconsider.
  		 */
  		SLIST_FOREACH_SAFE(wmm, &wif->mac_maclist, wm, twmm)
  			if (wmm->mac_status == RowStatus_active) {
  				SLIST_REMOVE(&wif->mac_maclist, wmm,
  				    wlan_mac_mac, wm);
  				wlan_mac_free_mac(wmm);
  			}
  		(void)wlan_get_mac_acl_macs(wif);
  	}
  	wlan_maclist_age = time(NULL);
  }
  
  static struct wlan_mac_mac *
  wlan_get_acl_mac(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
  {
  	char wname[IFNAMSIZ];
  	char mac[IEEE80211_ADDR_LEN];
  
  	if (wlan_mac_index_decode(oid, sub, wname, mac) < 0)
  		return (NULL);
  
  	if ((*wif = wlan_find_interface(wname)) == NULL)
  		return (NULL);
  
  	return (wlan_mac_find_mac(*wif, mac));
  }
  
  static struct wlan_mac_mac *
  wlan_get_next_acl_mac(const struct asn_oid *oid, uint sub,
      struct wlan_iface **wif)
  {
  	char wname[IFNAMSIZ];
  	char mac[IEEE80211_ADDR_LEN];
  	struct wlan_mac_mac *wmm;
  
  	if (oid->len - sub == 0) {
  		for (*wif = wlan_first_interface(); *wif != NULL;
  		    *wif = wlan_next_interface(*wif)) {
  			wmm = SLIST_FIRST(&(*wif)->mac_maclist);
  			if (wmm != NULL)
  				return (wmm);
  		}
  		return (NULL);
  	}
  
  	if (wlan_mac_index_decode(oid, sub, wname, mac) < 0 ||
  	    (*wif = wlan_find_interface(wname)) == NULL ||
  	    (wmm = wlan_mac_find_mac(*wif, mac)) == NULL)
  		return (NULL);
  
  	if ((wmm = SLIST_NEXT(wmm, wm)) != NULL)
  		return (wmm);
  
  	while ((*wif = wlan_next_interface(*wif)) != NULL)
  		if ((wmm = SLIST_FIRST(&(*wif)->mac_maclist)) != NULL)
  			break;
  
  	return (wmm);
  }
  
  static int
  wlan_acl_mac_set_status(struct snmp_context *ctx, struct snmp_value *val,
      uint sub)
  {
  	char wname[IFNAMSIZ];
  	uint8_t mac[IEEE80211_ADDR_LEN];
  	struct wlan_iface *wif;
  	struct wlan_mac_mac *macl;
  
  	if (wlan_mac_index_decode(&val->var, sub, wname, mac) < 0)
  		return (SNMP_ERR_GENERR);
  	macl = wlan_get_acl_mac(&val->var, sub, &wif);
  
  	switch (val->v.integer) {
  	case RowStatus_createAndGo:
  		if (macl != NULL)
  			return (SNMP_ERR_INCONS_NAME);
  		break;
  	case RowStatus_destroy:
  		if (macl == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		ctx->scratch->int1 = RowStatus_active;
  		return (SNMP_ERR_NOERROR);
  	default:
  		return (SNMP_ERR_INCONS_VALUE);
  	}
  
  
  	if (wif == NULL || !wif->macsupported)
  		return (SNMP_ERR_INCONS_VALUE);
  
  	if ((macl = wlan_mac_new_mac((const uint8_t *)mac)) == NULL)
  		return (SNMP_ERR_GENERR);
  
  	ctx->scratch->int1 = RowStatus_destroy;
  
  	if (wlan_mac_add_mac(wif, macl) < 0) {
  		wlan_mac_free_mac(macl);
  		return (SNMP_ERR_GENERR);
  	}
  
  	ctx->scratch->int1 = RowStatus_destroy;
  	if (wlan_add_mac_acl_mac(wif, macl) < 0) {
  		(void)wlan_mac_delete_mac(wif, macl);
  		return (SNMP_ERR_GENERR);
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  /*
   * Wireless interfaces operating as mesh points.
   */
  static struct wlan_iface *
  wlan_mesh_first_interface(void)
  {
  	struct wlan_iface *wif;
  
  	SLIST_FOREACH(wif, &wlan_ifaces, w_if)
  		if (wif->mode == WlanIfaceOperatingModeType_meshPoint &&
  		    wif->status == RowStatus_active)
  			break;
  
  	return (wif);
  }
  
  static struct wlan_iface *
  wlan_mesh_next_interface(struct wlan_iface *wif)
  {
  	struct wlan_iface *nwif;
  
  	while ((nwif = wlan_next_interface(wif)) != NULL) {
  		if (nwif->mode == WlanIfaceOperatingModeType_meshPoint &&
  		    nwif->status == RowStatus_active)
  			break;
  		wif = nwif;
  	}
  
  	return (nwif);
  }
  
  static struct wlan_iface *
  wlan_mesh_get_iface(const struct asn_oid *oid, uint sub)
  {
  	struct wlan_iface *wif;
  
  	if ((wif = wlan_get_interface(oid, sub)) == NULL)
  		return (NULL);
  
  	if (wif->mode != WlanIfaceOperatingModeType_meshPoint)
  		return (NULL);
  
  	return (wif);
  }
  
  static struct wlan_iface *
  wlan_mesh_get_next_iface(const struct asn_oid *oid, uint sub)
  {
  	uint32_t i;
  	uint8_t wname[IFNAMSIZ];
  	struct wlan_iface *wif;
  
  	if (oid->len - sub == 0)
  		return (wlan_mesh_first_interface());
  
  	if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= IFNAMSIZ)
  		return (NULL);
  
  	memset(wname, 0, IFNAMSIZ);
  	for (i = 0; i < oid->subs[sub]; i++)
  		wname[i] = oid->subs[sub + i + 1];
  	wname[i] = '\0';
  
  	if ((wif = wlan_find_interface(wname)) == NULL)
  		return (NULL);
  
  	return (wlan_mesh_next_interface(wif));
  }
  
  /*
   * The neighbors of wireless interfaces operating as mesh points.
   */
  static struct wlan_peer *
  wlan_mesh_get_peer(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
  {
  	char wname[IFNAMSIZ];
  	uint8_t pmac[IEEE80211_ADDR_LEN];
  
  	if (wlan_mac_index_decode(oid, sub, wname, pmac) < 0)
  		return (NULL);
  
  	if ((*wif = wlan_find_interface(wname)) == NULL ||
  	    (*wif)->mode != WlanIfaceOperatingModeType_meshPoint)
  		return (NULL);
  
  	return (wlan_find_peer(*wif, pmac));
  }
  
  static struct wlan_peer *
  wlan_mesh_get_next_peer(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
  {
  	char wname[IFNAMSIZ];
  	char pmac[IEEE80211_ADDR_LEN];
  	struct wlan_peer *wip;
  
  	if (oid->len - sub == 0) {
  		for (*wif = wlan_mesh_first_interface(); *wif != NULL;
  		    *wif = wlan_mesh_next_interface(*wif)) {
  			wip = SLIST_FIRST(&(*wif)->peerlist);
  			if (wip != NULL)
  				return (wip);
  		}
  		return (NULL);
  	}
  
  	if (wlan_mac_index_decode(oid, sub, wname, pmac) < 0 ||
  	    (*wif = wlan_find_interface(wname)) == NULL ||
  	    (*wif)->mode != WlanIfaceOperatingModeType_meshPoint ||
  	    (wip = wlan_find_peer(*wif, pmac)) == NULL)
  		return (NULL);
  
  	if ((wip = SLIST_NEXT(wip, wp)) != NULL)
  		return (wip);
  
  	while ((*wif = wlan_mesh_next_interface(*wif)) != NULL)
  		if ((wip = SLIST_FIRST(&(*wif)->peerlist)) != NULL)
  			break;
  
  	return (wip);
  }
  
  /*
   * Mesh routing table.
   */
  static void
  wlan_mesh_free_routes(struct wlan_iface *wif)
  {
  	struct wlan_mesh_route *wmr;
  
  	while ((wmr = SLIST_FIRST(&wif->mesh_routelist)) != NULL) {
  		SLIST_REMOVE_HEAD(&wif->mesh_routelist, wr);
  		free(wmr);
  	}
  
  	SLIST_INIT(&wif->mesh_routelist);
  }
  
  static struct wlan_mesh_route *
  wlan_mesh_find_route(struct wlan_iface *wif, uint8_t *dstmac)
  {
  	struct wlan_mesh_route *wmr;
  
  	if (wif->mode != WlanIfaceOperatingModeType_meshPoint)
  		return (NULL);
  
  	SLIST_FOREACH(wmr, &wif->mesh_routelist, wr)
  		if (memcmp(wmr->imroute.imr_dest, dstmac,
  		    IEEE80211_ADDR_LEN) == 0)
  			break;
  
  	return (wmr);
  }
  
  struct wlan_mesh_route *
  wlan_mesh_new_route(const uint8_t *dstmac)
  {
  	struct wlan_mesh_route *wmr;
  
  	if ((wmr = (struct wlan_mesh_route *)malloc(sizeof(*wmr))) == NULL)
  		return (NULL);
  
  	memset(wmr, 0, sizeof(*wmr));
  	memcpy(wmr->imroute.imr_dest, dstmac, IEEE80211_ADDR_LEN);
  	wmr->mroute_status = RowStatus_notReady;
  
  	return (wmr);
  }
  
  void
  wlan_mesh_free_route(struct wlan_mesh_route *wmr)
  {
  	free(wmr);
  }
  
  int
  wlan_mesh_add_rtentry(struct wlan_iface *wif, struct wlan_mesh_route *wmr)
  {
  	struct wlan_mesh_route *temp, *prev;
  
  	SLIST_FOREACH(temp, &wif->mesh_routelist, wr)
  		if (memcmp(temp->imroute.imr_dest, wmr->imroute.imr_dest,
  		    IEEE80211_ADDR_LEN) == 0)
  			return (-1);
  
  	if ((prev = SLIST_FIRST(&wif->mesh_routelist)) == NULL ||
  	    memcmp(wmr->imroute.imr_dest, prev->imroute.imr_dest,
  	    IEEE80211_ADDR_LEN) < 0) {
  	    	SLIST_INSERT_HEAD(&wif->mesh_routelist, wmr, wr);
  	    	return (0);
  	}
  
  	SLIST_FOREACH(temp, &wif->mesh_routelist, wr) {
  		if (memcmp(wmr->imroute.imr_dest, temp->imroute.imr_dest,
  		    IEEE80211_ADDR_LEN) < 0)
  			break;
  		prev = temp;
  	}
  
  	SLIST_INSERT_AFTER(prev, wmr, wr);
  	return (0);
  }
  
  static int
  wlan_mesh_delete_route(struct wlan_iface *wif, struct wlan_mesh_route *wmr)
  {
  	if (wmr->mroute_status == RowStatus_active &&
  	    wlan_mesh_del_route(wif, wmr) < 0)
  		return (-1);
  
  	SLIST_REMOVE(&wif->mesh_routelist, wmr, wlan_mesh_route, wr);
  	free(wmr);
  
  	return (0);
  }
  
  static void
  wlan_mesh_update_routes(void)
  {
  	struct wlan_iface *wif;
  	struct wlan_mesh_route *wmr, *twmr;
  
  	if ((time(NULL) - wlan_mrlist_age) <= WLAN_LIST_MAXAGE)
  		return;
  
  	for (wif = wlan_mesh_first_interface(); wif != NULL;
  	    wif = wlan_mesh_next_interface(wif)) {
  		/*
  		 * Nuke old entries - XXX - they are likely not to
  		 * change often - reconsider.
  		 */
  		SLIST_FOREACH_SAFE(wmr, &wif->mesh_routelist, wr, twmr)
  			if (wmr->mroute_status == RowStatus_active) {
  				SLIST_REMOVE(&wif->mesh_routelist, wmr,
  				    wlan_mesh_route, wr);
  				wlan_mesh_free_route(wmr);
  			}
  		(void)wlan_mesh_get_routelist(wif);
  	}
  	wlan_mrlist_age = time(NULL);
  }
  
  static struct wlan_mesh_route *
  wlan_mesh_get_route(const struct asn_oid *oid, uint sub, struct wlan_iface **wif)
  {
  	char wname[IFNAMSIZ];
  	char dstmac[IEEE80211_ADDR_LEN];
  
  	if (wlan_mac_index_decode(oid, sub, wname, dstmac) < 0)
  		return (NULL);
  
  	if ((*wif = wlan_find_interface(wname)) == NULL)
  		return (NULL);
  
  	return (wlan_mesh_find_route(*wif, dstmac));
  }
  
  static struct wlan_mesh_route *
  wlan_mesh_get_next_route(const struct asn_oid *oid, uint sub,
      struct wlan_iface **wif)
  {
  	char wname[IFNAMSIZ];
  	char dstmac[IEEE80211_ADDR_LEN];
  	struct wlan_mesh_route *wmr;
  
  	if (oid->len - sub == 0) {
  		for (*wif = wlan_mesh_first_interface(); *wif != NULL;
  		    *wif = wlan_mesh_next_interface(*wif)) {
  			wmr = SLIST_FIRST(&(*wif)->mesh_routelist);
  			if (wmr != NULL)
  				return (wmr);
  		}
  		return (NULL);
  	}
  
  	if (wlan_mac_index_decode(oid, sub, wname, dstmac) < 0 ||
  	    (*wif = wlan_find_interface(wname)) == NULL ||
  	    (wmr = wlan_mesh_find_route(*wif, dstmac)) == NULL)
  		return (NULL);
  
  	if ((wmr = SLIST_NEXT(wmr, wr)) != NULL)
  		return (wmr);
  
  	while ((*wif = wlan_mesh_next_interface(*wif)) != NULL)
  		if ((wmr = SLIST_FIRST(&(*wif)->mesh_routelist)) != NULL)
  			break;
  
  	return (wmr);
  }
  
  static int
  wlan_mesh_route_set_status(struct snmp_context *ctx, struct snmp_value *val,
      uint sub)
  {
  	char wname[IFNAMSIZ];
  	char mac[IEEE80211_ADDR_LEN];
  	struct wlan_mesh_route *wmr;
  	struct wlan_iface *wif;
  
  	if (wlan_mac_index_decode(&val->var, sub, wname, mac) < 0)
  		return (SNMP_ERR_GENERR);
  	wmr = wlan_mesh_get_route(&val->var, sub, &wif);
  
  	switch (val->v.integer) {
  	case RowStatus_createAndGo:
  		if (wmr != NULL)
  			return (SNMP_ERR_INCONS_NAME);
  		break;
  	case RowStatus_destroy:
  		if (wmr == NULL)
  			return (SNMP_ERR_NOSUCHNAME);
  		ctx->scratch->int1 = RowStatus_active;
  		return (SNMP_ERR_NOERROR);
  	default:
  		return (SNMP_ERR_INCONS_VALUE);
  	}
  
  	if ((wif = wlan_find_interface(wname)) == NULL)
  		return (SNMP_ERR_INCONS_NAME);
  
  	if ((wmr = wlan_mesh_new_route(mac)) == NULL)
  		return (SNMP_ERR_GENERR);
  
  	if (wlan_mesh_add_rtentry(wif, wmr) < 0) {
  		wlan_mesh_free_route(wmr);
  		return (SNMP_ERR_GENERR);
  	}
  
  	ctx->scratch->int1 = RowStatus_destroy;
  	if (wlan_mesh_add_route(wif, wmr) < 0) {
  		(void)wlan_mesh_delete_route(wif, wmr);
  		return (SNMP_ERR_GENERR);
  	}
  
  	return (SNMP_ERR_NOERROR);
  }
  
  /*
   * Wlan snmp module initialization hook.
   * Returns 0 on success, < 0 on error.
   */
  static int
  wlan_init(struct lmodule * mod __unused, int argc __unused,
       char *argv[] __unused)
  {
  	if (wlan_kmodules_load() < 0)
  		return (-1);
  
  	if (wlan_ioctl_init() < 0)
  		return (-1);
  
  	/* Register for new interface creation notifications. */
  	if (mib_register_newif(wlan_attach_newif, wlan_module)) {
  		syslog(LOG_ERR, "Cannot register newif function: %s",
  		    strerror(errno));
  		return (-1);
  	}
  
  	return (0);
  }
  
  /*
   * Wlan snmp module finalization hook.
   */
  static int
  wlan_fini(void)
  {
  	mib_unregister_newif(wlan_module);
  	or_unregister(reg_wlan);
  
  	/* XXX: Cleanup! */
  	wlan_free_iflist();
  
  	return (0);
  }
  
  /*
   * Refetch all available data from the kernel.
   */
  static void
  wlan_update_data(void *arg __unused)
  {
  }
  
  /*
   * Wlan snmp module start operation.
   */
  static void
  wlan_start(void)
  {
  	struct mibif *ifp;
  
  	reg_wlan = or_register(&oid_wlan,
  	    "The MIB module for managing wireless networking.", wlan_module);
  
  	 /* Add the existing wlan interfaces. */
  	 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
  		wlan_attach_newif(ifp);
  
  	wlan_data_timer = timer_start_repeat(wlan_poll_ticks,
  	    wlan_poll_ticks, wlan_update_data, NULL, wlan_module);
  }
  
  /*
   * Dump the Wlan snmp module data on SIGUSR1.
   */
  static void
  wlan_dump(void)
  {
  	/* XXX: Print some debug info to syslog. */
  	struct wlan_iface *wif;
  
  	for (wif = wlan_first_interface(); wif != NULL;
  	    wif = wlan_next_interface(wif))
  		syslog(LOG_ERR, "wlan iface %s", wif->wname);
  }
  
  const char wlan_comment[] = \
  "This module implements the BEGEMOT MIB for wireless networking.";
  
  const struct snmp_module config = {
  	.comment =	wlan_comment,
  	.init =		wlan_init,
  	.fini =		wlan_fini,
  	.start =	wlan_start,
  	.tree =		wlan_ctree,
  	.dump =		wlan_dump,
  	.tree_size =	wlan_CTREE_SIZE,
  };
  