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>
27 #include <freeradius-devel/ident.h>
30 #include <freeradius-devel/autoconf.h>
33 #include <sys/socket.h>
36 #ifdef HAVE_NETINET_IN_H
37 #include <netinet/in.h>
47 #include <freeradius-devel/radiusd.h>
48 #include <freeradius-devel/radius_snmp.h>
49 #include <freeradius-devel/smux.h>
51 #define min(A,B) ((A) < (B) ? (A) : (B))
55 /* internal prototypes */
56 static int oid_compare (oid *, int, oid *, int);
58 /* SMUX subtree vector. */
59 static struct list *treelist = NULL;
63 static size_t smux_oid_len;
66 oid_copy (void *dest, void *src, size_t size)
68 return memcpy (dest, src, size * sizeof (oid));
73 oid2in_addr (oid my_oid[], int len, struct in_addr *addr)
81 pnt = (u_char *) addr;
83 for (i = 0; i < len; i++)
88 oid_copy_addr (oid my_oid[], struct in_addr *addr, int len)
96 pnt = (u_char *) addr;
98 for (i = 0; i < len; i++)
101 #endif /* NOT USED */
104 oid_compare (oid *o1, int o1_len, oid *o2, int o2_len)
108 for (i = 0; i < min (o1_len, o2_len); i++) {
111 else if (o1[i] > o2[i])
123 oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
127 for (i = 0; i < min (o1_len, o2_len); i++) {
130 else if (o1[i] > o2[i])
140 smux_oid_dump(const char *prefix, oid *my_oid, size_t oid_len)
144 char buf[MAX_OID_LEN * 3];
148 for (i = 0; i < oid_len; i++) {
149 sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) my_oid[i]);
152 DEBUG2 ("%s: %s", prefix, buf);
161 struct addrinfo hints, *res0, *res;
164 struct sockaddr_in serv;
170 memset(&hints, 0, sizeof(hints));
171 hints.ai_family = PF_UNSPEC;
172 hints.ai_socktype = SOCK_STREAM;
173 gai = getaddrinfo(NULL, "smux", &hints, &res0);
174 if (gai == EAI_SERVICE) {
175 char servbuf[NI_MAXSERV];
176 sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
177 gai = getaddrinfo(NULL, servbuf, &hints, &res0);
180 DEBUG("Cannot locate loopback service smux");
183 for(res=res0; res; res=res->ai_next) {
184 fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
187 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
189 setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
191 ret = connect (fd, res->ai_addr, res->ai_addrlen);
201 DEBUG ("Can't connect to SNMP agent with SMUX");
203 fd = socket (AF_INET, SOCK_STREAM, 0);
205 DEBUG ("Can't make socket for SNMP");
209 memset (&serv, 0, sizeof (struct sockaddr_in));
210 serv.sin_family = AF_INET;
212 serv.sin_len = sizeof (struct sockaddr_in);
213 #endif /* HAVE_SIN_LEN */
215 sp = getservbyname ("smux", "tcp");
217 serv.sin_port = sp->s_port;
219 serv.sin_port = htons (SMUX_PORT_DEFAULT);
221 serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
223 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
225 setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
228 ret = connect (fd, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
231 DEBUG ("Can't connect to SNMP agent with SMUX: %s", strerror(errno));
239 smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
240 long errindex, u_char val_type, const void *arg, size_t arg_len)
244 u_char *ptr, *h1, *h1e, *h2, *h2e;
251 DEBUG2("SMUX GETRSP send");
252 DEBUG2("SMUX GETRSP reqid: %ld", reqid);
255 /* Place holder h1 for complete sequence */
256 ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
259 ptr = asn_build_int (ptr, &len,
260 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
261 &reqid, sizeof (reqid));
263 DEBUG2("SMUX GETRSP errstat: %ld", errstat);
265 ptr = asn_build_int (ptr, &len,
266 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
267 &errstat, sizeof (errstat));
268 DEBUG2("SMUX GETRSP errindex: %ld", errindex);
270 ptr = asn_build_int (ptr, &len,
271 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
272 &errindex, sizeof (errindex));
275 /* Place holder h2 for one variable */
276 ptr = asn_build_sequence (ptr, &len,
277 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
281 ptr = snmp_build_var_op (ptr, objid, &objid_len,
282 val_type, arg_len, arg, &len);
284 /* Now variable size is known, fill in size */
285 asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
287 /* Fill in size of whole sequence */
288 asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
290 DEBUG2("SMUX getresp send: %d", ptr - buf);
292 ret = send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
296 smux_var (char *ptr, int len, oid objid[], size_t *objid_len,
298 u_char *var_val_type,
306 DEBUG2("SMUX var parse: len %d", len);
309 ptr = asn_parse_header (ptr, &len, &type);
311 DEBUG2("SMUX var parse: type %d len %d", type, len);
312 DEBUG2("SMUX var parse: type must be %d", (ASN_SEQUENCE | ASN_CONSTRUCTOR));
314 /* Parse var option. */
315 *objid_len = MAX_OID_LEN;
316 ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
317 &val_len, &val, &len);
320 *var_val_len = val_len;
323 *var_value = (void*) val;
326 *var_val_type = val_type;
328 /* Requested object id length is objid_len. */
329 smux_oid_dump ("Request OID", objid, *objid_len);
331 DEBUG2 ("SMUX val_type: %d", val_type);
333 /* Check request value type. */
336 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
342 DEBUG2 ("ASN_INTEGER");
348 DEBUG2 ("ASN_COUNTER");
351 DEBUG2 ("ASN_COUNTER64");
354 DEBUG2 ("ASN_IPADDRESS");
357 DEBUG2 ("ASN_OCTET_STR");
362 DEBUG2 ("ASN_OPAQUE");
364 case SNMP_NOSUCHOBJECT:
365 DEBUG2 ("SNMP_NOSUCHOBJECT");
367 case SNMP_NOSUCHINSTANCE:
368 DEBUG2 ("SNMP_NOSUCHINSTANCE");
370 case SNMP_ENDOFMIBVIEW:
371 DEBUG2 ("SNMP_ENDOFMIBVIEW");
374 DEBUG2 ("ASN_BIT_STR");
377 DEBUG2 ("Unknown type");
383 /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
384 ucd-snmp smux and as such suppose, that the peer receives in the message
385 only one variable. Fortunately, IBM seems to do the same in AIX. */
388 smux_set (oid *reqid, size_t *reqid_len,
389 u_char val_type, void *val, size_t val_len, int action)
392 struct subtree *subtree;
399 const unsigned char *statP = NULL;
400 WriteMethod *write_method = NULL;
402 if (!rad_snmp.snmp_write_access)
403 return SNMP_ERR_NOSUCHNAME;
406 for (l = treelist; l; l=l->next) {
408 subresult = oid_compare_part (reqid, *reqid_len,
409 subtree->name, subtree->name_len);
411 /* Subtree matched. */
412 if (subresult == 0) {
413 /* Prepare suffix. */
414 suffix = reqid + subtree->name_len;
415 suffix_len = *reqid_len - subtree->name_len;
418 /* Check variables. */
419 for (j = 0; j < subtree->variables_num; j++) {
420 v = &subtree->variables[j];
422 /* Always check suffix */
423 result = oid_compare_part (suffix, suffix_len,
424 v->name, v->namelen);
426 /* This is exact match so result must be zero. */
428 DEBUG2 ("SMUX function call index is %d", v->magic);
430 statP = (*v->findVar) (v, suffix, &suffix_len, 1,
431 &val_len, &write_method);
434 return (*write_method)(action, val, val_type, val_len, statP, suffix, suffix_len);
437 return SNMP_ERR_READONLY;
441 /* If above execution is failed or oid is small (so
442 there is no further match). */
444 return SNMP_ERR_NOSUCHNAME;
448 return SNMP_ERR_NOSUCHNAME;
452 smux_get (oid *reqid, size_t *reqid_len, int exact,
453 u_char *val_type,const void **val, size_t *val_len)
456 struct subtree *subtree;
463 WriteMethod *write_method=NULL;
466 for (l = treelist; l; l=l->next) {
468 subresult = oid_compare_part (reqid, *reqid_len,
469 subtree->name, subtree->name_len);
471 /* Subtree matched. */
472 if (subresult == 0) {
473 /* Prepare suffix. */
474 suffix = reqid + subtree->name_len;
475 suffix_len = *reqid_len - subtree->name_len;
478 /* Check variables. */
479 for (j = 0; j < subtree->variables_num; j++) {
480 v = &subtree->variables[j];
482 /* Always check suffix */
483 result = oid_compare_part (suffix, suffix_len,
484 v->name, v->namelen);
486 /* This is exact match so result must be zero. */
488 DEBUG2 ("SMUX function call index is %d", v->magic);
490 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
491 val_len, &write_method);
493 /* There is no instance. */
495 return SNMP_ERR_NOSUCHNAME;
497 /* Call is suceed. */
503 /* If above execution is failed or oid is small (so
504 there is no further match). */
506 return SNMP_ERR_NOSUCHNAME;
510 return SNMP_ERR_NOSUCHNAME;
514 smux_getnext (oid *reqid, size_t *reqid_len, int exact,
515 u_char *val_type, const void **val, size_t *val_len)
518 oid save[MAX_OID_LEN];
520 struct subtree *subtree;
527 WriteMethod *write_method=NULL;
529 /* Save incoming request. */
530 oid_copy (save, reqid, *reqid_len);
531 savelen = *reqid_len;
533 /* Check for best matching subtree */
535 for (l = treelist; l; l=l->next) {
538 subresult = oid_compare_part (reqid, *reqid_len,
539 subtree->name, subtree->name_len);
541 /* If request is in the tree. The agent has to make sure we
542 only receive requests we have registered for. */
543 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
544 behave as if it manages the whole SNMP MIB tree itself. It's the
545 duty of the master agent to collect the best answer and return it
546 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
547 :-). ucd-snmp really behaves bad here as it actually might ask
548 multiple times for the same GETNEXT request as it throws away the
549 answer when it expects it in a different subtree and might come
550 back later with the very same request. --jochen */
552 if (subresult <= 0) {
553 /* Prepare suffix. */
554 suffix = reqid + subtree->name_len;
555 suffix_len = *reqid_len - subtree->name_len;
557 oid_copy(reqid, subtree->name, subtree->name_len);
558 *reqid_len = subtree->name_len;
560 for (j = 0; j < subtree->variables_num; j++) {
562 v = &subtree->variables[j];
564 /* Next then check result >= 0. */
566 result = oid_compare_part (suffix, suffix_len,
567 v->name, v->namelen);
570 DEBUG2 ("SMUX function call index is %d", v->magic);
572 oid_copy(suffix, v->name, v->namelen);
573 suffix_len = v->namelen;
575 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
576 val_len, &write_method);
577 *reqid_len = suffix_len + subtree->name_len;
586 memcpy (reqid, save, savelen * sizeof(oid));
587 *reqid_len = savelen;
589 return SNMP_ERR_NOSUCHNAME;
592 /* GET message header. */
594 smux_parse_get_header (char *ptr, size_t *len, long *reqid)
601 ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
603 DEBUG2 ("SMUX GET reqid: %ld len: %d", *reqid, (int) *len);
606 ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
608 DEBUG2 ("SMUX GET errstat %ld len: %d", errstat, *len);
611 ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
613 DEBUG2 ("SMUX GET errindex %ld len: %d", errindex, *len);
619 smux_parse_set (char *ptr, size_t len, int action)
622 oid my_oid[MAX_OID_LEN];
629 DEBUG2 ("SMUX SET(%s) message parse: len %d",
630 (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
633 /* Parse SET message header. */
634 ptr = smux_parse_get_header (ptr, &len, &reqid);
636 /* Parse SET message object ID. */
637 ptr = smux_var (ptr, len, my_oid, &oid_len, &val_len, &val_type, &val);
639 ret = smux_set (my_oid, &oid_len, val_type, val, val_len, action);
640 DEBUG2 ("SMUX SET ret %d", ret);
643 if (RESERVE1 == action)
644 smux_getresp_send (my_oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
648 smux_parse_get (char *ptr, size_t len, int exact)
651 oid my_oid[MAX_OID_LEN];
658 DEBUG2 ("SMUX GET message parse: len %d", len);
660 /* Parse GET message header. */
661 ptr = smux_parse_get_header (ptr, &len, &reqid);
663 /* Parse GET message object ID. We needn't the value come */
664 ptr = smux_var (ptr, len, my_oid, &oid_len, NULL, NULL, NULL);
666 /* Traditional getstatptr. */
668 ret = smux_get (my_oid, &oid_len, exact, &val_type, &val, &val_len);
670 ret = smux_getnext (my_oid, &oid_len, exact, &val_type, &val, &val_len);
674 smux_getresp_send (my_oid, oid_len, reqid, 0, 0, val_type, val, val_len);
676 smux_getresp_send (my_oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
679 /* Parse SMUX_CLOSE message. */
681 smux_parse_close (char *ptr, int len)
686 reason = (reason << 8) | (long) *ptr;
689 DEBUG ("SMUX_CLOSE with reason: %ld", reason);
692 /* SMUX_RRSP message. */
694 smux_parse_rrsp (char *ptr, int len)
699 ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
701 DEBUG2 ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
704 /* Parse SMUX message. */
706 smux_parse (char *ptr, int len)
708 /* this buffer we'll use for SOUT message. We could allocate it with malloc and
709 save only static pointer/lenght, but IMHO static buffer is a faster solusion */
710 static u_char sout_save_buff[SMUXMAXPKTSIZE];
711 static int sout_save_len = 0;
713 int len_income = len; /* see note below: YYY */
717 rollback = ptr[2]; /* important only for SMUX_SOUT */
719 process_rest: /* see note below: YYY */
721 /* Parse SMUX message type and subsequent length. */
722 ptr = asn_parse_header (ptr, &len, &type);
724 DEBUG2 ("SMUX message received type: %d rest len: %d", type, len);
728 /* Open must be not send from SNMP agent. */
729 DEBUG ("SMUX_OPEN received: resetting connection.");
733 /* SMUX_RREQ message is invalid for us. */
734 DEBUG ("SMUX_RREQ received: resetting connection.");
738 /* SMUX_SOUT message is now valied for us. */
739 DEBUG2 ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
741 if (sout_save_len > 0) {
742 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
745 DEBUG ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
747 if (len_income > 3) {
748 /* YYY: this strange code has to solve the "slow peer"
749 problem: When agent sends SMUX_SOUT message it doesn't
750 wait any responce and may send some next message to
751 subagent. Then the peer in 'smux_read()' will recieve
752 from socket the 'concatenated' buffer, contaning both
753 SMUX_SOUT message and the next one
754 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
755 the buffer is longer than 3 ( length of SMUX_SOUT ), we
756 must process the rest of it. This effect may be observed
757 if DEBUG is set to >1 */
759 len = len_income - 3;
764 /* SMUX_GETRSP message is invalid for us. */
765 DEBUG ("SMUX_GETRSP received: resetting connection.");
769 /* Close SMUX connection. */
770 DEBUG2 ("SMUX_CLOSE");
771 smux_parse_close (ptr, len);
775 /* This is response for register message. */
776 DEBUG2 ("SMUX_RRSP");
777 smux_parse_rrsp (ptr, len);
780 /* Exact request for object id. */
782 smux_parse_get (ptr, len, 1);
785 /* Next request for object id. */
786 DEBUG2 ("SMUX_GETNEXT");
787 smux_parse_get (ptr, len, 0);
790 /* SMUX_SET is supported with some limitations. */
792 /* save the data for future SMUX_SOUT */
793 memcpy (sout_save_buff, ptr, len);
795 smux_parse_set (ptr, len, RESERVE1);
798 DEBUG ("Unknown type: %d", type);
804 /* SMUX message read function. */
809 u_char buf[SMUXMAXPKTSIZE];
812 rad_snmp.smux_event=SMUX_NONE;
813 DEBUG2 ("SMUX read start");
815 /* Read message from SMUX socket. */
816 len = recv (rad_snmp.smux_fd, buf, SMUXMAXPKTSIZE, 0);
819 DEBUG ("Can't read all SMUX packet: %s", strerror (errno));
820 close (rad_snmp.smux_fd);
821 rad_snmp.smux_fd = -1;
822 rad_snmp.smux_event=SMUX_CONNECT;
827 DEBUG ("SMUX connection closed: %d", rad_snmp.smux_fd);
828 close (rad_snmp.smux_fd);
829 rad_snmp.smux_fd = -1;
830 rad_snmp.smux_event=SMUX_CONNECT;
834 DEBUG2 ("SMUX read len: %d", len);
836 /* Parse the message. */
837 ret = smux_parse (buf, len);
840 close (rad_snmp.smux_fd);
841 rad_snmp.smux_fd = -1;
842 rad_snmp.smux_event=SMUX_CONNECT;
846 rad_snmp.smux_event=SMUX_READ;
857 u_long smux_proto_version;
858 u_char rad_progname[] = "radiusd";
860 smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
861 DEBUG2 ("SMUX open progname: %s", rad_progname);
862 DEBUG2 ("SMUX open password: %s", rad_snmp.smux_password);
867 /* SMUX Header. As placeholder. */
868 ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
871 smux_proto_version = 0;
872 ptr = asn_build_int (ptr, &len,
873 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
874 &smux_proto_version, sizeof (u_long));
876 /* SMUX connection oid. */
877 ptr = asn_build_objid (ptr, &len,
879 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
880 smux_oid, smux_oid_len);
882 /* SMUX connection description. */
883 ptr = asn_build_string (ptr, &len,
885 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
886 rad_progname, strlen (rad_progname));
888 /* SMUX connection password. */
889 ptr = asn_build_string (ptr, &len,
891 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
892 rad_snmp.smux_password, strlen(rad_snmp.smux_password));
894 /* Fill in real SMUX header. We exclude ASN header size (2). */
896 asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
898 return send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
909 struct subtree *subtree;
914 for (l = treelist; l; l=l->next) {
920 /* SMUX RReq Header. */
921 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
923 /* Register MIB tree. */
924 ptr = asn_build_objid (ptr, &len,
926 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
927 subtree->name, subtree->name_len);
931 ptr = asn_build_int (ptr, &len,
932 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
933 &priority, sizeof (u_long));
936 operation = rad_snmp.snmp_write_access ? 2 : 1; /* Register R/O or R/W */
937 ptr = asn_build_int (ptr, &len,
938 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
939 &operation, sizeof (u_long));
941 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
942 DEBUG2 ("SMUX register priority: %ld", priority);
943 DEBUG2 ("SMUX register operation: %ld", operation);
946 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
947 ret = send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
954 /* Try to connect to SNMP agent. */
960 rad_snmp.smux_event=SMUX_NONE;
961 DEBUG2 ("SMUX connect try %d", rad_snmp.smux_failures + 1);
963 /* Make socket. Try to connect. */
964 rad_snmp.smux_fd = smux_sock ();
965 if (rad_snmp.smux_fd < 0) {
966 if (++rad_snmp.smux_failures < rad_snmp.smux_max_failures)
967 rad_snmp.smux_event=SMUX_CONNECT;
974 DEBUG ("SMUX open 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 /* Send any outstanding register PDUs. */
982 ret = smux_register ();
984 DEBUG ("SMUX register message send failed: %s", strerror (errno));
985 close (rad_snmp.smux_fd);
986 rad_snmp.smux_fd = -1;
987 rad_snmp.smux_event=SMUX_CONNECT;
991 /* Everything goes fine. */
992 rad_snmp.smux_event=SMUX_READ;
997 /* Clear all SMUX related resources. */
1001 rad_snmp.smux_event=SMUX_NONE;
1002 if (rad_snmp.smux_fd >= 0)
1003 close (rad_snmp.smux_fd);
1004 rad_snmp.smux_fd = -1;
1008 smux_str2oid (char *str, oid *my_oid, size_t *oid_len)
1023 if (! isdigit ((int) *str))
1026 while (isdigit ((int) *str)) {
1028 val += (*str - '0');
1037 my_oid[len++] = val;
1042 my_oid[len++] = val;
1049 smux_oid_dup (oid *objid, size_t objid_len)
1053 new = (oid *)rad_malloc(sizeof (oid) * objid_len);
1054 oid_copy (new, objid, objid_len);
1060 smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
1061 size_t *var_len, WriteMethod **write_method)
1063 oid fulloid[MAX_OID_LEN];
1066 oid_copy (fulloid, v->name, v->namelen);
1067 fulloid[v->namelen] = 0;
1068 /* Check against full instance. */
1069 ret = oid_compare (name, *length, fulloid, v->namelen + 1);
1071 /* Check single instance. */
1072 if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
1073 return MATCH_FAILED;
1075 /* In case of getnext, fill in full instance. */
1076 memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
1077 *length = v->namelen + 1;
1080 *var_len = sizeof(long); /* default to 'long' results */
1082 return MATCH_SUCCEEDED;
1085 /* Initialize some values then schedule first SMUX connection. */
1087 smux_init (oid defoid[], size_t defoid_len)
1090 smux_oid_len = defoid_len;
1093 /* Register subtree to smux master tree. */
1095 smux_register_mib(UNUSED const char *descr, struct variable *var, size_t width,
1096 int num, oid name[], size_t namelen)
1098 struct subtree *tree, *tt;
1099 struct list *l, *ll;
1101 tree = (struct subtree *)rad_malloc(sizeof(struct subtree));
1102 oid_copy (tree->name, name, namelen);
1103 tree->name_len = namelen;
1104 tree->variables = var;
1105 tree->variables_num = num;
1106 tree->variables_width = width;
1107 tree->registered = 0;
1108 l = (struct list *)rad_malloc(sizeof(struct list));
1111 /* Build a treelist sorted by the name. This makes GETNEXT simpler */
1112 if (treelist == NULL) {
1116 tt = (struct subtree*) treelist->data;
1117 if (oid_compare(name, namelen, tt->name, tt->name_len) < 0) {
1122 for (ll = treelist; ll->next; ll=ll->next) {
1123 tt = (struct subtree*) ll->next->data;
1124 if (oid_compare(name, namelen, tt->name, tt->name_len) < 0) {
1136 rad_snmp.smux_event=SMUX_CONNECT;
1139 #endif /* WITH_SNMP */