5 #include <net-snmp/net-snmp-config.h>
10 #if TIME_WITH_SYS_TIME
12 # include <sys/timeb.h>
14 # include <sys/time.h>
19 # include <sys/time.h>
24 #ifdef HAVE_SYS_SOCKET_H
25 #include <sys/socket.h>
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
41 #ifdef HAVE_ARPA_INET_H
42 #include <arpa/inet.h>
49 #include <net-snmp/types.h>
50 #include <net-snmp/output_api.h>
51 #include <net-snmp/utilities.h>
52 #include <net-snmp/library/tools.h> /* for "internal" definitions */
54 #include <net-snmp/library/snmp_api.h>
55 #include <net-snmp/library/mib.h>
56 #include <net-snmp/library/scapi.h>
64 * buf pointer to a buffer pointer
65 * buf_len pointer to current size of buffer in bytes
67 * This function increase the size of the buffer pointed at by *buf, which is
68 * initially of size *buf_len. Contents are preserved **AT THE BOTTOM END OF
69 * THE BUFFER**. If memory can be (re-)allocated then it returns 1, else it
75 snmp_realloc(u_char ** buf, size_t * buf_len)
77 u_char *new_buf = NULL;
78 size_t new_buf_len = 0;
85 * The current re-allocation algorithm is to increase the buffer size by
86 * whichever is the greater of 256 bytes or the current buffer size, up to
87 * a maximum increase of 8192 bytes.
90 if (*buf_len <= 255) {
91 new_buf_len = *buf_len + 256;
92 } else if (*buf_len > 255 && *buf_len <= 8191) {
93 new_buf_len = *buf_len * 2;
94 } else if (*buf_len > 8191) {
95 new_buf_len = *buf_len + 8192;
99 new_buf = (u_char *) malloc(new_buf_len);
101 new_buf = (u_char *) realloc(*buf, new_buf_len);
104 if (new_buf != NULL) {
106 *buf_len = new_buf_len;
114 snmp_strcat(u_char ** buf, size_t * buf_len, size_t * out_len,
115 int allow_realloc, const u_char * s)
117 if (buf == NULL || buf_len == NULL || out_len == NULL) {
123 * Appending a NULL string always succeeds since it is a NOP.
128 while ((*out_len + strlen((const char *) s) + 1) >= *buf_len) {
129 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
134 strcpy((char *) (*buf + *out_len), (const char *) s);
135 *out_len += strlen((char *) (*buf + *out_len));
139 /*******************************************************************-o-******
143 * *buf Pointer at bytes to free.
144 * size Number of bytes in buf.
147 free_zero(void *buf, size_t size)
150 memset(buf, 0, size);
154 } /* end free_zero() */
158 #if BRCM_SNMP_NOT_USED
159 /*******************************************************************-o-******
163 * size Number of bytes to malloc() and fill with random bytes.
165 * Returns pointer to allocaed & set buffer on success, size contains
166 * number of random bytes filled.
168 * buf is NULL and *size set to KMT error value upon failure.
172 malloc_random(size_t * size)
174 int rval = SNMPERR_SUCCESS;
175 u_char *buf = (u_char *) calloc(1, *size);
178 rval = sc_random(buf, size);
181 free_zero(buf, *size);
190 } /* end malloc_random() */
192 #endif /* BRCM_SNMP_NOT_USED */
195 /*******************************************************************-o-******
199 * to Pointer to allocate and copy memory to.
200 * from Pointer to copy memory from.
201 * size Size of the data to be copied.
204 * SNMPERR_SUCCESS On success.
205 * SNMPERR_GENERR On failure.
208 memdup(u_char ** to, const u_char * from, size_t size)
211 return SNMPERR_GENERR;
214 return SNMPERR_SUCCESS;
216 if ((*to = (u_char *) malloc(size)) == NULL)
217 return SNMPERR_GENERR;
218 memcpy(*to, from, size);
219 return SNMPERR_SUCCESS;
223 /** copies a (possible) unterminated string of a given length into a
224 * new buffer and null terminates it as well (new buffer MAY be one
225 * byte longer to account for this */
227 netsnmp_strdup_and_null(const u_char * from, size_t from_len)
231 if (from_len == 0 || from[from_len - 1] != '\0') {
232 ret = malloc(from_len + 1);
235 ret[from_len] = '\0';
237 ret = malloc(from_len);
240 ret[from_len - 1] = '\0';
242 memcpy(ret, from, from_len);
246 /*******************************************************************-o-******
250 * *input Binary data.
251 * len Length of binary data.
252 * **output NULL terminated string equivalent in hex.
255 * olen Length of output string not including NULL terminator.
257 * FIX Is there already one of these in the UCD SNMP codebase?
258 * The old one should be used, or this one should be moved to
259 * snmplib/snmp_api.c.
262 binary_to_hex(const u_char * input, size_t len, char **output)
264 u_int olen = (len * 2) + 1;
265 char *s = (char *) calloc(1, olen), *op = s;
266 const u_char *ip = input;
269 while (ip - input < (int) len) {
270 *op++ = VAL2HEX((*ip >> 4) & 0xf);
271 *op++ = VAL2HEX(*ip & 0xf);
279 } /* end binary_to_hex() */
284 /*******************************************************************-o-******
288 * *input Printable data in base16.
289 * len Length in bytes of data.
290 * **output Binary data equivalent to input.
293 * SNMPERR_GENERR Failure.
294 * <len> Otherwise, Length of allocated string.
297 * Input of an odd length is right aligned.
299 * FIX Another version of "hex-to-binary" which takes odd length input
300 * strings. It also allocates the memory to hold the binary data.
301 * Should be integrated with the official hex_to_binary() function.
304 hex_to_binary2(const u_char * input, size_t len, char **output)
306 u_int olen = (len / 2) + (len % 2);
307 char *s = (char *) calloc(1, (olen) ? olen : 1), *op = s;
308 const u_char *ip = input;
315 goto hex_to_binary2_quit;
316 *op++ = HEX2VAL(*ip);
320 while (ip - input < (int) len) {
322 goto hex_to_binary2_quit;
323 *op = HEX2VAL(*ip) << 4;
327 goto hex_to_binary2_quit;
328 *op++ += HEX2VAL(*ip);
339 } /* end hex_to_binary2() */
342 snmp_decimal_to_binary(u_char ** buf, size_t * buf_len, size_t * out_len,
343 int allow_realloc, const char *decimal)
346 const char *cp = decimal;
348 if (buf == NULL || buf_len == NULL || out_len == NULL
349 || decimal == NULL) {
353 while (*cp != '\0') {
354 if (isspace((int) *cp) || *cp == '.') {
358 if (!isdigit((int) *cp)) {
361 if ((subid = atoi(cp)) > 255) {
364 if ((*out_len >= *buf_len) &&
365 !(allow_realloc && snmp_realloc(buf, buf_len))) {
368 *(*buf + *out_len) = (u_char) subid;
370 while (isdigit((int) *cp)) {
378 snmp_hex_to_binary(u_char ** buf, size_t * buf_len, size_t * out_len,
379 int allow_realloc, const char *hex)
382 const char *cp = hex;
384 if (buf == NULL || buf_len == NULL || out_len == NULL || hex == NULL) {
388 if ((*cp == '0') && ((*(cp + 1) == 'x') || (*(cp + 1) == 'X'))) {
392 while (*cp != '\0') {
393 if (isspace((int) *cp)) {
397 if (!isxdigit((int) *cp)) {
400 if (sscanf(cp, "%2x", &subid) == 0) {
403 if ((*out_len >= *buf_len) &&
404 !(allow_realloc && snmp_realloc(buf, buf_len))) {
407 *(*buf + *out_len) = (u_char) subid;
411 * Odd number of hex digits is an error.
421 /*******************************************************************-o-******
425 * *title (May be NULL.)
430 dump_chunk(const char *debugtoken, const char *title, const u_char * buf,
433 u_int printunit = 64; /* XXX Make global. */
434 char chunk[SNMP_MAXBUF], *s, *sp;
436 if (title && (*title != '\0')) {
437 DEBUGMSGTL((debugtoken, "%s\n", title));
441 memset(chunk, 0, SNMP_MAXBUF);
442 size = binary_to_hex(buf, size, &s);
446 if (size > (int) printunit) {
447 strncpy(chunk, sp, printunit);
448 chunk[printunit] = '\0';
449 DEBUGMSGTL((debugtoken, "\t%s\n", chunk));
451 DEBUGMSGTL((debugtoken, "\t%s\n", sp));
461 } /* end dump_chunk() */
466 /*******************************************************************-o-******
474 * Allocated memory pointing to a string of buflen char representing
475 * a printf'able form of the snmpEngineID.
477 * -OR- NULL on error.
480 * Translates the snmpEngineID TC into a printable string. From RFC 2271,
481 * Section 5 (pp. 36-37):
483 * First bit: 0 Bit string structured by means non-SNMPv3.
484 * 1 Structure described by SNMPv3 SnmpEngineID TC.
486 * Bytes 1-4: Enterprise ID. (High bit of first byte is ignored.)
488 * Byte 5: 0 (RESERVED by IANA.)
489 * 1 IPv4 address. ( 4 octets)
490 * 2 IPv6 address. ( 16 octets)
491 * 3 MAC address. ( 6 octets)
492 * 4 Locally defined text. (0-27 octets)
493 * 5 Locally defined octets. (0-27 octets)
494 * 6-127 (RESERVED for enterprise.)
496 * Bytes 6-32: (Determined by byte 5.)
499 * Non-printable characters are given in hex. Text is given in quotes.
500 * IP and MAC addresses are given in standard (UN*X) conventions. Sections
501 * are comma separated.
503 * esp, remaining_len and s trace the state of the constructed buffer.
504 * s will be defined if there is something to return, and it will point
505 * to the end of the constructed buffer.
508 * ASSUME "Text" means printable characters.
510 * XXX Must the snmpEngineID always have a minimum length of 12?
511 * (Cf. part 2 of the TC definition.)
512 * XXX Does not enforce upper-bound of 32 bytes.
513 * XXX Need a switch to decide whether to use DNS name instead of a simple
516 * FIX Use something other than sprint_hexstring which doesn't add
517 * trailing spaces and (sometimes embedded) newlines...
519 #ifdef SNMP_TESTING_CODE
521 dump_snmpEngineID(const u_char * estring, size_t * estring_len)
523 #define eb(b) ( *(esp+b) & 0xff )
525 int rval = SNMPERR_SUCCESS, gotviolation = 0, slen = 0;
528 char buf[SNMP_MAXBUF], *s = NULL, *t;
529 const u_char *esp = estring;
531 struct in_addr iaddr;
538 if (!estring || (*estring_len <= 0)) {
539 QUITFUN(SNMPERR_GENERR, dump_snmpEngineID_quit);
541 remaining_len = *estring_len;
542 memset(buf, 0, SNMP_MAXBUF);
547 * Test first bit. Return immediately with a hex string, or
548 * begin by formatting the enterprise ID.
550 if (!(*esp & 0x80)) {
551 sprint_hexstring(buf, esp, remaining_len);
552 s = strchr(buf, '\0');
554 goto dump_snmpEngineID_quit;
558 s += sprintf(s, "enterprise %d, ", ((*(esp + 0) & 0x7f) << 24) |
559 ((*(esp + 1) & 0xff) << 16) |
560 ((*(esp + 2) & 0xff) << 8) | ((*(esp + 3) & 0xff)));
565 if (remaining_len < 5) { /* XXX Violating string. */
566 goto dump_snmpEngineID_quit;
569 esp += 4; /* Incremented one more in the switch below. */
575 * Act on the fifth byte.
577 switch ((int) *esp++) {
578 case 1: /* IPv4 address. */
580 if (remaining_len < 4)
581 goto dump_snmpEngineID_violation;
582 memcpy(&iaddr.s_addr, esp, 4);
584 if (!(t = inet_ntoa(iaddr)))
585 goto dump_snmpEngineID_violation;
586 s += sprintf(s, "%s", t);
592 case 2: /* IPv6 address. */
594 if (remaining_len < 16)
595 goto dump_snmpEngineID_violation;
598 "%02X%02X %02X%02X %02X%02X %02X%02X::"
599 "%02X%02X %02X%02X %02X%02X %02X%02X",
600 eb(0), eb(1), eb(2), eb(3),
601 eb(4), eb(5), eb(6), eb(7),
602 eb(8), eb(9), eb(10), eb(11),
603 eb(12), eb(13), eb(14), eb(15));
609 case 3: /* MAC address. */
611 if (remaining_len < 6)
612 goto dump_snmpEngineID_violation;
614 s += sprintf(s, "%02X:%02X:%02X:%02X:%02X:%02X",
615 eb(0), eb(1), eb(2), eb(3), eb(4), eb(5));
624 * Doesn't exist on all (many) architectures
627 * s += snprintf(s, remaining_len+3, "\"%s\"", esp);
629 s += sprintf(s, "\"%s\"", esp);
630 goto dump_snmpEngineID_quit;
632 /*NOTREACHED*/ case 5: /* Octets. */
634 sprint_hexstring(s, esp, remaining_len);
635 s = strchr(buf, '\0');
637 goto dump_snmpEngineID_quit;
639 /*NOTREACHED*/ dump_snmpEngineID_violation:
640 case 0: /* Violation of RESERVED,
641 * * -OR- of expected length.
644 s += sprintf(s, "!!! ");
646 default: /* Unknown encoding. */
649 s += sprintf(s, "??? ");
651 sprint_hexstring(s, esp, remaining_len);
652 s = strchr(buf, '\0');
655 goto dump_snmpEngineID_quit;
662 * Cases 1-3 (IP and MAC addresses) should not have trailing
663 * octets, but perhaps they do. Throw them in too. XXX
665 if (remaining_len > 0) {
666 s += sprintf(s, " (??? ");
668 sprint_hexstring(s, esp, remaining_len);
669 s = strchr(buf, '\0');
672 s += sprintf(s, ")");
677 dump_snmpEngineID_quit:
681 memcpy(s, buf, (slen) - 1);
684 memset(buf, 0, SNMP_MAXBUF); /* XXX -- Overkill? XXX: Yes! */
689 } /* end dump_snmpEngineID() */
690 #endif /* SNMP_TESTING_CODE */
694 * create a new time marker.
695 * NOTE: Caller must free time marker when no longer needed.
698 atime_newMarker(void)
700 marker_t pm = (marker_t) calloc(1, sizeof(struct timeval));
701 gettimeofday((struct timeval *) pm, 0);
709 atime_setMarker(marker_t pm)
714 gettimeofday((struct timeval *) pm, 0);
719 * Returns the difference (in msec) between the two markers
722 atime_diff(marker_t first, marker_t second)
724 struct timeval *tv1, *tv2, diff;
726 tv1 = (struct timeval *) first;
727 tv2 = (struct timeval *) second;
729 diff.tv_sec = tv2->tv_sec - tv1->tv_sec - 1;
730 diff.tv_usec = tv2->tv_usec - tv1->tv_usec + 1000000;
732 return (diff.tv_sec * 1000 + diff.tv_usec / 1000);
736 * Returns the difference (in u_long msec) between the two markers
739 uatime_diff(marker_t first, marker_t second)
741 struct timeval *tv1, *tv2, diff;
743 tv1 = (struct timeval *) first;
744 tv2 = (struct timeval *) second;
746 diff.tv_sec = tv2->tv_sec - tv1->tv_sec - 1;
747 diff.tv_usec = tv2->tv_usec - tv1->tv_usec + 1000000;
749 return (((u_long) diff.tv_sec) * 1000 + diff.tv_usec / 1000);
753 * Returns the difference (in u_long 1/100th secs) between the two markers
754 * (functionally this is what sysUpTime needs)
757 uatime_hdiff(marker_t first, marker_t second)
759 struct timeval *tv1, *tv2, diff;
762 tv1 = (struct timeval *) first;
763 tv2 = (struct timeval *) second;
765 diff.tv_sec = tv2->tv_sec - tv1->tv_sec - 1;
766 diff.tv_usec = tv2->tv_usec - tv1->tv_usec + 1000000;
768 res = ((u_long) diff.tv_sec) * 100 + diff.tv_usec / 10000;
773 * Test: Has (marked time plus delta) exceeded current time (in msec) ?
774 * Returns 0 if test fails or cannot be tested (no marker).
777 atime_ready(marker_t pm, int deltaT)
784 now = atime_newMarker();
786 diff = atime_diff(pm, now);
795 * Test: Has (marked time plus delta) exceeded current time (in msec) ?
796 * Returns 0 if test fails or cannot be tested (no marker).
799 uatime_ready(marker_t pm, unsigned int deltaT)
806 now = atime_newMarker();
808 diff = uatime_diff(pm, now);
818 * Time-related utility functions
822 * Return the number of timeTicks since the given marker
825 marker_tticks(marker_t pm)
828 marker_t now = atime_newMarker();
830 res = atime_diff(pm, now);
832 return res / 10; /* atime_diff works in msec, not csec */
836 timeval_tticks(struct timeval *tv)
838 return marker_tticks((marker_t) tv);