6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2000,2006 The FreeRADIUS server project
21 * Copyright 1999 Jochen Friedrich <jochen@scram.de>
22 * Copyright 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
25 #include <freeradius-devel/ident.h>
28 #include <freeradius-devel/radiusd.h>
32 #include <freeradius-devel/radius_snmp.h>
33 #include <freeradius-devel/smux.h>
40 #define min(A,B) ((A) < (B) ? (A) : (B))
44 /* internal prototypes */
45 static int oid_compare (oid *, size_t, oid *, size_t);
47 /* SMUX subtree vector. */
48 static struct list *treelist = NULL;
52 static size_t smux_oid_len;
55 oid_copy (void *dest, void *src, size_t size)
57 return memcpy (dest, src, size * sizeof (oid));
62 oid2in_addr (oid my_oid[], int len, struct in_addr *addr)
70 pnt = (u_char *) addr;
72 for (i = 0; i < len; i++)
77 oid_copy_addr (oid my_oid[], struct in_addr *addr, int len)
85 pnt = (u_char *) addr;
87 for (i = 0; i < len; i++)
93 oid_compare (oid *o1, size_t o1_len, oid *o2, size_t o2_len)
97 for (i = 0; i < min (o1_len, o2_len); i++) {
100 else if (o1[i] > o2[i])
112 oid_compare_part (oid *o1, size_t o1_len, oid *o2, size_t o2_len)
116 for (i = 0; i < min (o1_len, o2_len); i++) {
119 else if (o1[i] > o2[i])
129 smux_oid_dump(const char *prefix, oid *my_oid, size_t oid_len)
133 char buf[MAX_OID_LEN * 3];
137 for (i = 0; i < oid_len; i++) {
138 sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) my_oid[i]);
141 DEBUG2 ("SMUX %s: %s", prefix, buf);
150 struct addrinfo hints, *res0, *res;
153 struct sockaddr_in serv;
159 memset(&hints, 0, sizeof(hints));
160 hints.ai_family = PF_UNSPEC;
161 hints.ai_socktype = SOCK_STREAM;
162 gai = getaddrinfo(NULL, "smux", &hints, &res0);
163 if (gai == EAI_SERVICE) {
164 char servbuf[NI_MAXSERV];
165 sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
166 gai = getaddrinfo(NULL, servbuf, &hints, &res0);
169 DEBUG("Cannot locate loopback service smux");
172 for(res=res0; res; res=res->ai_next) {
173 fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
176 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
178 setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
180 ret = connect (fd, res->ai_addr, res->ai_addrlen);
190 DEBUG ("Can't connect to SNMP agent with SMUX");
192 fd = socket (AF_INET, SOCK_STREAM, 0);
194 DEBUG ("Can't make socket for SNMP");
198 memset (&serv, 0, sizeof (struct sockaddr_in));
199 serv.sin_family = AF_INET;
201 serv.sin_len = sizeof (struct sockaddr_in);
202 #endif /* HAVE_SIN_LEN */
204 sp = getservbyname ("smux", "tcp");
206 serv.sin_port = sp->s_port;
208 serv.sin_port = htons (SMUX_PORT_DEFAULT);
210 serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
212 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
214 setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
217 ret = connect (fd, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
220 DEBUG ("Can't connect to SNMP agent with SMUX: %s", strerror(errno));
228 smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
229 long errindex, u_char val_type, void *arg, size_t arg_len)
233 u_char *ptr, *h1, *h1e, *h2, *h2e;
240 DEBUG3("SMUX GETRSP send");
241 DEBUG3("SMUX GETRSP reqid: %ld", reqid);
244 /* Place holder h1 for complete sequence */
245 ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
248 ptr = asn_build_int (ptr, &len,
249 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
250 &reqid, sizeof (reqid));
252 DEBUG3("SMUX GETRSP errstat: %ld", errstat);
254 ptr = asn_build_int (ptr, &len,
255 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
256 &errstat, sizeof (errstat));
257 DEBUG3("SMUX GETRSP errindex: %ld", errindex);
259 ptr = asn_build_int (ptr, &len,
260 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
261 &errindex, sizeof (errindex));
264 /* Place holder h2 for one variable */
265 ptr = asn_build_sequence (ptr, &len,
266 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
270 ptr = snmp_build_var_op (ptr, objid, &objid_len,
271 val_type, arg_len, arg, &len);
273 /* Now variable size is known, fill in size */
274 asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
276 /* Fill in size of whole sequence */
277 asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
279 DEBUG2("SMUX getresp send: %d", ptr - buf);
281 ret = send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
285 smux_var (u_char *ptr, size_t len, oid objid[], size_t *objid_len,
287 u_char *var_val_type,
295 DEBUG3("SMUX var parse: len %d", len);
298 ptr = asn_parse_header (ptr, &len, &type);
300 DEBUG3("SMUX var parse: type %d len %d", type, len);
301 DEBUG3("SMUX var parse: type must be %d", (ASN_SEQUENCE | ASN_CONSTRUCTOR));
303 /* Parse var option. */
304 *objid_len = MAX_OID_LEN;
305 ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
306 &val_len, &val, &len);
309 *var_val_len = val_len;
312 *var_value = (void*) val;
315 *var_val_type = val_type;
317 /* Requested object id length is objid_len. */
318 smux_oid_dump ("Request OID", objid, *objid_len);
320 DEBUG3 ("SMUX val_type: %d", val_type);
322 /* Check request value type. */
325 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
331 DEBUG3 ("ASN_INTEGER");
337 DEBUG3 ("ASN_COUNTER");
340 DEBUG3 ("ASN_COUNTER64");
343 DEBUG3 ("ASN_IPADDRESS");
346 DEBUG3 ("ASN_OCTET_STR");
351 DEBUG3 ("ASN_OPAQUE");
353 case SNMP_NOSUCHOBJECT:
354 DEBUG3 ("SNMP_NOSUCHOBJECT");
356 case SNMP_NOSUCHINSTANCE:
357 DEBUG3 ("SNMP_NOSUCHINSTANCE");
359 case SNMP_ENDOFMIBVIEW:
360 DEBUG3 ("SNMP_ENDOFMIBVIEW");
363 DEBUG3 ("ASN_BIT_STR");
366 DEBUG3 ("Unknown type");
372 /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
373 ucd-snmp smux and as such suppose, that the peer receives in the message
374 only one variable. Fortunately, IBM seems to do the same in AIX. */
377 smux_set (oid *reqid, size_t *reqid_len,
378 u_char val_type, void *val, size_t val_len, int action)
381 struct subtree *subtree;
388 const unsigned char *statP = NULL;
389 WriteMethod *write_method = NULL;
391 if (!rad_snmp.snmp_write_access)
392 return SNMP_ERR_NOSUCHNAME;
395 for (l = treelist; l; l=l->next) {
397 subresult = oid_compare_part (reqid, *reqid_len,
398 subtree->name, subtree->name_len);
400 /* Subtree matched. */
401 if (subresult == 0) {
402 /* Prepare suffix. */
403 suffix = reqid + subtree->name_len;
404 suffix_len = *reqid_len - subtree->name_len;
407 /* Check variables. */
408 for (j = 0; j < subtree->variables_num; j++) {
409 v = &subtree->variables[j];
411 /* Always check suffix */
412 result = oid_compare_part (suffix, suffix_len,
413 v->name, v->namelen);
415 /* This is exact match so result must be zero. */
417 DEBUG3 ("SMUX function call index is %d", v->magic);
419 statP = (*v->findVar) (v, suffix, &suffix_len, 1,
420 &val_len, &write_method);
423 return (*write_method)(action, val, val_type, val_len, statP, suffix, suffix_len);
426 return SNMP_ERR_READONLY;
430 /* If above execution is failed or oid is small (so
431 there is no further match). */
433 return SNMP_ERR_NOSUCHNAME;
437 return SNMP_ERR_NOSUCHNAME;
441 smux_get (oid *reqid, size_t *reqid_len, int exact,
442 u_char *val_type,u_char **val, size_t *val_len)
445 struct subtree *subtree;
452 WriteMethod *write_method=NULL;
455 for (l = treelist; l; l=l->next) {
457 subresult = oid_compare_part (reqid, *reqid_len,
458 subtree->name, subtree->name_len);
460 /* Subtree matched. */
461 if (subresult == 0) {
462 /* Prepare suffix. */
463 suffix = reqid + subtree->name_len;
464 suffix_len = *reqid_len - subtree->name_len;
467 /* Check variables. */
468 for (j = 0; j < subtree->variables_num; j++) {
469 v = &subtree->variables[j];
471 /* Always check suffix */
472 result = oid_compare_part (suffix, suffix_len,
473 v->name, v->namelen);
475 /* This is exact match so result must be zero. */
477 DEBUG3 ("SMUX function call index is %d", v->magic);
479 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
480 val_len, &write_method);
481 /* There is no instance. */
483 return SNMP_ERR_NOSUCHNAME;
485 /* Call is suceed. */
491 /* If above execution is failed or oid is small (so
492 there is no further match). */
494 return SNMP_ERR_NOSUCHNAME;
498 return SNMP_ERR_NOSUCHNAME;
502 smux_getnext (oid *reqid, size_t *reqid_len, int exact,
503 u_char *val_type, u_char **val, size_t *val_len)
506 oid save[MAX_OID_LEN];
508 struct subtree *subtree;
515 WriteMethod *write_method=NULL;
517 /* Save incoming request. */
518 oid_copy (save, reqid, *reqid_len);
519 savelen = *reqid_len;
521 /* Check for best matching subtree */
523 for (l = treelist; l; l=l->next) {
526 subresult = oid_compare_part (reqid, *reqid_len,
527 subtree->name, subtree->name_len);
529 /* If request is in the tree. The agent has to make sure we
530 only receive requests we have registered for. */
531 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
532 behave as if it manages the whole SNMP MIB tree itself. It's the
533 duty of the master agent to collect the best answer and return it
534 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
535 :-). ucd-snmp really behaves bad here as it actually might ask
536 multiple times for the same GETNEXT request as it throws away the
537 answer when it expects it in a different subtree and might come
538 back later with the very same request. --jochen */
540 if (subresult <= 0) {
541 /* Prepare suffix. */
542 suffix = reqid + subtree->name_len;
543 suffix_len = *reqid_len - subtree->name_len;
545 oid_copy(reqid, subtree->name, subtree->name_len);
546 *reqid_len = subtree->name_len;
548 for (j = 0; j < subtree->variables_num; j++) {
550 v = &subtree->variables[j];
552 /* Next then check result >= 0. */
554 result = oid_compare_part (suffix, suffix_len,
555 v->name, v->namelen);
558 DEBUG3 ("SMUX function call index is %d", v->magic);
560 oid_copy(suffix, v->name, v->namelen);
561 suffix_len = v->namelen;
563 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
564 val_len, &write_method);
565 *reqid_len = suffix_len + subtree->name_len;
574 memcpy (reqid, save, savelen * sizeof(oid));
575 *reqid_len = savelen;
577 return SNMP_ERR_NOSUCHNAME;
580 /* GET message header. */
582 smux_parse_get_header (u_char *ptr, size_t *len, long *reqid)
589 ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
591 DEBUG3 ("SMUX GET reqid: %ld len: %d", *reqid, (int) *len);
594 ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
596 DEBUG3 ("SMUX GET errstat %ld len: %d", errstat, *len);
599 ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
601 DEBUG3 ("SMUX GET errindex %ld len: %d", errindex, *len);
607 smux_parse_set (u_char *ptr, size_t len, int action)
610 oid my_oid[MAX_OID_LEN];
617 DEBUG3 ("SMUX SET(%s) message parse: len %d",
618 (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
621 /* Parse SET message header. */
622 ptr = smux_parse_get_header (ptr, &len, &reqid);
624 /* Parse SET message object ID. */
625 ptr = smux_var (ptr, len, my_oid, &oid_len, &val_len, &val_type, &val);
627 ret = smux_set (my_oid, &oid_len, val_type, val, val_len, action);
628 DEBUG2 ("SMUX SET ret %d", ret);
631 if (RESERVE1 == action)
632 smux_getresp_send (my_oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
636 smux_parse_get (u_char *ptr, size_t len, int exact)
639 oid my_oid[MAX_OID_LEN];
646 DEBUG3 ("SMUX GET message parse: len %d", len);
648 /* Parse GET message header. */
649 ptr = smux_parse_get_header (ptr, &len, &reqid);
651 /* Parse GET message object ID. We needn't the value come */
652 ptr = smux_var (ptr, len, my_oid, &oid_len, NULL, NULL, NULL);
654 /* Traditional getstatptr. */
656 ret = smux_get (my_oid, &oid_len, exact, &val_type, &val, &val_len);
658 ret = smux_getnext (my_oid, &oid_len, exact, &val_type, &val, &val_len);
662 smux_getresp_send (my_oid, oid_len, reqid, 0, 0, val_type, val, val_len);
664 smux_getresp_send (my_oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
667 /* Parse SMUX_CLOSE message. */
669 smux_parse_close (u_char *ptr, size_t len)
674 reason = (reason << 8) | (long) *ptr;
677 DEBUG ("SMUX_CLOSE with reason: %ld", reason);
680 /* SMUX_RRSP message. */
682 smux_parse_rrsp (u_char *ptr, size_t len)
687 ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
689 DEBUG3 ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
692 /* Parse SMUX message. */
694 smux_parse (u_char *ptr, size_t len)
696 /* this buffer we'll use for SOUT message. We could allocate it with malloc and
697 save only static pointer/lenght, but IMHO static buffer is a faster solusion */
698 static u_char sout_save_buff[SMUXMAXPKTSIZE];
699 static size_t sout_save_len = 0;
701 int len_income = len; /* see note below: YYY */
705 rollback = ptr[2]; /* important only for SMUX_SOUT */
707 process_rest: /* see note below: YYY */
709 /* Parse SMUX message type and subsequent length. */
710 ptr = asn_parse_header (ptr, &len, &type);
712 DEBUG2 ("SMUX message received type: %d rest len: %d", type, len);
716 /* Open must be not send from SNMP agent. */
717 DEBUG ("SMUX_OPEN received: resetting connection.");
721 /* SMUX_RREQ message is invalid for us. */
722 DEBUG ("SMUX_RREQ received: resetting connection.");
726 /* SMUX_SOUT message is now valied for us. */
727 DEBUG2 ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
729 if (sout_save_len > 0) {
730 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
733 DEBUG ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
735 if (len_income > 3) {
736 /* YYY: this strange code has to solve the "slow peer"
737 problem: When agent sends SMUX_SOUT message it doesn't
738 wait any responce and may send some next message to
739 subagent. Then the peer in 'smux_read()' will recieve
740 from socket the 'concatenated' buffer, contaning both
741 SMUX_SOUT message and the next one
742 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
743 the buffer is longer than 3 ( length of SMUX_SOUT ), we
744 must process the rest of it. This effect may be observed
745 if DEBUG is set to >1 */
747 len = len_income - 3;
752 /* SMUX_GETRSP message is invalid for us. */
753 DEBUG ("SMUX_GETRSP received: resetting connection.");
757 /* Close SMUX connection. */
758 DEBUG3 ("SMUX_CLOSE");
759 smux_parse_close (ptr, len);
763 /* This is response for register message. */
764 DEBUG3 ("SMUX_RRSP");
765 smux_parse_rrsp (ptr, len);
768 /* Exact request for object id. */
770 smux_parse_get (ptr, len, 1);
773 /* Next request for object id. */
774 DEBUG3 ("SMUX_GETNEXT");
775 smux_parse_get (ptr, len, 0);
778 /* SMUX_SET is supported with some limitations. */
780 /* save the data for future SMUX_SOUT */
781 memcpy (sout_save_buff, ptr, len);
783 smux_parse_set (ptr, len, RESERVE1);
786 DEBUG ("SMUX Unknown type: %d", type);
792 /* SMUX message read function. */
797 u_char buf[SMUXMAXPKTSIZE];
800 rad_snmp.smux_event=SMUX_NONE;
801 DEBUG3 ("SMUX read start");
803 /* Read message from SMUX socket. */
804 len = recv (rad_snmp.smux_fd, buf, SMUXMAXPKTSIZE, 0);
807 DEBUG ("Can't read all SMUX packet: %s", strerror (errno));
808 close (rad_snmp.smux_fd);
809 rad_snmp.smux_fd = -1;
810 rad_snmp.smux_event=SMUX_CONNECT;
815 DEBUG ("SMUX connection closed: %d", rad_snmp.smux_fd);
816 close (rad_snmp.smux_fd);
817 rad_snmp.smux_fd = -1;
818 rad_snmp.smux_event=SMUX_CONNECT;
822 DEBUG3 ("SMUX read len: %d", len);
824 /* Parse the message. */
825 ret = smux_parse (buf, len);
828 close (rad_snmp.smux_fd);
829 rad_snmp.smux_fd = -1;
830 rad_snmp.smux_event=SMUX_CONNECT;
834 rad_snmp.smux_event=SMUX_READ;
845 long smux_proto_version;
846 char rad_progname[] = "radiusd";
848 smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
849 DEBUG2 ("SMUX open progname: %s", rad_progname);
850 DEBUG2 ("SMUX open password: %s", rad_snmp.smux_password);
855 /* SMUX Header. As placeholder. */
856 ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
859 smux_proto_version = 0;
860 ptr = asn_build_int (ptr, &len,
861 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
862 &smux_proto_version, sizeof (u_long));
864 /* SMUX connection oid. */
865 ptr = asn_build_objid (ptr, &len,
867 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
868 smux_oid, smux_oid_len);
870 /* SMUX connection description. */
871 ptr = asn_build_string (ptr, &len,
873 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
874 (u_char *) rad_progname, strlen(rad_progname));
876 /* SMUX connection password. */
877 ptr = asn_build_string (ptr, &len,
879 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
880 (const u_char *) rad_snmp.smux_password, strlen(rad_snmp.smux_password));
882 /* Fill in real SMUX header. We exclude ASN header size (2). */
884 asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
886 return send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
898 struct subtree *subtree;
903 for (l = treelist; l; l=l->next) {
909 /* SMUX RReq Header. */
910 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
912 /* Register MIB tree. */
913 ptr = asn_build_objid (ptr, &len,
915 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
916 subtree->name, subtree->name_len);
920 ptr = asn_build_int (ptr, &len,
921 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
922 &priority, sizeof (u_long));
925 operation = rad_snmp.snmp_write_access ? 2 : 1; /* Register R/O or R/W */
926 ptr = asn_build_int (ptr, &len,
927 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
928 &operation, sizeof (u_long));
930 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
931 DEBUG2 ("SMUX register priority: %ld", priority);
932 DEBUG2 ("SMUX register operation: %ld", operation);
935 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
936 ret = send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
944 /* Try to connect to SNMP agent. */
950 rad_snmp.smux_event=SMUX_NONE;
951 DEBUG2 ("SMUX connect try %d", rad_snmp.smux_failures + 1);
953 /* Make socket. Try to connect. */
954 rad_snmp.smux_fd = smux_sock ();
955 if (rad_snmp.smux_fd < 0) {
956 if (++rad_snmp.smux_failures < rad_snmp.smux_max_failures)
957 rad_snmp.smux_event=SMUX_CONNECT;
964 DEBUG ("SMUX open message send failed: %s", strerror (errno));
965 close (rad_snmp.smux_fd);
966 rad_snmp.smux_fd = -1;
967 rad_snmp.smux_event=SMUX_CONNECT;
971 /* Send any outstanding register PDUs. */
972 ret = smux_register ();
974 DEBUG ("SMUX register message send failed: %s", strerror (errno));
975 close (rad_snmp.smux_fd);
976 rad_snmp.smux_fd = -1;
977 rad_snmp.smux_event=SMUX_CONNECT;
981 /* Everything goes fine. */
982 rad_snmp.smux_event=SMUX_READ;
987 /* Clear all SMUX related resources. */
991 rad_snmp.smux_event=SMUX_NONE;
992 if (rad_snmp.smux_fd >= 0)
993 close (rad_snmp.smux_fd);
994 rad_snmp.smux_fd = -1;
998 smux_str2oid (char *str, oid *my_oid, size_t *oid_len)
1013 if (! isdigit ((int) *str))
1016 while (isdigit ((int) *str)) {
1018 val += (*str - '0');
1027 my_oid[len++] = val;
1032 my_oid[len++] = val;
1039 smux_oid_dup (oid *objid, size_t objid_len)
1043 new = (oid *)rad_malloc(sizeof (oid) * objid_len);
1044 oid_copy (new, objid, objid_len);
1050 smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
1051 size_t *var_len, WriteMethod **write_method)
1053 oid fulloid[MAX_OID_LEN];
1056 oid_copy (fulloid, v->name, v->namelen);
1057 fulloid[v->namelen] = 0;
1058 /* Check against full instance. */
1059 ret = oid_compare (name, *length, fulloid, v->namelen + 1);
1061 /* Check single instance. */
1062 if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
1063 return MATCH_FAILED;
1065 /* In case of getnext, fill in full instance. */
1066 memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
1067 *length = v->namelen + 1;
1070 *var_len = sizeof(long); /* default to 'long' results */
1072 return MATCH_SUCCEEDED;
1075 /* Initialize some values then schedule first SMUX connection. */
1077 smux_init (oid defoid[], size_t defoid_len)
1080 smux_oid_len = defoid_len;
1083 /* Register subtree to smux master tree. */
1085 smux_register_mib(UNUSED const char *descr, struct variable *var, size_t width,
1086 int num, oid name[], size_t namelen)
1088 struct subtree *tree, *tt;
1089 struct list *l, *ll;
1091 tree = (struct subtree *)rad_malloc(sizeof(struct subtree));
1092 oid_copy (tree->name, name, namelen);
1093 tree->name_len = namelen;
1094 tree->variables = var;
1095 tree->variables_num = num;
1096 tree->variables_width = width;
1097 tree->registered = 0;
1098 l = (struct list *)rad_malloc(sizeof(struct list));
1101 /* Build a treelist sorted by the name. This makes GETNEXT simpler */
1102 if (treelist == NULL) {
1106 tt = (struct subtree*) treelist->data;
1107 if (oid_compare(name, namelen, tt->name, tt->name_len) < 0) {
1112 for (ll = treelist; ll->next; ll=ll->next) {
1113 tt = (struct subtree*) ll->next->data;
1114 if (oid_compare(name, namelen, tt->name, tt->name_len) < 0) {
1126 rad_snmp.smux_event=SMUX_CONNECT;
1129 #endif /* WITH_SNMP */