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>