Annotation of embedaddon/quagga/lib/smux.c, revision 1.1
1.1 ! misho 1: /* SNMP support
! 2: * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
! 3: *
! 4: * This file is part of GNU Zebra.
! 5: *
! 6: * GNU Zebra is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2, or (at your option) any
! 9: * later version.
! 10: *
! 11: * GNU Zebra is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of
! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
! 14: * General Public License for more details.
! 15: *
! 16: * You should have received a copy of the GNU General Public License
! 17: * along with GNU Zebra; see the file COPYING. If not, write to the Free
! 18: * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
! 19: * 02111-1307, USA.
! 20: */
! 21:
! 22: #include <zebra.h>
! 23:
! 24: #ifdef HAVE_SNMP
! 25: #ifdef HAVE_NETSNMP
! 26: #include <net-snmp/net-snmp-config.h>
! 27: #include <net-snmp/net-snmp-includes.h>
! 28: #else
! 29: #include <asn1.h>
! 30: #include <snmp.h>
! 31: #include <snmp_impl.h>
! 32: #endif
! 33:
! 34: #include "log.h"
! 35: #include "thread.h"
! 36: #include "linklist.h"
! 37: #include "command.h"
! 38: #include <lib/version.h>
! 39: #include "memory.h"
! 40: #include "sockunion.h"
! 41: #include "smux.h"
! 42:
! 43: #define min(A,B) ((A) < (B) ? (A) : (B))
! 44:
! 45: enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ};
! 46:
! 47: void smux_event (enum smux_event, int);
! 48:
! 49:
! 50: /* SMUX socket. */
! 51: int smux_sock = -1;
! 52:
! 53: /* SMUX subtree list. */
! 54: struct list *treelist;
! 55:
! 56: /* SMUX oid. */
! 57: oid *smux_oid = NULL;
! 58: size_t smux_oid_len;
! 59:
! 60: /* SMUX password. */
! 61: char *smux_passwd = NULL;
! 62:
! 63: /* SMUX read threads. */
! 64: struct thread *smux_read_thread;
! 65:
! 66: /* SMUX connect thrads. */
! 67: struct thread *smux_connect_thread;
! 68:
! 69: /* SMUX debug flag. */
! 70: int debug_smux = 0;
! 71:
! 72: /* SMUX failure count. */
! 73: int fail = 0;
! 74:
! 75: /* SMUX node. */
! 76: static struct cmd_node smux_node =
! 77: {
! 78: SMUX_NODE,
! 79: "" /* SMUX has no interface. */
! 80: };
! 81:
! 82: /* thread master */
! 83: static struct thread_master *master;
! 84:
! 85: void *
! 86: oid_copy (void *dest, const void *src, size_t size)
! 87: {
! 88: return memcpy (dest, src, size * sizeof (oid));
! 89: }
! 90:
! 91: void
! 92: oid2in_addr (oid oid[], int len, struct in_addr *addr)
! 93: {
! 94: int i;
! 95: u_char *pnt;
! 96:
! 97: if (len == 0)
! 98: return;
! 99:
! 100: pnt = (u_char *) addr;
! 101:
! 102: for (i = 0; i < len; i++)
! 103: *pnt++ = oid[i];
! 104: }
! 105:
! 106: void
! 107: oid_copy_addr (oid oid[], struct in_addr *addr, int len)
! 108: {
! 109: int i;
! 110: u_char *pnt;
! 111:
! 112: if (len == 0)
! 113: return;
! 114:
! 115: pnt = (u_char *) addr;
! 116:
! 117: for (i = 0; i < len; i++)
! 118: oid[i] = *pnt++;
! 119: }
! 120:
! 121: int
! 122: oid_compare (oid *o1, int o1_len, oid *o2, int o2_len)
! 123: {
! 124: int i;
! 125:
! 126: for (i = 0; i < min (o1_len, o2_len); i++)
! 127: {
! 128: if (o1[i] < o2[i])
! 129: return -1;
! 130: else if (o1[i] > o2[i])
! 131: return 1;
! 132: }
! 133: if (o1_len < o2_len)
! 134: return -1;
! 135: if (o1_len > o2_len)
! 136: return 1;
! 137:
! 138: return 0;
! 139: }
! 140:
! 141: static int
! 142: oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
! 143: {
! 144: int i;
! 145:
! 146: for (i = 0; i < min (o1_len, o2_len); i++)
! 147: {
! 148: if (o1[i] < o2[i])
! 149: return -1;
! 150: else if (o1[i] > o2[i])
! 151: return 1;
! 152: }
! 153: if (o1_len < o2_len)
! 154: return -1;
! 155:
! 156: return 0;
! 157: }
! 158:
! 159: static void
! 160: smux_oid_dump (const char *prefix, const oid *oid, size_t oid_len)
! 161: {
! 162: unsigned int i;
! 163: int first = 1;
! 164: char buf[MAX_OID_LEN * 3];
! 165:
! 166: buf[0] = '\0';
! 167:
! 168: for (i = 0; i < oid_len; i++)
! 169: {
! 170: sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]);
! 171: first = 0;
! 172: }
! 173: zlog_debug ("%s: %s", prefix, buf);
! 174: }
! 175:
! 176: static int
! 177: smux_socket (void)
! 178: {
! 179: int ret;
! 180: #ifdef HAVE_IPV6
! 181: struct addrinfo hints, *res0, *res;
! 182: int gai;
! 183: #else
! 184: struct sockaddr_in serv;
! 185: struct servent *sp;
! 186: #endif
! 187: int sock = 0;
! 188:
! 189: #ifdef HAVE_IPV6
! 190: memset(&hints, 0, sizeof(hints));
! 191: hints.ai_family = PF_UNSPEC;
! 192: hints.ai_socktype = SOCK_STREAM;
! 193: gai = getaddrinfo(NULL, "smux", &hints, &res0);
! 194: if (gai == EAI_SERVICE)
! 195: {
! 196: char servbuf[NI_MAXSERV];
! 197: sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
! 198: servbuf[sizeof (servbuf) - 1] = '\0';
! 199: gai = getaddrinfo(NULL, servbuf, &hints, &res0);
! 200: }
! 201: if (gai)
! 202: {
! 203: zlog_warn("Cannot locate loopback service smux");
! 204: return -1;
! 205: }
! 206: for(res=res0; res; res=res->ai_next)
! 207: {
! 208: if (res->ai_family != AF_INET
! 209: #ifdef HAVE_IPV6
! 210: && res->ai_family != AF_INET6
! 211: #endif /* HAVE_IPV6 */
! 212: )
! 213: continue;
! 214:
! 215: sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
! 216: if (sock < 0)
! 217: continue;
! 218: sockopt_reuseaddr (sock);
! 219: sockopt_reuseport (sock);
! 220: ret = connect (sock, res->ai_addr, res->ai_addrlen);
! 221: if (ret < 0)
! 222: {
! 223: close(sock);
! 224: sock = -1;
! 225: continue;
! 226: }
! 227: break;
! 228: }
! 229: freeaddrinfo(res0);
! 230: if (sock < 0)
! 231: zlog_warn ("Can't connect to SNMP agent with SMUX");
! 232: #else
! 233: sock = socket (AF_INET, SOCK_STREAM, 0);
! 234: if (sock < 0)
! 235: {
! 236: zlog_warn ("Can't make socket for SNMP");
! 237: return -1;
! 238: }
! 239:
! 240: memset (&serv, 0, sizeof (struct sockaddr_in));
! 241: serv.sin_family = AF_INET;
! 242: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 243: serv.sin_len = sizeof (struct sockaddr_in);
! 244: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 245:
! 246: sp = getservbyname ("smux", "tcp");
! 247: if (sp != NULL)
! 248: serv.sin_port = sp->s_port;
! 249: else
! 250: serv.sin_port = htons (SMUX_PORT_DEFAULT);
! 251:
! 252: serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
! 253:
! 254: sockopt_reuseaddr (sock);
! 255: sockopt_reuseport (sock);
! 256:
! 257: ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
! 258: if (ret < 0)
! 259: {
! 260: close (sock);
! 261: smux_sock = -1;
! 262: zlog_warn ("Can't connect to SNMP agent with SMUX");
! 263: return -1;
! 264: }
! 265: #endif
! 266: return sock;
! 267: }
! 268:
! 269: static void
! 270: smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
! 271: long errindex, u_char val_type, void *arg, size_t arg_len)
! 272: {
! 273: int ret;
! 274: u_char buf[BUFSIZ];
! 275: u_char *ptr, *h1, *h1e, *h2, *h2e;
! 276: size_t len, length;
! 277:
! 278: ptr = buf;
! 279: len = BUFSIZ;
! 280: length = len;
! 281:
! 282: if (debug_smux)
! 283: {
! 284: zlog_debug ("SMUX GETRSP send");
! 285: zlog_debug ("SMUX GETRSP reqid: %ld", reqid);
! 286: }
! 287:
! 288: h1 = ptr;
! 289: /* Place holder h1 for complete sequence */
! 290: ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
! 291: h1e = ptr;
! 292:
! 293: ptr = asn_build_int (ptr, &len,
! 294: (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
! 295: &reqid, sizeof (reqid));
! 296:
! 297: if (debug_smux)
! 298: zlog_debug ("SMUX GETRSP errstat: %ld", errstat);
! 299:
! 300: ptr = asn_build_int (ptr, &len,
! 301: (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
! 302: &errstat, sizeof (errstat));
! 303: if (debug_smux)
! 304: zlog_debug ("SMUX GETRSP errindex: %ld", errindex);
! 305:
! 306: ptr = asn_build_int (ptr, &len,
! 307: (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
! 308: &errindex, sizeof (errindex));
! 309:
! 310: h2 = ptr;
! 311: /* Place holder h2 for one variable */
! 312: ptr = asn_build_sequence (ptr, &len,
! 313: (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
! 314: 0);
! 315: h2e = ptr;
! 316:
! 317: ptr = snmp_build_var_op (ptr, objid, &objid_len,
! 318: val_type, arg_len, arg, &len);
! 319:
! 320: /* Now variable size is known, fill in size */
! 321: asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
! 322:
! 323: /* Fill in size of whole sequence */
! 324: asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
! 325:
! 326: if (debug_smux)
! 327: zlog_debug ("SMUX getresp send: %td", (ptr - buf));
! 328:
! 329: ret = send (smux_sock, buf, (ptr - buf), 0);
! 330: }
! 331:
! 332: static u_char *
! 333: smux_var (u_char *ptr, size_t len, oid objid[], size_t *objid_len,
! 334: size_t *var_val_len,
! 335: u_char *var_val_type,
! 336: void **var_value)
! 337: {
! 338: u_char type;
! 339: u_char val_type;
! 340: size_t val_len;
! 341: u_char *val;
! 342:
! 343: if (debug_smux)
! 344: zlog_debug ("SMUX var parse: len %zd", len);
! 345:
! 346: /* Parse header. */
! 347: ptr = asn_parse_header (ptr, &len, &type);
! 348:
! 349: if (debug_smux)
! 350: {
! 351: zlog_debug ("SMUX var parse: type %d len %zd", type, len);
! 352: zlog_debug ("SMUX var parse: type must be %d",
! 353: (ASN_SEQUENCE | ASN_CONSTRUCTOR));
! 354: }
! 355:
! 356: /* Parse var option. */
! 357: *objid_len = MAX_OID_LEN;
! 358: ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
! 359: &val_len, &val, &len);
! 360:
! 361: if (var_val_len)
! 362: *var_val_len = val_len;
! 363:
! 364: if (var_value)
! 365: *var_value = (void*) val;
! 366:
! 367: if (var_val_type)
! 368: *var_val_type = val_type;
! 369:
! 370: /* Requested object id length is objid_len. */
! 371: if (debug_smux)
! 372: smux_oid_dump ("Request OID", objid, *objid_len);
! 373:
! 374: if (debug_smux)
! 375: zlog_debug ("SMUX val_type: %d", val_type);
! 376:
! 377: /* Check request value type. */
! 378: if (debug_smux)
! 379: switch (val_type)
! 380: {
! 381: case ASN_NULL:
! 382: /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
! 383: ASN_NULL. */
! 384: zlog_debug ("ASN_NULL");
! 385: break;
! 386:
! 387: case ASN_INTEGER:
! 388: zlog_debug ("ASN_INTEGER");
! 389: break;
! 390: case ASN_COUNTER:
! 391: case ASN_GAUGE:
! 392: case ASN_TIMETICKS:
! 393: case ASN_UINTEGER:
! 394: zlog_debug ("ASN_COUNTER");
! 395: break;
! 396: case ASN_COUNTER64:
! 397: zlog_debug ("ASN_COUNTER64");
! 398: break;
! 399: case ASN_IPADDRESS:
! 400: zlog_debug ("ASN_IPADDRESS");
! 401: break;
! 402: case ASN_OCTET_STR:
! 403: zlog_debug ("ASN_OCTET_STR");
! 404: break;
! 405: case ASN_OPAQUE:
! 406: case ASN_NSAP:
! 407: case ASN_OBJECT_ID:
! 408: zlog_debug ("ASN_OPAQUE");
! 409: break;
! 410: case SNMP_NOSUCHOBJECT:
! 411: zlog_debug ("SNMP_NOSUCHOBJECT");
! 412: break;
! 413: case SNMP_NOSUCHINSTANCE:
! 414: zlog_debug ("SNMP_NOSUCHINSTANCE");
! 415: break;
! 416: case SNMP_ENDOFMIBVIEW:
! 417: zlog_debug ("SNMP_ENDOFMIBVIEW");
! 418: break;
! 419: case ASN_BIT_STR:
! 420: zlog_debug ("ASN_BIT_STR");
! 421: break;
! 422: default:
! 423: zlog_debug ("Unknown type");
! 424: break;
! 425: }
! 426: return ptr;
! 427: }
! 428:
! 429: /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
! 430: ucd-snmp smux and as such suppose, that the peer receives in the message
! 431: only one variable. Fortunately, IBM seems to do the same in AIX. */
! 432:
! 433: static int
! 434: smux_set (oid *reqid, size_t *reqid_len,
! 435: u_char val_type, void *val, size_t val_len, int action)
! 436: {
! 437: int j;
! 438: struct subtree *subtree;
! 439: struct variable *v;
! 440: int subresult;
! 441: oid *suffix;
! 442: size_t suffix_len;
! 443: int result;
! 444: u_char *statP = NULL;
! 445: WriteMethod *write_method = NULL;
! 446: struct listnode *node, *nnode;
! 447:
! 448: /* Check */
! 449: for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
! 450: {
! 451: subresult = oid_compare_part (reqid, *reqid_len,
! 452: subtree->name, subtree->name_len);
! 453:
! 454: /* Subtree matched. */
! 455: if (subresult == 0)
! 456: {
! 457: /* Prepare suffix. */
! 458: suffix = reqid + subtree->name_len;
! 459: suffix_len = *reqid_len - subtree->name_len;
! 460: result = subresult;
! 461:
! 462: /* Check variables. */
! 463: for (j = 0; j < subtree->variables_num; j++)
! 464: {
! 465: v = &subtree->variables[j];
! 466:
! 467: /* Always check suffix */
! 468: result = oid_compare_part (suffix, suffix_len,
! 469: v->name, v->namelen);
! 470:
! 471: /* This is exact match so result must be zero. */
! 472: if (result == 0)
! 473: {
! 474: if (debug_smux)
! 475: zlog_debug ("SMUX function call index is %d", v->magic);
! 476:
! 477: statP = (*v->findVar) (v, suffix, &suffix_len, 1,
! 478: &val_len, &write_method);
! 479:
! 480: if (write_method)
! 481: {
! 482: return (*write_method)(action, val, val_type, val_len,
! 483: statP, suffix, suffix_len, v);
! 484: }
! 485: else
! 486: {
! 487: return SNMP_ERR_READONLY;
! 488: }
! 489: }
! 490:
! 491: /* If above execution is failed or oid is small (so
! 492: there is no further match). */
! 493: if (result < 0)
! 494: return SNMP_ERR_NOSUCHNAME;
! 495: }
! 496: }
! 497: }
! 498: return SNMP_ERR_NOSUCHNAME;
! 499: }
! 500:
! 501: static int
! 502: smux_get (oid *reqid, size_t *reqid_len, int exact,
! 503: u_char *val_type,void **val, size_t *val_len)
! 504: {
! 505: int j;
! 506: struct subtree *subtree;
! 507: struct variable *v;
! 508: int subresult;
! 509: oid *suffix;
! 510: size_t suffix_len;
! 511: int result;
! 512: WriteMethod *write_method=NULL;
! 513: struct listnode *node, *nnode;
! 514:
! 515: /* Check */
! 516: for (ALL_LIST_ELEMENTS (treelist, node, nnode,subtree))
! 517: {
! 518: subresult = oid_compare_part (reqid, *reqid_len,
! 519: subtree->name, subtree->name_len);
! 520:
! 521: /* Subtree matched. */
! 522: if (subresult == 0)
! 523: {
! 524: /* Prepare suffix. */
! 525: suffix = reqid + subtree->name_len;
! 526: suffix_len = *reqid_len - subtree->name_len;
! 527: result = subresult;
! 528:
! 529: /* Check variables. */
! 530: for (j = 0; j < subtree->variables_num; j++)
! 531: {
! 532: v = &subtree->variables[j];
! 533:
! 534: /* Always check suffix */
! 535: result = oid_compare_part (suffix, suffix_len,
! 536: v->name, v->namelen);
! 537:
! 538: /* This is exact match so result must be zero. */
! 539: if (result == 0)
! 540: {
! 541: if (debug_smux)
! 542: zlog_debug ("SMUX function call index is %d", v->magic);
! 543:
! 544: *val = (*v->findVar) (v, suffix, &suffix_len, exact,
! 545: val_len, &write_method);
! 546:
! 547: /* There is no instance. */
! 548: if (*val == NULL)
! 549: return SNMP_NOSUCHINSTANCE;
! 550:
! 551: /* Call is suceed. */
! 552: *val_type = v->type;
! 553:
! 554: return 0;
! 555: }
! 556:
! 557: /* If above execution is failed or oid is small (so
! 558: there is no further match). */
! 559: if (result < 0)
! 560: return SNMP_ERR_NOSUCHNAME;
! 561: }
! 562: }
! 563: }
! 564: return SNMP_ERR_NOSUCHNAME;
! 565: }
! 566:
! 567: static int
! 568: smux_getnext (oid *reqid, size_t *reqid_len, int exact,
! 569: u_char *val_type,void **val, size_t *val_len)
! 570: {
! 571: int j;
! 572: oid save[MAX_OID_LEN];
! 573: int savelen = 0;
! 574: struct subtree *subtree;
! 575: struct variable *v;
! 576: int subresult;
! 577: oid *suffix;
! 578: size_t suffix_len;
! 579: int result;
! 580: WriteMethod *write_method=NULL;
! 581: struct listnode *node, *nnode;
! 582:
! 583:
! 584: /* Save incoming request. */
! 585: oid_copy (save, reqid, *reqid_len);
! 586: savelen = *reqid_len;
! 587:
! 588: /* Check */
! 589: for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
! 590: {
! 591: subresult = oid_compare_part (reqid, *reqid_len,
! 592: subtree->name, subtree->name_len);
! 593:
! 594: /* If request is in the tree. The agent has to make sure we
! 595: only receive requests we have registered for. */
! 596: /* Unfortunately, that's not true. In fact, a SMUX subagent has to
! 597: behave as if it manages the whole SNMP MIB tree itself. It's the
! 598: duty of the master agent to collect the best answer and return it
! 599: to the manager. See RFC 1227 chapter 3.1.6 for the glory details
! 600: :-). ucd-snmp really behaves bad here as it actually might ask
! 601: multiple times for the same GETNEXT request as it throws away the
! 602: answer when it expects it in a different subtree and might come
! 603: back later with the very same request. --jochen */
! 604:
! 605: if (subresult <= 0)
! 606: {
! 607: /* Prepare suffix. */
! 608: suffix = reqid + subtree->name_len;
! 609: suffix_len = *reqid_len - subtree->name_len;
! 610: if (subresult < 0)
! 611: {
! 612: oid_copy(reqid, subtree->name, subtree->name_len);
! 613: *reqid_len = subtree->name_len;
! 614: }
! 615: for (j = 0; j < subtree->variables_num; j++)
! 616: {
! 617: result = subresult;
! 618: v = &subtree->variables[j];
! 619:
! 620: /* Next then check result >= 0. */
! 621: if (result == 0)
! 622: result = oid_compare_part (suffix, suffix_len,
! 623: v->name, v->namelen);
! 624:
! 625: if (result <= 0)
! 626: {
! 627: if (debug_smux)
! 628: zlog_debug ("SMUX function call index is %d", v->magic);
! 629: if(result<0)
! 630: {
! 631: oid_copy(suffix, v->name, v->namelen);
! 632: suffix_len = v->namelen;
! 633: }
! 634: *val = (*v->findVar) (v, suffix, &suffix_len, exact,
! 635: val_len, &write_method);
! 636: *reqid_len = suffix_len + subtree->name_len;
! 637: if (*val)
! 638: {
! 639: *val_type = v->type;
! 640: return 0;
! 641: }
! 642: }
! 643: }
! 644: }
! 645: }
! 646: memcpy (reqid, save, savelen * sizeof(oid));
! 647: *reqid_len = savelen;
! 648:
! 649: return SNMP_ERR_NOSUCHNAME;
! 650: }
! 651:
! 652: /* GET message header. */
! 653: static u_char *
! 654: smux_parse_get_header (u_char *ptr, size_t *len, long *reqid)
! 655: {
! 656: u_char type;
! 657: long errstat;
! 658: long errindex;
! 659:
! 660: /* Request ID. */
! 661: ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
! 662:
! 663: if (debug_smux)
! 664: zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len);
! 665:
! 666: /* Error status. */
! 667: ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
! 668:
! 669: if (debug_smux)
! 670: zlog_debug ("SMUX GET errstat %ld len: %zd", errstat, *len);
! 671:
! 672: /* Error index. */
! 673: ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
! 674:
! 675: if (debug_smux)
! 676: zlog_debug ("SMUX GET errindex %ld len: %zd", errindex, *len);
! 677:
! 678: return ptr;
! 679: }
! 680:
! 681: static void
! 682: smux_parse_set (u_char *ptr, size_t len, int action)
! 683: {
! 684: long reqid;
! 685: oid oid[MAX_OID_LEN];
! 686: size_t oid_len;
! 687: u_char val_type;
! 688: void *val;
! 689: size_t val_len;
! 690: int ret;
! 691:
! 692: if (debug_smux)
! 693: zlog_debug ("SMUX SET(%s) message parse: len %zd",
! 694: (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
! 695: len);
! 696:
! 697: /* Parse SET message header. */
! 698: ptr = smux_parse_get_header (ptr, &len, &reqid);
! 699:
! 700: /* Parse SET message object ID. */
! 701: ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val);
! 702:
! 703: ret = smux_set (oid, &oid_len, val_type, val, val_len, action);
! 704: if (debug_smux)
! 705: zlog_debug ("SMUX SET ret %d", ret);
! 706:
! 707: /* Return result. */
! 708: if (RESERVE1 == action)
! 709: smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
! 710: }
! 711:
! 712: static void
! 713: smux_parse_get (u_char *ptr, size_t len, int exact)
! 714: {
! 715: long reqid;
! 716: oid oid[MAX_OID_LEN];
! 717: size_t oid_len;
! 718: u_char val_type;
! 719: void *val;
! 720: size_t val_len;
! 721: int ret;
! 722:
! 723: if (debug_smux)
! 724: zlog_debug ("SMUX GET message parse: len %zd", len);
! 725:
! 726: /* Parse GET message header. */
! 727: ptr = smux_parse_get_header (ptr, &len, &reqid);
! 728:
! 729: /* Parse GET message object ID. We needn't the value come */
! 730: ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL);
! 731:
! 732: /* Traditional getstatptr. */
! 733: if (exact)
! 734: ret = smux_get (oid, &oid_len, exact, &val_type, &val, &val_len);
! 735: else
! 736: ret = smux_getnext (oid, &oid_len, exact, &val_type, &val, &val_len);
! 737:
! 738: /* Return result. */
! 739: if (ret == 0)
! 740: smux_getresp_send (oid, oid_len, reqid, 0, 0, val_type, val, val_len);
! 741: else
! 742: smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
! 743: }
! 744:
! 745: /* Parse SMUX_CLOSE message. */
! 746: static void
! 747: smux_parse_close (u_char *ptr, int len)
! 748: {
! 749: long reason = 0;
! 750:
! 751: while (len--)
! 752: {
! 753: reason = (reason << 8) | (long) *ptr;
! 754: ptr++;
! 755: }
! 756: zlog_info ("SMUX_CLOSE with reason: %ld", reason);
! 757: }
! 758:
! 759: /* SMUX_RRSP message. */
! 760: static void
! 761: smux_parse_rrsp (u_char *ptr, size_t len)
! 762: {
! 763: u_char val;
! 764: long errstat;
! 765:
! 766: ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
! 767:
! 768: if (debug_smux)
! 769: zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
! 770: }
! 771:
! 772: /* Parse SMUX message. */
! 773: static int
! 774: smux_parse (u_char *ptr, size_t len)
! 775: {
! 776: /* This buffer we'll use for SOUT message. We could allocate it with
! 777: malloc and save only static pointer/lenght, but IMHO static
! 778: buffer is a faster solusion. */
! 779: static u_char sout_save_buff[SMUXMAXPKTSIZE];
! 780: static int sout_save_len = 0;
! 781:
! 782: int len_income = len; /* see note below: YYY */
! 783: u_char type;
! 784: u_char rollback;
! 785:
! 786: rollback = ptr[2]; /* important only for SMUX_SOUT */
! 787:
! 788: process_rest: /* see note below: YYY */
! 789:
! 790: /* Parse SMUX message type and subsequent length. */
! 791: ptr = asn_parse_header (ptr, &len, &type);
! 792:
! 793: if (debug_smux)
! 794: zlog_debug ("SMUX message received type: %d rest len: %zd", type, len);
! 795:
! 796: switch (type)
! 797: {
! 798: case SMUX_OPEN:
! 799: /* Open must be not send from SNMP agent. */
! 800: zlog_warn ("SMUX_OPEN received: resetting connection.");
! 801: return -1;
! 802: break;
! 803: case SMUX_RREQ:
! 804: /* SMUX_RREQ message is invalid for us. */
! 805: zlog_warn ("SMUX_RREQ received: resetting connection.");
! 806: return -1;
! 807: break;
! 808: case SMUX_SOUT:
! 809: /* SMUX_SOUT message is now valied for us. */
! 810: if (debug_smux)
! 811: zlog_debug ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
! 812:
! 813: if (sout_save_len > 0)
! 814: {
! 815: smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
! 816: sout_save_len = 0;
! 817: }
! 818: else
! 819: zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
! 820:
! 821: if (len_income > 3)
! 822: {
! 823: /* YYY: this strange code has to solve the "slow peer"
! 824: problem: When agent sends SMUX_SOUT message it doesn't
! 825: wait any responce and may send some next message to
! 826: subagent. Then the peer in 'smux_read()' will recieve
! 827: from socket the 'concatenated' buffer, contaning both
! 828: SMUX_SOUT message and the next one
! 829: (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
! 830: the buffer is longer than 3 ( length of SMUX_SOUT ), we
! 831: must process the rest of it. This effect may be observed
! 832: if 'debug_smux' is set to '1' */
! 833: ptr++;
! 834: len = len_income - 3;
! 835: goto process_rest;
! 836: }
! 837: break;
! 838: case SMUX_GETRSP:
! 839: /* SMUX_GETRSP message is invalid for us. */
! 840: zlog_warn ("SMUX_GETRSP received: resetting connection.");
! 841: return -1;
! 842: break;
! 843: case SMUX_CLOSE:
! 844: /* Close SMUX connection. */
! 845: if (debug_smux)
! 846: zlog_debug ("SMUX_CLOSE");
! 847: smux_parse_close (ptr, len);
! 848: return -1;
! 849: break;
! 850: case SMUX_RRSP:
! 851: /* This is response for register message. */
! 852: if (debug_smux)
! 853: zlog_debug ("SMUX_RRSP");
! 854: smux_parse_rrsp (ptr, len);
! 855: break;
! 856: case SMUX_GET:
! 857: /* Exact request for object id. */
! 858: if (debug_smux)
! 859: zlog_debug ("SMUX_GET");
! 860: smux_parse_get (ptr, len, 1);
! 861: break;
! 862: case SMUX_GETNEXT:
! 863: /* Next request for object id. */
! 864: if (debug_smux)
! 865: zlog_debug ("SMUX_GETNEXT");
! 866: smux_parse_get (ptr, len, 0);
! 867: break;
! 868: case SMUX_SET:
! 869: /* SMUX_SET is supported with some limitations. */
! 870: if (debug_smux)
! 871: zlog_debug ("SMUX_SET");
! 872:
! 873: /* save the data for future SMUX_SOUT */
! 874: memcpy (sout_save_buff, ptr, len);
! 875: sout_save_len = len;
! 876: smux_parse_set (ptr, len, RESERVE1);
! 877: break;
! 878: default:
! 879: zlog_info ("Unknown type: %d", type);
! 880: break;
! 881: }
! 882: return 0;
! 883: }
! 884:
! 885: /* SMUX message read function. */
! 886: static int
! 887: smux_read (struct thread *t)
! 888: {
! 889: int sock;
! 890: int len;
! 891: u_char buf[SMUXMAXPKTSIZE];
! 892: int ret;
! 893:
! 894: /* Clear thread. */
! 895: sock = THREAD_FD (t);
! 896: smux_read_thread = NULL;
! 897:
! 898: if (debug_smux)
! 899: zlog_debug ("SMUX read start");
! 900:
! 901: /* Read message from SMUX socket. */
! 902: len = recv (sock, buf, SMUXMAXPKTSIZE, 0);
! 903:
! 904: if (len < 0)
! 905: {
! 906: zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno));
! 907: close (sock);
! 908: smux_sock = -1;
! 909: smux_event (SMUX_CONNECT, 0);
! 910: return -1;
! 911: }
! 912:
! 913: if (len == 0)
! 914: {
! 915: zlog_warn ("SMUX connection closed: %d", sock);
! 916: close (sock);
! 917: smux_sock = -1;
! 918: smux_event (SMUX_CONNECT, 0);
! 919: return -1;
! 920: }
! 921:
! 922: if (debug_smux)
! 923: zlog_debug ("SMUX read len: %d", len);
! 924:
! 925: /* Parse the message. */
! 926: ret = smux_parse (buf, len);
! 927:
! 928: if (ret < 0)
! 929: {
! 930: close (sock);
! 931: smux_sock = -1;
! 932: smux_event (SMUX_CONNECT, 0);
! 933: return -1;
! 934: }
! 935:
! 936: /* Regiser read thread. */
! 937: smux_event (SMUX_READ, sock);
! 938:
! 939: return 0;
! 940: }
! 941:
! 942: static int
! 943: smux_open (int sock)
! 944: {
! 945: u_char buf[BUFSIZ];
! 946: u_char *ptr;
! 947: size_t len;
! 948: long version;
! 949: u_char progname[] = QUAGGA_PROGNAME "-" QUAGGA_VERSION;
! 950:
! 951: if (debug_smux)
! 952: {
! 953: smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
! 954: zlog_debug ("SMUX open progname: %s", progname);
! 955: zlog_debug ("SMUX open password: %s", smux_passwd);
! 956: }
! 957:
! 958: ptr = buf;
! 959: len = BUFSIZ;
! 960:
! 961: /* SMUX Header. As placeholder. */
! 962: ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
! 963:
! 964: /* SMUX Open. */
! 965: version = 0;
! 966: ptr = asn_build_int (ptr, &len,
! 967: (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
! 968: &version, sizeof (version));
! 969:
! 970: /* SMUX connection oid. */
! 971: ptr = asn_build_objid (ptr, &len,
! 972: (u_char)
! 973: (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
! 974: smux_oid, smux_oid_len);
! 975:
! 976: /* SMUX connection description. */
! 977: ptr = asn_build_string (ptr, &len,
! 978: (u_char)
! 979: (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
! 980: progname, strlen (progname));
! 981:
! 982: /* SMUX connection password. */
! 983: ptr = asn_build_string (ptr, &len,
! 984: (u_char)
! 985: (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
! 986: (u_char *)smux_passwd, strlen (smux_passwd));
! 987:
! 988: /* Fill in real SMUX header. We exclude ASN header size (2). */
! 989: len = BUFSIZ;
! 990: asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
! 991:
! 992: return send (sock, buf, (ptr - buf), 0);
! 993: }
! 994:
! 995: int
! 996: smux_trap (const oid *name, size_t namelen,
! 997: const oid *iname, size_t inamelen,
! 998: const struct trap_object *trapobj, size_t trapobjlen,
! 999: unsigned int tick, u_char sptrap)
! 1000: {
! 1001: unsigned int i;
! 1002: u_char buf[BUFSIZ];
! 1003: u_char *ptr;
! 1004: size_t len, length;
! 1005: struct in_addr addr;
! 1006: unsigned long val;
! 1007: u_char *h1, *h1e;
! 1008:
! 1009: ptr = buf;
! 1010: len = BUFSIZ;
! 1011: length = len;
! 1012:
! 1013: /* When SMUX connection is not established. */
! 1014: if (smux_sock < 0)
! 1015: return 0;
! 1016:
! 1017: /* SMUX header. */
! 1018: ptr = asn_build_header (ptr, &len, (u_char) SMUX_TRAP, 0);
! 1019:
! 1020: /* Sub agent enterprise oid. */
! 1021: ptr = asn_build_objid (ptr, &len,
! 1022: (u_char)
! 1023: (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
! 1024: smux_oid, smux_oid_len);
! 1025:
! 1026: /* IP address. */
! 1027: addr.s_addr = 0;
! 1028: ptr = asn_build_string (ptr, &len,
! 1029: (u_char)
! 1030: (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_IPADDRESS),
! 1031: (u_char *)&addr, sizeof (addr));
! 1032:
! 1033: /* Generic trap integer. */
! 1034: val = SNMP_TRAP_ENTERPRISESPECIFIC;
! 1035: ptr = asn_build_int (ptr, &len,
! 1036: (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
! 1037: (long *)&val, sizeof (val));
! 1038:
! 1039: /* Specific trap integer. */
! 1040: val = sptrap;
! 1041: ptr = asn_build_int (ptr, &len,
! 1042: (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
! 1043: (long *)&val, sizeof (val));
! 1044:
! 1045: /* Timeticks timestamp. */
! 1046: val = 0;
! 1047: ptr = asn_build_unsigned_int (ptr, &len,
! 1048: (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_TIMETICKS),
! 1049: &val, sizeof (val));
! 1050:
! 1051: /* Variables. */
! 1052: h1 = ptr;
! 1053: ptr = asn_build_sequence (ptr, &len,
! 1054: (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
! 1055: 0);
! 1056:
! 1057:
! 1058: /* Iteration for each objects. */
! 1059: h1e = ptr;
! 1060: for (i = 0; i < trapobjlen; i++)
! 1061: {
! 1062: int ret;
! 1063: oid oid[MAX_OID_LEN];
! 1064: size_t oid_len;
! 1065: void *val;
! 1066: size_t val_len;
! 1067: u_char val_type;
! 1068:
! 1069: /* Make OID. */
! 1070: if (trapobj[i].namelen > 0)
! 1071: {
! 1072: oid_copy (oid, name, namelen);
! 1073: oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen);
! 1074: oid_copy (oid + namelen + trapobj[i].namelen, iname, inamelen);
! 1075: oid_len = namelen + trapobj[i].namelen + inamelen;
! 1076: }
! 1077: else
! 1078: {
! 1079: oid_copy (oid, name, namelen);
! 1080: oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen * (-1));
! 1081: oid_len = namelen + trapobj[i].namelen * (-1) ;
! 1082: }
! 1083:
! 1084: if (debug_smux)
! 1085: {
! 1086: smux_oid_dump ("Trap", name, namelen);
! 1087: if (trapobj[i].namelen < 0)
! 1088: smux_oid_dump ("Trap",
! 1089: trapobj[i].name, (- 1) * (trapobj[i].namelen));
! 1090: else
! 1091: {
! 1092: smux_oid_dump ("Trap", trapobj[i].name, (trapobj[i].namelen));
! 1093: smux_oid_dump ("Trap", iname, inamelen);
! 1094: }
! 1095: smux_oid_dump ("Trap", oid, oid_len);
! 1096: zlog_info ("BUFSIZ: %d // oid_len: %lu", BUFSIZ, (u_long)oid_len);
! 1097: }
! 1098:
! 1099: ret = smux_get (oid, &oid_len, 1, &val_type, &val, &val_len);
! 1100:
! 1101: if (debug_smux)
! 1102: zlog_debug ("smux_get result %d", ret);
! 1103:
! 1104: if (ret == 0)
! 1105: ptr = snmp_build_var_op (ptr, oid, &oid_len,
! 1106: val_type, val_len, val, &len);
! 1107: }
! 1108:
! 1109: /* Now variable size is known, fill in size */
! 1110: asn_build_sequence(h1, &length,
! 1111: (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
! 1112: ptr - h1e);
! 1113:
! 1114: /* Fill in size of whole sequence */
! 1115: len = BUFSIZ;
! 1116: asn_build_header (buf, &len, (u_char) SMUX_TRAP, (ptr - buf) - 2);
! 1117:
! 1118: return send (smux_sock, buf, (ptr - buf), 0);
! 1119: }
! 1120:
! 1121: static int
! 1122: smux_register (int sock)
! 1123: {
! 1124: u_char buf[BUFSIZ];
! 1125: u_char *ptr;
! 1126: int ret;
! 1127: size_t len;
! 1128: long priority;
! 1129: long operation;
! 1130: struct subtree *subtree;
! 1131: struct listnode *node, *nnode;
! 1132:
! 1133: ret = 0;
! 1134:
! 1135: for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
! 1136: {
! 1137: ptr = buf;
! 1138: len = BUFSIZ;
! 1139:
! 1140: /* SMUX RReq Header. */
! 1141: ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
! 1142:
! 1143: /* Register MIB tree. */
! 1144: ptr = asn_build_objid (ptr, &len,
! 1145: (u_char)
! 1146: (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
! 1147: subtree->name, subtree->name_len);
! 1148:
! 1149: /* Priority. */
! 1150: priority = -1;
! 1151: ptr = asn_build_int (ptr, &len,
! 1152: (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
! 1153: &priority, sizeof (priority));
! 1154:
! 1155: /* Operation. */
! 1156: operation = 2; /* Register R/W */
! 1157: ptr = asn_build_int (ptr, &len,
! 1158: (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
! 1159: &operation, sizeof (operation));
! 1160:
! 1161: if (debug_smux)
! 1162: {
! 1163: smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
! 1164: zlog_debug ("SMUX register priority: %ld", priority);
! 1165: zlog_debug ("SMUX register operation: %ld", operation);
! 1166: }
! 1167:
! 1168: len = BUFSIZ;
! 1169: asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
! 1170: ret = send (sock, buf, (ptr - buf), 0);
! 1171: if (ret < 0)
! 1172: return ret;
! 1173: }
! 1174: return ret;
! 1175: }
! 1176:
! 1177: /* Try to connect to SNMP agent. */
! 1178: static int
! 1179: smux_connect (struct thread *t)
! 1180: {
! 1181: int ret;
! 1182:
! 1183: if (debug_smux)
! 1184: zlog_debug ("SMUX connect try %d", fail + 1);
! 1185:
! 1186: /* Clear thread poner of myself. */
! 1187: smux_connect_thread = NULL;
! 1188:
! 1189: /* Make socket. Try to connect. */
! 1190: smux_sock = smux_socket ();
! 1191: if (smux_sock < 0)
! 1192: {
! 1193: if (++fail < SMUX_MAX_FAILURE)
! 1194: smux_event (SMUX_CONNECT, 0);
! 1195: return 0;
! 1196: }
! 1197:
! 1198: /* Send OPEN PDU. */
! 1199: ret = smux_open (smux_sock);
! 1200: if (ret < 0)
! 1201: {
! 1202: zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno));
! 1203: close (smux_sock);
! 1204: smux_sock = -1;
! 1205: if (++fail < SMUX_MAX_FAILURE)
! 1206: smux_event (SMUX_CONNECT, 0);
! 1207: return -1;
! 1208: }
! 1209:
! 1210: /* Send any outstanding register PDUs. */
! 1211: ret = smux_register (smux_sock);
! 1212: if (ret < 0)
! 1213: {
! 1214: zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno));
! 1215: close (smux_sock);
! 1216: smux_sock = -1;
! 1217: if (++fail < SMUX_MAX_FAILURE)
! 1218: smux_event (SMUX_CONNECT, 0);
! 1219: return -1;
! 1220: }
! 1221:
! 1222: /* Everything goes fine. */
! 1223: smux_event (SMUX_READ, smux_sock);
! 1224:
! 1225: return 0;
! 1226: }
! 1227:
! 1228: /* Clear all SMUX related resources. */
! 1229: static void
! 1230: smux_stop (void)
! 1231: {
! 1232: if (smux_read_thread)
! 1233: {
! 1234: thread_cancel (smux_read_thread);
! 1235: smux_read_thread = NULL;
! 1236: }
! 1237:
! 1238: if (smux_connect_thread)
! 1239: {
! 1240: thread_cancel (smux_connect_thread);
! 1241: smux_connect_thread = NULL;
! 1242: }
! 1243:
! 1244: if (smux_sock >= 0)
! 1245: {
! 1246: close (smux_sock);
! 1247: smux_sock = -1;
! 1248: }
! 1249: }
! 1250:
! 1251:
! 1252:
! 1253: void
! 1254: smux_event (enum smux_event event, int sock)
! 1255: {
! 1256: switch (event)
! 1257: {
! 1258: case SMUX_SCHEDULE:
! 1259: smux_connect_thread = thread_add_event (master, smux_connect, NULL, 0);
! 1260: break;
! 1261: case SMUX_CONNECT:
! 1262: smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10);
! 1263: break;
! 1264: case SMUX_READ:
! 1265: smux_read_thread = thread_add_read (master, smux_read, NULL, sock);
! 1266: break;
! 1267: default:
! 1268: break;
! 1269: }
! 1270: }
! 1271:
! 1272: static int
! 1273: smux_str2oid (const char *str, oid *oid, size_t *oid_len)
! 1274: {
! 1275: int len;
! 1276: int val;
! 1277:
! 1278: len = 0;
! 1279: val = 0;
! 1280: *oid_len = 0;
! 1281:
! 1282: if (*str == '.')
! 1283: str++;
! 1284: if (*str == '\0')
! 1285: return 0;
! 1286:
! 1287: while (1)
! 1288: {
! 1289: if (! isdigit (*str))
! 1290: return -1;
! 1291:
! 1292: while (isdigit (*str))
! 1293: {
! 1294: val *= 10;
! 1295: val += (*str - '0');
! 1296: str++;
! 1297: }
! 1298:
! 1299: if (*str == '\0')
! 1300: break;
! 1301: if (*str != '.')
! 1302: return -1;
! 1303:
! 1304: oid[len++] = val;
! 1305: val = 0;
! 1306: str++;
! 1307: }
! 1308:
! 1309: oid[len++] = val;
! 1310: *oid_len = len;
! 1311:
! 1312: return 0;
! 1313: }
! 1314:
! 1315: static oid *
! 1316: smux_oid_dup (oid *objid, size_t objid_len)
! 1317: {
! 1318: oid *new;
! 1319:
! 1320: new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len);
! 1321: oid_copy (new, objid, objid_len);
! 1322:
! 1323: return new;
! 1324: }
! 1325:
! 1326: static int
! 1327: smux_peer_oid (struct vty *vty, const char *oid_str, const char *passwd_str)
! 1328: {
! 1329: int ret;
! 1330: oid oid[MAX_OID_LEN];
! 1331: size_t oid_len;
! 1332:
! 1333: ret = smux_str2oid (oid_str, oid, &oid_len);
! 1334: if (ret != 0)
! 1335: {
! 1336: vty_out (vty, "object ID malformed%s", VTY_NEWLINE);
! 1337: return CMD_WARNING;
! 1338: }
! 1339:
! 1340: if (smux_oid)
! 1341: {
! 1342: free (smux_oid);
! 1343: smux_oid = NULL;
! 1344: }
! 1345:
! 1346: /* careful, smux_passwd might point to string constant */
! 1347: if (smux_passwd)
! 1348: {
! 1349: free (smux_passwd);
! 1350: smux_passwd = NULL;
! 1351: }
! 1352:
! 1353: smux_oid = smux_oid_dup (oid, oid_len);
! 1354: smux_oid_len = oid_len;
! 1355:
! 1356: if (passwd_str)
! 1357: smux_passwd = strdup (passwd_str);
! 1358: else
! 1359: smux_passwd = strdup ("");
! 1360:
! 1361: return 0;
! 1362: }
! 1363:
! 1364: int
! 1365: smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
! 1366: size_t *var_len, WriteMethod **write_method)
! 1367: {
! 1368: oid fulloid[MAX_OID_LEN];
! 1369: int ret;
! 1370:
! 1371: oid_copy (fulloid, v->name, v->namelen);
! 1372: fulloid[v->namelen] = 0;
! 1373: /* Check against full instance. */
! 1374: ret = oid_compare (name, *length, fulloid, v->namelen + 1);
! 1375:
! 1376: /* Check single instance. */
! 1377: if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
! 1378: return MATCH_FAILED;
! 1379:
! 1380: /* In case of getnext, fill in full instance. */
! 1381: memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
! 1382: *length = v->namelen + 1;
! 1383:
! 1384: *write_method = 0;
! 1385: *var_len = sizeof(long); /* default to 'long' results */
! 1386:
! 1387: return MATCH_SUCCEEDED;
! 1388: }
! 1389:
! 1390: static int
! 1391: smux_peer_default (void)
! 1392: {
! 1393: if (smux_oid)
! 1394: {
! 1395: free (smux_oid);
! 1396: smux_oid = NULL;
! 1397: }
! 1398:
! 1399: /* careful, smux_passwd might be pointing at string constant */
! 1400: if (smux_passwd)
! 1401: {
! 1402: free (smux_passwd);
! 1403: smux_passwd = NULL;
! 1404: }
! 1405:
! 1406: return CMD_SUCCESS;
! 1407: }
! 1408:
! 1409: DEFUN (smux_peer,
! 1410: smux_peer_cmd,
! 1411: "smux peer OID",
! 1412: "SNMP MUX protocol settings\n"
! 1413: "SNMP MUX peer settings\n"
! 1414: "Object ID used in SMUX peering\n")
! 1415: {
! 1416: if (smux_peer_oid (vty, argv[0], NULL) == 0)
! 1417: {
! 1418: smux_start();
! 1419: return CMD_SUCCESS;
! 1420: }
! 1421: else
! 1422: return CMD_WARNING;
! 1423: }
! 1424:
! 1425: DEFUN (smux_peer_password,
! 1426: smux_peer_password_cmd,
! 1427: "smux peer OID PASSWORD",
! 1428: "SNMP MUX protocol settings\n"
! 1429: "SNMP MUX peer settings\n"
! 1430: "SMUX peering object ID\n"
! 1431: "SMUX peering password\n")
! 1432: {
! 1433: if (smux_peer_oid (vty, argv[0], argv[1]) == 0)
! 1434: {
! 1435: smux_start();
! 1436: return CMD_SUCCESS;
! 1437: }
! 1438: else
! 1439: return CMD_WARNING;
! 1440: }
! 1441:
! 1442: DEFUN (no_smux_peer,
! 1443: no_smux_peer_cmd,
! 1444: "no smux peer",
! 1445: NO_STR
! 1446: "SNMP MUX protocol settings\n"
! 1447: "SNMP MUX peer settings\n")
! 1448: {
! 1449: smux_stop();
! 1450: return smux_peer_default ();
! 1451: }
! 1452:
! 1453: ALIAS (no_smux_peer,
! 1454: no_smux_peer_oid_cmd,
! 1455: "no smux peer OID",
! 1456: NO_STR
! 1457: "SNMP MUX protocol settings\n"
! 1458: "SNMP MUX peer settings\n"
! 1459: "SMUX peering object ID\n")
! 1460:
! 1461: ALIAS (no_smux_peer,
! 1462: no_smux_peer_oid_password_cmd,
! 1463: "no smux peer OID PASSWORD",
! 1464: NO_STR
! 1465: "SNMP MUX protocol settings\n"
! 1466: "SNMP MUX peer settings\n"
! 1467: "SMUX peering object ID\n"
! 1468: "SMUX peering password\n")
! 1469:
! 1470: static int
! 1471: config_write_smux (struct vty *vty)
! 1472: {
! 1473: int first = 1;
! 1474: unsigned int i;
! 1475:
! 1476: if (smux_oid)
! 1477: {
! 1478: vty_out (vty, "smux peer ");
! 1479: for (i = 0; i < smux_oid_len; i++)
! 1480: {
! 1481: vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]);
! 1482: first = 0;
! 1483: }
! 1484: vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE);
! 1485: }
! 1486: return 0;
! 1487: }
! 1488:
! 1489: /* Register subtree to smux master tree. */
! 1490: void
! 1491: smux_register_mib (const char *descr, struct variable *var,
! 1492: size_t width, int num,
! 1493: oid name[], size_t namelen)
! 1494: {
! 1495: struct subtree *tree;
! 1496:
! 1497: tree = (struct subtree *)malloc(sizeof(struct subtree));
! 1498: oid_copy (tree->name, name, namelen);
! 1499: tree->name_len = namelen;
! 1500: tree->variables = var;
! 1501: tree->variables_num = num;
! 1502: tree->variables_width = width;
! 1503: tree->registered = 0;
! 1504: listnode_add_sort(treelist, tree);
! 1505: }
! 1506:
! 1507: /* Compare function to keep treelist sorted */
! 1508: static int
! 1509: smux_tree_cmp(struct subtree *tree1, struct subtree *tree2)
! 1510: {
! 1511: return oid_compare(tree1->name, tree1->name_len,
! 1512: tree2->name, tree2->name_len);
! 1513: }
! 1514:
! 1515: /* Initialize some values then schedule first SMUX connection. */
! 1516: void
! 1517: smux_init (struct thread_master *tm)
! 1518: {
! 1519: /* copy callers thread master */
! 1520: master = tm;
! 1521:
! 1522: /* Make MIB tree. */
! 1523: treelist = list_new();
! 1524: treelist->cmp = (int (*)(void *, void *))smux_tree_cmp;
! 1525:
! 1526: /* Install commands. */
! 1527: install_node (&smux_node, config_write_smux);
! 1528:
! 1529: install_element (CONFIG_NODE, &smux_peer_cmd);
! 1530: install_element (CONFIG_NODE, &smux_peer_password_cmd);
! 1531: install_element (CONFIG_NODE, &no_smux_peer_cmd);
! 1532: install_element (CONFIG_NODE, &no_smux_peer_oid_cmd);
! 1533: install_element (CONFIG_NODE, &no_smux_peer_oid_password_cmd);
! 1534: }
! 1535:
! 1536: void
! 1537: smux_start(void)
! 1538: {
! 1539: /* Close any existing connections. */
! 1540: smux_stop();
! 1541:
! 1542: /* Schedule first connection. */
! 1543: smux_event (SMUX_SCHEDULE, 0);
! 1544: }
! 1545: #endif /* HAVE_SNMP */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>