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