]> git.proxmox.com Git - mirror_frr.git/blob - lib/smux.c
Merge remote-tracking branch 'origin/stable/3.0'
[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 = NULL;
1201 thread_add_event(smux_master, smux_connect, NULL, 0,
1202 &smux_connect_thread);
1203 break;
1204 case SMUX_CONNECT:
1205 smux_connect_thread = NULL;
1206 thread_add_timer(smux_master, smux_connect, NULL, 10,
1207 &smux_connect_thread);
1208 break;
1209 case SMUX_READ:
1210 smux_read_thread = NULL;
1211 thread_add_read(smux_master, smux_read, NULL, sock, &smux_read_thread);
1212 break;
1213 default:
1214 break;
1215 }
1216 }
1217
1218 static int
1219 smux_str2oid (const char *str, oid *oid, size_t *oid_len)
1220 {
1221 int len;
1222 int val;
1223
1224 len = 0;
1225 val = 0;
1226 *oid_len = 0;
1227
1228 if (*str == '.')
1229 str++;
1230 if (*str == '\0')
1231 return 0;
1232
1233 while (1)
1234 {
1235 if (! isdigit (*str))
1236 return -1;
1237
1238 while (isdigit (*str))
1239 {
1240 val *= 10;
1241 val += (*str - '0');
1242 str++;
1243 }
1244
1245 if (*str == '\0')
1246 break;
1247 if (*str != '.')
1248 return -1;
1249
1250 oid[len++] = val;
1251 val = 0;
1252 str++;
1253 }
1254
1255 oid[len++] = val;
1256 *oid_len = len;
1257
1258 return 0;
1259 }
1260
1261 static oid *
1262 smux_oid_dup (oid *objid, size_t objid_len)
1263 {
1264 oid *new;
1265
1266 new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len);
1267 oid_copy (new, objid, objid_len);
1268
1269 return new;
1270 }
1271
1272 static int
1273 smux_peer_oid (struct vty *vty, const char *oid_str, const char *passwd_str)
1274 {
1275 int ret;
1276 oid oid[MAX_OID_LEN];
1277 size_t oid_len;
1278
1279 ret = smux_str2oid (oid_str, oid, &oid_len);
1280 if (ret != 0)
1281 {
1282 vty_out (vty, "object ID malformed%s", VTY_NEWLINE);
1283 return CMD_WARNING;
1284 }
1285
1286 if (smux_oid)
1287 {
1288 free (smux_oid);
1289 smux_oid = NULL;
1290 }
1291
1292 /* careful, smux_passwd might point to string constant */
1293 if (smux_passwd)
1294 {
1295 free (smux_passwd);
1296 smux_passwd = NULL;
1297 }
1298
1299 smux_oid = smux_oid_dup (oid, oid_len);
1300 smux_oid_len = oid_len;
1301
1302 if (passwd_str)
1303 smux_passwd = strdup (passwd_str);
1304 else
1305 smux_passwd = strdup ("");
1306
1307 return 0;
1308 }
1309
1310 static int
1311 smux_peer_default (void)
1312 {
1313 if (smux_oid)
1314 {
1315 free (smux_oid);
1316 smux_oid = NULL;
1317 }
1318
1319 /* careful, smux_passwd might be pointing at string constant */
1320 if (smux_passwd)
1321 {
1322 free (smux_passwd);
1323 smux_passwd = NULL;
1324 }
1325
1326 return CMD_SUCCESS;
1327 }
1328
1329 DEFUN (smux_peer,
1330 smux_peer_cmd,
1331 "smux peer OID",
1332 "SNMP MUX protocol settings\n"
1333 "SNMP MUX peer settings\n"
1334 "Object ID used in SMUX peering\n")
1335 {
1336 int idx_oid = 2;
1337 if (smux_peer_oid (vty, argv[idx_oid]->arg, NULL) == 0)
1338 {
1339 smux_start();
1340 return CMD_SUCCESS;
1341 }
1342 else
1343 return CMD_WARNING;
1344 }
1345
1346 DEFUN (smux_peer_password,
1347 smux_peer_password_cmd,
1348 "smux peer OID PASSWORD",
1349 "SNMP MUX protocol settings\n"
1350 "SNMP MUX peer settings\n"
1351 "SMUX peering object ID\n"
1352 "SMUX peering password\n")
1353 {
1354 int idx_oid = 2;
1355 if (smux_peer_oid (vty, argv[idx_oid]->arg, argv[3]->rg) == 0)
1356 {
1357 smux_start();
1358 return CMD_SUCCESS;
1359 }
1360 else
1361 return CMD_WARNING;
1362 }
1363
1364 DEFUN (no_smux_peer,
1365 no_smux_peer_cmd,
1366 "no smux peer [OID [PASSWORD]]",
1367 NO_STR
1368 "SNMP MUX protocol settings\n"
1369 "SNMP MUX peer settings\n"
1370 "SMUX peering object ID\n"
1371 "SMUX peering password\n")
1372 {
1373 smux_stop();
1374 return smux_peer_default ();
1375 }
1376
1377 static int
1378 config_write_smux (struct vty *vty)
1379 {
1380 int first = 1;
1381 unsigned int i;
1382
1383 if (smux_oid)
1384 {
1385 vty_out (vty, "smux peer ");
1386 for (i = 0; i < smux_oid_len; i++)
1387 {
1388 vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]);
1389 first = 0;
1390 }
1391 vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE);
1392 }
1393 return 0;
1394 }
1395
1396 /* Register subtree to smux master tree. */
1397 void
1398 smux_register_mib (const char *descr, struct variable *var,
1399 size_t width, int num,
1400 oid name[], size_t namelen)
1401 {
1402 struct subtree *tree;
1403
1404 tree = (struct subtree *)malloc(sizeof(struct subtree));
1405 oid_copy (tree->name, name, namelen);
1406 tree->name_len = namelen;
1407 tree->variables = var;
1408 tree->variables_num = num;
1409 tree->variables_width = width;
1410 tree->registered = 0;
1411 listnode_add_sort(treelist, tree);
1412 }
1413
1414 /* Compare function to keep treelist sorted */
1415 static int
1416 smux_tree_cmp(struct subtree *tree1, struct subtree *tree2)
1417 {
1418 return oid_compare(tree1->name, tree1->name_len,
1419 tree2->name, tree2->name_len);
1420 }
1421
1422 /* Initialize some values then schedule first SMUX connection. */
1423 void
1424 smux_init (struct thread_master *tm)
1425 {
1426 assert (tm);
1427 /* copy callers thread master */
1428 smux_master = tm;
1429
1430 /* Make MIB tree. */
1431 treelist = list_new();
1432 treelist->cmp = (int (*)(void *, void *))smux_tree_cmp;
1433
1434 /* Install commands. */
1435 install_node (&smux_node, config_write_smux);
1436
1437 install_element (CONFIG_NODE, &smux_peer_cmd);
1438 install_element (CONFIG_NODE, &smux_peer_password_cmd);
1439 install_element (CONFIG_NODE, &no_smux_peer_cmd);
1440 install_element (CONFIG_NODE, &no_smux_peer_oid_cmd);
1441 install_element (CONFIG_NODE, &no_smux_peer_oid_password_cmd);
1442 }
1443
1444 void
1445 smux_start(void)
1446 {
1447 /* Close any existing connections. */
1448 smux_stop();
1449
1450 /* Schedule first connection. */
1451 smux_event (SMUX_SCHEDULE, 0);
1452 }
1453 #endif /* SNMP_SMUX */