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