]>
Commit | Line | Data |
---|---|---|
718e3744 | 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 | ||
d6be5fb9 | 24 | #if defined HAVE_SNMP && defined SNMP_SMUX |
07661cb5 | 25 | #include <net-snmp/net-snmp-config.h> |
fb62a3ce | 26 | #include <net-snmp/net-snmp-includes.h> |
718e3744 | 27 | |
718e3744 | 28 | #include "log.h" |
29 | #include "thread.h" | |
30 | #include "linklist.h" | |
31 | #include "command.h" | |
5e4fa164 | 32 | #include <lib/version.h> |
718e3744 | 33 | #include "memory.h" |
34 | #include "sockunion.h" | |
dd488a78 | 35 | #include "smux.h" |
718e3744 | 36 | |
3a4c9688 VB |
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 | ||
718e3744 | 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); | |
6b0655a2 | 81 | |
718e3744 | 82 | |
83 | /* SMUX socket. */ | |
84 | int smux_sock = -1; | |
85 | ||
86 | /* SMUX subtree list. */ | |
87 | struct list *treelist; | |
88 | ||
89 | /* SMUX oid. */ | |
c75105ab | 90 | oid *smux_oid = NULL; |
718e3744 | 91 | size_t smux_oid_len; |
92 | ||
718e3744 | 93 | /* SMUX password. */ |
c75105ab | 94 | char *smux_passwd = NULL; |
718e3744 | 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. */ | |
7fc626de | 109 | static struct cmd_node smux_node = |
718e3744 | 110 | { |
111 | SMUX_NODE, | |
112 | "" /* SMUX has no interface. */ | |
113 | }; | |
dd488a78 | 114 | |
115 | /* thread master */ | |
79159516 | 116 | static struct thread_master *smux_master; |
6b0655a2 | 117 | |
0be8dfb2 | 118 | static int |
718e3744 | 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 | } | |
6b0655a2 | 135 | |
0be8dfb2 | 136 | static void |
65d3fbb4 | 137 | smux_oid_dump (const char *prefix, const oid *oid, size_t oid_len) |
718e3744 | 138 | { |
9035efaa | 139 | unsigned int i; |
718e3744 | 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 | } | |
8ddca704 | 150 | zlog_debug ("%s: %s", prefix, buf); |
718e3744 | 151 | } |
152 | ||
0be8dfb2 | 153 | static int |
65d3fbb4 | 154 | smux_socket (void) |
718e3744 | 155 | { |
156 | int ret; | |
718e3744 | 157 | struct addrinfo hints, *res0, *res; |
158 | int gai; | |
718e3744 | 159 | int sock = 0; |
160 | ||
718e3744 | 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 | |
718e3744 | 180 | && res->ai_family != AF_INET6 |
718e3744 | 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"); | |
718e3744 | 201 | return sock; |
202 | } | |
203 | ||
0be8dfb2 | 204 | static void |
718e3744 | 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 | { | |
718e3744 | 208 | u_char buf[BUFSIZ]; |
209 | u_char *ptr, *h1, *h1e, *h2, *h2e; | |
70e149e0 | 210 | size_t len, length; |
718e3744 | 211 | |
212 | ptr = buf; | |
213 | len = BUFSIZ; | |
214 | length = len; | |
215 | ||
216 | if (debug_smux) | |
217 | { | |
8ddca704 | 218 | zlog_debug ("SMUX GETRSP send"); |
219 | zlog_debug ("SMUX GETRSP reqid: %ld", reqid); | |
718e3744 | 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) | |
8ddca704 | 232 | zlog_debug ("SMUX GETRSP errstat: %ld", errstat); |
718e3744 | 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) | |
8ddca704 | 238 | zlog_debug ("SMUX GETRSP errindex: %ld", errindex); |
718e3744 | 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) | |
0be8dfb2 | 261 | zlog_debug ("SMUX getresp send: %td", (ptr - buf)); |
718e3744 | 262 | |
004b1238 | 263 | send (smux_sock, buf, (ptr - buf), 0); |
718e3744 | 264 | } |
265 | ||
0be8dfb2 CC |
266 | static u_char * |
267 | smux_var (u_char *ptr, size_t len, oid objid[], size_t *objid_len, | |
718e3744 | 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) | |
0be8dfb2 | 278 | zlog_debug ("SMUX var parse: len %zd", len); |
718e3744 | 279 | |
280 | /* Parse header. */ | |
281 | ptr = asn_parse_header (ptr, &len, &type); | |
282 | ||
283 | if (debug_smux) | |
284 | { | |
0be8dfb2 | 285 | zlog_debug ("SMUX var parse: type %d len %zd", type, len); |
8ddca704 | 286 | zlog_debug ("SMUX var parse: type must be %d", |
718e3744 | 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) | |
8ddca704 | 309 | zlog_debug ("SMUX val_type: %d", val_type); |
718e3744 | 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. */ | |
8ddca704 | 318 | zlog_debug ("ASN_NULL"); |
718e3744 | 319 | break; |
320 | ||
321 | case ASN_INTEGER: | |
8ddca704 | 322 | zlog_debug ("ASN_INTEGER"); |
718e3744 | 323 | break; |
324 | case ASN_COUNTER: | |
325 | case ASN_GAUGE: | |
326 | case ASN_TIMETICKS: | |
327 | case ASN_UINTEGER: | |
8ddca704 | 328 | zlog_debug ("ASN_COUNTER"); |
718e3744 | 329 | break; |
330 | case ASN_COUNTER64: | |
8ddca704 | 331 | zlog_debug ("ASN_COUNTER64"); |
718e3744 | 332 | break; |
333 | case ASN_IPADDRESS: | |
8ddca704 | 334 | zlog_debug ("ASN_IPADDRESS"); |
718e3744 | 335 | break; |
336 | case ASN_OCTET_STR: | |
8ddca704 | 337 | zlog_debug ("ASN_OCTET_STR"); |
718e3744 | 338 | break; |
339 | case ASN_OPAQUE: | |
340 | case ASN_NSAP: | |
341 | case ASN_OBJECT_ID: | |
8ddca704 | 342 | zlog_debug ("ASN_OPAQUE"); |
718e3744 | 343 | break; |
344 | case SNMP_NOSUCHOBJECT: | |
8ddca704 | 345 | zlog_debug ("SNMP_NOSUCHOBJECT"); |
718e3744 | 346 | break; |
347 | case SNMP_NOSUCHINSTANCE: | |
8ddca704 | 348 | zlog_debug ("SNMP_NOSUCHINSTANCE"); |
718e3744 | 349 | break; |
350 | case SNMP_ENDOFMIBVIEW: | |
8ddca704 | 351 | zlog_debug ("SNMP_ENDOFMIBVIEW"); |
718e3744 | 352 | break; |
353 | case ASN_BIT_STR: | |
8ddca704 | 354 | zlog_debug ("ASN_BIT_STR"); |
718e3744 | 355 | break; |
356 | default: | |
8ddca704 | 357 | zlog_debug ("Unknown type"); |
718e3744 | 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 | ||
0be8dfb2 | 367 | static int |
718e3744 | 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; | |
70e149e0 | 376 | size_t suffix_len; |
718e3744 | 377 | int result; |
378 | u_char *statP = NULL; | |
379 | WriteMethod *write_method = NULL; | |
1eb8ef25 | 380 | struct listnode *node, *nnode; |
718e3744 | 381 | |
382 | /* Check */ | |
1eb8ef25 | 383 | for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree)) |
718e3744 | 384 | { |
718e3744 | 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) | |
8ddca704 | 409 | zlog_debug ("SMUX function call index is %d", v->magic); |
718e3744 | 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, | |
3a4c9688 | 417 | statP, suffix, suffix_len); |
718e3744 | 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 | ||
0be8dfb2 | 435 | static int |
718e3744 | 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; | |
70e149e0 | 444 | size_t suffix_len; |
718e3744 | 445 | int result; |
446 | WriteMethod *write_method=NULL; | |
1eb8ef25 | 447 | struct listnode *node, *nnode; |
718e3744 | 448 | |
449 | /* Check */ | |
1eb8ef25 | 450 | for (ALL_LIST_ELEMENTS (treelist, node, nnode,subtree)) |
718e3744 | 451 | { |
718e3744 | 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) | |
8ddca704 | 476 | zlog_debug ("SMUX function call index is %d", v->magic); |
718e3744 | 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 | ||
0be8dfb2 | 501 | static int |
718e3744 | 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; | |
70e149e0 | 512 | size_t suffix_len; |
718e3744 | 513 | int result; |
514 | WriteMethod *write_method=NULL; | |
1eb8ef25 | 515 | struct listnode *node, *nnode; |
718e3744 | 516 | |
517 | ||
518 | /* Save incoming request. */ | |
519 | oid_copy (save, reqid, *reqid_len); | |
520 | savelen = *reqid_len; | |
521 | ||
522 | /* Check */ | |
1eb8ef25 | 523 | for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree)) |
718e3744 | 524 | { |
718e3744 | 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) | |
8ddca704 | 562 | zlog_debug ("SMUX function call index is %d", v->magic); |
718e3744 | 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. */ | |
0be8dfb2 CC |
587 | static u_char * |
588 | smux_parse_get_header (u_char *ptr, size_t *len, long *reqid) | |
718e3744 | 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) | |
8ddca704 | 598 | zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len); |
718e3744 | 599 | |
600 | /* Error status. */ | |
601 | ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat)); | |
602 | ||
603 | if (debug_smux) | |
0be8dfb2 | 604 | zlog_debug ("SMUX GET errstat %ld len: %zd", errstat, *len); |
718e3744 | 605 | |
606 | /* Error index. */ | |
607 | ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex)); | |
608 | ||
609 | if (debug_smux) | |
0be8dfb2 | 610 | zlog_debug ("SMUX GET errindex %ld len: %zd", errindex, *len); |
718e3744 | 611 | |
612 | return ptr; | |
613 | } | |
614 | ||
0be8dfb2 CC |
615 | static void |
616 | smux_parse_set (u_char *ptr, size_t len, int action) | |
718e3744 | 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) | |
0be8dfb2 | 627 | zlog_debug ("SMUX SET(%s) message parse: len %zd", |
718e3744 | 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) | |
8ddca704 | 639 | zlog_debug ("SMUX SET ret %d", ret); |
718e3744 | 640 | |
641 | /* Return result. */ | |
642 | if (RESERVE1 == action) | |
643 | smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0); | |
644 | } | |
645 | ||
0be8dfb2 CC |
646 | static void |
647 | smux_parse_get (u_char *ptr, size_t len, int exact) | |
718e3744 | 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) | |
0be8dfb2 | 658 | zlog_debug ("SMUX GET message parse: len %zd", len); |
718e3744 | 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. */ | |
0be8dfb2 CC |
680 | static void |
681 | smux_parse_close (u_char *ptr, int len) | |
718e3744 | 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. */ | |
0be8dfb2 CC |
694 | static void |
695 | smux_parse_rrsp (u_char *ptr, size_t len) | |
718e3744 | 696 | { |
0be8dfb2 | 697 | u_char val; |
718e3744 | 698 | long errstat; |
699 | ||
700 | ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat)); | |
701 | ||
702 | if (debug_smux) | |
8ddca704 | 703 | zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val, errstat); |
718e3744 | 704 | } |
705 | ||
706 | /* Parse SMUX message. */ | |
0be8dfb2 CC |
707 | static int |
708 | smux_parse (u_char *ptr, size_t len) | |
718e3744 | 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) | |
0be8dfb2 | 728 | zlog_debug ("SMUX message received type: %d rest len: %zd", type, len); |
718e3744 | 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) | |
8ddca704 | 745 | zlog_debug ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit"); |
718e3744 | 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) | |
8ddca704 | 780 | zlog_debug ("SMUX_CLOSE"); |
718e3744 | 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) | |
8ddca704 | 787 | zlog_debug ("SMUX_RRSP"); |
718e3744 | 788 | smux_parse_rrsp (ptr, len); |
789 | break; | |
790 | case SMUX_GET: | |
791 | /* Exact request for object id. */ | |
792 | if (debug_smux) | |
8ddca704 | 793 | zlog_debug ("SMUX_GET"); |
718e3744 | 794 | smux_parse_get (ptr, len, 1); |
795 | break; | |
796 | case SMUX_GETNEXT: | |
797 | /* Next request for object id. */ | |
798 | if (debug_smux) | |
8ddca704 | 799 | zlog_debug ("SMUX_GETNEXT"); |
718e3744 | 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) | |
8ddca704 | 805 | zlog_debug ("SMUX_SET"); |
718e3744 | 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. */ | |
0be8dfb2 | 820 | static int |
718e3744 | 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) | |
8ddca704 | 833 | zlog_debug ("SMUX read start"); |
718e3744 | 834 | |
835 | /* Read message from SMUX socket. */ | |
836 | len = recv (sock, buf, SMUXMAXPKTSIZE, 0); | |
837 | ||
838 | if (len < 0) | |
839 | { | |
6099b3b5 | 840 | zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno)); |
718e3744 | 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) | |
8ddca704 | 857 | zlog_debug ("SMUX read len: %d", len); |
718e3744 | 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 | ||
0be8dfb2 | 876 | static int |
718e3744 | 877 | smux_open (int sock) |
878 | { | |
879 | u_char buf[BUFSIZ]; | |
880 | u_char *ptr; | |
70e149e0 | 881 | size_t len; |
0be8dfb2 | 882 | long version; |
b2f36157 | 883 | const char progname[] = FRR_SMUX_NAME "-" FRR_VERSION; |
718e3744 | 884 | |
885 | if (debug_smux) | |
886 | { | |
887 | smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len); | |
8ddca704 | 888 | zlog_debug ("SMUX open progname: %s", progname); |
889 | zlog_debug ("SMUX open password: %s", smux_passwd); | |
718e3744 | 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), | |
965b83f9 | 902 | &version, sizeof (version)); |
718e3744 | 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), | |
004b1238 | 914 | (const u_char *) progname, strlen (progname)); |
718e3744 | 915 | |
916 | /* SMUX connection password. */ | |
917 | ptr = asn_build_string (ptr, &len, | |
918 | (u_char) | |
919 | (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), | |
0be8dfb2 | 920 | (u_char *)smux_passwd, strlen (smux_passwd)); |
718e3744 | 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 | ||
b7c0d065 VB |
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. */ | |
718e3744 | 934 | int |
b7c0d065 VB |
935 | smux_trap (struct variable *vp, size_t vp_len, |
936 | const oid *ename, size_t enamelen, | |
937 | const oid *name, size_t namelen, | |
65d3fbb4 SH |
938 | const oid *iname, size_t inamelen, |
939 | const struct trap_object *trapobj, size_t trapobjlen, | |
4b89e45d | 940 | u_char sptrap) |
718e3744 | 941 | { |
9035efaa | 942 | unsigned int i; |
718e3744 | 943 | u_char buf[BUFSIZ]; |
944 | u_char *ptr; | |
70e149e0 | 945 | size_t len, length; |
718e3744 | 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), | |
965b83f9 | 972 | (u_char *)&addr, sizeof (addr)); |
718e3744 | 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), | |
0be8dfb2 | 978 | (long *)&val, sizeof (val)); |
718e3744 | 979 | |
980 | /* Specific trap integer. */ | |
020709f9 | 981 | val = sptrap; |
718e3744 | 982 | ptr = asn_build_int (ptr, &len, |
983 | (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), | |
0be8dfb2 | 984 | (long *)&val, sizeof (val)); |
718e3744 | 985 | |
986 | /* Timeticks timestamp. */ | |
987 | val = 0; | |
988 | ptr = asn_build_unsigned_int (ptr, &len, | |
989 | (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_TIMETICKS), | |
965b83f9 | 990 | &val, sizeof (val)); |
718e3744 | 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. */ | |
5e4914c3 | 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 | } | |
718e3744 | 1024 | |
5e4914c3 | 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); | |
eda9ba74 | 1037 | zlog_info ("BUFSIZ: %d // oid_len: %lu", BUFSIZ, (u_long)oid_len); |
5e4914c3 | 1038 | } |
718e3744 | 1039 | |
1040 | ret = smux_get (oid, &oid_len, 1, &val_type, &val, &val_len); | |
1041 | ||
1042 | if (debug_smux) | |
8ddca704 | 1043 | zlog_debug ("smux_get result %d", ret); |
718e3744 | 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 | ||
0be8dfb2 | 1062 | static int |
718e3744 | 1063 | smux_register (int sock) |
1064 | { | |
1065 | u_char buf[BUFSIZ]; | |
1066 | u_char *ptr; | |
70e149e0 | 1067 | int ret; |
1068 | size_t len; | |
718e3744 | 1069 | long priority; |
1070 | long operation; | |
1071 | struct subtree *subtree; | |
1eb8ef25 | 1072 | struct listnode *node, *nnode; |
718e3744 | 1073 | |
1074 | ret = 0; | |
1075 | ||
1eb8ef25 | 1076 | for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree)) |
718e3744 | 1077 | { |
1078 | ptr = buf; | |
1079 | len = BUFSIZ; | |
1080 | ||
718e3744 | 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), | |
965b83f9 | 1094 | &priority, sizeof (priority)); |
718e3744 | 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), | |
965b83f9 | 1100 | &operation, sizeof (operation)); |
718e3744 | 1101 | |
1102 | if (debug_smux) | |
1103 | { | |
1104 | smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len); | |
8ddca704 | 1105 | zlog_debug ("SMUX register priority: %ld", priority); |
1106 | zlog_debug ("SMUX register operation: %ld", operation); | |
718e3744 | 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. */ | |
0be8dfb2 | 1119 | static int |
718e3744 | 1120 | smux_connect (struct thread *t) |
1121 | { | |
1122 | int ret; | |
1123 | ||
1124 | if (debug_smux) | |
8ddca704 | 1125 | zlog_debug ("SMUX connect try %d", fail + 1); |
718e3744 | 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 | { | |
6099b3b5 | 1143 | zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno)); |
718e3744 | 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 | { | |
6099b3b5 | 1155 | zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno)); |
718e3744 | 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. */ | |
0be8dfb2 | 1170 | static void |
65d3fbb4 | 1171 | smux_stop (void) |
718e3744 | 1172 | { |
1173 | if (smux_read_thread) | |
a56ef883 PJ |
1174 | { |
1175 | thread_cancel (smux_read_thread); | |
1176 | smux_read_thread = NULL; | |
1177 | } | |
1178 | ||
718e3744 | 1179 | if (smux_connect_thread) |
a56ef883 PJ |
1180 | { |
1181 | thread_cancel (smux_connect_thread); | |
1182 | smux_connect_thread = NULL; | |
1183 | } | |
718e3744 | 1184 | |
1185 | if (smux_sock >= 0) | |
1186 | { | |
1187 | close (smux_sock); | |
1188 | smux_sock = -1; | |
1189 | } | |
1190 | } | |
6b0655a2 | 1191 | |
dd488a78 | 1192 | |
718e3744 | 1193 | |
1194 | void | |
1195 | smux_event (enum smux_event event, int sock) | |
1196 | { | |
1197 | switch (event) | |
1198 | { | |
1199 | case SMUX_SCHEDULE: | |
79159516 | 1200 | smux_connect_thread = thread_add_event (smux_master, smux_connect, NULL, 0); |
718e3744 | 1201 | break; |
1202 | case SMUX_CONNECT: | |
79159516 | 1203 | smux_connect_thread = thread_add_timer (smux_master, smux_connect, NULL, 10); |
718e3744 | 1204 | break; |
1205 | case SMUX_READ: | |
79159516 | 1206 | smux_read_thread = thread_add_read (smux_master, smux_read, NULL, sock); |
718e3744 | 1207 | break; |
1208 | default: | |
1209 | break; | |
1210 | } | |
1211 | } | |
6b0655a2 | 1212 | |
0be8dfb2 | 1213 | static int |
9035efaa | 1214 | smux_str2oid (const char *str, oid *oid, size_t *oid_len) |
718e3744 | 1215 | { |
1216 | int len; | |
1217 | int val; | |
1218 | ||
1219 | len = 0; | |
1220 | val = 0; | |
1221 | *oid_len = 0; | |
1222 | ||
1223 | if (*str == '.') | |
1224 | str++; | |
1225 | if (*str == '\0') | |
1226 | return 0; | |
1227 | ||
1228 | while (1) | |
1229 | { | |
1230 | if (! isdigit (*str)) | |
1231 | return -1; | |
1232 | ||
1233 | while (isdigit (*str)) | |
1234 | { | |
1235 | val *= 10; | |
1236 | val += (*str - '0'); | |
1237 | str++; | |
1238 | } | |
1239 | ||
1240 | if (*str == '\0') | |
1241 | break; | |
1242 | if (*str != '.') | |
1243 | return -1; | |
1244 | ||
1245 | oid[len++] = val; | |
1246 | val = 0; | |
1247 | str++; | |
1248 | } | |
1249 | ||
1250 | oid[len++] = val; | |
1251 | *oid_len = len; | |
1252 | ||
1253 | return 0; | |
1254 | } | |
1255 | ||
0be8dfb2 | 1256 | static oid * |
718e3744 | 1257 | smux_oid_dup (oid *objid, size_t objid_len) |
1258 | { | |
1259 | oid *new; | |
1260 | ||
1261 | new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len); | |
1262 | oid_copy (new, objid, objid_len); | |
1263 | ||
1264 | return new; | |
1265 | } | |
1266 | ||
0be8dfb2 | 1267 | static int |
9035efaa | 1268 | smux_peer_oid (struct vty *vty, const char *oid_str, const char *passwd_str) |
718e3744 | 1269 | { |
1270 | int ret; | |
1271 | oid oid[MAX_OID_LEN]; | |
1272 | size_t oid_len; | |
1273 | ||
1274 | ret = smux_str2oid (oid_str, oid, &oid_len); | |
1275 | if (ret != 0) | |
1276 | { | |
1277 | vty_out (vty, "object ID malformed%s", VTY_NEWLINE); | |
1278 | return CMD_WARNING; | |
1279 | } | |
1280 | ||
c75105ab | 1281 | if (smux_oid) |
1282 | { | |
1283 | free (smux_oid); | |
1284 | smux_oid = NULL; | |
1285 | } | |
718e3744 | 1286 | |
9035efaa | 1287 | /* careful, smux_passwd might point to string constant */ |
c75105ab | 1288 | if (smux_passwd) |
718e3744 | 1289 | { |
1290 | free (smux_passwd); | |
1291 | smux_passwd = NULL; | |
1292 | } | |
1293 | ||
1294 | smux_oid = smux_oid_dup (oid, oid_len); | |
1295 | smux_oid_len = oid_len; | |
1296 | ||
1297 | if (passwd_str) | |
1298 | smux_passwd = strdup (passwd_str); | |
c75105ab | 1299 | else |
1300 | smux_passwd = strdup (""); | |
718e3744 | 1301 | |
c75105ab | 1302 | return 0; |
718e3744 | 1303 | } |
1304 | ||
0be8dfb2 | 1305 | static int |
65d3fbb4 | 1306 | smux_peer_default (void) |
718e3744 | 1307 | { |
c75105ab | 1308 | if (smux_oid) |
718e3744 | 1309 | { |
1310 | free (smux_oid); | |
c75105ab | 1311 | smux_oid = NULL; |
718e3744 | 1312 | } |
9035efaa | 1313 | |
1314 | /* careful, smux_passwd might be pointing at string constant */ | |
c75105ab | 1315 | if (smux_passwd) |
718e3744 | 1316 | { |
1317 | free (smux_passwd); | |
c75105ab | 1318 | smux_passwd = NULL; |
718e3744 | 1319 | } |
c75105ab | 1320 | |
718e3744 | 1321 | return CMD_SUCCESS; |
1322 | } | |
1323 | ||
1324 | DEFUN (smux_peer, | |
1325 | smux_peer_cmd, | |
1326 | "smux peer OID", | |
1327 | "SNMP MUX protocol settings\n" | |
1328 | "SNMP MUX peer settings\n" | |
1329 | "Object ID used in SMUX peering\n") | |
1330 | { | |
c349116d DW |
1331 | int idx_oid = 2; |
1332 | if (smux_peer_oid (vty, argv[idx_oid]->arg, NULL) == 0) | |
c75105ab | 1333 | { |
1334 | smux_start(); | |
1335 | return CMD_SUCCESS; | |
1336 | } | |
1337 | else | |
1338 | return CMD_WARNING; | |
718e3744 | 1339 | } |
1340 | ||
1341 | DEFUN (smux_peer_password, | |
1342 | smux_peer_password_cmd, | |
1343 | "smux peer OID PASSWORD", | |
1344 | "SNMP MUX protocol settings\n" | |
1345 | "SNMP MUX peer settings\n" | |
1346 | "SMUX peering object ID\n" | |
1347 | "SMUX peering password\n") | |
1348 | { | |
c349116d DW |
1349 | int idx_oid = 2; |
1350 | if (smux_peer_oid (vty, argv[idx_oid]->arg, argv[3]->rg) == 0) | |
c75105ab | 1351 | { |
1352 | smux_start(); | |
1353 | return CMD_SUCCESS; | |
1354 | } | |
1355 | else | |
1356 | return CMD_WARNING; | |
718e3744 | 1357 | } |
1358 | ||
1359 | DEFUN (no_smux_peer, | |
1360 | no_smux_peer_cmd, | |
aa1c90a4 | 1361 | "no smux peer [OID [PASSWORD]]", |
718e3744 | 1362 | NO_STR |
1363 | "SNMP MUX protocol settings\n" | |
aa1c90a4 QY |
1364 | "SNMP MUX peer settings\n" |
1365 | "SMUX peering object ID\n" | |
1366 | "SMUX peering password\n") | |
718e3744 | 1367 | { |
c75105ab | 1368 | smux_stop(); |
718e3744 | 1369 | return smux_peer_default (); |
1370 | } | |
1371 | ||
0be8dfb2 | 1372 | static int |
718e3744 | 1373 | config_write_smux (struct vty *vty) |
1374 | { | |
1375 | int first = 1; | |
9035efaa | 1376 | unsigned int i; |
718e3744 | 1377 | |
c75105ab | 1378 | if (smux_oid) |
718e3744 | 1379 | { |
1380 | vty_out (vty, "smux peer "); | |
1381 | for (i = 0; i < smux_oid_len; i++) | |
1382 | { | |
1383 | vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]); | |
1384 | first = 0; | |
1385 | } | |
1386 | vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE); | |
1387 | } | |
1388 | return 0; | |
1389 | } | |
1390 | ||
1391 | /* Register subtree to smux master tree. */ | |
1392 | void | |
c9eca01b | 1393 | smux_register_mib (const char *descr, struct variable *var, |
1394 | size_t width, int num, | |
718e3744 | 1395 | oid name[], size_t namelen) |
1396 | { | |
1397 | struct subtree *tree; | |
1398 | ||
1399 | tree = (struct subtree *)malloc(sizeof(struct subtree)); | |
1400 | oid_copy (tree->name, name, namelen); | |
1401 | tree->name_len = namelen; | |
1402 | tree->variables = var; | |
1403 | tree->variables_num = num; | |
1404 | tree->variables_width = width; | |
1405 | tree->registered = 0; | |
1406 | listnode_add_sort(treelist, tree); | |
1407 | } | |
1408 | ||
718e3744 | 1409 | /* Compare function to keep treelist sorted */ |
1410 | static int | |
1411 | smux_tree_cmp(struct subtree *tree1, struct subtree *tree2) | |
1412 | { | |
1413 | return oid_compare(tree1->name, tree1->name_len, | |
1414 | tree2->name, tree2->name_len); | |
1415 | } | |
1416 | ||
1417 | /* Initialize some values then schedule first SMUX connection. */ | |
1418 | void | |
c75105ab | 1419 | smux_init (struct thread_master *tm) |
718e3744 | 1420 | { |
79159516 | 1421 | assert (tm); |
dd488a78 | 1422 | /* copy callers thread master */ |
79159516 | 1423 | smux_master = tm; |
718e3744 | 1424 | |
1425 | /* Make MIB tree. */ | |
1426 | treelist = list_new(); | |
1427 | treelist->cmp = (int (*)(void *, void *))smux_tree_cmp; | |
1428 | ||
1429 | /* Install commands. */ | |
1430 | install_node (&smux_node, config_write_smux); | |
1431 | ||
1432 | install_element (CONFIG_NODE, &smux_peer_cmd); | |
1433 | install_element (CONFIG_NODE, &smux_peer_password_cmd); | |
1434 | install_element (CONFIG_NODE, &no_smux_peer_cmd); | |
c75105ab | 1435 | install_element (CONFIG_NODE, &no_smux_peer_oid_cmd); |
1436 | install_element (CONFIG_NODE, &no_smux_peer_oid_password_cmd); | |
718e3744 | 1437 | } |
1438 | ||
1439 | void | |
1440 | smux_start(void) | |
1441 | { | |
a56ef883 PJ |
1442 | /* Close any existing connections. */ |
1443 | smux_stop(); | |
1444 | ||
718e3744 | 1445 | /* Schedule first connection. */ |
1446 | smux_event (SMUX_SCHEDULE, 0); | |
1447 | } | |
1448 | #endif /* HAVE_SNMP */ |