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