2 * Copyright (c) 2001-2002
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
5 * Copyright (c) 2003-2004
9 * Author: Hartmut Brandt <harti@freebsd.org>
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $Begemot: libunimsg/snmp_atm/snmp_atm.c,v 1.3 2005/05/23 11:46:46 brandt_h Exp $
34 * SNMP module for ATM hardware interfaces.
41 #include <sys/ioctl.h>
48 #include <net/if_types.h>
49 #include <net/if_media.h>
50 #include <net/if_atm.h>
52 struct lmodule *module;
54 /* list of all (known) ATM interfaces */
55 struct atmif_list atmif_list = TAILQ_HEAD_INITIALIZER(atmif_list);
57 /* whether we are started or not */
60 /* last time table was changed */
61 static uint64_t last_change;
63 /* for the registration */
64 static const struct asn_oid oid_begemotAtm = OIDX_begemotAtm;
66 /* the registration */
70 * Find an ATM interface by name
73 atm_find_if_name(const char *name)
75 struct atmif_priv *aif;
77 TAILQ_FOREACH(aif, &atmif_list, link)
78 if (strcmp(aif->pub.ifp->name, name) == 0)
84 * get the interface from the interface index
87 atm_find_if(u_int ifindex)
89 struct atmif_priv *aif;
91 TAILQ_FOREACH(aif, &atmif_list, link)
92 if (aif->index == ifindex)
98 * Send notification to all listeners.
101 atmif_send_notification(struct atmif_priv *aif, enum atmif_notify code,
104 struct atmif_reg *r0, *r1;
106 r0 = TAILQ_FIRST(&aif->notify);
108 r1 = TAILQ_NEXT(r0, link);
109 r0->func(&aif->pub, code, arg, r0->data);
115 * Destroy an interface
118 atmif_destroy(struct atmif_priv *aif)
120 struct atmif_reg *r0;
122 atmif_send_notification(aif, ATMIF_NOTIFY_DESTROY,
125 atmif_sys_destroy(aif);
127 if (aif->ifpreg != NULL)
128 mibif_unnotify(aif->ifpreg);
130 while ((r0 = TAILQ_FIRST(&aif->notify)) != NULL) {
131 TAILQ_REMOVE(&aif->notify, r0, link);
135 TAILQ_REMOVE(&atmif_list, aif, link);
138 last_change = this_tick;
142 * Function gets called from the MIB-II module for events on that interface
145 atmif_notify(struct mibif *ifp __unused, enum mibif_notify event, void *data)
147 struct atmif_priv *aif = data;
151 case MIBIF_NOTIFY_DESTROY:
158 * Check the carrier state of the interface
161 atmif_check_carrier(struct atmif_priv *aif)
163 struct ifmediareq ifmr;
164 enum atmif_carrier_state ost = aif->pub.carrier;
166 memset(&ifmr, 0, sizeof(ifmr));
167 strcpy(ifmr.ifm_name, aif->pub.ifp->name);
169 if (ioctl(mib_netsock, SIOCGIFMEDIA, &ifmr) == -1) {
170 aif->pub.carrier = ATMIF_CARRIER_UNKNOWN;
173 if (!ifmr.ifm_status & IFM_AVALID) {
174 aif->pub.carrier = ATMIF_CARRIER_UNKNOWN;
177 if (ifmr.ifm_status & IFM_ACTIVE)
178 aif->pub.carrier = ATMIF_CARRIER_ON;
180 aif->pub.carrier = ATMIF_CARRIER_OFF;
182 if (ost != aif->pub.carrier)
183 atmif_send_notification(aif, ATMIF_NOTIFY_CARRIER,
188 * Retrieve the SUNI mode
191 atmif_get_mode(struct atmif_priv *aif)
193 struct ifmediareq ifmr;
195 memset(&ifmr, 0, sizeof(ifmr));
196 strcpy(ifmr.ifm_name, aif->pub.ifp->name);
198 if (ioctl(mib_netsock, SIOCGIFMEDIA, &ifmr) < 0) {
199 syslog(LOG_ERR, "SIOCGIFMEDIA: %m");
200 aif->pub.mode = ATMIF_SUNI_MODE_UNKNOWN;
201 return (SNMP_ERR_GENERR);
203 if (ifmr.ifm_current & IFM_ATM_SDH)
204 aif->pub.mode = ATMIF_SUNI_MODE_SDH;
206 aif->pub.mode = ATMIF_SUNI_MODE_SONET;
208 return (SNMP_ERR_NOERROR);
212 * Change the SUNI mod
215 atmif_set_mode(struct atmif_priv *aif, int newmode)
217 struct ifmediareq ifmr;
220 memset(&ifmr, 0, sizeof(ifmr));
221 strcpy(ifmr.ifm_name, aif->pub.ifp->name);
223 /* get current mode */
224 if (ioctl(mib_netsock, SIOCGIFMEDIA, &ifmr) < 0) {
225 syslog(LOG_ERR, "SIOCGIFMEDIA: %m");
226 return (SNMP_ERR_GENERR);
229 memset(&ifr, 0, sizeof(ifr));
230 strcpy(ifr.ifr_name, aif->pub.ifp->name);
232 ifr.ifr_media = ifmr.ifm_current;
233 if (newmode == ATMIF_SUNI_MODE_SDH)
234 ifr.ifr_media |= IFM_ATM_SDH;
236 ifr.ifr_media &= ~IFM_ATM_SDH;
238 if (ioctl(mib_netsock, SIOCSIFMEDIA, &ifr) < 0) {
239 syslog(LOG_ERR, "SIOCSIFMEDIA: %m");
240 return (SNMP_ERR_GENERR);
243 aif->pub.mode = newmode;
244 return (SNMP_ERR_NOERROR);
248 * Attach to an ATM interface
251 attach_if(struct mibif *ifp)
253 struct atmif_priv *aif;
255 /* we should not know it */
256 TAILQ_FOREACH(aif, &atmif_list, link)
257 if (aif->pub.ifp == ifp) {
258 syslog(LOG_CRIT, "new ATM if already known '%s'",
266 if ((aif = malloc(sizeof(*aif))) == NULL) {
267 syslog(LOG_ERR, "new atmif: %m");
270 memset(aif, 0, sizeof(*aif));
273 aif->index = ifp->index;
274 TAILQ_INIT(&aif->notify);
276 if (atmif_sys_attach_if(aif)) {
281 aif->ifpreg = mibif_notify(ifp, module, atmif_notify, aif);
283 aif->pub.carrier = ATMIF_CARRIER_UNKNOWN;
284 atmif_check_carrier(aif);
285 (void)atmif_get_mode(aif);
287 INSERT_OBJECT_INT(aif, &atmif_list);
289 last_change = this_tick;
295 * Function gets called when a new interface is created. If this is an
296 * ATM interface, hook in. Claim the interface in any case even when
297 * the creation of our data structures fails.
300 new_if(struct mibif *ifp)
302 if (!started || ifp->mib.ifmd_data.ifi_type != IFT_ATM ||
303 ifp->xnotify != NULL)
318 reg_atm = or_register(&oid_begemotAtm,
319 "The Begemot MIB for ATM interfaces.", module);
322 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp))
323 if (ifp->mib.ifmd_data.ifi_type == IFT_ATM &&
324 ifp->xnotify == NULL)
329 * Called when modules is loaded
332 atm_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
336 /* register to get creation messages for ATM interfaces */
337 if (mib_register_newif(new_if, module)) {
338 syslog(LOG_ERR, "cannot register newif function: %m");
346 * Called when module gets unloaded - free all resources
351 struct atmif_priv *aif;
353 while ((aif = TAILQ_FIRST(&atmif_list)) != NULL)
356 mib_unregister_newif(module);
357 or_unregister(reg_atm);
363 * Other module unloaded/loaded
366 atm_loading(const struct lmodule *mod, int loading)
368 struct atmif_priv *aif;
369 struct atmif_reg *r0, *r1;
372 /* remove notifications for this module */
373 TAILQ_FOREACH(aif, &atmif_list, link)
374 TAILQ_FOREACH_SAFE(r0, &aif->notify, link, r1) {
375 if (r0->mod == mod) {
376 TAILQ_REMOVE(&aif->notify, r0, link);
383 const struct snmp_module config = {
384 .comment = "This module implements a private MIB for ATM interfaces.",
389 .tree_size = atm_CTREE_SIZE,
390 .loading = atm_loading
394 * Get the interface point for a table access
397 atmif_get_aif(struct snmp_value *value, u_int sub, enum snmp_op op,
398 struct atmif_priv **aifp)
402 case SNMP_OP_GETNEXT:
403 if ((*aifp = NEXT_OBJECT_INT(&atmif_list,
404 &value->var, sub)) == NULL)
405 return (SNMP_ERR_NOSUCHNAME);
406 value->var.len = sub + 1;
407 value->var.subs[sub] = (*aifp)->index;
411 if ((*aifp = FIND_OBJECT_INT(&atmif_list,
412 &value->var, sub)) == NULL)
413 return (SNMP_ERR_NOSUCHNAME);
417 if ((*aifp = FIND_OBJECT_INT(&atmif_list,
418 &value->var, sub)) == NULL)
419 return (SNMP_ERR_NO_CREATION);
422 case SNMP_OP_ROLLBACK:
424 if ((*aifp = FIND_OBJECT_INT(&atmif_list,
425 &value->var, sub)) == NULL)
427 return (SNMP_ERR_NOERROR);
430 if ((*aifp)->pub.mib->pcr == 0) {
431 mib_fetch_ifmib((*aifp)->pub.ifp);
432 atmif_sys_fill_mib(*aifp);
433 atmif_check_carrier(*aifp);
436 return (SNMP_ERR_NOERROR);
440 * Table of all ATM interfaces
443 op_atmif(struct snmp_context *ctx __unused, struct snmp_value *value,
444 u_int sub, u_int vindex __unused, enum snmp_op op)
446 struct atmif_priv *aif;
449 if ((err = atmif_get_aif(value, sub, op, &aif)) != SNMP_ERR_NOERROR)
452 if (op == SNMP_OP_SET) {
453 switch (value->var.subs[sub - 1]) {
456 return (SNMP_ERR_NOT_WRITEABLE);
458 case LEAF_begemotAtmIfMode:
459 if ((err = atmif_get_mode(aif)) != SNMP_ERR_NOERROR)
461 if (aif->pub.mode == ATMIF_SUNI_MODE_UNKNOWN)
462 return (SNMP_ERR_INCONS_VALUE);
463 if (value->v.integer != ATMIF_SUNI_MODE_SONET &&
464 value->v.integer != ATMIF_SUNI_MODE_SDH)
465 return (SNMP_ERR_WRONG_VALUE);
466 if ((u_int)value->v.integer == aif->pub.mode)
467 return (SNMP_ERR_NOERROR);
468 return (atmif_set_mode(aif, value->v.integer));
473 switch (value->var.subs[sub - 1]) {
475 case LEAF_begemotAtmIfName:
476 return (string_get(value, aif->pub.ifp->name, -1));
478 case LEAF_begemotAtmIfPcr:
479 value->v.uint32 = aif->pub.mib->pcr;
480 return (SNMP_ERR_NOERROR);
482 case LEAF_begemotAtmIfMedia:
483 value->v.integer = aif->pub.mib->media;
484 return (SNMP_ERR_NOERROR);
486 case LEAF_begemotAtmIfVpiBits:
487 value->v.uint32 = aif->pub.mib->vpi_bits;
488 return (SNMP_ERR_NOERROR);
490 case LEAF_begemotAtmIfVciBits:
491 value->v.uint32 = aif->pub.mib->vci_bits;
492 return (SNMP_ERR_NOERROR);
494 case LEAF_begemotAtmIfMaxVpcs:
495 value->v.uint32 = aif->pub.mib->max_vpcs;
496 return (SNMP_ERR_NOERROR);
498 case LEAF_begemotAtmIfMaxVccs:
499 value->v.uint32 = aif->pub.mib->max_vccs;
500 return (SNMP_ERR_NOERROR);
502 case LEAF_begemotAtmIfEsi:
503 return (string_get(value, aif->pub.mib->esi, 6));
505 case LEAF_begemotAtmIfCarrierStatus:
506 value->v.integer = aif->pub.carrier;
507 return (SNMP_ERR_NOERROR);
509 case LEAF_begemotAtmIfMode:
510 if ((err = atmif_get_mode(aif)) != SNMP_ERR_NOERROR)
512 value->v.integer = aif->pub.mode;
513 return (SNMP_ERR_NOERROR);
522 op_atmhw(struct snmp_context *ctx __unused, struct snmp_value *value,
523 u_int sub, u_int vindex __unused, enum snmp_op op)
525 struct atmif_priv *aif;
528 if ((err = atmif_get_aif(value, sub, op, &aif)) != SNMP_ERR_NOERROR)
530 if (op == SNMP_OP_SET)
531 return (SNMP_ERR_NOT_WRITEABLE);
533 switch (value->var.subs[sub - 1]) {
535 case LEAF_begemotAtmHWVendor:
536 return (atm_sys_get_hw_vendor(aif, value));
538 case LEAF_begemotAtmHWDevice:
539 return (atm_sys_get_hw_device(aif, value));
541 case LEAF_begemotAtmHWSerial:
542 value->v.uint32 = aif->pub.mib->serial;
543 return (SNMP_ERR_NOERROR);
545 case LEAF_begemotAtmHWVersion:
546 value->v.uint32 = aif->pub.mib->hw_version;
547 return (SNMP_ERR_NOERROR);
549 case LEAF_begemotAtmHWSoftVersion:
550 value->v.uint32 = aif->pub.mib->sw_version;
551 return (SNMP_ERR_NOERROR);
561 op_atm(struct snmp_context *ctx __unused, struct snmp_value *value,
562 u_int sub, u_int vindex __unused, enum snmp_op op)
566 case SNMP_OP_GETNEXT:
570 switch (value->var.subs[sub - 1]) {
572 case LEAF_begemotAtmIfTableLastChange:
574 (last_change == 0 ? 0 : last_change - start_tick);
575 return (SNMP_ERR_NOERROR);
580 return (SNMP_ERR_NOT_WRITEABLE);
582 case SNMP_OP_ROLLBACK:
590 * Register for interface notifications
593 atm_notify_aif(struct atmif *pub, const struct lmodule *mod,
594 atmif_event_f func, void *arg)
596 struct atmif_priv *aif = (struct atmif_priv *)pub;
597 struct atmif_reg *r0;
599 if ((r0 = malloc(sizeof(*r0))) == NULL) {
600 syslog(LOG_CRIT, "out of memory");
608 TAILQ_INSERT_TAIL(&aif->notify, r0, link);
617 atm_unnotify_aif(void *arg)
619 struct atmif_reg *r0 = arg;
621 TAILQ_REMOVE(&r0->aif->notify, r0, link);