summaryrefslogtreecommitdiffstats
path: root/contrib/ngatm/snmp_atm/snmp_atm.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ngatm/snmp_atm/snmp_atm.c')
-rw-r--r--contrib/ngatm/snmp_atm/snmp_atm.c622
1 files changed, 622 insertions, 0 deletions
diff --git a/contrib/ngatm/snmp_atm/snmp_atm.c b/contrib/ngatm/snmp_atm/snmp_atm.c
new file mode 100644
index 0000000..1106e8a
--- /dev/null
+++ b/contrib/ngatm/snmp_atm/snmp_atm.c
@@ -0,0 +1,622 @@
+/*
+ * Copyright (c) 2001-2002
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ * Copyright (c) 2003-2004
+ * Hartmut Brandt.
+ * All rights reserved.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ *
+ * 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 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 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.
+ *
+ * $Begemot: libunimsg/snmp_atm/snmp_atm.c,v 1.2 2004/08/06 17:30:40 brandt Exp $
+ *
+ * SNMP module for ATM hardware interfaces.
+ */
+
+#include "atm.h"
+#include "atm_tree.h"
+#include "atm_oid.h"
+
+#include <sys/ioctl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <syslog.h>
+#include <net/if_types.h>
+#include <net/if_media.h>
+#include <net/if_atm.h>
+
+struct lmodule *module;
+
+/* list of all (known) ATM interfaces */
+struct atmif_list atmif_list = TAILQ_HEAD_INITIALIZER(atmif_list);
+
+/* whether we are started or not */
+static int started;
+
+/* last time table was changed */
+static uint32_t last_change;
+
+/* for the registration */
+static const struct asn_oid oid_begemotAtm = OIDX_begemotAtm;
+
+/* the registration */
+static u_int reg_atm;
+
+/*
+ * Find an ATM interface by name
+ */
+struct atmif *
+atm_find_if_name(const char *name)
+{
+ struct atmif_priv *aif;
+
+ TAILQ_FOREACH(aif, &atmif_list, link)
+ if (strcmp(aif->pub.ifp->name, name) == 0)
+ return (&aif->pub);
+ return (NULL);
+}
+
+/*
+ * get the interface from the interface index
+ */
+struct atmif *
+atm_find_if(u_int ifindex)
+{
+ struct atmif_priv *aif;
+
+ TAILQ_FOREACH(aif, &atmif_list, link)
+ if (aif->index == ifindex)
+ return (&aif->pub);
+ return (NULL);
+}
+
+/*
+ * Send notification to all listeners.
+ */
+void
+atmif_send_notification(struct atmif_priv *aif, enum atmif_notify code,
+ uintptr_t arg)
+{
+ struct atmif_reg *r0, *r1;
+
+ r0 = TAILQ_FIRST(&aif->notify);
+ while (r0 != NULL) {
+ r1 = TAILQ_NEXT(r0, link);
+ r0->func(&aif->pub, code, arg, r0->data);
+ r0 = r1;
+ }
+}
+
+/*
+ * Destroy an interface
+ */
+static void
+atmif_destroy(struct atmif_priv *aif)
+{
+ struct atmif_reg *r0;
+
+ atmif_send_notification(aif, ATMIF_NOTIFY_DESTROY,
+ (uintptr_t)0);
+
+ atmif_sys_destroy(aif);
+
+ if (aif->ifpreg != NULL)
+ mibif_unnotify(aif->ifpreg);
+
+ while ((r0 = TAILQ_FIRST(&aif->notify)) != NULL) {
+ TAILQ_REMOVE(&aif->notify, r0, link);
+ free(r0);
+ }
+
+ TAILQ_REMOVE(&atmif_list, aif, link);
+ free(aif);
+
+ last_change = this_tick;
+}
+
+/*
+ * Function gets called from the MIB-II module for events on that interface
+ */
+static void
+atmif_notify(struct mibif *ifp __unused, enum mibif_notify event, void *data)
+{
+ struct atmif_priv *aif = data;
+
+ switch (event) {
+
+ case MIBIF_NOTIFY_DESTROY:
+ atmif_destroy(aif);
+ break;
+ }
+}
+
+/*
+ * Check the carrier state of the interface
+ */
+void
+atmif_check_carrier(struct atmif_priv *aif)
+{
+ struct ifmediareq ifmr;
+ enum atmif_carrier_state ost = aif->pub.carrier;
+
+ memset(&ifmr, 0, sizeof(ifmr));
+ strcpy(ifmr.ifm_name, aif->pub.ifp->name);
+
+ if (ioctl(mib_netsock, SIOCGIFMEDIA, &ifmr) == -1) {
+ aif->pub.carrier = ATMIF_CARRIER_UNKNOWN;
+ return;
+ }
+ if (!ifmr.ifm_status & IFM_AVALID) {
+ aif->pub.carrier = ATMIF_CARRIER_UNKNOWN;
+ return;
+ }
+ if (ifmr.ifm_status & IFM_ACTIVE)
+ aif->pub.carrier = ATMIF_CARRIER_ON;
+ else
+ aif->pub.carrier = ATMIF_CARRIER_OFF;
+
+ if (ost != aif->pub.carrier)
+ atmif_send_notification(aif, ATMIF_NOTIFY_CARRIER,
+ (uintptr_t)ost);
+}
+
+/*
+ * Retrieve the SUNI mode
+ */
+static int
+atmif_get_mode(struct atmif_priv *aif)
+{
+ struct ifmediareq ifmr;
+
+ memset(&ifmr, 0, sizeof(ifmr));
+ strcpy(ifmr.ifm_name, aif->pub.ifp->name);
+
+ if (ioctl(mib_netsock, SIOCGIFMEDIA, &ifmr) < 0) {
+ syslog(LOG_ERR, "SIOCGIFMEDIA: %m");
+ aif->pub.mode = ATMIF_SUNI_MODE_UNKNOWN;
+ return (SNMP_ERR_GENERR);
+ }
+ if (ifmr.ifm_current & IFM_ATM_SDH)
+ aif->pub.mode = ATMIF_SUNI_MODE_SDH;
+ else
+ aif->pub.mode = ATMIF_SUNI_MODE_SONET;
+
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Change the SUNI mod
+ */
+static int
+atmif_set_mode(struct atmif_priv *aif, int newmode)
+{
+ struct ifmediareq ifmr;
+ struct ifreq ifr;
+
+ memset(&ifmr, 0, sizeof(ifmr));
+ strcpy(ifmr.ifm_name, aif->pub.ifp->name);
+
+ /* get current mode */
+ if (ioctl(mib_netsock, SIOCGIFMEDIA, &ifmr) < 0) {
+ syslog(LOG_ERR, "SIOCGIFMEDIA: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, aif->pub.ifp->name);
+
+ ifr.ifr_media = ifmr.ifm_current;
+ if (newmode == ATMIF_SUNI_MODE_SDH)
+ ifr.ifr_media |= IFM_ATM_SDH;
+ else
+ ifr.ifr_media &= ~IFM_ATM_SDH;
+
+ if (ioctl(mib_netsock, SIOCSIFMEDIA, &ifr) < 0) {
+ syslog(LOG_ERR, "SIOCSIFMEDIA: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ aif->pub.mode = newmode;
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Attach to an ATM interface
+ */
+static void
+attach_if(struct mibif *ifp)
+{
+ struct atmif_priv *aif;
+
+ /* we should not know it */
+ TAILQ_FOREACH(aif, &atmif_list, link)
+ if (aif->pub.ifp == ifp) {
+ syslog(LOG_CRIT, "new ATM if already known '%s'",
+ ifp->name);
+ return;
+ }
+
+ /*
+ * tap it
+ */
+ if ((aif = malloc(sizeof(*aif))) == NULL) {
+ syslog(LOG_ERR, "new atmif: %m");
+ return;
+ }
+ memset(aif, 0, sizeof(*aif));
+
+ aif->pub.ifp = ifp;
+ aif->index = ifp->index;
+
+ if (atmif_sys_attach_if(aif)) {
+ free(aif);
+ return;
+ }
+
+ aif->ifpreg = mibif_notify(ifp, module, atmif_notify, aif);
+
+ aif->pub.carrier = ATMIF_CARRIER_UNKNOWN;
+ atmif_check_carrier(aif);
+ (void)atmif_get_mode(aif);
+
+ INSERT_OBJECT_INT(aif, &atmif_list);
+
+ last_change = this_tick;
+
+ return;
+}
+
+/*
+ * Function gets called when a new interface is created. If this is an
+ * ATM interface, hook in. Claim the interface in any case even when
+ * the creation of our data structures fails.
+ */
+static int
+new_if(struct mibif *ifp)
+{
+ if (!started || ifp->mib.ifmd_data.ifi_type != IFT_ATM ||
+ ifp->xnotify != NULL)
+ return (0);
+
+ attach_if(ifp);
+ return (1);
+}
+
+/*
+ * Start the module
+ */
+static void
+atm_start(void)
+{
+ struct mibif *ifp;
+
+ reg_atm = or_register(&oid_begemotAtm,
+ "The Begemot MIB for ATM interfaces.", module);
+
+ started = 1;
+ for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
+ if (ifp->mib.ifmd_data.ifi_type == IFT_ATM &&
+ ifp->xnotify == NULL)
+ attach_if(ifp);
+}
+
+/*
+ * Called when modules is loaded
+ */
+static int
+atm_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
+{
+ module = mod;
+
+ /* register to get creation messages for ATM interfaces */
+ if (mib_register_newif(new_if, module)) {
+ syslog(LOG_ERR, "cannot register newif function: %m");
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Called when module gets unloaded - free all resources
+ */
+static int
+atm_fini(void)
+{
+ struct atmif_priv *aif;
+
+ while ((aif = TAILQ_FIRST(&atmif_list)) != NULL)
+ atmif_destroy(aif);
+
+ mib_unregister_newif(module);
+ or_unregister(reg_atm);
+
+ return (0);
+}
+
+/*
+ * Other module unloaded/loaded
+ */
+static void
+atm_loading(const struct lmodule *mod, int loading)
+{
+ struct atmif_priv *aif;
+ struct atmif_reg *r0, *r1;
+
+ if (!loading) {
+ /* remove notifications for this module */
+ TAILQ_FOREACH(aif, &atmif_list, link)
+ TAILQ_FOREACH_SAFE(r0, &aif->notify, link, r1) {
+ if (r0->mod == mod) {
+ TAILQ_REMOVE(&aif->notify, r0, link);
+ free(r0);
+ }
+ }
+ }
+}
+
+const struct snmp_module config = {
+ .comment = "This module implements a private MIB for ATM interfaces.",
+ .init = atm_init,
+ .fini = atm_fini,
+ .start = atm_start,
+ .tree = atm_ctree,
+ .tree_size = atm_CTREE_SIZE,
+ .loading = atm_loading
+};
+
+/*
+ * Get the interface point for a table access
+ */
+int
+atmif_get_aif(struct snmp_value *value, u_int sub, enum snmp_op op,
+ struct atmif_priv **aifp)
+{
+ switch (op) {
+
+ case SNMP_OP_GETNEXT:
+ if ((*aifp = NEXT_OBJECT_INT(&atmif_list,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ value->var.len = sub + 1;
+ value->var.subs[sub] = (*aifp)->index;
+ break;
+
+ case SNMP_OP_GET:
+ if ((*aifp = FIND_OBJECT_INT(&atmif_list,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
+ break;
+
+ case SNMP_OP_SET:
+ if ((*aifp = FIND_OBJECT_INT(&atmif_list,
+ &value->var, sub)) == NULL)
+ return (SNMP_ERR_NO_CREATION);
+ break;
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ if ((*aifp = FIND_OBJECT_INT(&atmif_list,
+ &value->var, sub)) == NULL)
+ abort();
+ return (SNMP_ERR_NOERROR);
+ }
+
+ if ((*aifp)->pub.mib->pcr == 0) {
+ mib_fetch_ifmib((*aifp)->pub.ifp);
+ atmif_sys_fill_mib(*aifp);
+ atmif_check_carrier(*aifp);
+ }
+
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Table of all ATM interfaces
+ */
+int
+op_atmif(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int vindex __unused, enum snmp_op op)
+{
+ struct atmif_priv *aif;
+ int err;
+
+ if ((err = atmif_get_aif(value, sub, op, &aif)) != SNMP_ERR_NOERROR)
+ return (err);
+
+ if (op == SNMP_OP_SET) {
+ switch (value->var.subs[sub - 1]) {
+
+ default:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case LEAF_begemotAtmIfMode:
+ if ((err = atmif_get_mode(aif)) != SNMP_ERR_NOERROR)
+ return (err);
+ if (aif->pub.mode == ATMIF_SUNI_MODE_UNKNOWN)
+ return (SNMP_ERR_INCONS_VALUE);
+ if (value->v.integer != ATMIF_SUNI_MODE_SONET &&
+ value->v.integer != ATMIF_SUNI_MODE_SDH)
+ return (SNMP_ERR_WRONG_VALUE);
+ if ((u_int)value->v.integer == aif->pub.mode)
+ return (SNMP_ERR_NOERROR);
+ return (atmif_set_mode(aif, value->v.integer));
+ }
+ abort();
+ }
+
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_begemotAtmIfName:
+ return (string_get(value, aif->pub.ifp->name, -1));
+
+ case LEAF_begemotAtmIfPcr:
+ value->v.uint32 = aif->pub.mib->pcr;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotAtmIfMedia:
+ value->v.integer = aif->pub.mib->media;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotAtmIfVpiBits:
+ value->v.uint32 = aif->pub.mib->vpi_bits;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotAtmIfVciBits:
+ value->v.uint32 = aif->pub.mib->vci_bits;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotAtmIfMaxVpcs:
+ value->v.uint32 = aif->pub.mib->max_vpcs;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotAtmIfMaxVccs:
+ value->v.uint32 = aif->pub.mib->max_vccs;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotAtmIfEsi:
+ return (string_get(value, aif->pub.mib->esi, 6));
+
+ case LEAF_begemotAtmIfCarrierStatus:
+ value->v.integer = aif->pub.carrier;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotAtmIfMode:
+ if ((err = atmif_get_mode(aif)) != SNMP_ERR_NOERROR)
+ return (err);
+ value->v.integer = aif->pub.mode;
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+}
+
+/*
+ * Hardware table
+ */
+int
+op_atmhw(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int vindex __unused, enum snmp_op op)
+{
+ struct atmif_priv *aif;
+ int err;
+
+ if ((err = atmif_get_aif(value, sub, op, &aif)) != SNMP_ERR_NOERROR)
+ return (err);
+ if (op == SNMP_OP_SET)
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_begemotAtmHWVendor:
+ return (atm_sys_get_hw_vendor(aif, value));
+
+ case LEAF_begemotAtmHWDevice:
+ return (atm_sys_get_hw_device(aif, value));
+
+ case LEAF_begemotAtmHWSerial:
+ value->v.uint32 = aif->pub.mib->serial;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotAtmHWVersion:
+ value->v.uint32 = aif->pub.mib->hw_version;
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_begemotAtmHWSoftVersion:
+ value->v.uint32 = aif->pub.mib->sw_version;
+ return (SNMP_ERR_NOERROR);
+
+ }
+ abort();
+}
+
+/*
+ * Scalars
+ */
+int
+op_atm(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int vindex __unused, enum snmp_op op)
+{
+ switch (op) {
+
+ case SNMP_OP_GETNEXT:
+ abort();
+
+ case SNMP_OP_GET:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_begemotAtmIfTableLastChange:
+ value->v.uint32 =
+ (last_change == 0 ? 0 : last_change - start_tick);
+ return (SNMP_ERR_NOERROR);
+ }
+ abort();
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ abort();
+ }
+ abort();
+}
+
+/*
+ * Register for interface notifications
+ */
+void *
+atm_notify_aif(struct atmif *pub, const struct lmodule *mod,
+ atmif_event_f func, void *arg)
+{
+ struct atmif_priv *aif = (struct atmif_priv *)pub;
+ struct atmif_reg *r0;
+
+ if ((r0 = malloc(sizeof(*r0))) == NULL) {
+ syslog(LOG_CRIT, "out of memory");
+ return (NULL);
+ }
+ r0->func = func;
+ r0->mod = mod;
+ r0->data = arg;
+ r0->aif = aif;
+
+ TAILQ_INSERT_TAIL(&aif->notify, r0, link);
+
+ return (r0);
+}
+
+/*
+ * Unregister it
+ */
+void
+atm_unnotify_aif(void *arg)
+{
+ struct atmif_reg *r0 = arg;
+
+ TAILQ_REMOVE(&r0->aif->notify, r0, link);
+ free(r0);
+}
OpenPOWER on IntegriCloud