15455Sdg/*
21541Srgrimes * Copyright (c) 2001-2002
31541Srgrimes *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
41549Srgrimes *	All rights reserved.
51549Srgrimes * Copyright (c) 2003-2004
61549Srgrimes *	Hartmut Brandt.
71549Srgrimes *	All rights reserved.
81541Srgrimes *
91549Srgrimes * Author: Hartmut Brandt <harti@freebsd.org>
101541Srgrimes *
111541Srgrimes * Redistribution and use in source and binary forms, with or without
121541Srgrimes * modification, are permitted provided that the following conditions
131541Srgrimes * are met:
141541Srgrimes * 1. Redistributions of source code must retain the above copyright
151541Srgrimes *    notice, this list of conditions and the following disclaimer.
161541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171541Srgrimes *    notice, this list of conditions and the following disclaimer in the
181541Srgrimes *    documentation and/or other materials provided with the distribution.
191541Srgrimes *
201541Srgrimes * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
211541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2258705Scharnier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
241541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301541Srgrimes * SUCH DAMAGE.
311541Srgrimes *
321541Srgrimes * $Begemot: libunimsg/snmp_atm/snmp_atm.c,v 1.3 2005/05/23 11:46:46 brandt_h Exp $
331541Srgrimes *
341541Srgrimes * SNMP module for ATM hardware interfaces.
351541Srgrimes */
361541Srgrimes
371541Srgrimes#include "atm.h"
381541Srgrimes#include "atm_tree.h"
391541Srgrimes#include "atm_oid.h"
401541Srgrimes
411817Sdg#include <sys/ioctl.h>
421541Srgrimes
431541Srgrimes#include <stdio.h>
441541Srgrimes#include <stdlib.h>
451541Srgrimes#include <string.h>
461541Srgrimes#include <errno.h>
471541Srgrimes#include <syslog.h>
485455Sdg#include <net/if_types.h>
491541Srgrimes#include <net/if_media.h>
501541Srgrimes#include <net/if_atm.h>
511541Srgrimes
521541Srgrimesstruct lmodule *module;
531541Srgrimes
545455Sdg/* list of all (known) ATM interfaces */
555455Sdgstruct atmif_list atmif_list = TAILQ_HEAD_INITIALIZER(atmif_list);
565455Sdg
571541Srgrimes/* whether we are started or not */
585455Sdgstatic int started;
591541Srgrimes
601541Srgrimes/* last time table was changed */
611541Srgrimesstatic uint64_t last_change;
621541Srgrimes
631541Srgrimes/* for the registration */
641541Srgrimesstatic const struct asn_oid oid_begemotAtm = OIDX_begemotAtm;
651541Srgrimes
661541Srgrimes/* the registration */
671541Srgrimesstatic u_int reg_atm;
681817Sdg
6950477Speter/*
701541Srgrimes * Find an ATM interface by name
711541Srgrimes */
721541Srgrimesstruct atmif *
731541Srgrimesatm_find_if_name(const char *name)
741541Srgrimes{
751541Srgrimes	struct atmif_priv *aif;
761541Srgrimes
771541Srgrimes	TAILQ_FOREACH(aif, &atmif_list, link)
781549Srgrimes		if (strcmp(aif->pub.ifp->name, name) == 0)
799507Sdg			return (&aif->pub);
801549Srgrimes	return (NULL);
8112662Sdg}
821541Srgrimes
831541Srgrimes/*
8412662Sdg * get the interface from the interface index
8522521Sdyson */
8612662Sdgstruct atmif *
8712662Sdgatm_find_if(u_int ifindex)
8812662Sdg{
891541Srgrimes	struct atmif_priv *aif;
901541Srgrimes
914207Sdg	TAILQ_FOREACH(aif, &atmif_list, link)
929507Sdg		if (aif->index == ifindex)
939507Sdg			return (&aif->pub);
9412662Sdg	return (NULL);
951541Srgrimes}
9633181Seivind
9733181Seivind/*
981549Srgrimes * Send notification to all listeners.
9932585Sdyson */
10032585Sdysonvoid
1011549Srgrimesatmif_send_notification(struct atmif_priv *aif, enum atmif_notify code,
1021549Srgrimes    uintptr_t arg)
10334202Sdyson{
10434202Sdyson	struct atmif_reg *r0, *r1;
10534202Sdyson
10634202Sdyson	r0 = TAILQ_FIRST(&aif->notify);
10734202Sdyson	while (r0 != NULL) {
10834202Sdyson		r1 = TAILQ_NEXT(r0, link);
10934202Sdyson		r0->func(&aif->pub, code, arg, r0->data);
11034202Sdyson		r0 = r1;
11134202Sdyson	}
11234202Sdyson}
11334202Sdyson
11434202Sdyson/*
11534202Sdyson * Destroy an interface
11642957Sdillon */
11734202Sdysonstatic void
11834202Sdysonatmif_destroy(struct atmif_priv *aif)
11938799Sdfr{
12034202Sdyson	struct atmif_reg *r0;
12134202Sdyson
12234202Sdyson	atmif_send_notification(aif, ATMIF_NOTIFY_DESTROY,
12334202Sdyson	    (uintptr_t)0);
12442957Sdillon
12534202Sdyson	atmif_sys_destroy(aif);
12634202Sdyson
12734202Sdyson	if (aif->ifpreg != NULL)
12834202Sdyson		mibif_unnotify(aif->ifpreg);
12934202Sdyson
13034202Sdyson	while ((r0 = TAILQ_FIRST(&aif->notify)) != NULL) {
13134202Sdyson		TAILQ_REMOVE(&aif->notify, r0, link);
13234202Sdyson		free(r0);
13334202Sdyson	}
13434202Sdyson
13534202Sdyson	TAILQ_REMOVE(&atmif_list, aif, link);
13634202Sdyson	free(aif);
13734202Sdyson
13834202Sdyson	last_change = this_tick;
13934202Sdyson}
14034202Sdyson
14134202Sdyson/*
14234202Sdyson * Function gets called from the MIB-II module for events on that interface
14334202Sdyson */
14434202Sdysonstatic void
14534202Sdysonatmif_notify(struct mibif *ifp __unused, enum mibif_notify event, void *data)
14634202Sdyson{
14734202Sdyson	struct atmif_priv *aif = data;
14834202Sdyson
14934202Sdyson	switch (event) {
15034202Sdyson
15134202Sdyson	  case MIBIF_NOTIFY_DESTROY:
15234202Sdyson		atmif_destroy(aif);
15334202Sdyson		break;
15434202Sdyson	}
1551541Srgrimes}
15651488Sdillon
15751488Sdillon/*
15851488Sdillon * Check the carrier state of the interface
15951488Sdillon */
16051488Sdillonvoid
16151488Sdillonatmif_check_carrier(struct atmif_priv *aif)
16251488Sdillon{
16351488Sdillon	struct ifmediareq ifmr;
16451488Sdillon	enum atmif_carrier_state ost = aif->pub.carrier;
16551488Sdillon
1661541Srgrimes	memset(&ifmr, 0, sizeof(ifmr));
1671541Srgrimes	strcpy(ifmr.ifm_name, aif->pub.ifp->name);
16858634Scharnier
1691541Srgrimes	if (ioctl(mib_netsock, SIOCGIFMEDIA, &ifmr) == -1) {
1701541Srgrimes		aif->pub.carrier = ATMIF_CARRIER_UNKNOWN;
1711541Srgrimes		return;
1721541Srgrimes	}
1731541Srgrimes	if (!(ifmr.ifm_status & IFM_AVALID)) {
1741541Srgrimes		aif->pub.carrier = ATMIF_CARRIER_UNKNOWN;
1751541Srgrimes		return;
1761541Srgrimes	}
1771541Srgrimes	if (ifmr.ifm_status & IFM_ACTIVE)
1781541Srgrimes		aif->pub.carrier = ATMIF_CARRIER_ON;
1791541Srgrimes	else
1801541Srgrimes		aif->pub.carrier = ATMIF_CARRIER_OFF;
1811541Srgrimes
1821541Srgrimes	if (ost != aif->pub.carrier)
1831541Srgrimes		atmif_send_notification(aif, ATMIF_NOTIFY_CARRIER,
18428751Sbde		    (uintptr_t)ost);
1851541Srgrimes}
1865455Sdg
1875455Sdg/*
1885455Sdg * Retrieve the SUNI mode
18932702Sdyson */
1905455Sdgstatic int
1915455Sdgatmif_get_mode(struct atmif_priv *aif)
19234202Sdyson{
19332702Sdyson	struct ifmediareq ifmr;
19434202Sdyson
1951541Srgrimes	memset(&ifmr, 0, sizeof(ifmr));
1965455Sdg	strcpy(ifmr.ifm_name, aif->pub.ifp->name);
19734202Sdyson
1981541Srgrimes	if (ioctl(mib_netsock, SIOCGIFMEDIA, &ifmr) < 0) {
1995455Sdg		syslog(LOG_ERR, "SIOCGIFMEDIA: %m");
2001541Srgrimes		aif->pub.mode = ATMIF_SUNI_MODE_UNKNOWN;
2011541Srgrimes		return (SNMP_ERR_GENERR);
2025455Sdg	}
2035455Sdg	if (ifmr.ifm_current & IFM_ATM_SDH)
2041541Srgrimes		aif->pub.mode = ATMIF_SUNI_MODE_SDH;
20551488Sdillon	else
20634202Sdyson		aif->pub.mode = ATMIF_SUNI_MODE_SONET;
20734202Sdyson
20834202Sdyson	return (SNMP_ERR_NOERROR);
20932585Sdyson}
21032585Sdyson
21132585Sdyson/*
21232585Sdyson * Change the SUNI mod
21332585Sdyson */
21432585Sdysonstatic int
21532585Sdysonatmif_set_mode(struct atmif_priv *aif, int newmode)
21632585Sdyson{
21732585Sdyson	struct ifmediareq ifmr;
21832585Sdyson	struct ifreq ifr;
21932585Sdyson
22032585Sdyson	memset(&ifmr, 0, sizeof(ifmr));
22134202Sdyson	strcpy(ifmr.ifm_name, aif->pub.ifp->name);
22232585Sdyson
22334202Sdyson	/* get current mode */
22432585Sdyson	if (ioctl(mib_netsock, SIOCGIFMEDIA, &ifmr) < 0) {
22532585Sdyson		syslog(LOG_ERR, "SIOCGIFMEDIA: %m");
22632585Sdyson		return (SNMP_ERR_GENERR);
22732585Sdyson	}
22832585Sdyson
22932585Sdyson	memset(&ifr, 0, sizeof(ifr));
23032585Sdyson	strcpy(ifr.ifr_name, aif->pub.ifp->name);
23132585Sdyson
23232585Sdyson	ifr.ifr_media = ifmr.ifm_current;
23334202Sdyson	if (newmode == ATMIF_SUNI_MODE_SDH)
23434202Sdyson		ifr.ifr_media |= IFM_ATM_SDH;
2351541Srgrimes	else
2367695Sdg		ifr.ifr_media &= ~IFM_ATM_SDH;
23734202Sdyson
23832702Sdyson	if (ioctl(mib_netsock, SIOCSIFMEDIA, &ifr) < 0) {
23934202Sdyson		syslog(LOG_ERR, "SIOCSIFMEDIA: %m");
24020054Sdyson		return (SNMP_ERR_GENERR);
24137563Sbde	}
24220054Sdyson
24320054Sdyson	aif->pub.mode = newmode;
24420449Sdyson	return (SNMP_ERR_NOERROR);
24532286Sdyson}
24632286Sdyson
24732286Sdyson/*
24832286Sdyson * Attach to an ATM interface
24932286Sdyson */
25034202Sdysonstatic void
25138135Sdfrattach_if(struct mibif *ifp)
25232286Sdyson{
25334202Sdyson	struct atmif_priv *aif;
25431853Sdyson
25534202Sdyson	/* we should not know it */
25634202Sdyson	TAILQ_FOREACH(aif, &atmif_list, link)
25734202Sdyson		if (aif->pub.ifp == ifp) {
25831853Sdyson			syslog(LOG_CRIT, "new ATM if already known '%s'",
2597695Sdg			    ifp->name);
26034202Sdyson			return;
2611541Srgrimes		}
2621541Srgrimes
2631541Srgrimes	/*
2641541Srgrimes	 * tap it
26534202Sdyson	 */
2661541Srgrimes	if ((aif = malloc(sizeof(*aif))) == NULL) {
2675455Sdg		syslog(LOG_ERR, "new atmif: %m");
2685455Sdg		return;
2691541Srgrimes	}
2701541Srgrimes	memset(aif, 0, sizeof(*aif));
27134202Sdyson
27234202Sdyson	aif->pub.ifp = ifp;
2731541Srgrimes	aif->index = ifp->index;
2741541Srgrimes	TAILQ_INIT(&aif->notify);
27542957Sdillon
27642957Sdillon	if (atmif_sys_attach_if(aif)) {
27742957Sdillon		free(aif);
27832585Sdyson		return;
27934202Sdyson	}
28034202Sdyson
28132585Sdyson	aif->ifpreg = mibif_notify(ifp, module, atmif_notify, aif);
28232585Sdyson
28342957Sdillon	aif->pub.carrier = ATMIF_CARRIER_UNKNOWN;
28442957Sdillon	atmif_check_carrier(aif);
28542957Sdillon	(void)atmif_get_mode(aif);
28642957Sdillon
28732585Sdyson	INSERT_OBJECT_INT(aif, &atmif_list);
28834202Sdyson
28934202Sdyson	last_change = this_tick;
29041322Sdg
2911541Srgrimes	return;
29242957Sdillon}
29342957Sdillon
29442957Sdillon/*
29542957Sdillon * Function gets called when a new interface is created. If this is an
29642957Sdillon * ATM interface, hook in. Claim the interface in any case even when
29758634Scharnier * the creation of our data structures fails.
29842957Sdillon */
29942957Sdillonstatic int
30042957Sdillonnew_if(struct mibif *ifp)
30142957Sdillon{
30242957Sdillon	if (!started || ifp->mib.ifmd_data.ifi_type != IFT_ATM ||
30342957Sdillon	    ifp->xnotify != NULL)
30442957Sdillon		return (0);
30542957Sdillon
3061541Srgrimes	attach_if(ifp);
30742957Sdillon	return (1);
30834202Sdyson}
30942957Sdillon
31042957Sdillon/*
31134202Sdyson * Start the module
3121541Srgrimes */
3131541Srgrimesstatic void
3147695Sdgatm_start(void)
31534202Sdyson{
31641322Sdg	struct mibif *ifp;
31734202Sdyson
31841322Sdg	reg_atm = or_register(&oid_begemotAtm,
31916268Sdyson	    "The Begemot MIB for ATM interfaces.", module);
32051488Sdillon
32134202Sdyson	started = 1;
32234202Sdyson	for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
3235455Sdg		if (ifp->mib.ifmd_data.ifi_type == IFT_ATM &&
3245455Sdg		    ifp->xnotify == NULL)
3255455Sdg			attach_if(ifp);
32643086Sdillon}
32742957Sdillon
32842957Sdillon/*
32942957Sdillon * Called when modules is loaded
33042957Sdillon */
33142957Sdillonstatic int
33242957Sdillonatm_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
3331541Srgrimes{
33438799Sdfr	module = mod;
33534202Sdyson
33634202Sdyson	/* register to get creation messages for ATM interfaces */
3375455Sdg	if (mib_register_newif(new_if, module)) {
3385455Sdg		syslog(LOG_ERR, "cannot register newif function: %m");
33933936Sdyson		return (-1);
3401541Srgrimes	}
3411541Srgrimes
34242957Sdillon	return (0);
34342957Sdillon}
34451488Sdillon
34551488Sdillon/*
34642957Sdillon * Called when module gets unloaded - free all resources
34742957Sdillon */
34851488Sdillonstatic int
34934202Sdysonatm_fini(void)
35034202Sdyson{
3518585Sdg	struct atmif_priv *aif;
3528585Sdg
35310988Sdyson	while ((aif = TAILQ_FIRST(&atmif_list)) != NULL)
3541541Srgrimes		atmif_destroy(aif);
3555455Sdg
3561541Srgrimes	mib_unregister_newif(module);
35751488Sdillon	or_unregister(reg_atm);
35851488Sdillon
35951488Sdillon	return (0);
36051488Sdillon}
36151488Sdillon
36234202Sdyson/*
36334202Sdyson * Other module unloaded/loaded
3641541Srgrimes */
3651541Srgrimesstatic void
3661541Srgrimesatm_loading(const struct lmodule *mod, int loading)
3671541Srgrimes{
36832585Sdyson	struct atmif_priv *aif;
3695455Sdg	struct atmif_reg *r0, *r1;
37042957Sdillon
37151488Sdillon	if (!loading) {
37251488Sdillon		/* remove notifications for this module */
37351488Sdillon		TAILQ_FOREACH(aif, &atmif_list, link)
37451488Sdillon			TAILQ_FOREACH_SAFE(r0, &aif->notify, link, r1) {
37551488Sdillon				if (r0->mod == mod) {
37651488Sdillon					TAILQ_REMOVE(&aif->notify, r0, link);
37751488Sdillon					free(r0);
37842957Sdillon				}
37942957Sdillon			}
38051488Sdillon	}
3811541Srgrimes}
3821549Srgrimes
38315819Sdysonconst struct snmp_module config = {
38449338Salc	.comment = "This module implements a private MIB for ATM interfaces.",
3851541Srgrimes	.init =		atm_init,
38649338Salc	.fini =		atm_fini,
38715819Sdyson	.start =	atm_start,
38815819Sdyson	.tree =		atm_ctree,
38932702Sdyson	.tree_size =	atm_CTREE_SIZE,
39034202Sdyson	.loading =	atm_loading
39132702Sdyson};
39232702Sdyson
39332702Sdyson/*
39434202Sdyson * Get the interface point for a table access
39532702Sdyson */
39632702Sdysonint
39715819Sdysonatmif_get_aif(struct snmp_value *value, u_int sub, enum snmp_op op,
39815819Sdyson    struct atmif_priv **aifp)
39934202Sdyson{
40051488Sdillon	switch (op) {
40151488Sdillon
40251488Sdillon	  case SNMP_OP_GETNEXT:
40351488Sdillon		if ((*aifp = NEXT_OBJECT_INT(&atmif_list,
40451488Sdillon		    &value->var, sub)) == NULL)
40515819Sdyson			return (SNMP_ERR_NOSUCHNAME);
40651488Sdillon		value->var.len = sub + 1;
40751488Sdillon		value->var.subs[sub] = (*aifp)->index;
40815819Sdyson		break;
40915819Sdyson
41051488Sdillon	  case SNMP_OP_GET:
41115819Sdyson		if ((*aifp = FIND_OBJECT_INT(&atmif_list,
41246349Salc		    &value->var, sub)) == NULL)
41346349Salc			return (SNMP_ERR_NOSUCHNAME);
41446349Salc		break;
41546349Salc
41646349Salc	  case SNMP_OP_SET:
41746349Salc		if ((*aifp = FIND_OBJECT_INT(&atmif_list,
41834202Sdyson		    &value->var, sub)) == NULL)
41924678Speter			return (SNMP_ERR_NO_CREATION);
42015819Sdyson		break;
42115819Sdyson
42234202Sdyson	  case SNMP_OP_ROLLBACK:
42315819Sdyson	  case SNMP_OP_COMMIT:
42415819Sdyson		if ((*aifp = FIND_OBJECT_INT(&atmif_list,
42516058Sdyson		    &value->var, sub)) == NULL)
42661081Sdillon			abort();
42716058Sdyson		return (SNMP_ERR_NOERROR);
42815819Sdyson	}
42915819Sdyson
43015819Sdyson	if ((*aifp)->pub.mib->pcr == 0) {
43115819Sdyson		mib_fetch_ifmib((*aifp)->pub.ifp);
43215819Sdyson		atmif_sys_fill_mib(*aifp);
43315819Sdyson		atmif_check_carrier(*aifp);
43415819Sdyson	}
43515819Sdyson
43615819Sdyson	return (SNMP_ERR_NOERROR);
43715819Sdyson}
43815819Sdyson
43915819Sdyson/*
44015819Sdyson * Table of all ATM interfaces
44115819Sdyson */
44215819Sdysonint
44315819Sdysonop_atmif(struct snmp_context *ctx __unused, struct snmp_value *value,
4441541Srgrimes    u_int sub, u_int vindex __unused, enum snmp_op op)
4455455Sdg{
4465455Sdg	struct atmif_priv *aif;
4475455Sdg	int err;
4485455Sdg
4495455Sdg	if ((err = atmif_get_aif(value, sub, op, &aif)) != SNMP_ERR_NOERROR)
4505455Sdg		return (err);
4515455Sdg
4525455Sdg	if (op == SNMP_OP_SET) {
4535455Sdg		switch (value->var.subs[sub - 1]) {
4545455Sdg
45542957Sdillon		  default:
45642957Sdillon			return (SNMP_ERR_NOT_WRITEABLE);
4571549Srgrimes
4583449Sphk		  case LEAF_begemotAtmIfMode:
45934202Sdyson			if ((err = atmif_get_mode(aif)) != SNMP_ERR_NOERROR)
4601541Srgrimes				return (err);
4611541Srgrimes			if (aif->pub.mode == ATMIF_SUNI_MODE_UNKNOWN)
46251488Sdillon				return (SNMP_ERR_INCONS_VALUE);
46351488Sdillon			if (value->v.integer != ATMIF_SUNI_MODE_SONET &&
46451488Sdillon			    value->v.integer != ATMIF_SUNI_MODE_SDH)
46551488Sdillon				return (SNMP_ERR_WRONG_VALUE);
46651488Sdillon			if ((u_int)value->v.integer == aif->pub.mode)
46751488Sdillon				return (SNMP_ERR_NOERROR);
4685455Sdg			return (atmif_set_mode(aif, value->v.integer));
46942957Sdillon		}
47042957Sdillon		abort();
4711541Srgrimes	}
47234202Sdyson
4731541Srgrimes	switch (value->var.subs[sub - 1]) {
4741549Srgrimes
47534202Sdyson	  case LEAF_begemotAtmIfName:
4769507Sdg		return (string_get(value, aif->pub.ifp->name, -1));
47710988Sdyson
4781541Srgrimes	  case LEAF_begemotAtmIfPcr:
4791541Srgrimes		value->v.uint32 = aif->pub.mib->pcr;
48017312Sdyson		return (SNMP_ERR_NOERROR);
48117312Sdyson
48217312Sdyson	  case LEAF_begemotAtmIfMedia:
48317312Sdyson		value->v.integer = aif->pub.mib->media;
48417312Sdyson		return (SNMP_ERR_NOERROR);
4855455Sdg
4865455Sdg	  case LEAF_begemotAtmIfVpiBits:
4875455Sdg		value->v.uint32 = aif->pub.mib->vpi_bits;
4881541Srgrimes		return (SNMP_ERR_NOERROR);
48934202Sdyson
49034202Sdyson	  case LEAF_begemotAtmIfVciBits:
49134202Sdyson		value->v.uint32 = aif->pub.mib->vci_bits;
49217312Sdyson		return (SNMP_ERR_NOERROR);
4937695Sdg
4948876Srgrimes	  case LEAF_begemotAtmIfMaxVpcs:
4951549Srgrimes		value->v.uint32 = aif->pub.mib->max_vpcs;
49642957Sdillon		return (SNMP_ERR_NOERROR);
4971541Srgrimes
4981541Srgrimes	  case LEAF_begemotAtmIfMaxVccs:
4995455Sdg		value->v.uint32 = aif->pub.mib->max_vccs;
5005455Sdg		return (SNMP_ERR_NOERROR);
5015455Sdg
5028876Srgrimes	  case LEAF_begemotAtmIfEsi:
5039507Sdg		return (string_get(value, aif->pub.mib->esi, 6));
5045455Sdg
5058876Srgrimes	  case LEAF_begemotAtmIfCarrierStatus:
5065455Sdg		value->v.integer = aif->pub.carrier;
5079507Sdg		return (SNMP_ERR_NOERROR);
5085455Sdg
5095455Sdg	  case LEAF_begemotAtmIfMode:
5101541Srgrimes		if ((err = atmif_get_mode(aif)) != SNMP_ERR_NOERROR)
5111549Srgrimes			return (err);
5124207Sdg		value->v.integer = aif->pub.mode;
51337843Sdg		return (SNMP_ERR_NOERROR);
51437843Sdg	}
5151549Srgrimes	abort();
5164207Sdg}
5171549Srgrimes
5184207Sdg/*
5195455Sdg * Hardware table
5205455Sdg */
5215455Sdgint
5224207Sdgop_atmhw(struct snmp_context *ctx __unused, struct snmp_value *value,
52334202Sdyson    u_int sub, u_int vindex __unused, enum snmp_op op)
52432585Sdyson{
52534202Sdyson	struct atmif_priv *aif;
52634202Sdyson	int err;
52734202Sdyson
5284207Sdg	if ((err = atmif_get_aif(value, sub, op, &aif)) != SNMP_ERR_NOERROR)
5291541Srgrimes		return (err);
53034202Sdyson	if (op == SNMP_OP_SET)
53134202Sdyson		return (SNMP_ERR_NOT_WRITEABLE);
53234202Sdyson
5331549Srgrimes	switch (value->var.subs[sub - 1]) {
5341549Srgrimes
5351549Srgrimes	  case LEAF_begemotAtmHWVendor:
5361549Srgrimes		return (atm_sys_get_hw_vendor(aif, value));
5371541Srgrimes
5381541Srgrimes	  case LEAF_begemotAtmHWDevice:
53951488Sdillon		return (atm_sys_get_hw_device(aif, value));
5401541Srgrimes
54142957Sdillon	  case LEAF_begemotAtmHWSerial:
54242957Sdillon		value->v.uint32 = aif->pub.mib->serial;
5431541Srgrimes		return (SNMP_ERR_NOERROR);
54434202Sdyson
54534202Sdyson	  case LEAF_begemotAtmHWVersion:
5461541Srgrimes		value->v.uint32 = aif->pub.mib->hw_version;
5471541Srgrimes		return (SNMP_ERR_NOERROR);
5485455Sdg
5495455Sdg	  case LEAF_begemotAtmHWSoftVersion:
5501541Srgrimes		value->v.uint32 = aif->pub.mib->sw_version;
5511541Srgrimes		return (SNMP_ERR_NOERROR);
55234202Sdyson
55334202Sdyson	}
5541541Srgrimes	abort();
5551541Srgrimes}
5565455Sdg
5575455Sdg/*
5581541Srgrimes * Scalars
55934202Sdyson */
56034202Sdysonint
5611541Srgrimesop_atm(struct snmp_context *ctx __unused, struct snmp_value *value,
56234202Sdyson    u_int sub, u_int vindex __unused, enum snmp_op op)
56334202Sdyson{
56434202Sdyson	switch (op) {
5651541Srgrimes
56634202Sdyson	  case SNMP_OP_GETNEXT:
5671541Srgrimes		abort();
56846349Salc
56946349Salc	  case SNMP_OP_GET:
57046349Salc		switch (value->var.subs[sub - 1]) {
57134202Sdyson
57234202Sdyson		  case LEAF_begemotAtmIfTableLastChange:
57346349Salc			value->v.uint32 =
57446349Salc			    (last_change == 0 ? 0 : last_change - start_tick);
57544250Salc			return (SNMP_ERR_NOERROR);
57617312Sdyson		}
57746349Salc		abort();
57842957Sdillon
5795455Sdg	  case SNMP_OP_SET:
58034202Sdyson		return (SNMP_ERR_NOT_WRITEABLE);
58134202Sdyson
5821549Srgrimes	  case SNMP_OP_ROLLBACK:
58342957Sdillon	  case SNMP_OP_COMMIT:
58434202Sdyson		abort();
58538135Sdfr	}
5861541Srgrimes	abort();
5871541Srgrimes}
58842957Sdillon
58942408Seivind/*
59042408Seivind * Register for interface notifications
5911541Srgrimes */
5921541Srgrimesvoid *
5935455Sdgatm_notify_aif(struct atmif *pub, const struct lmodule *mod,
5945455Sdg    atmif_event_f func, void *arg)
5951541Srgrimes{
5961541Srgrimes	struct atmif_priv *aif = (struct atmif_priv *)pub;
5971541Srgrimes	struct atmif_reg *r0;
5985455Sdg
5995455Sdg	if ((r0 = malloc(sizeof(*r0))) == NULL) {
6005455Sdg		syslog(LOG_CRIT, "out of memory");
6011541Srgrimes		return (NULL);
6021541Srgrimes	}
60334202Sdyson	r0->func = func;
6045455Sdg	r0->mod = mod;
6055455Sdg	r0->data = arg;
6061541Srgrimes	r0->aif = aif;
6071541Srgrimes
6085455Sdg	TAILQ_INSERT_TAIL(&aif->notify, r0, link);
6091541Srgrimes
61042957Sdillon	return (r0);
61142957Sdillon}
61242957Sdillon
61342957Sdillon/*
61442957Sdillon * Unregister it
61542957Sdillon */
61642957Sdillonvoid
61742957Sdillonatm_unnotify_aif(void *arg)
6181541Srgrimes{
61934202Sdyson	struct atmif_reg *r0 = arg;
62014316Sdyson
62114316Sdyson	TAILQ_REMOVE(&r0->aif->notify, r0, link);
62214316Sdyson	free(r0);
62334202Sdyson}
62414316Sdyson