Annotation of embedaddon/quagga/lib/smux.c, revision 1.1.1.2

1.1       misho       1: /* SNMP support
                      2:  * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
                      3:  *
                      4:  * This file is part of GNU Zebra.
                      5:  *
                      6:  * GNU Zebra is free software; you can redistribute it and/or modify it
                      7:  * under the terms of the GNU General Public License as published by the
                      8:  * Free Software Foundation; either version 2, or (at your option) any
                      9:  * later version.
                     10:  *
                     11:  * GNU Zebra is distributed in the hope that it will be useful, but
                     12:  * WITHOUT ANY WARRANTY; without even the implied warranty of
                     13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     14:  * General Public License for more details.
                     15:  *
                     16:  * You should have received a copy of the GNU General Public License
                     17:  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
                     18:  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
                     19:  * 02111-1307, USA.  
                     20:  */
                     21: 
                     22: #include <zebra.h>
                     23: 
                     24: #ifdef HAVE_SNMP
                     25: #ifdef HAVE_NETSNMP
                     26: #include <net-snmp/net-snmp-config.h>
                     27: #include <net-snmp/net-snmp-includes.h>
                     28: #else
                     29: #include <asn1.h>
                     30: #include <snmp.h>
                     31: #include <snmp_impl.h>
                     32: #endif
                     33: 
                     34: #include "log.h"
                     35: #include "thread.h"
                     36: #include "linklist.h"
                     37: #include "command.h"
                     38: #include <lib/version.h>
                     39: #include "memory.h"
                     40: #include "sockunion.h"
                     41: #include "smux.h"
                     42: 
                     43: #define min(A,B) ((A) < (B) ? (A) : (B))
                     44: 
                     45: enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ};
                     46: 
                     47: void smux_event (enum smux_event, int);
                     48: 
                     49: 
                     50: /* SMUX socket. */
                     51: int smux_sock = -1;
                     52: 
                     53: /* SMUX subtree list. */
                     54: struct list *treelist;
                     55: 
                     56: /* SMUX oid. */
                     57: oid *smux_oid = NULL;
                     58: size_t smux_oid_len;
                     59: 
                     60: /* SMUX password. */
                     61: char *smux_passwd = NULL;
                     62: 
                     63: /* SMUX read threads. */
                     64: struct thread *smux_read_thread;
                     65: 
                     66: /* SMUX connect thrads. */
                     67: struct thread *smux_connect_thread;
                     68: 
                     69: /* SMUX debug flag. */
                     70: int debug_smux = 0;
                     71: 
                     72: /* SMUX failure count. */
                     73: int fail = 0;
                     74: 
                     75: /* SMUX node. */
                     76: static struct cmd_node smux_node =
                     77: {
                     78:   SMUX_NODE,
                     79:   ""                            /* SMUX has no interface. */
                     80: };
                     81: 
                     82: /* thread master */
                     83: static struct thread_master *master;
                     84: 
                     85: void *
                     86: oid_copy (void *dest, const void *src, size_t size)
                     87: {
                     88:   return memcpy (dest, src, size * sizeof (oid));
                     89: }
                     90: 
                     91: void
                     92: oid2in_addr (oid oid[], int len, struct in_addr *addr)
                     93: {
                     94:   int i;
                     95:   u_char *pnt;
                     96:   
                     97:   if (len == 0)
                     98:     return;
                     99: 
                    100:   pnt = (u_char *) addr;
                    101: 
                    102:   for (i = 0; i < len; i++)
                    103:     *pnt++ = oid[i];
                    104: }
                    105: 
                    106: void
                    107: oid_copy_addr (oid oid[], struct in_addr *addr, int len)
                    108: {
                    109:   int i;
                    110:   u_char *pnt;
                    111:   
                    112:   if (len == 0)
                    113:     return;
                    114: 
                    115:   pnt = (u_char *) addr;
                    116: 
                    117:   for (i = 0; i < len; i++)
                    118:     oid[i] = *pnt++;
                    119: }
                    120: 
                    121: int
                    122: oid_compare (oid *o1, int o1_len, oid *o2, int o2_len)
                    123: {
                    124:   int i;
                    125: 
                    126:   for (i = 0; i < min (o1_len, o2_len); i++)
                    127:     {
                    128:       if (o1[i] < o2[i])
                    129:        return -1;
                    130:       else if (o1[i] > o2[i])
                    131:        return 1;
                    132:     }
                    133:   if (o1_len < o2_len)
                    134:     return -1;
                    135:   if (o1_len > o2_len)
                    136:     return 1;
                    137: 
                    138:   return 0;
                    139: }
                    140: 
                    141: static int
                    142: oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
                    143: {
                    144:   int i;
                    145: 
                    146:   for (i = 0; i < min (o1_len, o2_len); i++)
                    147:     {
                    148:       if (o1[i] < o2[i])
                    149:        return -1;
                    150:       else if (o1[i] > o2[i])
                    151:        return 1;
                    152:     }
                    153:   if (o1_len < o2_len)
                    154:     return -1;
                    155: 
                    156:   return 0;
                    157: }
                    158: 
                    159: static void
                    160: smux_oid_dump (const char *prefix, const oid *oid, size_t oid_len)
                    161: {
                    162:   unsigned int i;
                    163:   int first = 1;
                    164:   char buf[MAX_OID_LEN * 3];
                    165: 
                    166:   buf[0] = '\0';
                    167: 
                    168:   for (i = 0; i < oid_len; i++)
                    169:     {
                    170:       sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]);
                    171:       first = 0;
                    172:     }
                    173:   zlog_debug ("%s: %s", prefix, buf);
                    174: }
                    175: 
                    176: static int
                    177: smux_socket (void)
                    178: {
                    179:   int ret;
                    180: #ifdef HAVE_IPV6
                    181:   struct addrinfo hints, *res0, *res;
                    182:   int gai;
                    183: #else
                    184:   struct sockaddr_in serv;
                    185:   struct servent *sp;
                    186: #endif
                    187:   int sock = 0;
                    188: 
                    189: #ifdef HAVE_IPV6
                    190:   memset(&hints, 0, sizeof(hints));
                    191:   hints.ai_family = PF_UNSPEC;
                    192:   hints.ai_socktype = SOCK_STREAM;
                    193:   gai = getaddrinfo(NULL, "smux", &hints, &res0);
                    194:   if (gai == EAI_SERVICE)
                    195:     {
                    196:       char servbuf[NI_MAXSERV];
                    197:       sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
                    198:       servbuf[sizeof (servbuf) - 1] = '\0';
                    199:       gai = getaddrinfo(NULL, servbuf, &hints, &res0);
                    200:     }
                    201:   if (gai)
                    202:     {
                    203:       zlog_warn("Cannot locate loopback service smux");
                    204:       return -1;
                    205:     }
                    206:   for(res=res0; res; res=res->ai_next)
                    207:     {
                    208:       if (res->ai_family != AF_INET 
                    209: #ifdef HAVE_IPV6
                    210:          && res->ai_family != AF_INET6
                    211: #endif /* HAVE_IPV6 */
                    212:          )
                    213:        continue;
                    214: 
                    215:       sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
                    216:       if (sock < 0)
                    217:        continue;
                    218:       sockopt_reuseaddr (sock);
                    219:       sockopt_reuseport (sock);
                    220:       ret = connect (sock, res->ai_addr, res->ai_addrlen);
                    221:       if (ret < 0)
                    222:        {
                    223:          close(sock);
                    224:          sock = -1;
                    225:          continue;
                    226:        }
                    227:       break;
                    228:     }
                    229:   freeaddrinfo(res0);
                    230:   if (sock < 0)
                    231:     zlog_warn ("Can't connect to SNMP agent with SMUX");
                    232: #else
                    233:   sock = socket (AF_INET, SOCK_STREAM, 0);
                    234:   if (sock < 0)
                    235:     {
                    236:       zlog_warn ("Can't make socket for SNMP");
                    237:       return -1;
                    238:     }
                    239: 
                    240:   memset (&serv, 0, sizeof (struct sockaddr_in));
                    241:   serv.sin_family = AF_INET;
                    242: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
                    243:   serv.sin_len = sizeof (struct sockaddr_in);
                    244: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
                    245: 
                    246:   sp = getservbyname ("smux", "tcp");
                    247:   if (sp != NULL) 
                    248:     serv.sin_port = sp->s_port;
                    249:   else
                    250:     serv.sin_port = htons (SMUX_PORT_DEFAULT);
                    251: 
                    252:   serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
                    253: 
                    254:   sockopt_reuseaddr (sock);
                    255:   sockopt_reuseport (sock);
                    256: 
                    257:   ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
                    258:   if (ret < 0)
                    259:     {
                    260:       close (sock);
                    261:       smux_sock = -1;
                    262:       zlog_warn ("Can't connect to SNMP agent with SMUX");
                    263:       return -1;
                    264:     }
                    265: #endif
                    266:   return sock;
                    267: }
                    268: 
                    269: static void
                    270: smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
                    271:                   long errindex, u_char val_type, void *arg, size_t arg_len)
                    272: {
                    273:   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:   
1.1.1.2 ! misho     328:   send (smux_sock, buf, (ptr - buf), 0);
1.1       misho     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;
1.1.1.2 ! misho     948:   const char progname[] = QUAGGA_PROGNAME "-" QUAGGA_VERSION;
1.1       misho     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),
1.1.1.2 ! misho     979:                          (const u_char *) progname, strlen (progname));
1.1       misho     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>