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[] =
28 #include <freeradius-devel/autoconf.h>
32 #include <sys/socket.h>
35 #ifdef HAVE_NETINET_IN_H
36 #include <netinet/in.h>
46 #include <freeradius-devel/radiusd.h>
47 #include <freeradius-devel/radius_snmp.h>
48 #include <freeradius-devel/smux.h>
50 #define min(A,B) ((A) < (B) ? (A) : (B))
54 /* internal prototypes */
55 static int oid_compare (oid *, int, oid *, int);
57 /* SMUX subtree vector. */
58 static struct list *treelist = NULL;
62 static size_t smux_oid_len;
65 oid_copy (void *dest, void *src, size_t size)
67 return memcpy (dest, src, size * sizeof (oid));
72 oid2in_addr (oid my_oid[], int len, struct in_addr *addr)
80 pnt = (u_char *) addr;
82 for (i = 0; i < len; i++)
87 oid_copy_addr (oid my_oid[], struct in_addr *addr, int len)
95 pnt = (u_char *) addr;
97 for (i = 0; i < len; i++)
100 #endif /* NOT USED */
103 oid_compare (oid *o1, int o1_len, oid *o2, int o2_len)
107 for (i = 0; i < min (o1_len, o2_len); i++) {
110 else if (o1[i] > o2[i])
122 oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
126 for (i = 0; i < min (o1_len, o2_len); i++) {
129 else if (o1[i] > o2[i])
139 smux_oid_dump(const char *prefix, oid *my_oid, size_t oid_len)
143 char buf[MAX_OID_LEN * 3];
147 for (i = 0; i < oid_len; i++) {
148 sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) my_oid[i]);
151 DEBUG2 ("%s: %s", prefix, buf);
160 struct addrinfo hints, *res0, *res;
163 struct sockaddr_in serv;
169 memset(&hints, 0, sizeof(hints));
170 hints.ai_family = PF_UNSPEC;
171 hints.ai_socktype = SOCK_STREAM;
172 gai = getaddrinfo(NULL, "smux", &hints, &res0);
173 if (gai == EAI_SERVICE) {
174 char servbuf[NI_MAXSERV];
175 sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
176 gai = getaddrinfo(NULL, servbuf, &hints, &res0);
179 DEBUG("Cannot locate loopback service smux");
182 for(res=res0; res; res=res->ai_next) {
183 fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
186 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
188 setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
190 ret = connect (fd, res->ai_addr, res->ai_addrlen);
200 DEBUG ("Can't connect to SNMP agent with SMUX");
202 fd = socket (AF_INET, SOCK_STREAM, 0);
204 DEBUG ("Can't make socket for SNMP");
208 memset (&serv, 0, sizeof (struct sockaddr_in));
209 serv.sin_family = AF_INET;
211 serv.sin_len = sizeof (struct sockaddr_in);
212 #endif /* HAVE_SIN_LEN */
214 sp = getservbyname ("smux", "tcp");
216 serv.sin_port = sp->s_port;
218 serv.sin_port = htons (SMUX_PORT_DEFAULT);
220 serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
222 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
224 setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
227 ret = connect (fd, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
230 DEBUG ("Can't connect to SNMP agent with SMUX: %s", strerror(errno));
238 smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
239 long errindex, u_char val_type, const void *arg, size_t arg_len)
243 u_char *ptr, *h1, *h1e, *h2, *h2e;
250 DEBUG2("SMUX GETRSP send");
251 DEBUG2("SMUX GETRSP reqid: %ld", reqid);
254 /* Place holder h1 for complete sequence */
255 ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
258 ptr = asn_build_int (ptr, &len,
259 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
260 &reqid, sizeof (reqid));
262 DEBUG2("SMUX GETRSP errstat: %ld", errstat);
264 ptr = asn_build_int (ptr, &len,
265 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
266 &errstat, sizeof (errstat));
267 DEBUG2("SMUX GETRSP errindex: %ld", errindex);
269 ptr = asn_build_int (ptr, &len,
270 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
271 &errindex, sizeof (errindex));
274 /* Place holder h2 for one variable */
275 ptr = asn_build_sequence (ptr, &len,
276 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
280 ptr = snmp_build_var_op (ptr, objid, &objid_len,
281 val_type, arg_len, arg, &len);
283 /* Now variable size is known, fill in size */
284 asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
286 /* Fill in size of whole sequence */
287 asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
289 DEBUG2("SMUX getresp send: %d", ptr - buf);
291 ret = send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
295 smux_var (char *ptr, int len, oid objid[], size_t *objid_len,
297 u_char *var_val_type,
305 DEBUG2("SMUX var parse: len %d", len);
308 ptr = asn_parse_header (ptr, &len, &type);
310 DEBUG2("SMUX var parse: type %d len %d", type, len);
311 DEBUG2("SMUX var parse: type must be %d", (ASN_SEQUENCE | ASN_CONSTRUCTOR));
313 /* Parse var option. */
314 *objid_len = MAX_OID_LEN;
315 ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
316 &val_len, &val, &len);
319 *var_val_len = val_len;
322 *var_value = (void*) val;
325 *var_val_type = val_type;
327 /* Requested object id length is objid_len. */
328 smux_oid_dump ("Request OID", objid, *objid_len);
330 DEBUG2 ("SMUX val_type: %d", val_type);
332 /* Check request value type. */
335 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
341 DEBUG2 ("ASN_INTEGER");
347 DEBUG2 ("ASN_COUNTER");
350 DEBUG2 ("ASN_COUNTER64");
353 DEBUG2 ("ASN_IPADDRESS");
356 DEBUG2 ("ASN_OCTET_STR");
361 DEBUG2 ("ASN_OPAQUE");
363 case SNMP_NOSUCHOBJECT:
364 DEBUG2 ("SNMP_NOSUCHOBJECT");
366 case SNMP_NOSUCHINSTANCE:
367 DEBUG2 ("SNMP_NOSUCHINSTANCE");
369 case SNMP_ENDOFMIBVIEW:
370 DEBUG2 ("SNMP_ENDOFMIBVIEW");
373 DEBUG2 ("ASN_BIT_STR");
376 DEBUG2 ("Unknown type");
382 /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
383 ucd-snmp smux and as such suppose, that the peer receives in the message
384 only one variable. Fortunately, IBM seems to do the same in AIX. */
387 smux_set (oid *reqid, size_t *reqid_len,
388 u_char val_type, void *val, size_t val_len, int action)
391 struct subtree *subtree;
398 const unsigned char *statP = NULL;
399 WriteMethod *write_method = NULL;
401 if (!rad_snmp.snmp_write_access)
402 return SNMP_ERR_NOSUCHNAME;
405 for (l = treelist; l; l=l->next) {
407 subresult = oid_compare_part (reqid, *reqid_len,
408 subtree->name, subtree->name_len);
410 /* Subtree matched. */
411 if (subresult == 0) {
412 /* Prepare suffix. */
413 suffix = reqid + subtree->name_len;
414 suffix_len = *reqid_len - subtree->name_len;
417 /* Check variables. */
418 for (j = 0; j < subtree->variables_num; j++) {
419 v = &subtree->variables[j];
421 /* Always check suffix */
422 result = oid_compare_part (suffix, suffix_len,
423 v->name, v->namelen);
425 /* This is exact match so result must be zero. */
427 DEBUG2 ("SMUX function call index is %d", v->magic);
429 statP = (*v->findVar) (v, suffix, &suffix_len, 1,
430 &val_len, &write_method);
433 return (*write_method)(action, val, val_type, val_len, statP, suffix, suffix_len);
436 return SNMP_ERR_READONLY;
440 /* If above execution is failed or oid is small (so
441 there is no further match). */
443 return SNMP_ERR_NOSUCHNAME;
447 return SNMP_ERR_NOSUCHNAME;
451 smux_get (oid *reqid, size_t *reqid_len, int exact,
452 u_char *val_type,const void **val, size_t *val_len)
455 struct subtree *subtree;
462 WriteMethod *write_method=NULL;
465 for (l = treelist; l; l=l->next) {
467 subresult = oid_compare_part (reqid, *reqid_len,
468 subtree->name, subtree->name_len);
470 /* Subtree matched. */
471 if (subresult == 0) {
472 /* Prepare suffix. */
473 suffix = reqid + subtree->name_len;
474 suffix_len = *reqid_len - subtree->name_len;
477 /* Check variables. */
478 for (j = 0; j < subtree->variables_num; j++) {
479 v = &subtree->variables[j];
481 /* Always check suffix */
482 result = oid_compare_part (suffix, suffix_len,
483 v->name, v->namelen);
485 /* This is exact match so result must be zero. */
487 DEBUG2 ("SMUX function call index is %d", v->magic);
489 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
490 val_len, &write_method);
492 /* There is no instance. */
494 return SNMP_ERR_NOSUCHNAME;
496 /* Call is suceed. */
502 /* If above execution is failed or oid is small (so
503 there is no further match). */
505 return SNMP_ERR_NOSUCHNAME;
509 return SNMP_ERR_NOSUCHNAME;
513 smux_getnext (oid *reqid, size_t *reqid_len, int exact,
514 u_char *val_type, const void **val, size_t *val_len)
517 oid save[MAX_OID_LEN];
519 struct subtree *subtree;
526 WriteMethod *write_method=NULL;
528 /* Save incoming request. */
529 oid_copy (save, reqid, *reqid_len);
530 savelen = *reqid_len;
532 /* Check for best matching subtree */
534 for (l = treelist; l; l=l->next) {
537 subresult = oid_compare_part (reqid, *reqid_len,
538 subtree->name, subtree->name_len);
540 /* If request is in the tree. The agent has to make sure we
541 only receive requests we have registered for. */
542 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
543 behave as if it manages the whole SNMP MIB tree itself. It's the
544 duty of the master agent to collect the best answer and return it
545 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
546 :-). ucd-snmp really behaves bad here as it actually might ask
547 multiple times for the same GETNEXT request as it throws away the
548 answer when it expects it in a different subtree and might come
549 back later with the very same request. --jochen */
551 if (subresult <= 0) {
552 /* Prepare suffix. */
553 suffix = reqid + subtree->name_len;
554 suffix_len = *reqid_len - subtree->name_len;
556 oid_copy(reqid, subtree->name, subtree->name_len);
557 *reqid_len = subtree->name_len;
559 for (j = 0; j < subtree->variables_num; j++) {
561 v = &subtree->variables[j];
563 /* Next then check result >= 0. */
565 result = oid_compare_part (suffix, suffix_len,
566 v->name, v->namelen);
569 DEBUG2 ("SMUX function call index is %d", v->magic);
571 oid_copy(suffix, v->name, v->namelen);
572 suffix_len = v->namelen;
574 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
575 val_len, &write_method);
576 *reqid_len = suffix_len + subtree->name_len;
585 memcpy (reqid, save, savelen * sizeof(oid));
586 *reqid_len = savelen;
588 return SNMP_ERR_NOSUCHNAME;
591 /* GET message header. */
593 smux_parse_get_header (char *ptr, size_t *len, long *reqid)
600 ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
602 DEBUG2 ("SMUX GET reqid: %ld len: %d", *reqid, (int) *len);
605 ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
607 DEBUG2 ("SMUX GET errstat %ld len: %d", errstat, *len);
610 ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
612 DEBUG2 ("SMUX GET errindex %ld len: %d", errindex, *len);
618 smux_parse_set (char *ptr, size_t len, int action)
621 oid my_oid[MAX_OID_LEN];
628 DEBUG2 ("SMUX SET(%s) message parse: len %d",
629 (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
632 /* Parse SET message header. */
633 ptr = smux_parse_get_header (ptr, &len, &reqid);
635 /* Parse SET message object ID. */
636 ptr = smux_var (ptr, len, my_oid, &oid_len, &val_len, &val_type, &val);
638 ret = smux_set (my_oid, &oid_len, val_type, val, val_len, action);
639 DEBUG2 ("SMUX SET ret %d", ret);
642 if (RESERVE1 == action)
643 smux_getresp_send (my_oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
647 smux_parse_get (char *ptr, size_t len, int exact)
650 oid my_oid[MAX_OID_LEN];
657 DEBUG2 ("SMUX GET message parse: len %d", len);
659 /* Parse GET message header. */
660 ptr = smux_parse_get_header (ptr, &len, &reqid);
662 /* Parse GET message object ID. We needn't the value come */
663 ptr = smux_var (ptr, len, my_oid, &oid_len, NULL, NULL, NULL);
665 /* Traditional getstatptr. */
667 ret = smux_get (my_oid, &oid_len, exact, &val_type, &val, &val_len);
669 ret = smux_getnext (my_oid, &oid_len, exact, &val_type, &val, &val_len);
673 smux_getresp_send (my_oid, oid_len, reqid, 0, 0, val_type, val, val_len);
675 smux_getresp_send (my_oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
678 /* Parse SMUX_CLOSE message. */
680 smux_parse_close (char *ptr, int len)
685 reason = (reason << 8) | (long) *ptr;
688 DEBUG ("SMUX_CLOSE with reason: %ld", reason);
691 /* SMUX_RRSP message. */
693 smux_parse_rrsp (char *ptr, int len)
698 ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
700 DEBUG2 ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
703 /* Parse SMUX message. */
705 smux_parse (char *ptr, int len)
707 /* this buffer we'll use for SOUT message. We could allocate it with malloc and
708 save only static pointer/lenght, but IMHO static buffer is a faster solusion */
709 static u_char sout_save_buff[SMUXMAXPKTSIZE];
710 static int sout_save_len = 0;
712 int len_income = len; /* see note below: YYY */
716 rollback = ptr[2]; /* important only for SMUX_SOUT */
718 process_rest: /* see note below: YYY */
720 /* Parse SMUX message type and subsequent length. */
721 ptr = asn_parse_header (ptr, &len, &type);
723 DEBUG2 ("SMUX message received type: %d rest len: %d", type, len);
727 /* Open must be not send from SNMP agent. */
728 DEBUG ("SMUX_OPEN received: resetting connection.");
732 /* SMUX_RREQ message is invalid for us. */
733 DEBUG ("SMUX_RREQ received: resetting connection.");
737 /* SMUX_SOUT message is now valied for us. */
738 DEBUG2 ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
740 if (sout_save_len > 0) {
741 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
744 DEBUG ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
746 if (len_income > 3) {
747 /* YYY: this strange code has to solve the "slow peer"
748 problem: When agent sends SMUX_SOUT message it doesn't
749 wait any responce and may send some next message to
750 subagent. Then the peer in 'smux_read()' will recieve
751 from socket the 'concatenated' buffer, contaning both
752 SMUX_SOUT message and the next one
753 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
754 the buffer is longer than 3 ( length of SMUX_SOUT ), we
755 must process the rest of it. This effect may be observed
756 if DEBUG is set to >1 */
758 len = len_income - 3;
763 /* SMUX_GETRSP message is invalid for us. */
764 DEBUG ("SMUX_GETRSP received: resetting connection.");
768 /* Close SMUX connection. */
769 DEBUG2 ("SMUX_CLOSE");
770 smux_parse_close (ptr, len);
774 /* This is response for register message. */
775 DEBUG2 ("SMUX_RRSP");
776 smux_parse_rrsp (ptr, len);
779 /* Exact request for object id. */
781 smux_parse_get (ptr, len, 1);
784 /* Next request for object id. */
785 DEBUG2 ("SMUX_GETNEXT");
786 smux_parse_get (ptr, len, 0);
789 /* SMUX_SET is supported with some limitations. */
791 /* save the data for future SMUX_SOUT */
792 memcpy (sout_save_buff, ptr, len);
794 smux_parse_set (ptr, len, RESERVE1);
797 DEBUG ("Unknown type: %d", type);
803 /* SMUX message read function. */
808 u_char buf[SMUXMAXPKTSIZE];
811 rad_snmp.smux_event=SMUX_NONE;
812 DEBUG2 ("SMUX read start");
814 /* Read message from SMUX socket. */
815 len = recv (rad_snmp.smux_fd, buf, SMUXMAXPKTSIZE, 0);
818 DEBUG ("Can't read all SMUX packet: %s", strerror (errno));
819 close (rad_snmp.smux_fd);
820 rad_snmp.smux_fd = -1;
821 rad_snmp.smux_event=SMUX_CONNECT;
826 DEBUG ("SMUX connection closed: %d", rad_snmp.smux_fd);
827 close (rad_snmp.smux_fd);
828 rad_snmp.smux_fd = -1;
829 rad_snmp.smux_event=SMUX_CONNECT;
833 DEBUG2 ("SMUX read len: %d", len);
835 /* Parse the message. */
836 ret = smux_parse (buf, len);
839 close (rad_snmp.smux_fd);
840 rad_snmp.smux_fd = -1;
841 rad_snmp.smux_event=SMUX_CONNECT;
845 rad_snmp.smux_event=SMUX_READ;
856 u_long smux_proto_version;
857 u_char rad_progname[] = "radiusd";
859 smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
860 DEBUG2 ("SMUX open progname: %s", rad_progname);
861 DEBUG2 ("SMUX open password: %s", rad_snmp.smux_password);
866 /* SMUX Header. As placeholder. */
867 ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
870 smux_proto_version = 0;
871 ptr = asn_build_int (ptr, &len,
872 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
873 &smux_proto_version, sizeof (u_long));
875 /* SMUX connection oid. */
876 ptr = asn_build_objid (ptr, &len,
878 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
879 smux_oid, smux_oid_len);
881 /* SMUX connection description. */
882 ptr = asn_build_string (ptr, &len,
884 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
885 rad_progname, strlen (rad_progname));
887 /* SMUX connection password. */
888 ptr = asn_build_string (ptr, &len,
890 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
891 rad_snmp.smux_password, strlen(rad_snmp.smux_password));
893 /* Fill in real SMUX header. We exclude ASN header size (2). */
895 asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
897 return send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
908 struct subtree *subtree;
913 for (l = treelist; l; l=l->next) {
919 /* SMUX RReq Header. */
920 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
922 /* Register MIB tree. */
923 ptr = asn_build_objid (ptr, &len,
925 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
926 subtree->name, subtree->name_len);
930 ptr = asn_build_int (ptr, &len,
931 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
932 &priority, sizeof (u_long));
935 operation = rad_snmp.snmp_write_access ? 2 : 1; /* Register R/O or R/W */
936 ptr = asn_build_int (ptr, &len,
937 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
938 &operation, sizeof (u_long));
940 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
941 DEBUG2 ("SMUX register priority: %ld", priority);
942 DEBUG2 ("SMUX register operation: %ld", operation);
945 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
946 ret = send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
953 /* Try to connect to SNMP agent. */
959 rad_snmp.smux_event=SMUX_NONE;
960 DEBUG2 ("SMUX connect try %d", rad_snmp.smux_failures + 1);
962 /* Make socket. Try to connect. */
963 rad_snmp.smux_fd = smux_sock ();
964 if (rad_snmp.smux_fd < 0) {
965 if (++rad_snmp.smux_failures < rad_snmp.smux_max_failures)
966 rad_snmp.smux_event=SMUX_CONNECT;
973 DEBUG ("SMUX open message send failed: %s", strerror (errno));
974 close (rad_snmp.smux_fd);
975 rad_snmp.smux_fd = -1;
976 rad_snmp.smux_event=SMUX_CONNECT;
980 /* Send any outstanding register PDUs. */
981 ret = smux_register ();
983 DEBUG ("SMUX register message send failed: %s", strerror (errno));
984 close (rad_snmp.smux_fd);
985 rad_snmp.smux_fd = -1;
986 rad_snmp.smux_event=SMUX_CONNECT;
990 /* Everything goes fine. */
991 rad_snmp.smux_event=SMUX_READ;
996 /* Clear all SMUX related resources. */
1000 rad_snmp.smux_event=SMUX_NONE;
1001 if (rad_snmp.smux_fd >= 0)
1002 close (rad_snmp.smux_fd);
1003 rad_snmp.smux_fd = -1;
1007 smux_str2oid (char *str, oid *my_oid, size_t *oid_len)
1022 if (! isdigit ((int) *str))
1025 while (isdigit ((int) *str)) {
1027 val += (*str - '0');
1036 my_oid[len++] = val;
1041 my_oid[len++] = val;
1048 smux_oid_dup (oid *objid, size_t objid_len)
1052 new = (oid *)rad_malloc(sizeof (oid) * objid_len);
1053 oid_copy (new, objid, objid_len);
1059 smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
1060 size_t *var_len, WriteMethod **write_method)
1062 oid fulloid[MAX_OID_LEN];
1065 oid_copy (fulloid, v->name, v->namelen);
1066 fulloid[v->namelen] = 0;
1067 /* Check against full instance. */
1068 ret = oid_compare (name, *length, fulloid, v->namelen + 1);
1070 /* Check single instance. */
1071 if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
1072 return MATCH_FAILED;
1074 /* In case of getnext, fill in full instance. */
1075 memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
1076 *length = v->namelen + 1;
1079 *var_len = sizeof(long); /* default to 'long' results */
1081 return MATCH_SUCCEEDED;
1084 /* Initialize some values then schedule first SMUX connection. */
1086 smux_init (oid defoid[], size_t defoid_len)
1089 smux_oid_len = defoid_len;
1092 /* Register subtree to smux master tree. */
1094 smux_register_mib(UNUSED const char *descr, struct variable *var, size_t width,
1095 int num, oid name[], size_t namelen)
1097 struct subtree *tree, *tt;
1098 struct list *l, *ll;
1100 tree = (struct subtree *)rad_malloc(sizeof(struct subtree));
1101 oid_copy (tree->name, name, namelen);
1102 tree->name_len = namelen;
1103 tree->variables = var;
1104 tree->variables_num = num;
1105 tree->variables_width = width;
1106 tree->registered = 0;
1107 l = (struct list *)rad_malloc(sizeof(struct list));
1110 /* Build a treelist sorted by the name. This makes GETNEXT simpler */
1111 if (treelist == NULL) {
1115 tt = (struct subtree*) treelist->data;
1116 if (oid_compare(name, namelen, tt->name, tt->name_len) < 0) {
1121 for (ll = treelist; ll->next; ll=ll->next) {
1122 tt = (struct subtree*) ll->next->data;
1123 if (oid_compare(name, namelen, tt->name, tt->name_len) < 0) {
1135 rad_snmp.smux_event=SMUX_CONNECT;
1138 #endif /* WITH_SNMP */