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