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

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

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