1 /* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Author: Harti Brandt <harti@freebsd.org> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $Begemot: bsnmp/snmp_mibII/mibII_interfaces.c,v 1.13 2004/08/06 08:47:01 brandt Exp $ 30 * 31 * Interfaces group. 32 */ 33 #include "mibII.h" 34 #include "mibII_oid.h" 35 36 /* 37 * This structure catches all changes to a interface entry 38 */ 39 struct ifchange { 40 struct snmp_dependency dep; 41 42 u_int ifindex; 43 44 uint32_t set; 45 int promisc; 46 int admin; 47 int traps; 48 49 uint32_t rb; 50 int rb_flags; 51 int rb_traps; 52 }; 53 #define IFC_PROMISC 0x0001 54 #define IFC_ADMIN 0x0002 55 #define IFC_TRAPS 0x0004 56 #define IFRB_FLAGS 0x0001 57 #define IFRB_TRAPS 0x0002 58 59 static const struct asn_oid 60 oid_ifTable = OIDX_ifTable; 61 62 /* 63 * This function handles all changes to the interface table and interface 64 * extension table. 65 */ 66 static int 67 ifchange_func(struct snmp_context *ctx __unused, struct snmp_dependency *dep, 68 enum snmp_depop op) 69 { 70 struct ifchange *ifc = (struct ifchange *)dep; 71 struct mibif *ifp; 72 struct ifreq ifr, ifr1; 73 74 if ((ifp = mib_find_if(ifc->ifindex)) == NULL) 75 return (SNMP_ERR_NO_CREATION); 76 77 switch (op) { 78 79 case SNMP_DEPOP_COMMIT: 80 strncpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 81 if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr) == -1) { 82 syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name); 83 return (SNMP_ERR_GENERR); 84 } 85 if (ifc->set & IFC_PROMISC) { 86 ifr.ifr_flags &= ~IFF_PROMISC; 87 if (ifc->promisc) 88 ifr.ifr_flags |= IFF_PROMISC; 89 ifc->rb |= IFRB_FLAGS; 90 } 91 if (ifc->set & IFC_ADMIN) { 92 ifr.ifr_flags &= ~IFF_UP; 93 if (ifc->admin) 94 ifr.ifr_flags |= IFF_UP; 95 ifc->rb |= IFRB_FLAGS; 96 } 97 if (ifc->rb & IFRB_FLAGS) { 98 strncpy(ifr1.ifr_name, ifp->name, sizeof(ifr1.ifr_name)); 99 if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr1) == -1) { 100 syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name); 101 return (SNMP_ERR_GENERR); 102 } 103 ifc->rb_flags = ifr1.ifr_flags; 104 if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) { 105 syslog(LOG_ERR, "SIFFLAGS(%s): %m", ifp->name); 106 return (SNMP_ERR_GENERR); 107 } 108 (void)mib_fetch_ifmib(ifp); 109 } 110 if (ifc->set & IFC_TRAPS) { 111 ifc->rb |= IFRB_TRAPS; 112 ifc->rb_traps = ifp->trap_enable; 113 ifp->trap_enable = ifc->traps; 114 } 115 return (SNMP_ERR_NOERROR); 116 117 case SNMP_DEPOP_ROLLBACK: 118 if (ifc->rb & IFRB_FLAGS) { 119 strncpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 120 ifr.ifr_flags = ifc->rb_flags; 121 if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) { 122 syslog(LOG_ERR, "SIFFLAGS(%s): %m", ifp->name); 123 return (SNMP_ERR_UNDO_FAILED); 124 } 125 (void)mib_fetch_ifmib(ifp); 126 } 127 if (ifc->rb & IFRB_TRAPS) 128 ifp->trap_enable = ifc->rb_traps; 129 return (SNMP_ERR_NOERROR); 130 131 case SNMP_DEPOP_FINISH: 132 return (SNMP_ERR_NOERROR); 133 134 } 135 abort(); 136 } 137 138 static uint32_t 139 ticks_get_timeval(struct timeval *tv) 140 { 141 uint32_t v; 142 143 if (tv->tv_sec != 0 || tv->tv_usec != 0) { 144 v = 100 * tv->tv_sec + tv->tv_usec / 10000; 145 if (v > start_tick) 146 return (v - start_tick); 147 } 148 return (0); 149 } 150 151 /* 152 * Scalars 153 */ 154 int 155 op_interfaces(struct snmp_context *ctx __unused, struct snmp_value *value, 156 u_int sub, u_int idx __unused, enum snmp_op op) 157 { 158 switch (op) { 159 160 case SNMP_OP_GETNEXT: 161 abort(); 162 163 case SNMP_OP_GET: 164 break; 165 166 case SNMP_OP_SET: 167 return (SNMP_ERR_NOT_WRITEABLE); 168 169 case SNMP_OP_ROLLBACK: 170 case SNMP_OP_COMMIT: 171 abort(); 172 } 173 174 switch (value->var.subs[sub - 1]) { 175 176 case LEAF_ifNumber: 177 value->v.integer = mib_if_number; 178 break; 179 } 180 return (SNMP_ERR_NOERROR); 181 } 182 183 /* 184 * Iftable entry 185 */ 186 int 187 op_ifentry(struct snmp_context *ctx, struct snmp_value *value, 188 u_int sub, u_int iidx __unused, enum snmp_op op) 189 { 190 struct mibif *ifp = NULL; 191 int ret; 192 struct ifchange *ifc; 193 struct asn_oid idx; 194 195 switch (op) { 196 197 case SNMP_OP_GETNEXT: 198 if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL) 199 return (SNMP_ERR_NOSUCHNAME); 200 value->var.len = sub + 1; 201 value->var.subs[sub] = ifp->index; 202 break; 203 204 case SNMP_OP_GET: 205 if (value->var.len - sub != 1) 206 return (SNMP_ERR_NOSUCHNAME); 207 if ((ifp = mib_find_if(value->var.subs[sub])) == NULL) 208 return (SNMP_ERR_NOSUCHNAME); 209 break; 210 211 case SNMP_OP_SET: 212 if (value->var.len - sub != 1) 213 return (SNMP_ERR_NO_CREATION); 214 if ((ifp = mib_find_if(value->var.subs[sub])) == NULL) 215 return (SNMP_ERR_NO_CREATION); 216 if (value->var.subs[sub - 1] != LEAF_ifAdminStatus) 217 return (SNMP_ERR_NOT_WRITEABLE); 218 219 idx.len = 1; 220 idx.subs[0] = ifp->index; 221 222 if (value->v.integer != 1 && value->v.integer != 2) 223 return (SNMP_ERR_WRONG_VALUE); 224 225 if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx, 226 &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL) 227 return (SNMP_ERR_RES_UNAVAIL); 228 ifc->ifindex = ifp->index; 229 230 if (ifc->set & IFC_ADMIN) 231 return (SNMP_ERR_INCONS_VALUE); 232 ifc->set |= IFC_ADMIN; 233 ifc->admin = (value->v.integer == 1) ? 1 : 0; 234 235 return (SNMP_ERR_NOERROR); 236 237 case SNMP_OP_ROLLBACK: 238 case SNMP_OP_COMMIT: 239 return (SNMP_ERR_NOERROR); 240 } 241 242 if (ifp->mibtick < this_tick) 243 (void)mib_fetch_ifmib(ifp); 244 245 ret = SNMP_ERR_NOERROR; 246 switch (value->var.subs[sub - 1]) { 247 248 case LEAF_ifIndex: 249 value->v.integer = ifp->index; 250 break; 251 252 case LEAF_ifDescr: 253 ret = string_get(value, ifp->descr, -1); 254 break; 255 256 case LEAF_ifType: 257 value->v.integer = ifp->mib.ifmd_data.ifi_type; 258 break; 259 260 case LEAF_ifMtu: 261 value->v.integer = ifp->mib.ifmd_data.ifi_mtu; 262 break; 263 264 case LEAF_ifSpeed: 265 value->v.integer = ifp->mib.ifmd_data.ifi_baudrate; 266 break; 267 268 case LEAF_ifPhysAddress: 269 ret = string_get(value, ifp->physaddr, 270 ifp->physaddrlen); 271 break; 272 273 case LEAF_ifAdminStatus: 274 value->v.integer = 275 (ifp->mib.ifmd_flags & IFF_UP) ? 1 : 2; 276 break; 277 278 case LEAF_ifOperStatus: 279 value->v.integer = 280 (ifp->mib.ifmd_flags & IFF_RUNNING) ? 1 : 2; 281 break; 282 283 case LEAF_ifLastChange: 284 value->v.uint32 = 285 ticks_get_timeval(&ifp->mib.ifmd_data.ifi_lastchange); 286 break; 287 288 case LEAF_ifInOctets: 289 value->v.uint32 = ifp->mib.ifmd_data.ifi_ibytes; 290 break; 291 292 case LEAF_ifInUcastPkts: 293 value->v.uint32 = ifp->mib.ifmd_data.ifi_ipackets - 294 ifp->mib.ifmd_data.ifi_imcasts; 295 break; 296 297 case LEAF_ifInNUcastPkts: 298 value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts; 299 break; 300 301 case LEAF_ifInDiscards: 302 value->v.uint32 = ifp->mib.ifmd_data.ifi_iqdrops; 303 break; 304 305 case LEAF_ifInErrors: 306 value->v.uint32 = ifp->mib.ifmd_data.ifi_ierrors; 307 break; 308 309 case LEAF_ifInUnknownProtos: 310 value->v.uint32 = ifp->mib.ifmd_data.ifi_noproto; 311 break; 312 313 case LEAF_ifOutOctets: 314 value->v.uint32 = ifp->mib.ifmd_data.ifi_obytes; 315 break; 316 317 case LEAF_ifOutUcastPkts: 318 value->v.uint32 = ifp->mib.ifmd_data.ifi_opackets - 319 ifp->mib.ifmd_data.ifi_omcasts; 320 break; 321 322 case LEAF_ifOutNUcastPkts: 323 value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts; 324 break; 325 326 case LEAF_ifOutDiscards: 327 value->v.uint32 = ifp->mib.ifmd_snd_drops; 328 break; 329 330 case LEAF_ifOutErrors: 331 value->v.uint32 = ifp->mib.ifmd_data.ifi_oerrors; 332 break; 333 334 case LEAF_ifOutQLen: 335 value->v.uint32 = ifp->mib.ifmd_snd_len; 336 break; 337 338 case LEAF_ifSpecific: 339 value->v.oid = oid_zeroDotZero; 340 break; 341 } 342 return (SNMP_ERR_NOERROR); 343 } 344 345 /* 346 * IfXtable entry 347 */ 348 int 349 op_ifxtable(struct snmp_context *ctx, struct snmp_value *value, 350 u_int sub, u_int iidx __unused, enum snmp_op op) 351 { 352 struct mibif *ifp = NULL; 353 int ret; 354 struct ifchange *ifc; 355 struct asn_oid idx; 356 357 switch (op) { 358 359 again: 360 if (op != SNMP_OP_GETNEXT) 361 return (SNMP_ERR_NOSUCHNAME); 362 /* FALLTHROUGH */ 363 364 case SNMP_OP_GETNEXT: 365 if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL) 366 return (SNMP_ERR_NOSUCHNAME); 367 value->var.len = sub + 1; 368 value->var.subs[sub] = ifp->index; 369 break; 370 371 case SNMP_OP_GET: 372 if (value->var.len - sub != 1) 373 return (SNMP_ERR_NOSUCHNAME); 374 if ((ifp = mib_find_if(value->var.subs[sub])) == NULL) 375 return (SNMP_ERR_NOSUCHNAME); 376 break; 377 378 case SNMP_OP_SET: 379 if (value->var.len - sub != 1) 380 return (SNMP_ERR_NO_CREATION); 381 if ((ifp = mib_find_if(value->var.subs[sub])) == NULL) 382 return (SNMP_ERR_NO_CREATION); 383 384 idx.len = 1; 385 idx.subs[0] = ifp->index; 386 387 if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx, 388 &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL) 389 return (SNMP_ERR_RES_UNAVAIL); 390 ifc->ifindex = ifp->index; 391 392 switch (value->var.subs[sub - 1]) { 393 394 case LEAF_ifLinkUpDownTrapEnable: 395 if (value->v.integer != 1 && value->v.integer != 2) 396 return (SNMP_ERR_WRONG_VALUE); 397 if (ifc->set & IFC_TRAPS) 398 return (SNMP_ERR_INCONS_VALUE); 399 ifc->set |= IFC_TRAPS; 400 ifc->traps = (value->v.integer == 1) ? 1 : 0; 401 return (SNMP_ERR_NOERROR); 402 403 case LEAF_ifPromiscuousMode: 404 if (value->v.integer != 1 && value->v.integer != 2) 405 return (SNMP_ERR_WRONG_VALUE); 406 if (ifc->set & IFC_PROMISC) 407 return (SNMP_ERR_INCONS_VALUE); 408 ifc->set |= IFC_PROMISC; 409 ifc->promisc = (value->v.integer == 1) ? 1 : 0; 410 return (SNMP_ERR_NOERROR); 411 } 412 return (SNMP_ERR_NOT_WRITEABLE); 413 414 case SNMP_OP_ROLLBACK: 415 case SNMP_OP_COMMIT: 416 return (SNMP_ERR_NOERROR); 417 } 418 419 if (ifp->mibtick < this_tick) 420 (void)mib_fetch_ifmib(ifp); 421 422 ret = SNMP_ERR_NOERROR; 423 switch (value->var.subs[sub - 1]) { 424 425 case LEAF_ifName: 426 ret = string_get(value, ifp->name, -1); 427 break; 428 429 case LEAF_ifInMulticastPkts: 430 value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts; 431 break; 432 433 case LEAF_ifInBroadcastPkts: 434 value->v.uint32 = 0; 435 break; 436 437 case LEAF_ifOutMulticastPkts: 438 value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts; 439 break; 440 441 case LEAF_ifOutBroadcastPkts: 442 value->v.uint32 = 0; 443 break; 444 445 case LEAF_ifHCInOctets: 446 if (!(ifp->flags & MIBIF_HIGHSPEED)) 447 goto again; 448 value->v.counter64 = ifp->hc_inoctets; 449 break; 450 451 case LEAF_ifHCInUcastPkts: 452 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) 453 goto again; 454 value->v.counter64 = ifp->hc_ipackets - ifp->hc_imcasts; 455 break; 456 457 case LEAF_ifHCInMulticastPkts: 458 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) 459 goto again; 460 value->v.counter64 = ifp->hc_imcasts; 461 break; 462 463 case LEAF_ifHCInBroadcastPkts: 464 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) 465 goto again; 466 value->v.counter64 = 0; 467 break; 468 469 case LEAF_ifHCOutOctets: 470 if (!(ifp->flags & MIBIF_HIGHSPEED)) 471 goto again; 472 value->v.counter64 = ifp->hc_outoctets; 473 break; 474 475 case LEAF_ifHCOutUcastPkts: 476 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) 477 goto again; 478 value->v.counter64 = ifp->hc_opackets - ifp->hc_omcasts; 479 break; 480 481 case LEAF_ifHCOutMulticastPkts: 482 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) 483 goto again; 484 value->v.counter64 = ifp->hc_omcasts; 485 break; 486 487 case LEAF_ifHCOutBroadcastPkts: 488 if (!(ifp->flags & (MIBIF_VERYHIGHSPEED|MIBIF_HIGHSPEED))) 489 goto again; 490 value->v.counter64 = 0; 491 break; 492 493 case LEAF_ifLinkUpDownTrapEnable: 494 value->v.integer = ifp->trap_enable ? 1 : 2; 495 break; 496 497 case LEAF_ifHighSpeed: 498 value->v.integer = 499 (ifp->mib.ifmd_data.ifi_baudrate + 499999) / 1000000; 500 break; 501 502 case LEAF_ifPromiscuousMode: 503 value->v.integer = 504 (ifp->mib.ifmd_flags & IFF_PROMISC) ? 1 : 2; 505 break; 506 507 case LEAF_ifConnectorPresent: 508 value->v.integer = ifp->has_connector ? 1 : 2; 509 break; 510 511 case LEAF_ifAlias: 512 ret = string_get(value, "", -1); 513 break; 514 515 case LEAF_ifCounterDiscontinuityTime: 516 if (ifp->counter_disc > start_tick) 517 value->v.uint32 = ifp->counter_disc - start_tick; 518 else 519 value->v.uint32 = 0; 520 break; 521 } 522 return (ret); 523 } 524