File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / lib / smux.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:22:28 2012 UTC (11 years, 11 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_21, HEAD
quagga

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

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