snmp_atm.c revision 133488
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.2 2004/08/06 17:30:40 brandt 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 uint32_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 275 if (atmif_sys_attach_if(aif)) { 276 free(aif); 277 return; 278 } 279 280 aif->ifpreg = mibif_notify(ifp, module, atmif_notify, aif); 281 282 aif->pub.carrier = ATMIF_CARRIER_UNKNOWN; 283 atmif_check_carrier(aif); 284 (void)atmif_get_mode(aif); 285 286 INSERT_OBJECT_INT(aif, &atmif_list); 287 288 last_change = this_tick; 289 290 return; 291} 292 293/* 294 * Function gets called when a new interface is created. If this is an 295 * ATM interface, hook in. Claim the interface in any case even when 296 * the creation of our data structures fails. 297 */ 298static int 299new_if(struct mibif *ifp) 300{ 301 if (!started || ifp->mib.ifmd_data.ifi_type != IFT_ATM || 302 ifp->xnotify != NULL) 303 return (0); 304 305 attach_if(ifp); 306 return (1); 307} 308 309/* 310 * Start the module 311 */ 312static void 313atm_start(void) 314{ 315 struct mibif *ifp; 316 317 reg_atm = or_register(&oid_begemotAtm, 318 "The Begemot MIB for ATM interfaces.", module); 319 320 started = 1; 321 for (ifp = mib_first_if(); ifp != NULL; ifp = mib_next_if(ifp)) 322 if (ifp->mib.ifmd_data.ifi_type == IFT_ATM && 323 ifp->xnotify == NULL) 324 attach_if(ifp); 325} 326 327/* 328 * Called when modules is loaded 329 */ 330static int 331atm_init(struct lmodule *mod, int argc __unused, char *argv[] __unused) 332{ 333 module = mod; 334 335 /* register to get creation messages for ATM interfaces */ 336 if (mib_register_newif(new_if, module)) { 337 syslog(LOG_ERR, "cannot register newif function: %m"); 338 return (-1); 339 } 340 341 return (0); 342} 343 344/* 345 * Called when module gets unloaded - free all resources 346 */ 347static int 348atm_fini(void) 349{ 350 struct atmif_priv *aif; 351 352 while ((aif = TAILQ_FIRST(&atmif_list)) != NULL) 353 atmif_destroy(aif); 354 355 mib_unregister_newif(module); 356 or_unregister(reg_atm); 357 358 return (0); 359} 360 361/* 362 * Other module unloaded/loaded 363 */ 364static void 365atm_loading(const struct lmodule *mod, int loading) 366{ 367 struct atmif_priv *aif; 368 struct atmif_reg *r0, *r1; 369 370 if (!loading) { 371 /* remove notifications for this module */ 372 TAILQ_FOREACH(aif, &atmif_list, link) 373 TAILQ_FOREACH_SAFE(r0, &aif->notify, link, r1) { 374 if (r0->mod == mod) { 375 TAILQ_REMOVE(&aif->notify, r0, link); 376 free(r0); 377 } 378 } 379 } 380} 381 382const struct snmp_module config = { 383 .comment = "This module implements a private MIB for ATM interfaces.", 384 .init = atm_init, 385 .fini = atm_fini, 386 .start = atm_start, 387 .tree = atm_ctree, 388 .tree_size = atm_CTREE_SIZE, 389 .loading = atm_loading 390}; 391 392/* 393 * Get the interface point for a table access 394 */ 395int 396atmif_get_aif(struct snmp_value *value, u_int sub, enum snmp_op op, 397 struct atmif_priv **aifp) 398{ 399 switch (op) { 400 401 case SNMP_OP_GETNEXT: 402 if ((*aifp = NEXT_OBJECT_INT(&atmif_list, 403 &value->var, sub)) == NULL) 404 return (SNMP_ERR_NOSUCHNAME); 405 value->var.len = sub + 1; 406 value->var.subs[sub] = (*aifp)->index; 407 break; 408 409 case SNMP_OP_GET: 410 if ((*aifp = FIND_OBJECT_INT(&atmif_list, 411 &value->var, sub)) == NULL) 412 return (SNMP_ERR_NOSUCHNAME); 413 break; 414 415 case SNMP_OP_SET: 416 if ((*aifp = FIND_OBJECT_INT(&atmif_list, 417 &value->var, sub)) == NULL) 418 return (SNMP_ERR_NO_CREATION); 419 break; 420 421 case SNMP_OP_ROLLBACK: 422 case SNMP_OP_COMMIT: 423 if ((*aifp = FIND_OBJECT_INT(&atmif_list, 424 &value->var, sub)) == NULL) 425 abort(); 426 return (SNMP_ERR_NOERROR); 427 } 428 429 if ((*aifp)->pub.mib->pcr == 0) { 430 mib_fetch_ifmib((*aifp)->pub.ifp); 431 atmif_sys_fill_mib(*aifp); 432 atmif_check_carrier(*aifp); 433 } 434 435 return (SNMP_ERR_NOERROR); 436} 437 438/* 439 * Table of all ATM interfaces 440 */ 441int 442op_atmif(struct snmp_context *ctx __unused, struct snmp_value *value, 443 u_int sub, u_int vindex __unused, enum snmp_op op) 444{ 445 struct atmif_priv *aif; 446 int err; 447 448 if ((err = atmif_get_aif(value, sub, op, &aif)) != SNMP_ERR_NOERROR) 449 return (err); 450 451 if (op == SNMP_OP_SET) { 452 switch (value->var.subs[sub - 1]) { 453 454 default: 455 return (SNMP_ERR_NOT_WRITEABLE); 456 457 case LEAF_begemotAtmIfMode: 458 if ((err = atmif_get_mode(aif)) != SNMP_ERR_NOERROR) 459 return (err); 460 if (aif->pub.mode == ATMIF_SUNI_MODE_UNKNOWN) 461 return (SNMP_ERR_INCONS_VALUE); 462 if (value->v.integer != ATMIF_SUNI_MODE_SONET && 463 value->v.integer != ATMIF_SUNI_MODE_SDH) 464 return (SNMP_ERR_WRONG_VALUE); 465 if ((u_int)value->v.integer == aif->pub.mode) 466 return (SNMP_ERR_NOERROR); 467 return (atmif_set_mode(aif, value->v.integer)); 468 } 469 abort(); 470 } 471 472 switch (value->var.subs[sub - 1]) { 473 474 case LEAF_begemotAtmIfName: 475 return (string_get(value, aif->pub.ifp->name, -1)); 476 477 case LEAF_begemotAtmIfPcr: 478 value->v.uint32 = aif->pub.mib->pcr; 479 return (SNMP_ERR_NOERROR); 480 481 case LEAF_begemotAtmIfMedia: 482 value->v.integer = aif->pub.mib->media; 483 return (SNMP_ERR_NOERROR); 484 485 case LEAF_begemotAtmIfVpiBits: 486 value->v.uint32 = aif->pub.mib->vpi_bits; 487 return (SNMP_ERR_NOERROR); 488 489 case LEAF_begemotAtmIfVciBits: 490 value->v.uint32 = aif->pub.mib->vci_bits; 491 return (SNMP_ERR_NOERROR); 492 493 case LEAF_begemotAtmIfMaxVpcs: 494 value->v.uint32 = aif->pub.mib->max_vpcs; 495 return (SNMP_ERR_NOERROR); 496 497 case LEAF_begemotAtmIfMaxVccs: 498 value->v.uint32 = aif->pub.mib->max_vccs; 499 return (SNMP_ERR_NOERROR); 500 501 case LEAF_begemotAtmIfEsi: 502 return (string_get(value, aif->pub.mib->esi, 6)); 503 504 case LEAF_begemotAtmIfCarrierStatus: 505 value->v.integer = aif->pub.carrier; 506 return (SNMP_ERR_NOERROR); 507 508 case LEAF_begemotAtmIfMode: 509 if ((err = atmif_get_mode(aif)) != SNMP_ERR_NOERROR) 510 return (err); 511 value->v.integer = aif->pub.mode; 512 return (SNMP_ERR_NOERROR); 513 } 514 abort(); 515} 516 517/* 518 * Hardware table 519 */ 520int 521op_atmhw(struct snmp_context *ctx __unused, struct snmp_value *value, 522 u_int sub, u_int vindex __unused, enum snmp_op op) 523{ 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