snmp_atm.c revision 311937
1/* 2 * Copyright (c) 2001-2002 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * Copyright (c) 2003-2004 6 * Hartmut Brandt. 7 * All rights reserved. 8 * 9 * Author: Hartmut Brandt <harti@freebsd.org> 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 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. 19 * 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 30 * SUCH DAMAGE. 31 * 32 * $Begemot: libunimsg/snmp_atm/snmp_atm.c,v 1.3 2005/05/23 11:46:46 brandt_h Exp $ 33 * 34 * SNMP module for ATM hardware interfaces. 35 */ 36 37#include "atm.h" 38#include "atm_tree.h" 39#include "atm_oid.h" 40 41#include <sys/ioctl.h> 42 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46#include <errno.h> 47#include <syslog.h> 48#include <net/if_types.h> 49#include <net/if_media.h> 50#include <net/if_atm.h> 51 52struct lmodule *module; 53 54/* list of all (known) ATM interfaces */ 55struct atmif_list atmif_list = TAILQ_HEAD_INITIALIZER(atmif_list); 56 57/* whether we are started or not */ 58static int started; 59 60/* last time table was changed */ 61static uint64_t last_change; 62 63/* for the registration */ 64static const struct asn_oid oid_begemotAtm = OIDX_begemotAtm; 65 66/* the registration */ 67static u_int reg_atm; 68 69/* 70 * Find an ATM interface by name 71 */ 72struct atmif * 73atm_find_if_name(const char *name) 74{ 75 struct atmif_priv *aif; 76 77 TAILQ_FOREACH(aif, &atmif_list, link) 78 if (strcmp(aif->pub.ifp->name, name) == 0) 79 return (&aif->pub); 80 return (NULL); 81} 82 83/* 84 * get the interface from the interface index 85 */ 86struct atmif * 87atm_find_if(u_int ifindex) 88{ 89 struct atmif_priv *aif; 90 91 TAILQ_FOREACH(aif, &atmif_list, link) 92 if (aif->index == ifindex) 93 return (&aif->pub); 94 return (NULL); 95} 96 97/* 98 * Send notification to all listeners. 99 */ 100void 101atmif_send_notification(struct atmif_priv *aif, enum atmif_notify code, 102 uintptr_t arg) 103{ 104 struct atmif_reg *r0, *r1; 105 106 r0 = TAILQ_FIRST(&aif->notify); 107 while (r0 != NULL) { 108 r1 = TAILQ_NEXT(r0, link); 109 r0->func(&aif->pub, code, arg, r0->data); 110 r0 = r1; 111 } 112} 113 114/* 115 * Destroy an interface 116 */ 117static void 118atmif_destroy(struct atmif_priv *aif) 119{ 120 struct atmif_reg *r0; 121 122 atmif_send_notification(aif, ATMIF_NOTIFY_DESTROY, 123 (uintptr_t)0); 124 125 atmif_sys_destroy(aif); 126 127 if (aif->ifpreg != NULL) 128 mibif_unnotify(aif->ifpreg); 129 130 while ((r0 = TAILQ_FIRST(&aif->notify)) != NULL) { 131 TAILQ_REMOVE(&aif->notify, r0, link); 132 free(r0); 133 } 134 135 TAILQ_REMOVE(&atmif_list, aif, link); 136 free(aif); 137 138 last_change = this_tick; 139} 140 141/* 142 * Function gets called from the MIB-II module for events on that interface 143 */ 144static void 145atmif_notify(struct mibif *ifp __unused, enum mibif_notify event, void *data) 146{ 147 struct atmif_priv *aif = data; 148 149 switch (event) { 150 151 case MIBIF_NOTIFY_DESTROY: 152 atmif_destroy(aif); 153 break; 154 } 155} 156 157/* 158 * Check the carrier state of the interface 159 */ 160void 161atmif_check_carrier(struct atmif_priv *aif) 162{ 163 struct ifmediareq ifmr; 164 enum atmif_carrier_state ost = aif->pub.carrier; 165 166 memset(&ifmr, 0, sizeof(ifmr)); 167 strcpy(ifmr.ifm_name, aif->pub.ifp->name); 168 169 if (ioctl(mib_netsock, SIOCGIFMEDIA, &ifmr) == -1) { 170 aif->pub.carrier = ATMIF_CARRIER_UNKNOWN; 171 return; 172 } 173 if (!(ifmr.ifm_status & IFM_AVALID)) { 174 aif->pub.carrier = ATMIF_CARRIER_UNKNOWN; 175 return; 176 } 177 if (ifmr.ifm_status & IFM_ACTIVE) 178 aif->pub.carrier = ATMIF_CARRIER_ON; 179 else 180 aif->pub.carrier = ATMIF_CARRIER_OFF; 181 182 if (ost != aif->pub.carrier) 183 atmif_send_notification(aif, ATMIF_NOTIFY_CARRIER, 184 (uintptr_t)ost); 185} 186 187/* 188 * Retrieve the SUNI mode 189 */ 190static int 191atmif_get_mode(struct atmif_priv *aif) 192{ 193 struct ifmediareq ifmr; 194 195 memset(&ifmr, 0, sizeof(ifmr)); 196 strcpy(ifmr.ifm_name, aif->pub.ifp->name); 197 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); 202 } 203 if (ifmr.ifm_current & IFM_ATM_SDH) 204 aif->pub.mode = ATMIF_SUNI_MODE_SDH; 205 else 206 aif->pub.mode = ATMIF_SUNI_MODE_SONET; 207 208 return (SNMP_ERR_NOERROR); 209} 210 211/* 212 * Change the SUNI mod 213 */ 214static int 215atmif_set_mode(struct atmif_priv *aif, int newmode) 216{ 217 struct ifmediareq ifmr; 218 struct ifreq ifr; 219 220 memset(&ifmr, 0, sizeof(ifmr)); 221 strcpy(ifmr.ifm_name, aif->pub.ifp->name); 222 223 /* get current mode */ 224 if (ioctl(mib_netsock, SIOCGIFMEDIA, &ifmr) < 0) { 225 syslog(LOG_ERR, "SIOCGIFMEDIA: %m"); 226 return (SNMP_ERR_GENERR); 227 } 228 229 memset(&ifr, 0, sizeof(ifr)); 230 strcpy(ifr.ifr_name, aif->pub.ifp->name); 231 232 ifr.ifr_media = ifmr.ifm_current; 233 if (newmode == ATMIF_SUNI_MODE_SDH) 234 ifr.ifr_media |= IFM_ATM_SDH; 235 else 236 ifr.ifr_media &= ~IFM_ATM_SDH; 237 238 if (ioctl(mib_netsock, SIOCSIFMEDIA, &ifr) < 0) { 239 syslog(LOG_ERR, "SIOCSIFMEDIA: %m"); 240 return (SNMP_ERR_GENERR); 241 } 242 243 aif->pub.mode = newmode; 244 return (SNMP_ERR_NOERROR); 245} 246 247/* 248 * Attach to an ATM interface 249 */ 250static void 251attach_if(struct mibif *ifp) 252{ 253 struct atmif_priv *aif; 254 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'", 259 ifp->name); 260 return; 261 } 262 263 /* 264 * tap it 265 */ 266 if ((aif = malloc(sizeof(*aif))) == NULL) { 267 syslog(LOG_ERR, "new atmif: %m"); 268 return; 269 } 270 memset(aif, 0, sizeof(*aif)); 271 272 aif->pub.ifp = ifp; 273 aif->index = ifp->index; 274 TAILQ_INIT(&aif->notify); 275 276 if (atmif_sys_attach_if(aif)) { 277 free(aif); 278 return; 279 } 280 281 aif->ifpreg = mibif_notify(ifp, module, atmif_notify, aif); 282 283 aif->pub.carrier = ATMIF_CARRIER_UNKNOWN; 284 atmif_check_carrier(aif); 285 (void)atmif_get_mode(aif); 286 287 INSERT_OBJECT_INT(aif, &atmif_list); 288 289 last_change = this_tick; 290 291 return; 292} 293 294/* 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. 298 */ 299static int 300new_if(struct mibif *ifp) 301{ 302 if (!started || ifp->mib.ifmd_data.ifi_type != IFT_ATM || 303 ifp->xnotify != NULL) 304 return (0); 305 306 attach_if(ifp); 307 return (1); 308} 309 310/* 311 * Start the module 312 */ 313static void 314atm_start(void) 315{ 316 struct mibif *ifp; 317 318 reg_atm = or_register(&oid_begemotAtm, 319 "The Begemot MIB for ATM interfaces.", module); 320 321 started = 1; 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) 325 attach_if(ifp); 326} 327 328/* 329 * Called when modules is loaded 330 */ 331static int 332atm_init(struct lmodule *mod, int argc __unused, char *argv[] __unused) 333{ 334 module = mod; 335 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"); 339 return (-1); 340 } 341 342 return (0); 343} 344 345/* 346 * Called when module gets unloaded - free all resources 347 */ 348static int 349atm_fini(void) 350{ 351 struct atmif_priv *aif; 352 353 while ((aif = TAILQ_FIRST(&atmif_list)) != NULL) 354 atmif_destroy(aif); 355 356 mib_unregister_newif(module); 357 or_unregister(reg_atm); 358 359 return (0); 360} 361 362/* 363 * Other module unloaded/loaded 364 */ 365static void 366atm_loading(const struct lmodule *mod, int loading) 367{ 368 struct atmif_priv *aif; 369 struct atmif_reg *r0, *r1; 370 371 if (!loading) { 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); 377 free(r0); 378 } 379 } 380 } 381} 382 383const struct snmp_module config = { 384 .comment = "This module implements a private MIB for ATM interfaces.", 385 .init = atm_init, 386 .fini = atm_fini, 387 .start = atm_start, 388 .tree = atm_ctree, 389 .tree_size = atm_CTREE_SIZE, 390 .loading = atm_loading 391}; 392 393/* 394 * Get the interface point for a table access 395 */ 396int 397atmif_get_aif(struct snmp_value *value, u_int sub, enum snmp_op op, 398 struct atmif_priv **aifp) 399{ 400 switch (op) { 401 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; 408 break; 409 410 case SNMP_OP_GET: 411 if ((*aifp = FIND_OBJECT_INT(&atmif_list, 412 &value->var, sub)) == NULL) 413 return (SNMP_ERR_NOSUCHNAME); 414 break; 415 416 case SNMP_OP_SET: 417 if ((*aifp = FIND_OBJECT_INT(&atmif_list, 418 &value->var, sub)) == NULL) 419 return (SNMP_ERR_NO_CREATION); 420 break; 421 422 case SNMP_OP_ROLLBACK: 423 case SNMP_OP_COMMIT: 424 if ((*aifp = FIND_OBJECT_INT(&atmif_list, 425 &value->var, sub)) == NULL) 426 abort(); 427 return (SNMP_ERR_NOERROR); 428 } 429 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); 434 } 435 436 return (SNMP_ERR_NOERROR); 437} 438 439/* 440 * Table of all ATM interfaces 441 */ 442int 443op_atmif(struct snmp_context *ctx __unused, struct snmp_value *value, 444 u_int sub, u_int vindex __unused, enum snmp_op op) 445{ 446 struct atmif_priv *aif; 447 int err; 448 449 if ((err = atmif_get_aif(value, sub, op, &aif)) != SNMP_ERR_NOERROR) 450 return (err); 451 452 if (op == SNMP_OP_SET) { 453 switch (value->var.subs[sub - 1]) { 454 455 default: 456 return (SNMP_ERR_NOT_WRITEABLE); 457 458 case LEAF_begemotAtmIfMode: 459 if ((err = atmif_get_mode(aif)) != SNMP_ERR_NOERROR) 460 return (err); 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)); 469 } 470 abort(); 471 } 472 473 switch (value->var.subs[sub - 1]) { 474 475 case LEAF_begemotAtmIfName: 476 return (string_get(value, aif->pub.ifp->name, -1)); 477 478 case LEAF_begemotAtmIfPcr: 479 value->v.uint32 = aif->pub.mib->pcr; 480 return (SNMP_ERR_NOERROR); 481 482 case LEAF_begemotAtmIfMedia: 483 value->v.integer = aif->pub.mib->media; 484 return (SNMP_ERR_NOERROR); 485 486 case LEAF_begemotAtmIfVpiBits: 487 value->v.uint32 = aif->pub.mib->vpi_bits; 488 return (SNMP_ERR_NOERROR); 489 490 case LEAF_begemotAtmIfVciBits: 491 value->v.uint32 = aif->pub.mib->vci_bits; 492 return (SNMP_ERR_NOERROR); 493 494 case LEAF_begemotAtmIfMaxVpcs: 495 value->v.uint32 = aif->pub.mib->max_vpcs; 496 return (SNMP_ERR_NOERROR); 497 498 case LEAF_begemotAtmIfMaxVccs: 499 value->v.uint32 = aif->pub.mib->max_vccs; 500 return (SNMP_ERR_NOERROR); 501 502 case LEAF_begemotAtmIfEsi: 503 return (string_get(value, aif->pub.mib->esi, 6)); 504 505 case LEAF_begemotAtmIfCarrierStatus: 506 value->v.integer = aif->pub.carrier; 507 return (SNMP_ERR_NOERROR); 508 509 case LEAF_begemotAtmIfMode: 510 if ((err = atmif_get_mode(aif)) != SNMP_ERR_NOERROR) 511 return (err); 512 value->v.integer = aif->pub.mode; 513 return (SNMP_ERR_NOERROR); 514 } 515 abort(); 516} 517 518/* 519 * Hardware table 520 */ 521int 522op_atmhw(struct snmp_context *ctx __unused, struct snmp_value *value, 523 u_int sub, u_int vindex __unused, enum snmp_op op) 524{ 525 struct atmif_priv *aif; 526 int err; 527 528 if ((err = atmif_get_aif(value, sub, op, &aif)) != SNMP_ERR_NOERROR) 529 return (err); 530 if (op == SNMP_OP_SET) 531 return (SNMP_ERR_NOT_WRITEABLE); 532 533 switch (value->var.subs[sub - 1]) { 534 535 case LEAF_begemotAtmHWVendor: 536 return (atm_sys_get_hw_vendor(aif, value)); 537 538 case LEAF_begemotAtmHWDevice: 539 return (atm_sys_get_hw_device(aif, value)); 540 541 case LEAF_begemotAtmHWSerial: 542 value->v.uint32 = aif->pub.mib->serial; 543 return (SNMP_ERR_NOERROR); 544 545 case LEAF_begemotAtmHWVersion: 546 value->v.uint32 = aif->pub.mib->hw_version; 547 return (SNMP_ERR_NOERROR); 548 549 case LEAF_begemotAtmHWSoftVersion: 550 value->v.uint32 = aif->pub.mib->sw_version; 551 return (SNMP_ERR_NOERROR); 552 553 } 554 abort(); 555} 556 557/* 558 * Scalars 559 */ 560int 561op_atm(struct snmp_context *ctx __unused, struct snmp_value *value, 562 u_int sub, u_int vindex __unused, enum snmp_op op) 563{ 564 switch (op) { 565 566 case SNMP_OP_GETNEXT: 567 abort(); 568 569 case SNMP_OP_GET: 570 switch (value->var.subs[sub - 1]) { 571 572 case LEAF_begemotAtmIfTableLastChange: 573 value->v.uint32 = 574 (last_change == 0 ? 0 : last_change - start_tick); 575 return (SNMP_ERR_NOERROR); 576 } 577 abort(); 578 579 case SNMP_OP_SET: 580 return (SNMP_ERR_NOT_WRITEABLE); 581 582 case SNMP_OP_ROLLBACK: 583 case SNMP_OP_COMMIT: 584 abort(); 585 } 586 abort(); 587} 588 589/* 590 * Register for interface notifications 591 */ 592void * 593atm_notify_aif(struct atmif *pub, const struct lmodule *mod, 594 atmif_event_f func, void *arg) 595{ 596 struct atmif_priv *aif = (struct atmif_priv *)pub; 597 struct atmif_reg *r0; 598 599 if ((r0 = malloc(sizeof(*r0))) == NULL) { 600 syslog(LOG_CRIT, "out of memory"); 601 return (NULL); 602 } 603 r0->func = func; 604 r0->mod = mod; 605 r0->data = arg; 606 r0->aif = aif; 607 608 TAILQ_INSERT_TAIL(&aif->notify, r0, link); 609 610 return (r0); 611} 612 613/* 614 * Unregister it 615 */ 616void 617atm_unnotify_aif(void *arg) 618{ 619 struct atmif_reg *r0 = arg; 620 621 TAILQ_REMOVE(&r0->aif->notify, r0, link); 622 free(r0); 623} 624