snmp_atm.c revision 133488
16059Samurai/*
26059Samurai * Copyright (c) 2001-2002
36059Samurai *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
46059Samurai *	All rights reserved.
56059Samurai * Copyright (c) 2003-2004
66059Samurai *	Hartmut Brandt.
76059Samurai *	All rights reserved.
86059Samurai *
96059Samurai * Author: Hartmut Brandt <harti@freebsd.org>
106059Samurai *
116059Samurai * Redistribution and use in source and binary forms, with or without
126059Samurai * modification, are permitted provided that the following conditions
136059Samurai * are met:
146059Samurai * 1. Redistributions of source code must retain the above copyright
156059Samurai *    notice, this list of conditions and the following disclaimer.
166059Samurai * 2. Redistributions in binary form must reproduce the above copyright
176059Samurai *    notice, this list of conditions and the following disclaimer in the
186059Samurai *    documentation and/or other materials provided with the distribution.
198857Srgrimes *
2031962Sbrian * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
218857Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
226059Samurai * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
236059Samurai * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
246059Samurai * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
256059Samurai * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2630715Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2731195Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2831195Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2931195Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3030715Sbrian * SUCH DAMAGE.
316059Samurai *
326059Samurai * $Begemot: libunimsg/snmp_atm/snmp_atm.c,v 1.2 2004/08/06 17:30:40 brandt Exp $
336059Samurai *
346059Samurai * SNMP module for ATM hardware interfaces.
356059Samurai */
3613389Sphk
3731195Sbrian#include "atm.h"
3831343Sbrian#include "atm_tree.h"
3931195Sbrian#include "atm_oid.h"
4031343Sbrian
4131195Sbrian#include <sys/ioctl.h>
4230715Sbrian
4331343Sbrian#include <stdio.h>
4426031Sbrian#include <stdlib.h>
4531343Sbrian#include <string.h>
4630092Sbrian#include <errno.h>
4730715Sbrian#include <syslog.h>
4830715Sbrian#include <net/if_types.h>
4930715Sbrian#include <net/if_media.h>
5030733Sbrian#include <net/if_atm.h>
5130715Sbrian
5230715Sbrianstruct lmodule *module;
5331343Sbrian
5430715Sbrian/* list of all (known) ATM interfaces */
5530715Sbrianstruct atmif_list atmif_list = TAILQ_HEAD_INITIALIZER(atmif_list);
5630715Sbrian
5730715Sbrian/* whether we are started or not */
5830715Sbrianstatic int started;
5930715Sbrian
6030715Sbrian/* last time table was changed */
6126142Sbrianstatic uint32_t last_change;
626059Samurai
636059Samurai/* for the registration */
6429043Sbrianstatic const struct asn_oid oid_begemotAtm = OIDX_begemotAtm;
6530715Sbrian
6630715Sbrian/* the registration */
6730715Sbrianstatic u_int reg_atm;
6830733Sbrian
6931195Sbrian/*
7030715Sbrian * Find an ATM interface by name
716059Samurai */
726059Samuraistruct atmif *
736059Samuraiatm_find_if_name(const char *name)
7428679Sbrian{
7531343Sbrian	struct atmif_priv *aif;
766059Samurai
7726516Sbrian	TAILQ_FOREACH(aif, &atmif_list, link)
7826098Sbrian		if (strcmp(aif->pub.ifp->name, name) == 0)
796059Samurai			return (&aif->pub);
806059Samurai	return (NULL);
816059Samurai}
826059Samurai
836059Samurai/*
846059Samurai * get the interface from the interface index
856059Samurai */
866059Samuraistruct atmif *
876059Samuraiatm_find_if(u_int ifindex)
886059Samurai{
8928679Sbrian	struct atmif_priv *aif;
906059Samurai
916059Samurai	TAILQ_FOREACH(aif, &atmif_list, link)
926059Samurai		if (aif->index == ifindex)
936059Samurai			return (&aif->pub);
946059Samurai	return (NULL);
956059Samurai}
966059Samurai
976059Samurai/*
986059Samurai * Send notification to all listeners.
9926516Sbrian */
10026516Sbrianvoid
10129043Sbrianatmif_send_notification(struct atmif_priv *aif, enum atmif_notify code,
10226516Sbrian    uintptr_t arg)
10326516Sbrian{
10426516Sbrian	struct atmif_reg *r0, *r1;
10526516Sbrian
1066059Samurai	r0 = TAILQ_FIRST(&aif->notify);
1076059Samurai	while (r0 != NULL) {
1086059Samurai		r1 = TAILQ_NEXT(r0, link);
1096059Samurai		r0->func(&aif->pub, code, arg, r0->data);
1106059Samurai		r0 = r1;
1116059Samurai	}
1126059Samurai}
1136059Samurai
1146059Samurai/*
11531343Sbrian * Destroy an interface
1166059Samurai */
11728679Sbrianstatic void
1186059Samuraiatmif_destroy(struct atmif_priv *aif)
1196059Samurai{
1206059Samurai	struct atmif_reg *r0;
1216059Samurai
1226059Samurai	atmif_send_notification(aif, ATMIF_NOTIFY_DESTROY,
12331343Sbrian	    (uintptr_t)0);
12428679Sbrian
12528679Sbrian	atmif_sys_destroy(aif);
1266059Samurai
1276059Samurai	if (aif->ifpreg != NULL)
12813733Sdfr		mibif_unnotify(aif->ifpreg);
1296059Samurai
13031343Sbrian	while ((r0 = TAILQ_FIRST(&aif->notify)) != NULL) {
1316059Samurai		TAILQ_REMOVE(&aif->notify, r0, link);
13231343Sbrian		free(r0);
13328679Sbrian	}
1346059Samurai
1356059Samurai	TAILQ_REMOVE(&atmif_list, aif, link);
13628679Sbrian	free(aif);
1376059Samurai
1386059Samurai	last_change = this_tick;
13928679Sbrian}
14028679Sbrian
1416059Samurai/*
14228679Sbrian * Function gets called from the MIB-II module for events on that interface
1436059Samurai */
14428679Sbrianstatic void
1456059Samuraiatmif_notify(struct mibif *ifp __unused, enum mibif_notify event, void *data)
14628679Sbrian{
1476059Samurai	struct atmif_priv *aif = data;
1486059Samurai
1496059Samurai	switch (event) {
1506059Samurai
1516059Samurai	  case MIBIF_NOTIFY_DESTROY:
1526059Samurai		atmif_destroy(aif);
1536059Samurai		break;
15428679Sbrian	}
1556059Samurai}
1566059Samurai
1576059Samurai/*
1586059Samurai * Check the carrier state of the interface
1596059Samurai */
1606059Samuraivoid
1616059Samuraiatmif_check_carrier(struct atmif_priv *aif)
1626059Samurai{
1636059Samurai	struct ifmediareq ifmr;
1646059Samurai	enum atmif_carrier_state ost = aif->pub.carrier;
1656059Samurai
1666059Samurai	memset(&ifmr, 0, sizeof(ifmr));
1676059Samurai	strcpy(ifmr.ifm_name, aif->pub.ifp->name);
1686059Samurai
16928679Sbrian	if (ioctl(mib_netsock, SIOCGIFMEDIA, &ifmr) == -1) {
17028679Sbrian		aif->pub.carrier = ATMIF_CARRIER_UNKNOWN;
17128679Sbrian		return;
17228679Sbrian	}
17328679Sbrian	if (!ifmr.ifm_status & IFM_AVALID) {
17428679Sbrian		aif->pub.carrier = ATMIF_CARRIER_UNKNOWN;
17531143Sbrian		return;
17631143Sbrian	}
17731143Sbrian	if (ifmr.ifm_status & IFM_ACTIVE)
17831143Sbrian		aif->pub.carrier = ATMIF_CARRIER_ON;
1796059Samurai	else
1806059Samurai		aif->pub.carrier = ATMIF_CARRIER_OFF;
18128679Sbrian
1826059Samurai	if (ost != aif->pub.carrier)
1836059Samurai		atmif_send_notification(aif, ATMIF_NOTIFY_CARRIER,
1846059Samurai		    (uintptr_t)ost);
18528679Sbrian}
18628679Sbrian
18728679Sbrian/*
18828679Sbrian * Retrieve the SUNI mode
1896059Samurai */
1906059Samuraistatic int
19128679Sbrianatmif_get_mode(struct atmif_priv *aif)
19228679Sbrian{
19328679Sbrian	struct ifmediareq ifmr;
19428679Sbrian
1956059Samurai	memset(&ifmr, 0, sizeof(ifmr));
1966059Samurai	strcpy(ifmr.ifm_name, aif->pub.ifp->name);
1976059Samurai
19828679Sbrian	if (ioctl(mib_netsock, SIOCGIFMEDIA, &ifmr) < 0) {
19928679Sbrian		syslog(LOG_ERR, "SIOCGIFMEDIA: %m");
20028679Sbrian		aif->pub.mode = ATMIF_SUNI_MODE_UNKNOWN;
20128679Sbrian		return (SNMP_ERR_GENERR);
2026059Samurai	}
20328679Sbrian	if (ifmr.ifm_current & IFM_ATM_SDH)
20428679Sbrian		aif->pub.mode = ATMIF_SUNI_MODE_SDH;
20528679Sbrian	else
2066059Samurai		aif->pub.mode = ATMIF_SUNI_MODE_SONET;
2076059Samurai
20828679Sbrian	return (SNMP_ERR_NOERROR);
2096059Samurai}
2106059Samurai
21128679Sbrian/*
21228679Sbrian * Change the SUNI mod
21328679Sbrian */
2146059Samuraistatic int
21526516Sbrianatmif_set_mode(struct atmif_priv *aif, int newmode)
21628679Sbrian{
21726516Sbrian	struct ifmediareq ifmr;
21826516Sbrian	struct ifreq ifr;
2196059Samurai
2206059Samurai	memset(&ifmr, 0, sizeof(ifmr));
22128679Sbrian	strcpy(ifmr.ifm_name, aif->pub.ifp->name);
22228679Sbrian
2236059Samurai	/* get current mode */
22428679Sbrian	if (ioctl(mib_netsock, SIOCGIFMEDIA, &ifmr) < 0) {
22528679Sbrian		syslog(LOG_ERR, "SIOCGIFMEDIA: %m");
2266059Samurai		return (SNMP_ERR_GENERR);
22728679Sbrian	}
2286059Samurai
2296059Samurai	memset(&ifr, 0, sizeof(ifr));
2306059Samurai	strcpy(ifr.ifr_name, aif->pub.ifp->name);
2316059Samurai
23226516Sbrian	ifr.ifr_media = ifmr.ifm_current;
23328679Sbrian	if (newmode == ATMIF_SUNI_MODE_SDH)
2346059Samurai		ifr.ifr_media |= IFM_ATM_SDH;
2356059Samurai	else
2366059Samurai		ifr.ifr_media &= ~IFM_ATM_SDH;
2376059Samurai
2386059Samurai	if (ioctl(mib_netsock, SIOCSIFMEDIA, &ifr) < 0) {
23928679Sbrian		syslog(LOG_ERR, "SIOCSIFMEDIA: %m");
2406059Samurai		return (SNMP_ERR_GENERR);
24128679Sbrian	}
2426059Samurai
2436059Samurai	aif->pub.mode = newmode;
2446059Samurai	return (SNMP_ERR_NOERROR);
24528679Sbrian}
2466059Samurai
2476059Samurai/*
2486059Samurai * Attach to an ATM interface
2496059Samurai */
2506059Samuraistatic void
2516059Samuraiattach_if(struct mibif *ifp)
25230715Sbrian{
25313733Sdfr	struct atmif_priv *aif;
2546059Samurai
25531272Sbrian	/* we should not know it */
2566059Samurai	TAILQ_FOREACH(aif, &atmif_list, link)
2576059Samurai		if (aif->pub.ifp == ifp) {
2586059Samurai			syslog(LOG_CRIT, "new ATM if already known '%s'",
2596059Samurai			    ifp->name);
2606059Samurai			return;
2616059Samurai		}
2626059Samurai
2636059Samurai	/*
26428679Sbrian	 * tap it
2656059Samurai	 */
2666059Samurai	if ((aif = malloc(sizeof(*aif))) == NULL) {
2676059Samurai		syslog(LOG_ERR, "new atmif: %m");
2686059Samurai		return;
2696059Samurai	}
2706059Samurai	memset(aif, 0, sizeof(*aif));
2716059Samurai
2726059Samurai	aif->pub.ifp = ifp;
27326692Sbrian	aif->index = ifp->index;
27426692Sbrian
2756059Samurai	if (atmif_sys_attach_if(aif)) {
27626516Sbrian		free(aif);
27726692Sbrian		return;
2786059Samurai	}
27928679Sbrian
2808857Srgrimes	aif->ifpreg = mibif_notify(ifp, module, atmif_notify, aif);
28126692Sbrian
28228679Sbrian	aif->pub.carrier = ATMIF_CARRIER_UNKNOWN;
28328679Sbrian	atmif_check_carrier(aif);
28428679Sbrian	(void)atmif_get_mode(aif);
28526692Sbrian
2866059Samurai	INSERT_OBJECT_INT(aif, &atmif_list);
2876059Samurai
2886059Samurai	last_change = this_tick;
2896059Samurai
29026692Sbrian	return;
29128679Sbrian}
29228679Sbrian
29328679Sbrian/*
29428679Sbrian * Function gets called when a new interface is created. If this is an
29528679Sbrian * ATM interface, hook in. Claim the interface in any case even when
29628679Sbrian * the creation of our data structures fails.
29728679Sbrian */
2986059Samuraistatic int
2996059Samurainew_if(struct mibif *ifp)
3006059Samurai{
30126692Sbrian	if (!started || ifp->mib.ifmd_data.ifi_type != IFT_ATM ||
30228679Sbrian	    ifp->xnotify != NULL)
30328679Sbrian		return (0);
30428679Sbrian
30528679Sbrian	attach_if(ifp);
30628679Sbrian	return (1);
30728679Sbrian}
30828679Sbrian
3096059Samurai/*
3106059Samurai * Start the module
3116059Samurai */
31228679Sbrianstatic void
3136059Samuraiatm_start(void)
3146059Samurai{
31513733Sdfr	struct mibif *ifp;
3166059Samurai
31728679Sbrian	reg_atm = or_register(&oid_begemotAtm,
3186059Samurai	    "The Begemot MIB for ATM interfaces.", module);
31926692Sbrian
3206059Samurai	started = 1;
32128679Sbrian	for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
32228679Sbrian		if (ifp->mib.ifmd_data.ifi_type == IFT_ATM &&
32328679Sbrian		    ifp->xnotify == NULL)
32428679Sbrian			attach_if(ifp);
32528679Sbrian}
32628679Sbrian
3276059Samurai/*
3286059Samurai * Called when modules is loaded
32926692Sbrian */
33028679Sbrianstatic int
33128679Sbrianatm_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
33228679Sbrian{
3336059Samurai	module = mod;
3346059Samurai
33528679Sbrian	/* register to get creation messages for ATM interfaces */
33628679Sbrian	if (mib_register_newif(new_if, module)) {
33728679Sbrian		syslog(LOG_ERR, "cannot register newif function: %m");
33828679Sbrian		return (-1);
3396059Samurai	}
34028679Sbrian
3416059Samurai	return (0);
3426059Samurai}
34328679Sbrian
34426692Sbrian/*
34528679Sbrian * Called when module gets unloaded - free all resources
34628679Sbrian */
34728679Sbrianstatic int
34828679Sbrianatm_fini(void)
3496059Samurai{
3506059Samurai	struct atmif_priv *aif;
3516059Samurai
3526059Samurai	while ((aif = TAILQ_FIRST(&atmif_list)) != NULL)
35326692Sbrian		atmif_destroy(aif);
35413733Sdfr
35531142Sbrian	mib_unregister_newif(module);
35631142Sbrian	or_unregister(reg_atm);
35728679Sbrian
35828679Sbrian	return (0);
35928679Sbrian}
3606059Samurai
36128679Sbrian/*
36231142Sbrian * Other module unloaded/loaded
36331142Sbrian */
36430715Sbrianstatic void
3656735Samuraiatm_loading(const struct lmodule *mod, int loading)
36631142Sbrian{
36731142Sbrian	struct atmif_priv *aif;
36830715Sbrian	struct atmif_reg *r0, *r1;
3696735Samurai
37028679Sbrian	if (!loading) {
3716059Samurai		/* remove notifications for this module */
3726059Samurai		TAILQ_FOREACH(aif, &atmif_list, link)
3736059Samurai			TAILQ_FOREACH_SAFE(r0, &aif->notify, link, r1) {
3746059Samurai				if (r0->mod == mod) {
37528679Sbrian					TAILQ_REMOVE(&aif->notify, r0, link);
37628679Sbrian					free(r0);
3776059Samurai				}
3786059Samurai			}
3796059Samurai	}
38031343Sbrian}
3816059Samurai
38231195Sbrianconst struct snmp_module config = {
38331195Sbrian	.comment = "This module implements a private MIB for ATM interfaces.",
3846059Samurai	.init =		atm_init,
38528679Sbrian	.fini =		atm_fini,
38630715Sbrian	.start =	atm_start,
3876059Samurai	.tree =		atm_ctree,
3886059Samurai	.tree_size =	atm_CTREE_SIZE,
3896059Samurai	.loading =	atm_loading
3906059Samurai};
39131343Sbrian
39220365Sjkh/*
39331343Sbrian * Get the interface point for a table access
39426031Sbrian */
39526031Sbrianint
39626031Sbrianatmif_get_aif(struct snmp_value *value, u_int sub, enum snmp_op op,
39731195Sbrian    struct atmif_priv **aifp)
39831195Sbrian{
39926031Sbrian	switch (op) {
40026031Sbrian
40126516Sbrian	  case SNMP_OP_GETNEXT:
40226031Sbrian		if ((*aifp = NEXT_OBJECT_INT(&atmif_list,
40326031Sbrian		    &value->var, sub)) == NULL)
40426031Sbrian			return (SNMP_ERR_NOSUCHNAME);
40526031Sbrian		value->var.len = sub + 1;
40628679Sbrian		value->var.subs[sub] = (*aifp)->index;
40731195Sbrian		break;
40828679Sbrian
40928679Sbrian	  case SNMP_OP_GET:
41026031Sbrian		if ((*aifp = FIND_OBJECT_INT(&atmif_list,
41131272Sbrian		    &value->var, sub)) == NULL)
41226031Sbrian			return (SNMP_ERR_NOSUCHNAME);
41331195Sbrian		break;
41431962Sbrian
41531195Sbrian	  case SNMP_OP_SET:
41626031Sbrian		if ((*aifp = FIND_OBJECT_INT(&atmif_list,
41730092Sbrian		    &value->var, sub)) == NULL)
41830092Sbrian			return (SNMP_ERR_NO_CREATION);
41930092Sbrian		break;
42030092Sbrian
42130092Sbrian	  case SNMP_OP_ROLLBACK:
42226031Sbrian	  case SNMP_OP_COMMIT:
42326031Sbrian		if ((*aifp = FIND_OBJECT_INT(&atmif_list,
42431195Sbrian		    &value->var, sub)) == NULL)
42531195Sbrian			abort();
42628679Sbrian		return (SNMP_ERR_NOERROR);
42731962Sbrian	}
42831962Sbrian
42931962Sbrian	if ((*aifp)->pub.mib->pcr == 0) {
43031195Sbrian		mib_fetch_ifmib((*aifp)->pub.ifp);
43128679Sbrian		atmif_sys_fill_mib(*aifp);
43230092Sbrian		atmif_check_carrier(*aifp);
43330092Sbrian	}
43430092Sbrian
43530092Sbrian	return (SNMP_ERR_NOERROR);
43630092Sbrian}
43731195Sbrian
43828679Sbrian/*
43926031Sbrian * Table of all ATM interfaces
44028679Sbrian */
44131195Sbrianint
44231962Sbrianop_atmif(struct snmp_context *ctx __unused, struct snmp_value *value,
44331195Sbrian    u_int sub, u_int vindex __unused, enum snmp_op op)
44431195Sbrian{
44528679Sbrian	struct atmif_priv *aif;
44626031Sbrian	int err;
44731195Sbrian
44831962Sbrian	if ((err = atmif_get_aif(value, sub, op, &aif)) != SNMP_ERR_NOERROR)
44931195Sbrian		return (err);
45026031Sbrian
45126031Sbrian	if (op == SNMP_OP_SET) {
45231343Sbrian		switch (value->var.subs[sub - 1]) {
45331343Sbrian
45431343Sbrian		  default:
45531195Sbrian			return (SNMP_ERR_NOT_WRITEABLE);
45626031Sbrian
45726031Sbrian		  case LEAF_begemotAtmIfMode:
45826031Sbrian			if ((err = atmif_get_mode(aif)) != SNMP_ERR_NOERROR)
45931272Sbrian				return (err);
46031962Sbrian			if (aif->pub.mode == ATMIF_SUNI_MODE_UNKNOWN)
46131195Sbrian				return (SNMP_ERR_INCONS_VALUE);
46226031Sbrian			if (value->v.integer != ATMIF_SUNI_MODE_SONET &&
46330092Sbrian			    value->v.integer != ATMIF_SUNI_MODE_SDH)
46430092Sbrian				return (SNMP_ERR_WRONG_VALUE);
46530092Sbrian			if ((u_int)value->v.integer == aif->pub.mode)
46630092Sbrian				return (SNMP_ERR_NOERROR);
4676059Samurai			return (atmif_set_mode(aif, value->v.integer));
4686059Samurai		}
4696059Samurai		abort();
4706059Samurai	}
4716059Samurai
4726059Samurai	switch (value->var.subs[sub - 1]) {
47328679Sbrian
4746059Samurai	  case LEAF_begemotAtmIfName:
4756059Samurai		return (string_get(value, aif->pub.ifp->name, -1));
47628679Sbrian
4776059Samurai	  case LEAF_begemotAtmIfPcr:
4786059Samurai		value->v.uint32 = aif->pub.mib->pcr;
4796059Samurai		return (SNMP_ERR_NOERROR);
4806059Samurai
48130715Sbrian	  case LEAF_begemotAtmIfMedia:
4826059Samurai		value->v.integer = aif->pub.mib->media;
4836059Samurai		return (SNMP_ERR_NOERROR);
4846059Samurai
48530715Sbrian	  case LEAF_begemotAtmIfVpiBits:
4868857Srgrimes		value->v.uint32 = aif->pub.mib->vpi_bits;
4877001Samurai		return (SNMP_ERR_NOERROR);
4887001Samurai
4897001Samurai	  case LEAF_begemotAtmIfVciBits:
49030715Sbrian		value->v.uint32 = aif->pub.mib->vci_bits;
49128679Sbrian		return (SNMP_ERR_NOERROR);
49213733Sdfr
49328679Sbrian	  case LEAF_begemotAtmIfMaxVpcs:
49430715Sbrian		value->v.uint32 = aif->pub.mib->max_vpcs;
49528679Sbrian		return (SNMP_ERR_NOERROR);
49628679Sbrian
4977001Samurai	  case LEAF_begemotAtmIfMaxVccs:
49828679Sbrian		value->v.uint32 = aif->pub.mib->max_vccs;
4997001Samurai		return (SNMP_ERR_NOERROR);
50030715Sbrian
5017001Samurai	  case LEAF_begemotAtmIfEsi:
5026059Samurai		return (string_get(value, aif->pub.mib->esi, 6));
5036059Samurai
5046059Samurai	  case LEAF_begemotAtmIfCarrierStatus:
5056059Samurai		value->v.integer = aif->pub.carrier;
5066059Samurai		return (SNMP_ERR_NOERROR);
50725630Sbrian
5086059Samurai	  case LEAF_begemotAtmIfMode:
5096059Samurai		if ((err = atmif_get_mode(aif)) != SNMP_ERR_NOERROR)
5106059Samurai			return (err);
51113733Sdfr		value->v.integer = aif->pub.mode;
5126059Samurai		return (SNMP_ERR_NOERROR);
5136059Samurai	}
5146059Samurai	abort();
5156059Samurai}
51613733Sdfr
5176059Samurai/*
51831272Sbrian * Hardware table
51913733Sdfr */
52028679Sbrianint
5216059Samuraiop_atmhw(struct snmp_context *ctx __unused, struct snmp_value *value,
5226059Samurai    u_int sub, u_int vindex __unused, enum snmp_op op)
5236059Samurai{
524	struct atmif_priv *aif;
525	int err;
526
527	if ((err = atmif_get_aif(value, sub, op, &aif)) != SNMP_ERR_NOERROR)
528		return (err);
529	if (op == SNMP_OP_SET)
530		return (SNMP_ERR_NOT_WRITEABLE);
531
532	switch (value->var.subs[sub - 1]) {
533
534	  case LEAF_begemotAtmHWVendor:
535		return (atm_sys_get_hw_vendor(aif, value));
536
537	  case LEAF_begemotAtmHWDevice:
538		return (atm_sys_get_hw_device(aif, value));
539
540	  case LEAF_begemotAtmHWSerial:
541		value->v.uint32 = aif->pub.mib->serial;
542		return (SNMP_ERR_NOERROR);
543
544	  case LEAF_begemotAtmHWVersion:
545		value->v.uint32 = aif->pub.mib->hw_version;
546		return (SNMP_ERR_NOERROR);
547
548	  case LEAF_begemotAtmHWSoftVersion:
549		value->v.uint32 = aif->pub.mib->sw_version;
550		return (SNMP_ERR_NOERROR);
551
552	}
553	abort();
554}
555
556/*
557 * Scalars
558 */
559int
560op_atm(struct snmp_context *ctx __unused, struct snmp_value *value,
561    u_int sub, u_int vindex __unused, enum snmp_op op)
562{
563	switch (op) {
564
565	  case SNMP_OP_GETNEXT:
566		abort();
567
568	  case SNMP_OP_GET:
569		switch (value->var.subs[sub - 1]) {
570
571		  case LEAF_begemotAtmIfTableLastChange:
572			value->v.uint32 =
573			    (last_change == 0 ? 0 : last_change - start_tick);
574			return (SNMP_ERR_NOERROR);
575		}
576		abort();
577
578	  case SNMP_OP_SET:
579		return (SNMP_ERR_NOT_WRITEABLE);
580
581	  case SNMP_OP_ROLLBACK:
582	  case SNMP_OP_COMMIT:
583		abort();
584	}
585	abort();
586}
587
588/*
589 * Register for interface notifications
590 */
591void *
592atm_notify_aif(struct atmif *pub, const struct lmodule *mod,
593    atmif_event_f func, void *arg)
594{
595	struct atmif_priv *aif = (struct atmif_priv *)pub;
596	struct atmif_reg *r0;
597
598	if ((r0 = malloc(sizeof(*r0))) == NULL) {
599		syslog(LOG_CRIT, "out of memory");
600		return (NULL);
601	}
602	r0->func = func;
603	r0->mod = mod;
604	r0->data = arg;
605	r0->aif = aif;
606
607	TAILQ_INSERT_TAIL(&aif->notify, r0, link);
608
609	return (r0);
610}
611
612/*
613 * Unregister it
614 */
615void
616atm_unnotify_aif(void *arg)
617{
618	struct atmif_reg *r0 = arg;
619
620	TAILQ_REMOVE(&r0->aif->notify, r0, link);
621	free(r0);
622}
623