2 * Copyright (C) 2000 Jochen Friedrich <jochen@scram.de>
3 * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
5 * You should have received a copy of the GNU General Public License
6 * along with GNU Zebra; see the file COPYING. If not, write to the Free
7 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
11 static const char rcsid[] =
18 #include "libradius.h"
20 #include <sys/socket.h>
24 #include <netinet/in.h>
35 #include "radius_snmp.h"
38 #define min(A,B) ((A) < (B) ? (A) : (B))
42 /* internal prototypes */
43 static int oid_compare (oid *, int, oid *, int);
45 /* SMUX subtree vector. */
46 static struct list *treelist = NULL;
50 static size_t smux_oid_len;
54 oid_copy (void *dest, void *src, size_t size)
56 return memcpy (dest, src, size * sizeof (oid));
61 oid2in_addr (oid my_oid[], int len, struct in_addr *addr)
69 pnt = (u_char *) addr;
71 for (i = 0; i < len; i++)
76 oid_copy_addr (oid my_oid[], struct in_addr *addr, int len)
84 pnt = (u_char *) addr;
86 for (i = 0; i < len; i++)
92 oid_compare (oid *o1, int o1_len, oid *o2, int o2_len)
96 for (i = 0; i < min (o1_len, o2_len); i++)
100 else if (o1[i] > o2[i])
112 oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
116 for (i = 0; i < min (o1_len, o2_len); i++)
120 else if (o1[i] > o2[i])
130 smux_oid_dump(const char *prefix, oid *my_oid, size_t oid_len)
134 char buf[MAX_OID_LEN * 3];
138 for (i = 0; i < oid_len; i++)
140 sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) my_oid[i]);
143 DEBUG2 ("%s: %s", prefix, buf);
152 struct addrinfo hints, *res0, *res;
155 struct sockaddr_in serv;
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)
167 char servbuf[NI_MAXSERV];
168 sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
169 gai = getaddrinfo(NULL, servbuf, &hints, &res0);
173 DEBUG("Cannot locate loopback service smux");
176 for(res=res0; res; res=res->ai_next)
178 fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
181 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
183 setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
185 ret = connect (fd, res->ai_addr, res->ai_addrlen);
196 DEBUG ("Can't connect to SNMP agent with SMUX");
198 fd = socket (AF_INET, SOCK_STREAM, 0);
201 DEBUG ("Can't make socket for SNMP");
205 memset (&serv, 0, sizeof (struct sockaddr_in));
206 serv.sin_family = AF_INET;
208 serv.sin_len = sizeof (struct sockaddr_in);
209 #endif /* HAVE_SIN_LEN */
211 sp = getservbyname ("smux", "tcp");
213 serv.sin_port = sp->s_port;
215 serv.sin_port = htons (SMUX_PORT_DEFAULT);
217 serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
219 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
221 setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
224 ret = connect (fd, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
228 DEBUG ("Can't connect to SNMP agent with SMUX: %s", strerror(errno));
236 smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
237 long errindex, u_char val_type, const void *arg, size_t arg_len)
241 u_char *ptr, *h1, *h1e, *h2, *h2e;
248 DEBUG2("SMUX GETRSP send");
249 DEBUG2("SMUX GETRSP reqid: %ld", reqid);
252 /* Place holder h1 for complete sequence */
253 ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
256 ptr = asn_build_int (ptr, &len,
257 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
258 &reqid, sizeof (reqid));
260 DEBUG2("SMUX GETRSP errstat: %ld", errstat);
262 ptr = asn_build_int (ptr, &len,
263 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
264 &errstat, sizeof (errstat));
265 DEBUG2("SMUX GETRSP errindex: %ld", errindex);
267 ptr = asn_build_int (ptr, &len,
268 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
269 &errindex, sizeof (errindex));
272 /* Place holder h2 for one variable */
273 ptr = asn_build_sequence (ptr, &len,
274 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
278 ptr = snmp_build_var_op (ptr, objid, &objid_len,
279 val_type, arg_len, arg, &len);
281 /* Now variable size is known, fill in size */
282 asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
284 /* Fill in size of whole sequence */
285 asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
287 DEBUG2("SMUX getresp send: %d", ptr - buf);
289 ret = send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
293 smux_var (char *ptr, int len, oid objid[], size_t *objid_len,
295 u_char *var_val_type,
303 DEBUG2("SMUX var parse: len %d", len);
306 ptr = asn_parse_header (ptr, &len, &type);
308 DEBUG2("SMUX var parse: type %d len %d", type, len);
309 DEBUG2("SMUX var parse: type must be %d", (ASN_SEQUENCE | ASN_CONSTRUCTOR));
311 /* Parse var option. */
312 *objid_len = MAX_OID_LEN;
313 ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
314 &val_len, &val, &len);
317 *var_val_len = val_len;
320 *var_value = (void*) val;
323 *var_val_type = val_type;
325 /* Requested object id length is objid_len. */
326 smux_oid_dump ("Request OID", objid, *objid_len);
328 DEBUG2 ("SMUX val_type: %d", val_type);
330 /* Check request value type. */
334 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
340 DEBUG2 ("ASN_INTEGER");
346 DEBUG2 ("ASN_COUNTER");
349 DEBUG2 ("ASN_COUNTER64");
352 DEBUG2 ("ASN_IPADDRESS");
355 DEBUG2 ("ASN_OCTET_STR");
360 DEBUG2 ("ASN_OPAQUE");
362 case SNMP_NOSUCHOBJECT:
363 DEBUG2 ("SNMP_NOSUCHOBJECT");
365 case SNMP_NOSUCHINSTANCE:
366 DEBUG2 ("SNMP_NOSUCHINSTANCE");
368 case SNMP_ENDOFMIBVIEW:
369 DEBUG2 ("SNMP_ENDOFMIBVIEW");
372 DEBUG2 ("ASN_BIT_STR");
375 DEBUG2 ("Unknown type");
381 /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
382 ucd-snmp smux and as such suppose, that the peer receives in the message
383 only one variable. Fortunately, IBM seems to do the same in AIX. */
386 smux_set (oid *reqid, size_t *reqid_len,
387 u_char val_type, void *val, size_t val_len, int action)
390 struct subtree *subtree;
397 const unsigned char *statP = NULL;
398 WriteMethod *write_method = NULL;
400 if (!rad_snmp.snmp_write_access)
401 return SNMP_ERR_NOSUCHNAME;
404 for (l = treelist; l; l=l->next)
407 subresult = oid_compare_part (reqid, *reqid_len,
408 subtree->name, subtree->name_len);
410 /* Subtree matched. */
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++)
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. */
430 DEBUG2 ("SMUX function call index is %d", v->magic);
432 statP = (*v->findVar) (v, suffix, &suffix_len, 1,
433 &val_len, &write_method);
437 return (*write_method)(action, val, val_type, val_len, statP, suffix, suffix_len);
442 return SNMP_ERR_READONLY;
446 /* If above execution is failed or oid is small (so
447 there is no further match). */
449 return SNMP_ERR_NOSUCHNAME;
453 return SNMP_ERR_NOSUCHNAME;
457 smux_get (oid *reqid, size_t *reqid_len, int exact,
458 u_char *val_type,const void **val, size_t *val_len)
461 struct subtree *subtree;
468 WriteMethod *write_method=NULL;
471 for (l = treelist; l; l=l->next)
474 subresult = oid_compare_part (reqid, *reqid_len,
475 subtree->name, subtree->name_len);
477 /* Subtree matched. */
480 /* Prepare suffix. */
481 suffix = reqid + subtree->name_len;
482 suffix_len = *reqid_len - subtree->name_len;
485 /* Check variables. */
486 for (j = 0; j < subtree->variables_num; j++)
488 v = &subtree->variables[j];
490 /* Always check suffix */
491 result = oid_compare_part (suffix, suffix_len,
492 v->name, v->namelen);
494 /* This is exact match so result must be zero. */
497 DEBUG2 ("SMUX function call index is %d", v->magic);
499 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
500 val_len, &write_method);
502 /* There is no instance. */
504 return SNMP_ERR_NOSUCHNAME;
506 /* Call is suceed. */
512 /* If above execution is failed or oid is small (so
513 there is no further match). */
515 return SNMP_ERR_NOSUCHNAME;
519 return SNMP_ERR_NOSUCHNAME;
523 smux_getnext (oid *reqid, size_t *reqid_len, int exact,
524 u_char *val_type, const void **val, size_t *val_len)
527 oid save[MAX_OID_LEN];
529 struct subtree *subtree;
536 WriteMethod *write_method=NULL;
538 /* Save incoming request. */
539 oid_copy (save, reqid, *reqid_len);
540 savelen = *reqid_len;
542 /* Check for best matching subtree */
544 for (l = treelist; l; l=l->next)
548 subresult = oid_compare_part (reqid, *reqid_len,
549 subtree->name, subtree->name_len);
551 /* If request is in the tree. The agent has to make sure we
552 only receive requests we have registered for. */
553 /* Unfortunately, that's not true. In fact, a SMUX subagent has to
554 behave as if it manages the whole SNMP MIB tree itself. It's the
555 duty of the master agent to collect the best answer and return it
556 to the manager. See RFC 1227 chapter 3.1.6 for the glory details
557 :-). ucd-snmp really behaves bad here as it actually might ask
558 multiple times for the same GETNEXT request as it throws away the
559 answer when it expects it in a different subtree and might come
560 back later with the very same request. --jochen */
564 /* Prepare suffix. */
565 suffix = reqid + subtree->name_len;
566 suffix_len = *reqid_len - subtree->name_len;
569 oid_copy(reqid, subtree->name, subtree->name_len);
570 *reqid_len = subtree->name_len;
572 for (j = 0; j < subtree->variables_num; j++)
575 v = &subtree->variables[j];
577 /* Next then check result >= 0. */
579 result = oid_compare_part (suffix, suffix_len,
580 v->name, v->namelen);
584 DEBUG2 ("SMUX function call index is %d", v->magic);
587 oid_copy(suffix, v->name, v->namelen);
588 suffix_len = v->namelen;
590 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
591 val_len, &write_method);
592 *reqid_len = suffix_len + subtree->name_len;
602 memcpy (reqid, save, savelen * sizeof(oid));
603 *reqid_len = savelen;
605 return SNMP_ERR_NOSUCHNAME;
608 /* GET message header. */
610 smux_parse_get_header (char *ptr, size_t *len, long *reqid)
617 ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
619 DEBUG2 ("SMUX GET reqid: %ld len: %d", *reqid, (int) *len);
622 ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
624 DEBUG2 ("SMUX GET errstat %ld len: %d", errstat, *len);
627 ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
629 DEBUG2 ("SMUX GET errindex %ld len: %d", errindex, *len);
635 smux_parse_set (char *ptr, size_t len, int action)
638 oid my_oid[MAX_OID_LEN];
645 DEBUG2 ("SMUX SET(%s) message parse: len %d",
646 (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
649 /* Parse SET message header. */
650 ptr = smux_parse_get_header (ptr, &len, &reqid);
652 /* Parse SET message object ID. */
653 ptr = smux_var (ptr, len, my_oid, &oid_len, &val_len, &val_type, &val);
655 ret = smux_set (my_oid, &oid_len, val_type, val, val_len, action);
656 DEBUG2 ("SMUX SET ret %d", ret);
659 if (RESERVE1 == action)
660 smux_getresp_send (my_oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
664 smux_parse_get (char *ptr, size_t len, int exact)
667 oid my_oid[MAX_OID_LEN];
674 DEBUG2 ("SMUX GET message parse: len %d", len);
676 /* Parse GET message header. */
677 ptr = smux_parse_get_header (ptr, &len, &reqid);
679 /* Parse GET message object ID. We needn't the value come */
680 ptr = smux_var (ptr, len, my_oid, &oid_len, NULL, NULL, NULL);
682 /* Traditional getstatptr. */
684 ret = smux_get (my_oid, &oid_len, exact, &val_type, &val, &val_len);
686 ret = smux_getnext (my_oid, &oid_len, exact, &val_type, &val, &val_len);
690 smux_getresp_send (my_oid, oid_len, reqid, 0, 0, val_type, val, val_len);
692 smux_getresp_send (my_oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
695 /* Parse SMUX_CLOSE message. */
697 smux_parse_close (char *ptr, int len)
703 reason = (reason << 8) | (long) *ptr;
706 DEBUG ("SMUX_CLOSE with reason: %ld", reason);
709 /* SMUX_RRSP message. */
711 smux_parse_rrsp (char *ptr, int len)
716 ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
718 DEBUG2 ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
721 /* Parse SMUX message. */
723 smux_parse (char *ptr, int len)
725 /* this buffer we'll use for SOUT message. We could allocate it with malloc and
726 save only static pointer/lenght, but IMHO static buffer is a faster solusion */
727 static u_char sout_save_buff[SMUXMAXPKTSIZE];
728 static int sout_save_len = 0;
730 int len_income = len; /* see note below: YYY */
734 rollback = ptr[2]; /* important only for SMUX_SOUT */
736 process_rest: /* see note below: YYY */
738 /* Parse SMUX message type and subsequent length. */
739 ptr = asn_parse_header (ptr, &len, &type);
741 DEBUG2 ("SMUX message received type: %d rest len: %d", type, len);
746 /* Open must be not send from SNMP agent. */
747 DEBUG ("SMUX_OPEN received: resetting connection.");
751 /* SMUX_RREQ message is invalid for us. */
752 DEBUG ("SMUX_RREQ received: resetting connection.");
756 /* SMUX_SOUT message is now valied for us. */
757 DEBUG2 ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
759 if (sout_save_len > 0)
761 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
765 DEBUG ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
769 /* YYY: this strange code has to solve the "slow peer"
770 problem: When agent sends SMUX_SOUT message it doesn't
771 wait any responce and may send some next message to
772 subagent. Then the peer in 'smux_read()' will recieve
773 from socket the 'concatenated' buffer, contaning both
774 SMUX_SOUT message and the next one
775 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
776 the buffer is longer than 3 ( length of SMUX_SOUT ), we
777 must process the rest of it. This effect may be observed
778 if DEBUG is set to >1 */
780 len = len_income - 3;
785 /* SMUX_GETRSP message is invalid for us. */
786 DEBUG ("SMUX_GETRSP received: resetting connection.");
790 /* Close SMUX connection. */
791 DEBUG2 ("SMUX_CLOSE");
792 smux_parse_close (ptr, len);
796 /* This is response for register message. */
797 DEBUG2 ("SMUX_RRSP");
798 smux_parse_rrsp (ptr, len);
801 /* Exact request for object id. */
803 smux_parse_get (ptr, len, 1);
806 /* Next request for object id. */
807 DEBUG2 ("SMUX_GETNEXT");
808 smux_parse_get (ptr, len, 0);
811 /* SMUX_SET is supported with some limitations. */
814 /* save the data for future SMUX_SOUT */
815 memcpy (sout_save_buff, ptr, len);
817 smux_parse_set (ptr, len, RESERVE1);
820 DEBUG ("Unknown type: %d", type);
826 /* SMUX message read function. */
831 u_char buf[SMUXMAXPKTSIZE];
834 rad_snmp.smux_event=SMUX_NONE;
835 DEBUG2 ("SMUX read start");
837 /* Read message from SMUX socket. */
838 len = recv (rad_snmp.smux_fd, buf, SMUXMAXPKTSIZE, 0);
842 DEBUG ("Can't read all SMUX packet: %s", strerror (errno));
843 close (rad_snmp.smux_fd);
844 rad_snmp.smux_fd = -1;
845 rad_snmp.smux_event=SMUX_CONNECT;
851 DEBUG ("SMUX connection closed: %d", rad_snmp.smux_fd);
852 close (rad_snmp.smux_fd);
853 rad_snmp.smux_fd = -1;
854 rad_snmp.smux_event=SMUX_CONNECT;
858 DEBUG2 ("SMUX read len: %d", len);
860 /* Parse the message. */
861 ret = smux_parse (buf, len);
865 close (rad_snmp.smux_fd);
866 rad_snmp.smux_fd = -1;
867 rad_snmp.smux_event=SMUX_CONNECT;
871 rad_snmp.smux_event=SMUX_READ;
883 u_char progname[] = "radiusd";
885 smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
886 DEBUG2 ("SMUX open progname: %s", progname);
887 DEBUG2 ("SMUX open password: %s", rad_snmp.smux_password);
892 /* SMUX Header. As placeholder. */
893 ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
897 ptr = asn_build_int (ptr, &len,
898 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
899 &version, sizeof (u_long));
901 /* SMUX connection oid. */
902 ptr = asn_build_objid (ptr, &len,
904 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
905 smux_oid, smux_oid_len);
907 /* SMUX connection description. */
908 ptr = asn_build_string (ptr, &len,
910 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
911 progname, strlen (progname));
913 /* SMUX connection password. */
914 ptr = asn_build_string (ptr, &len,
916 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
917 rad_snmp.smux_password, strlen(rad_snmp.smux_password));
919 /* Fill in real SMUX header. We exclude ASN header size (2). */
921 asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
923 return send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
934 struct subtree *subtree;
939 for (l = treelist; l; l=l->next)
946 /* SMUX RReq Header. */
947 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
949 /* Register MIB tree. */
950 ptr = asn_build_objid (ptr, &len,
952 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
953 subtree->name, subtree->name_len);
957 ptr = asn_build_int (ptr, &len,
958 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
959 &priority, sizeof (u_long));
962 operation = rad_snmp.snmp_write_access ? 2 : 1; /* Register R/O or R/W */
963 ptr = asn_build_int (ptr, &len,
964 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
965 &operation, sizeof (u_long));
967 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
968 DEBUG2 ("SMUX register priority: %ld", priority);
969 DEBUG2 ("SMUX register operation: %ld", operation);
972 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
973 ret = send (rad_snmp.smux_fd, buf, (ptr - buf), 0);
980 /* Try to connect to SNMP agent. */
986 rad_snmp.smux_event=SMUX_NONE;
987 DEBUG2 ("SMUX connect try %d", rad_snmp.smux_failures + 1);
989 /* Make socket. Try to connect. */
990 rad_snmp.smux_fd = smux_sock ();
991 if (rad_snmp.smux_fd < 0) {
992 if (++rad_snmp.smux_failures < rad_snmp.smux_max_failures)
993 rad_snmp.smux_event=SMUX_CONNECT;
1000 DEBUG ("SMUX open message send failed: %s", strerror (errno));
1001 close (rad_snmp.smux_fd);
1002 rad_snmp.smux_fd = -1;
1003 rad_snmp.smux_event=SMUX_CONNECT;
1007 /* Send any outstanding register PDUs. */
1008 ret = smux_register ();
1011 DEBUG ("SMUX register message send failed: %s", strerror (errno));
1012 close (rad_snmp.smux_fd);
1013 rad_snmp.smux_fd = -1;
1014 rad_snmp.smux_event=SMUX_CONNECT;
1018 /* Everything goes fine. */
1019 rad_snmp.smux_event=SMUX_READ;
1024 /* Clear all SMUX related resources. */
1028 rad_snmp.smux_event=SMUX_NONE;
1029 if (rad_snmp.smux_fd >= 0)
1030 close (rad_snmp.smux_fd);
1031 rad_snmp.smux_fd = -1;
1035 smux_str2oid (char *str, oid *my_oid, size_t *oid_len)
1051 if (! isdigit (*str))
1054 while (isdigit (*str))
1057 val += (*str - '0');
1066 my_oid[len++] = val;
1071 my_oid[len++] = val;
1078 smux_oid_dup (oid *objid, size_t objid_len)
1082 new = (oid *)rad_malloc(sizeof (oid) * objid_len);
1083 oid_copy (new, objid, objid_len);
1089 smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
1090 size_t *var_len, WriteMethod **write_method)
1092 oid fulloid[MAX_OID_LEN];
1095 oid_copy (fulloid, v->name, v->namelen);
1096 fulloid[v->namelen] = 0;
1097 /* Check against full instance. */
1098 ret = oid_compare (name, *length, fulloid, v->namelen + 1);
1100 /* Check single instance. */
1101 if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
1102 return MATCH_FAILED;
1104 /* In case of getnext, fill in full instance. */
1105 memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
1106 *length = v->namelen + 1;
1109 *var_len = sizeof(long); /* default to 'long' results */
1111 return MATCH_SUCCEEDED;
1114 /* Initialize some values then schedule first SMUX connection. */
1116 smux_init (oid defoid[], size_t defoid_len)
1119 smux_oid_len = defoid_len;
1122 /* Register subtree to smux master tree. */
1124 smux_register_mib(const char *descr, struct variable *var, size_t width,
1125 int num, oid name[], size_t namelen)
1127 struct subtree *tree, *tt;
1128 struct list *l, *ll;
1130 tree = (struct subtree *)rad_malloc(sizeof(struct subtree));
1131 oid_copy (tree->name, name, namelen);
1132 tree->name_len = namelen;
1133 tree->variables = var;
1134 tree->variables_num = num;
1135 tree->variables_width = width;
1136 tree->registered = 0;
1137 l = (struct list *)rad_malloc(sizeof(struct list));
1140 /* Build a treelist sorted by the name. This makes GETNEXT simpler */
1141 if (treelist == NULL)
1146 tt = (struct subtree*) treelist->data;
1147 if (oid_compare(name, namelen, tt->name, tt->name_len) < 0)
1153 for (ll = treelist; ll->next; ll=ll->next)
1155 tt = (struct subtree*) ll->next->data;
1156 if (oid_compare(name, namelen, tt->name, tt->name_len) < 0)
1169 rad_snmp.smux_event=SMUX_CONNECT;
1172 #endif /* WITH_SNMP */