summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.c')
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.c4513
1 files changed, 4513 insertions, 0 deletions
diff --git a/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.c b/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.c
new file mode 100644
index 0000000..ec94ac6
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_snmp.c
@@ -0,0 +1,4513 @@
+/*-
+ * 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$
+ */
+
+#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,
+};
OpenPOWER on IntegriCloud