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

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

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