File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / lib / smux.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jul 21 23:54:39 2013 UTC (10 years, 11 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, HEAD
0.99.22

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>