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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Copyright 2000 The FreeRADIUS server project
21 * Copyright 1999 Jochen Friedrich <jochen@scram.de>
22 * Copyright 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
25 static const char rcsid[] =
32 #include "libradius.h"
34 #include <sys/socket.h>
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
49 #include "radius_snmp.h"
52 #define min(A,B) ((A) < (B) ? (A) : (B))
56 /* internal prototypes */
57 static int oid_compare (oid *, int, oid *, int);
59 /* SMUX subtree vector. */
60 static struct list *treelist = NULL;
64 static size_t smux_oid_len;
67 oid_copy (void *dest, void *src, size_t size)
69 return memcpy (dest, src, size * sizeof (oid));
74 oid2in_addr (oid my_oid[], int len, struct in_addr *addr)
82 pnt = (u_char *) addr;
84 for (i = 0; i < len; i++)
89 oid_copy_addr (oid my_oid[], struct in_addr *addr, int len)
97 pnt = (u_char *) addr;
99 for (i = 0; i < len; i++)
102 #endif /* NOT USED */
105 oid_compare (oid *o1, int o1_len, oid *o2, int o2_len)
109 for (i = 0; i < min (o1_len, o2_len); i++) {
112 else if (o1[i] > o2[i])
124 oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
128 for (i = 0; i < min (o1_len, o2_len); i++) {
131 else if (o1[i] > o2[i])
141 smux_oid_dump(const char *prefix, oid *my_oid, size_t oid_len)
145 char buf[MAX_OID_LEN * 3];
149 for (i = 0; i < oid_len; i++) {
150 sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) my_oid[i]);
153 DEBUG2 ("%s: %s", prefix, buf);
162 struct addrinfo hints, *res0, *res;
165 struct sockaddr_in serv;
171 memset(&hints, 0, sizeof(hints));
172 hints.ai_family = PF_UNSPEC;
173 hints.ai_socktype = SOCK_STREAM;
174 gai = getaddrinfo(NULL, "smux", &hints, &res0);
175 if (gai == EAI_SERVICE) {
176 char servbuf[NI_MAXSERV];
177 sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
178 gai = getaddrinfo(NULL, servbuf, &hints, &res0);
181 DEBUG("Cannot locate loopback service smux");
184 for(res=res0; res; res=res->ai_next) {
185 fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
188 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
190 setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
192 ret = connect (fd, res->ai_addr, res->ai_addrlen);
202 DEBUG ("Can't connect to SNMP agent with SMUX");
204 fd = socket (AF_INET, SOCK_STREAM, 0);
206 DEBUG ("Can't make socket for SNMP");
210 memset (&serv, 0, sizeof (struct sockaddr_in));
211 serv.sin_family = AF_INET;
213 serv.sin_len = sizeof (struct sockaddr_in);
214 #endif /* HAVE_SIN_LEN */
216 sp = getservbyname ("smux", "tcp");
218 serv.sin_port = sp->s_port;
220 serv.sin_port = htons (SMUX_PORT_DEFAULT);
222 serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
224 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
226 setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
229 ret = connect (fd, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
232 DEBUG ("Can't connect to SNMP agent with SMUX: %s", strerror(errno));
240 smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
241 long errindex, u_char val_type, const void *arg, size_t arg_len)
245 u_char *ptr, *h1, *h1e, *h2, *h2e;
252 DEBUG2("SMUX GETRSP send");
253 DEBUG2("SMUX GETRSP reqid: %ld", reqid);
256 /* Place holder h1 for complete sequence */
257 ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
260 ptr = asn_build_int (ptr, &len,
261 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
262 &reqid, sizeof (reqid));
264 DEBUG2("SMUX GETRSP errstat: %ld", errstat);
266 ptr = asn_build_int (ptr, &len,
267 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
268 &errstat, sizeof (errstat));
269 DEBUG2("SMUX GETRSP errindex: %ld", errindex);
271 ptr = asn_build_int (ptr, &len,
272 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
273 &errindex, sizeof (errindex));
276 /* Place holder h2 for one variable */
277 ptr = asn_build_sequence (ptr, &len,
278 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
282 ptr = snmp_build_var_op (ptr, objid, &objid_len,
283 val_type, arg_len, arg, &len);
285 /* Now variable size is known, fill in size */
286 asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
288 /* Fill in size of whole sequence */
289 asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
291 DEBUG2("SMUX getresp send: %d", ptr - buf);
293 ret = send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
297 smux_var (char *ptr, int len, oid objid[], size_t *objid_len,
299 u_char *var_val_type,
307 DEBUG2("SMUX var parse: len %d", len);
310 ptr = asn_parse_header (ptr, &len, &type);
312 DEBUG2("SMUX var parse: type %d len %d", type, len);
313 DEBUG2("SMUX var parse: type must be %d", (ASN_SEQUENCE | ASN_CONSTRUCTOR));
315 /* Parse var option. */
316 *objid_len = MAX_OID_LEN;
317 ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
318 &val_len, &val, &len);
321 *var_val_len = val_len;
324 *var_value = (void*) val;
327 *var_val_type = val_type;
329 /* Requested object id length is objid_len. */
330 smux_oid_dump ("Request OID", objid, *objid_len);
332 DEBUG2 ("SMUX val_type: %d", val_type);
334 /* Check request value type. */
337 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
343 DEBUG2 ("ASN_INTEGER");
349 DEBUG2 ("ASN_COUNTER");
352 DEBUG2 ("ASN_COUNTER64");
355 DEBUG2 ("ASN_IPADDRESS");
358 DEBUG2 ("ASN_OCTET_STR");
363 DEBUG2 ("ASN_OPAQUE");
365 case SNMP_NOSUCHOBJECT:
366 DEBUG2 ("SNMP_NOSUCHOBJECT");
368 case SNMP_NOSUCHINSTANCE:
369 DEBUG2 ("SNMP_NOSUCHINSTANCE");
371 case SNMP_ENDOFMIBVIEW:
372 DEBUG2 ("SNMP_ENDOFMIBVIEW");
375 DEBUG2 ("ASN_BIT_STR");
378 DEBUG2 ("Unknown type");
384 /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
385 ucd-snmp smux and as such suppose, that the peer receives in the message
386 only one variable. Fortunately, IBM seems to do the same in AIX. */
389 smux_set (oid *reqid, size_t *reqid_len,
390 u_char val_type, void *val, size_t val_len, int action)
393 struct subtree *subtree;
400 const unsigned char *statP = NULL;
401 WriteMethod *write_method = NULL;
403 if (!rad_snmp.snmp_write_access)
404 return SNMP_ERR_NOSUCHNAME;
407 for (l = treelist; l; l=l->next) {
409 subresult = oid_compare_part (reqid, *reqid_len,
410 subtree->name, subtree->name_len);
412 /* Subtree matched. */
413 if (subresult == 0) {
414 /* Prepare suffix. */
415 suffix = reqid + subtree->name_len;
416 suffix_len = *reqid_len - subtree->name_len;
419 /* Check variables. */
420 for (j = 0; j < subtree->variables_num; j++) {
421 v = &subtree->variables[j];
423 /* Always check suffix */
424 result = oid_compare_part (suffix, suffix_len,
425 v->name, v->namelen);
427 /* This is exact match so result must be zero. */
429 DEBUG2 ("SMUX function call index is %d", v->magic);
431 statP = (*v->findVar) (v, suffix, &suffix_len, 1,
432 &val_len, &write_method);
435 return (*write_method)(action, val, val_type, val_len, statP, suffix, suffix_len);
438 return SNMP_ERR_READONLY;
442 /* If above execution is failed or oid is small (so
443 there is no further match). */
445 return SNMP_ERR_NOSUCHNAME;
449 return SNMP_ERR_NOSUCHNAME;
453 smux_get (oid *reqid, size_t *reqid_len, int exact,
454 u_char *val_type,const void **val, size_t *val_len)
457 struct subtree *subtree;
464 WriteMethod *write_method=NULL;
467 for (l = treelist; l; l=l->next) {
469 subresult = oid_compare_part (reqid, *reqid_len,
470 subtree->name, subtree->name_len);
472 /* Subtree matched. */
473 if (subresult == 0) {
474 /* Prepare suffix. */
475 suffix = reqid + subtree->name_len;
476 suffix_len = *reqid_len - subtree->name_len;
479 /* Check variables. */
480 for (j = 0; j < subtree->variables_num; j++) {
481 v = &subtree->variables[j];
483 /* Always check suffix */
484 result = oid_compare_part (suffix, suffix_len,
485 v->name, v->namelen);
487 /* This is exact match so result must be zero. */
489 DEBUG2 ("SMUX function call index is %d", v->magic);
491 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
492 val_len, &write_method);
494 /* There is no instance. */
496 return SNMP_ERR_NOSUCHNAME;
498 /* Call is suceed. */
504 /* If above execution is failed or oid is small (so
505 there is no further match). */
507 return SNMP_ERR_NOSUCHNAME;
511 return SNMP_ERR_NOSUCHNAME;
515 smux_getnext (oid *reqid, size_t *reqid_len, int exact,
516 u_char *val_type, const void **val, size_t *val_len)
519 oid save[MAX_OID_LEN];
521 struct subtree *subtree;
528 WriteMethod *write_method=NULL;
530 /* Save incoming request. */
531 oid_copy (save, reqid, *reqid_len);
532 savelen = *reqid_len;
534 /* Check for best matching subtree */
536 for (l = treelist; l; l=l->next) {
539 subresult = oid_compare_part (reqid, *reqid_len,
540 subtree->name, subtree->name_len);
542 /* If request is in the tree. The agent has to make sure we
543 only receive requests we have registered for. */
544 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
545 behave as if it manages the whole SNMP MIB tree itself. It's the
546 duty of the master agent to collect the best answer and return it
547 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
548 :-). ucd-snmp really behaves bad here as it actually might ask
549 multiple times for the same GETNEXT request as it throws away the
550 answer when it expects it in a different subtree and might come
551 back later with the very same request. --jochen */
553 if (subresult <= 0) {
554 /* Prepare suffix. */
555 suffix = reqid + subtree->name_len;
556 suffix_len = *reqid_len - subtree->name_len;
558 oid_copy(reqid, subtree->name, subtree->name_len);
559 *reqid_len = subtree->name_len;
561 for (j = 0; j < subtree->variables_num; j++) {
563 v = &subtree->variables[j];
565 /* Next then check result >= 0. */
567 result = oid_compare_part (suffix, suffix_len,
568 v->name, v->namelen);
571 DEBUG2 ("SMUX function call index is %d", v->magic);
573 oid_copy(suffix, v->name, v->namelen);
574 suffix_len = v->namelen;
576 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
577 val_len, &write_method);
578 *reqid_len = suffix_len + subtree->name_len;
587 memcpy (reqid, save, savelen * sizeof(oid));
588 *reqid_len = savelen;
590 return SNMP_ERR_NOSUCHNAME;
593 /* GET message header. */
595 smux_parse_get_header (char *ptr, size_t *len, long *reqid)
602 ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
604 DEBUG2 ("SMUX GET reqid: %ld len: %d", *reqid, (int) *len);
607 ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
609 DEBUG2 ("SMUX GET errstat %ld len: %d", errstat, *len);
612 ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
614 DEBUG2 ("SMUX GET errindex %ld len: %d", errindex, *len);
620 smux_parse_set (char *ptr, size_t len, int action)
623 oid my_oid[MAX_OID_LEN];
630 DEBUG2 ("SMUX SET(%s) message parse: len %d",
631 (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
634 /* Parse SET message header. */
635 ptr = smux_parse_get_header (ptr, &len, &reqid);
637 /* Parse SET message object ID. */
638 ptr = smux_var (ptr, len, my_oid, &oid_len, &val_len, &val_type, &val);
640 ret = smux_set (my_oid, &oid_len, val_type, val, val_len, action);
641 DEBUG2 ("SMUX SET ret %d", ret);
644 if (RESERVE1 == action)
645 smux_getresp_send (my_oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
649 smux_parse_get (char *ptr, size_t len, int exact)
652 oid my_oid[MAX_OID_LEN];
659 DEBUG2 ("SMUX GET message parse: len %d", len);
661 /* Parse GET message header. */
662 ptr = smux_parse_get_header (ptr, &len, &reqid);
664 /* Parse GET message object ID. We needn't the value come */
665 ptr = smux_var (ptr, len, my_oid, &oid_len, NULL, NULL, NULL);
667 /* Traditional getstatptr. */
669 ret = smux_get (my_oid, &oid_len, exact, &val_type, &val, &val_len);
671 ret = smux_getnext (my_oid, &oid_len, exact, &val_type, &val, &val_len);
675 smux_getresp_send (my_oid, oid_len, reqid, 0, 0, val_type, val, val_len);
677 smux_getresp_send (my_oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
680 /* Parse SMUX_CLOSE message. */
682 smux_parse_close (char *ptr, int len)
687 reason = (reason << 8) | (long) *ptr;
690 DEBUG ("SMUX_CLOSE with reason: %ld", reason);
693 /* SMUX_RRSP message. */
695 smux_parse_rrsp (char *ptr, int len)
700 ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
702 DEBUG2 ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
705 /* Parse SMUX message. */
707 smux_parse (char *ptr, int len)
709 /* this buffer we'll use for SOUT message. We could allocate it with malloc and
710 save only static pointer/lenght, but IMHO static buffer is a faster solusion */
711 static u_char sout_save_buff[SMUXMAXPKTSIZE];
712 static int sout_save_len = 0;
714 int len_income = len; /* see note below: YYY */
718 rollback = ptr[2]; /* important only for SMUX_SOUT */
720 process_rest: /* see note below: YYY */
722 /* Parse SMUX message type and subsequent length. */
723 ptr = asn_parse_header (ptr, &len, &type);
725 DEBUG2 ("SMUX message received type: %d rest len: %d", type, len);
729 /* Open must be not send from SNMP agent. */
730 DEBUG ("SMUX_OPEN received: resetting connection.");
734 /* SMUX_RREQ message is invalid for us. */
735 DEBUG ("SMUX_RREQ received: resetting connection.");
739 /* SMUX_SOUT message is now valied for us. */
740 DEBUG2 ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
742 if (sout_save_len > 0) {
743 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
746 DEBUG ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
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 doesn't
751 wait any responce and may send some next message to
752 subagent. Then the peer in 'smux_read()' will recieve
753 from socket the 'concatenated' buffer, contaning both
754 SMUX_SOUT message and the next one
755 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
756 the buffer is longer than 3 ( length of SMUX_SOUT ), we
757 must process the rest of it. This effect may be observed
758 if DEBUG is set to >1 */
760 len = len_income - 3;
765 /* SMUX_GETRSP message is invalid for us. */
766 DEBUG ("SMUX_GETRSP received: resetting connection.");
770 /* Close SMUX connection. */
771 DEBUG2 ("SMUX_CLOSE");
772 smux_parse_close (ptr, len);
776 /* This is response for register message. */
777 DEBUG2 ("SMUX_RRSP");
778 smux_parse_rrsp (ptr, len);
781 /* Exact request for object id. */
783 smux_parse_get (ptr, len, 1);
786 /* Next request for object id. */
787 DEBUG2 ("SMUX_GETNEXT");
788 smux_parse_get (ptr, len, 0);
791 /* SMUX_SET is supported with some limitations. */
793 /* save the data for future SMUX_SOUT */
794 memcpy (sout_save_buff, ptr, len);
796 smux_parse_set (ptr, len, RESERVE1);
799 DEBUG ("Unknown type: %d", type);
805 /* SMUX message read function. */
810 u_char buf[SMUXMAXPKTSIZE];
813 rad_snmp.smux_event=SMUX_NONE;
814 DEBUG2 ("SMUX read start");
816 /* Read message from SMUX socket. */
817 len = recv (rad_snmp.smux_fd, buf, SMUXMAXPKTSIZE, 0);
820 DEBUG ("Can't read all SMUX packet: %s", strerror (errno));
821 close (rad_snmp.smux_fd);
822 rad_snmp.smux_fd = -1;
823 rad_snmp.smux_event=SMUX_CONNECT;
828 DEBUG ("SMUX connection closed: %d", rad_snmp.smux_fd);
829 close (rad_snmp.smux_fd);
830 rad_snmp.smux_fd = -1;
831 rad_snmp.smux_event=SMUX_CONNECT;
835 DEBUG2 ("SMUX read len: %d", len);
837 /* Parse the message. */
838 ret = smux_parse (buf, len);
841 close (rad_snmp.smux_fd);
842 rad_snmp.smux_fd = -1;
843 rad_snmp.smux_event=SMUX_CONNECT;
847 rad_snmp.smux_event=SMUX_READ;
858 u_long smux_proto_version;
859 u_char rad_progname[] = "radiusd";
861 smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
862 DEBUG2 ("SMUX open progname: %s", rad_progname);
863 DEBUG2 ("SMUX open password: %s", rad_snmp.smux_password);
868 /* SMUX Header. As placeholder. */
869 ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
872 smux_proto_version = 0;
873 ptr = asn_build_int (ptr, &len,
874 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
875 &smux_proto_version, sizeof (u_long));
877 /* SMUX connection oid. */
878 ptr = asn_build_objid (ptr, &len,
880 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
881 smux_oid, smux_oid_len);
883 /* SMUX connection description. */
884 ptr = asn_build_string (ptr, &len,
886 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
887 rad_progname, strlen (rad_progname));
889 /* SMUX connection password. */
890 ptr = asn_build_string (ptr, &len,
892 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
893 rad_snmp.smux_password, strlen(rad_snmp.smux_password));
895 /* Fill in real SMUX header. We exclude ASN header size (2). */
897 asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
899 return send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
910 struct subtree *subtree;
915 for (l = treelist; l; l=l->next) {
921 /* SMUX RReq Header. */
922 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
924 /* Register MIB tree. */
925 ptr = asn_build_objid (ptr, &len,
927 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
928 subtree->name, subtree->name_len);
932 ptr = asn_build_int (ptr, &len,
933 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
934 &priority, sizeof (u_long));
937 operation = rad_snmp.snmp_write_access ? 2 : 1; /* Register R/O or R/W */
938 ptr = asn_build_int (ptr, &len,
939 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
940 &operation, sizeof (u_long));
942 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
943 DEBUG2 ("SMUX register priority: %ld", priority);
944 DEBUG2 ("SMUX register operation: %ld", operation);
947 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
948 ret = send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
955 /* Try to connect to SNMP agent. */
961 rad_snmp.smux_event=SMUX_NONE;
962 DEBUG2 ("SMUX connect try %d", rad_snmp.smux_failures + 1);
964 /* Make socket. Try to connect. */
965 rad_snmp.smux_fd = smux_sock ();
966 if (rad_snmp.smux_fd < 0) {
967 if (++rad_snmp.smux_failures < rad_snmp.smux_max_failures)
968 rad_snmp.smux_event=SMUX_CONNECT;
975 DEBUG ("SMUX open message send failed: %s", strerror (errno));
976 close (rad_snmp.smux_fd);
977 rad_snmp.smux_fd = -1;
978 rad_snmp.smux_event=SMUX_CONNECT;
982 /* Send any outstanding register PDUs. */
983 ret = smux_register ();
985 DEBUG ("SMUX register message send failed: %s", strerror (errno));
986 close (rad_snmp.smux_fd);
987 rad_snmp.smux_fd = -1;
988 rad_snmp.smux_event=SMUX_CONNECT;
992 /* Everything goes fine. */
993 rad_snmp.smux_event=SMUX_READ;
998 /* Clear all SMUX related resources. */
1002 rad_snmp.smux_event=SMUX_NONE;
1003 if (rad_snmp.smux_fd >= 0)
1004 close (rad_snmp.smux_fd);
1005 rad_snmp.smux_fd = -1;
1009 smux_str2oid (char *str, oid *my_oid, size_t *oid_len)
1024 if (! isdigit ((int) *str))
1027 while (isdigit ((int) *str)) {
1029 val += (*str - '0');
1038 my_oid[len++] = val;
1043 my_oid[len++] = val;
1050 smux_oid_dup (oid *objid, size_t objid_len)
1054 new = (oid *)rad_malloc(sizeof (oid) * objid_len);
1055 oid_copy (new, objid, objid_len);
1061 smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
1062 size_t *var_len, WriteMethod **write_method)
1064 oid fulloid[MAX_OID_LEN];
1067 oid_copy (fulloid, v->name, v->namelen);
1068 fulloid[v->namelen] = 0;
1069 /* Check against full instance. */
1070 ret = oid_compare (name, *length, fulloid, v->namelen + 1);
1072 /* Check single instance. */
1073 if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
1074 return MATCH_FAILED;
1076 /* In case of getnext, fill in full instance. */
1077 memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
1078 *length = v->namelen + 1;
1081 *var_len = sizeof(long); /* default to 'long' results */
1083 return MATCH_SUCCEEDED;
1086 /* Initialize some values then schedule first SMUX connection. */
1088 smux_init (oid defoid[], size_t defoid_len)
1091 smux_oid_len = defoid_len;
1094 /* Register subtree to smux master tree. */
1096 smux_register_mib(const char *descr, struct variable *var, size_t width,
1097 int num, oid name[], size_t namelen)
1099 struct subtree *tree, *tt;
1100 struct list *l, *ll;
1102 tree = (struct subtree *)rad_malloc(sizeof(struct subtree));
1103 oid_copy (tree->name, name, namelen);
1104 tree->name_len = namelen;
1105 tree->variables = var;
1106 tree->variables_num = num;
1107 tree->variables_width = width;
1108 tree->registered = 0;
1109 l = (struct list *)rad_malloc(sizeof(struct list));
1112 /* Build a treelist sorted by the name. This makes GETNEXT simpler */
1113 if (treelist == NULL) {
1117 tt = (struct subtree*) treelist->data;
1118 if (oid_compare(name, namelen, tt->name, tt->name_len) < 0) {
1123 for (ll = treelist; ll->next; ll=ll->next) {
1124 tt = (struct subtree*) ll->next->data;
1125 if (oid_compare(name, namelen, tt->name, tt->name_len) < 0) {
1137 rad_snmp.smux_event=SMUX_CONNECT;
1140 #endif /* WITH_SNMP */