xref: /freebsd/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.c (revision 079171874c9bf263b69e3af10784ad2bcd1fe699)
1 /*-
2  * Copyright (c) 2006 The FreeBSD Project
3  * All rights reserved.
4  *
5  * Author: Shteryana Shopova <syrinx@FreeBSD.org>
6  *
7  * Redistribution of this software and documentation and use in source and
8  * binary forms, with or without modification, are permitted provided that
9  * the following conditions are met:
10  *
11  * 1. Redistributions of source code or documentation must retain the above
12  *    copyright notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * Textual conventions for OctetStrings
30  *
31  * $FreeBSD$
32  */
33 
34 #include <sys/param.h>
35 #include <sys/queue.h>
36 #include <sys/socket.h>
37 #include <sys/uio.h>
38 
39 #include <ctype.h>
40 #include <err.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <syslog.h>
47 #include <unistd.h>
48 
49 #include <arpa/inet.h>
50 #include <netinet/in.h>
51 
52 #include <bsnmp/asn1.h>
53 #include <bsnmp/snmp.h>
54 #include "bsnmptc.h"
55 #include "bsnmptools.h"
56 
57 /* OctetString, DisplayString */
58 static char *snmp_oct2str(uint32_t, char *, char *);
59 static char *snmp_str2asn_oid(char *, struct asn_oid *);
60 static int parse_octetstring(struct snmp_value *, char *);
61 
62 /* DateAndTime */
63 static char *snmp_octstr2date(uint32_t, char *, char *);
64 static char *snmp_date2asn_oid(char * , struct asn_oid *);
65 static int parse_dateandtime(struct snmp_value *, char *);
66 
67 /* PhysAddress */
68 static char *snmp_oct2physAddr(uint32_t, char *, char *);
69 static char *snmp_addr2asn_oid(char *, struct asn_oid *);
70 static int parse_physaddress(struct snmp_value *, char *);
71 
72 /* NTPTimeStamp */
73 static char *snmp_oct2ntp_ts(uint32_t, char *, char *);
74 static char *snmp_ntp_ts2asn_oid(char *, struct asn_oid *);
75 static int parse_ntp_ts(struct snmp_value *, char *);
76 
77 /* BridgeId */
78 static char *snmp_oct2bridgeid(uint32_t, char *, char *);
79 static char *snmp_bridgeid2oct(char *, struct asn_oid *);
80 static int parse_bridge_id(struct snmp_value *, char *);
81 
82 /* BridgePortId */
83 static char *snmp_oct2bport_id(uint32_t, char *, char *);
84 static char *snmp_bport_id2oct(char *, struct asn_oid *);
85 static int parse_bport_id(struct snmp_value *, char *);
86 
87 /* InetAddress */
88 static char *snmp_oct2inetaddr(uint32_t len, char *octets, char *buf);
89 static char *snmp_inetaddr2oct(char *str, struct asn_oid *oid);
90 static int32_t parse_inetaddr(struct snmp_value *value, char *string);
91 
92 static char *snmp_oct2bits(uint32_t len, char *octets, char *buf);
93 static char *snmp_bits2oct(char *str, struct asn_oid *oid);
94 static int32_t parse_bits(struct snmp_value *value, char *string);
95 
96 struct snmp_text_conv {
97 	enum snmp_tc	tc;
98 	const char	*tc_str;
99 	int32_t		len;
100 	snmp_oct2tc_f	oct2tc;
101 	snmp_tc2oid_f	tc2oid;
102 	snmp_tc2oct_f	tc2oct;
103 } text_convs[] = {
104 	{ SNMP_STRING, "OctetString", SNMP_VAR_STRSZ,
105 	  snmp_oct2str, snmp_str2asn_oid, parse_octetstring },
106 
107 	{ SNMP_DISPLAYSTRING, "DisplayString" , SNMP_VAR_STRSZ,
108 	  snmp_oct2str, snmp_str2asn_oid, parse_octetstring },
109 
110 	{ SNMP_DATEANDTIME, "DateAndTime", SNMP_DATETIME_STRSZ,
111 	  snmp_octstr2date, snmp_date2asn_oid, parse_dateandtime },
112 
113 	{ SNMP_PHYSADDR, "PhysAddress", SNMP_PHYSADDR_STRSZ,
114 	  snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },
115 
116 	{ SNMP_ATMESI, "AtmESI", SNMP_PHYSADDR_STRSZ,
117 	  snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },
118 
119 	{ SNMP_NTP_TIMESTAMP, "NTPTimeStamp", SNMP_NTP_TS_STRSZ,
120 	  snmp_oct2ntp_ts, snmp_ntp_ts2asn_oid, parse_ntp_ts },
121 
122 	{ SNMP_MACADDRESS, "MacAddress", SNMP_PHYSADDR_STRSZ,
123 	  snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },
124 
125 	{ SNMP_BRIDGE_ID, "BridgeId", SNMP_BRIDGEID_STRSZ,
126 	  snmp_oct2bridgeid, snmp_bridgeid2oct, parse_bridge_id },
127 
128 	{ SNMP_BPORT_ID, "BridgePortId", SNMP_BPORT_STRSZ,
129 	  snmp_oct2bport_id, snmp_bport_id2oct, parse_bport_id },
130 
131 	{ SNMP_INETADDRESS, "InetAddress", SNMP_INADDRS_STRSZ,
132 	  snmp_oct2inetaddr, snmp_inetaddr2oct, parse_inetaddr },
133 
134 	{ SNMP_TC_OWN, "BITS", SNMP_VAR_STRSZ,
135 	  snmp_oct2bits, snmp_bits2oct, parse_bits },
136 
137 	{ SNMP_UNKNOWN, "Unknown", SNMP_VAR_STRSZ, snmp_oct2str,
138 	  snmp_str2asn_oid, parse_octetstring }	/* keep last */
139 };
140 
141 /* Common API */
142 enum snmp_tc
143 snmp_get_tc(char *str)
144 {
145 	int i;
146 	for (i = 0; i < SNMP_UNKNOWN; i++) {
147 		if (!strncmp(text_convs[i].tc_str, str,
148 		    strlen(text_convs[i].tc_str)))
149 			return (text_convs[i].tc);
150 	}
151 
152 	return (SNMP_STRING);
153 }
154 
155 char *
156 snmp_oct2tc(enum snmp_tc tc, uint32_t len, char *octets)
157 {
158 	uint32_t tc_len;
159 	char * buf;
160 
161 	if (tc < 0 || tc > SNMP_UNKNOWN)
162 		tc = SNMP_UNKNOWN;
163 
164 	if (text_convs[tc].len > 0)
165 		tc_len = text_convs[tc].len;
166 	else
167 		tc_len = 2 * len + 3;
168 
169 	if ((buf = malloc(tc_len)) == NULL ) {
170 		syslog(LOG_ERR, "malloc failed - %s", strerror(errno));
171 		return (NULL);
172 	}
173 
174 	memset(buf, 0, tc_len);
175 	if (text_convs[tc].oct2tc(len, octets, buf) == NULL) {
176 		free(buf);
177 		return (NULL);
178 	}
179 
180 	return (buf);
181 }
182 
183 char *
184 snmp_tc2oid(enum snmp_tc tc, char *str, struct asn_oid *oid)
185 {
186 	if (tc < 0 || tc > SNMP_UNKNOWN)
187 		tc = SNMP_UNKNOWN;
188 
189 	return (text_convs[tc].tc2oid(str, oid));
190 }
191 
192 int32_t
193 snmp_tc2oct(enum snmp_tc tc, struct snmp_value *value, char *string)
194 {
195 	if (tc < 0 || tc > SNMP_UNKNOWN)
196 		tc = SNMP_UNKNOWN;
197 
198 	return (text_convs[tc].tc2oct(value, string));
199 }
200 
201 /*****************************************************
202 * Basic OctetString type.
203 */
204 static char *
205 snmp_oct2str(uint32_t len, char *octets, char *buf)
206 {
207 	uint8_t binary = 0;
208 	uint32_t i;
209 	char *ptr;
210 
211 	if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL)
212 		return (NULL);
213 
214 	for (ptr = buf, i = 0; i < len; i++)
215 		if (!isprint(octets[i])) {
216 			binary = 1;
217 			buf += sprintf(buf, "0x");
218 			break;
219 		}
220 
221 	for (ptr = buf, i = 0; i < len; i++)
222 		if (!binary)
223 			ptr += sprintf(ptr, "%c", octets[i]);
224 		else
225 			ptr += sprintf(ptr, "%2.2x", (u_char)octets[i]);
226 
227 	return (buf);
228 }
229 
230 static char *
231 snmp_str2asn_oid(char *str, struct asn_oid *oid)
232 {
233 	uint32_t i, len = 0;
234 
235 	/*
236 	 * OctetStrings are allowed max length of ASN_MAXOCTETSTRING,
237 	 * but trying to index an entry with such a long OctetString
238 	 * will fail anyway.
239 	 */
240 	for (len = 0; len < ASN_MAXOIDLEN; len++) {
241 		if (strchr(",]", *(str + len)) != NULL)
242 			break;
243 	}
244 
245 	if (len >= ASN_MAXOIDLEN)
246 		return (NULL);
247 
248 	if (snmp_suboid_append(oid, (asn_subid_t) len) < 0)
249 		return (NULL);
250 
251 	for (i = 0; i < len; i++)
252 		if (snmp_suboid_append(oid, (asn_subid_t) *(str + i)) < 0)
253 			return (NULL);
254 
255 	return (str + len);
256 }
257 
258 static int32_t
259 parse_octetstring(struct snmp_value *value, char *val)
260 {
261 	size_t len;
262 
263 	if ((len = strlen(val)) >= MAX_OCTSTRING_LEN) {
264 		warnx("Octetstring too long - %d is max allowed",
265 		    MAX_OCTSTRING_LEN - 1);
266 		return (-1);
267 	}
268 
269 	value->v.octetstring.len = len;
270 
271 	if((value->v.octetstring.octets = malloc(len)) == NULL) {
272 		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
273 		return (-1);
274 	}
275 
276 	memcpy(value->v.octetstring.octets, val, len);
277 	value->syntax = SNMP_SYNTAX_OCTETSTRING;
278 
279 	return (0);
280 }
281 
282 /*************************************************************
283  * DateAndTime
284  *************************************************************
285  * rfc 2579 specification:
286  * DateAndTime ::= TEXTUAL-CONVENTION
287  *   DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
288  *   STATUS	  current
289  *   DESCRIPTION
290  *	"A date-time specification.
291  *
292  *	field	octets	contents		range
293  *	-----	------	--------		-----
294  *	1	1-2	year*			0..65536
295  *	2	3	month			1..12
296  *	3	4	day			1..31
297  *	4	5	hour			0..23
298  *	5	6	minutes			0..59
299  *	6	7	seconds			0..60
300  *			(use 60 for leap-second)
301  *	7	8	deci-seconds		0..9
302  *	8	9	direction from UTC	'+' / '-'
303  *	9	10	hours from UTC*		0..13
304  *	10	11	minutes from UTC	0..59
305  *
306  *	* Notes:
307  *	    - the value of year is in network-byte order
308  *	    - daylight saving time in New Zealand is +13
309  *
310  *	For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
311  *	displayed as:
312  *
313  *		1992-5-26,13:30:15.0,-4:0
314  */
315 static char *
316 snmp_octstr2date(uint32_t len, char *octets, char *buf)
317 {
318 	int year;
319 	char *ptr;
320 
321 	if (len != SNMP_DATETIME_OCTETS || octets == NULL || buf == NULL)
322 		return (NULL);
323 
324 	buf[0]= '\0';
325 	year = (octets[0] << 8);
326 	year += (octets[1]);
327 
328 	ptr = buf;
329 	ptr += sprintf(ptr, "%4.4d-%.2d-%.2d, ", year, octets[2],octets[3]);
330 	ptr += sprintf(ptr, "%2.2d:%2.2d:%2.2d.%.2d, ", octets[4],octets[5],
331 	    octets[6],octets[7]);
332 	ptr += sprintf(ptr, "%c%.2d:%.2d", octets[8],octets[9],octets[10]);
333 
334 	return (buf);
335 }
336 
337 static char *
338 snmp_date2asn_oid(char *str, struct asn_oid *oid)
339 {
340 	char *endptr, *ptr;
341 	static const char UTC[3] = "UTC";
342 	int32_t saved_errno;
343 	uint32_t v;
344 
345 	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_DATETIME_OCTETS) < 0)
346 		return (NULL);
347 
348 	/* Read 'YYYY-' and write it in two subs. */
349 	ptr = str;
350 	saved_errno = errno;
351 	errno = 0;
352 	v = strtoul(ptr, &endptr, 10);
353 	if (v > 0xffff)
354 		goto error;
355 	else
356 		errno = saved_errno;
357 	if (*endptr != '-')
358 		goto error1;
359 	if (snmp_suboid_append(oid, (asn_subid_t) ((v & 0xff00) >> 8)) < 0)
360 		return (NULL);
361 	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
362 		return (NULL);
363 
364 	/* 'MM-' */
365 	ptr = endptr + 1;
366 	saved_errno = errno;
367 	v = strtoul(ptr, &endptr, 10);
368 	if (errno != 0)
369 		goto error;
370 	else
371 		errno = saved_errno;
372 	if (*endptr != '-')
373 		goto error1;
374 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
375 		return (NULL);
376 
377 	/* 'DD,' */
378 	ptr = endptr + 1;
379 	saved_errno = errno;
380 	v = strtoul(ptr, &endptr, 10);
381 	if (errno != 0)
382 		goto error;
383 	else
384 		errno = saved_errno;
385 	if (*endptr != '-')
386 		goto error1;
387 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
388 		return (NULL);
389 
390 	/* 'HH:' */
391 	ptr = endptr + 1;
392 	saved_errno = errno;
393 	v = strtoul(ptr, &endptr, 10);
394 	if (errno != 0)
395 		goto error;
396 	else
397 		errno = saved_errno;
398 	if (*endptr != ':')
399 		goto error1;
400 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
401 		return (NULL);
402 
403 	/* 'MM:' */
404 	ptr = endptr + 1;
405 	saved_errno = errno;
406 	v = strtoul(ptr, &endptr, 10);
407 	if (errno != 0)
408 		goto error;
409 	else
410 		errno = saved_errno;
411 	if (*endptr != ':')
412 		goto error1;
413 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
414 		return (NULL);
415 
416 	/* 'SS.' */
417 	ptr = endptr + 1;
418 	saved_errno = errno;
419 	v = strtoul(ptr, &endptr, 10);
420 	if (errno != 0)
421 		goto error;
422 	else
423 		errno = saved_errno;
424 	if (*endptr != '.')
425 		goto error1;
426 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
427 		return (NULL);
428 
429 	/* 'M(mseconds),' */
430 	ptr = endptr + 1;
431 	saved_errno = errno;
432 	v = strtoul(ptr, &endptr, 10);
433 	if (errno != 0)
434 		goto error;
435 	else
436 		errno = saved_errno;
437 	if (*endptr != ',')
438 		goto error1;
439 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
440 		return (NULL);
441 
442 	/* 'UTC' - optional */
443 	ptr = endptr + 1;
444 	if (strncmp(ptr, UTC, sizeof(UTC)) == 0)
445 		ptr += sizeof(UTC);
446 
447 	/* '+/-' */
448 	if (*ptr == '-' || *ptr == '+') {
449 		if (snmp_suboid_append(oid, (asn_subid_t) (*ptr)) < 0)
450 			return (NULL);
451 	} else
452 		goto error1;
453 
454 	/* 'HH:' */
455 	ptr = endptr + 1;
456 	saved_errno = errno;
457 	v = strtoul(ptr, &endptr, 10);
458 	if (errno != 0)
459 		goto error;
460 	else
461 		errno = saved_errno;
462 	if (*endptr != ':')
463 		goto error1;
464 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
465 		return (NULL);
466 
467 	/* 'MM' - last one - ignore endptr here. */
468 	ptr = endptr + 1;
469 	saved_errno = errno;
470 	v = strtoul(ptr, &endptr, 10);
471 	if (errno != 0)
472 		goto error;
473 	else
474 		errno = saved_errno;
475 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
476 		return (NULL);
477 
478 	return (endptr);
479 
480   error:
481 	errno = saved_errno;
482   error1:
483 	warnx("Date value %s not supported", str);
484 	return (NULL);
485 }
486 
487 /* Read a DateAndTime string eg. 1992-5-26,13:30:15.0,-4:0. */
488 static int32_t
489 parse_dateandtime(struct snmp_value *sv, char *val)
490 {
491 	char *endptr;
492 	uint32_t v;
493 	uint8_t	date[SNMP_DATETIME_OCTETS];
494 
495 	/* 'YYYY-' */
496 	v = strtoul(val, &endptr, 10);
497 	if (v > 0xffff || *endptr != '-')
498 		goto error;
499 	date[0] = ((v & 0xff00) >> 8);
500 	date[1] = (v & 0xff);
501 	val = endptr + 1;
502 
503 	/* 'MM-' */
504 	v = strtoul(val, &endptr, 10);
505 	if (v == 0 || v > 12 || *endptr != '-')
506 		goto error;
507 	date[2] = v;
508 	val = endptr + 1;
509 
510 	/* 'DD,' */
511 	v = strtoul(val, &endptr, 10);
512 	if (v == 0 || v > 31 || *endptr != ',')
513 		goto error;
514 	date[3] = v;
515 	val = endptr + 1;
516 
517 	/* 'HH:' */
518 	v = strtoul(val, &endptr, 10);
519 	if (v > 23 || *endptr != ':')
520 		goto error;
521 	date[4] = v;
522 	val = endptr + 1;
523 
524 	/* 'MM:' */
525 	v = strtoul(val, &endptr, 10);
526 	if (v > 59 || *endptr != ':')
527 		goto error;
528 	date[5] = v;
529 	val = endptr + 1;
530 
531 	/* 'SS.' */
532 	v = strtoul(val, &endptr, 10);
533 	if (v > 60 || *endptr != '.')
534 		goto error;
535 	date[6] = v;
536 	val = endptr + 1;
537 
538 	/* '(deci-)s,' */
539 	v = strtoul(val, &endptr, 10);
540 	if (v > 9 || *endptr != ',')
541 		goto error;
542 	date[7] = v;
543 	val = endptr + 1;
544 
545 	/* offset - '+/-' */
546 	if (*val != '-' && *val != '+')
547 		goto error;
548 	date[8] = (uint8_t) *val;
549 	val = endptr + 1;
550 
551 	/* 'HH:' - offset from UTC */
552 	v = strtoul(val, &endptr, 10);
553 	if (v > 13 || *endptr != ':')
554 		goto error;
555 	date[9] = v;
556 	val = endptr + 1;
557 
558 	/* 'MM'\0''  offset from UTC */
559 	v = strtoul(val, &endptr, 10);
560 	if (v > 59 || *endptr != '\0')
561 		goto error;
562 	date[10] = v;
563 
564 	if ((sv->v.octetstring.octets = malloc(SNMP_DATETIME_OCTETS)) == NULL) {
565 		warnx("malloc() failed - %s", strerror(errno));
566 		return (-1);
567 	}
568 
569 	sv->v.octetstring.len = SNMP_DATETIME_OCTETS;
570 	memcpy(sv->v.octetstring.octets, date, SNMP_DATETIME_OCTETS);
571 	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
572 	return (1);
573 
574   error:
575 	warnx("Date value %s not supported", val);
576 	return (-1);
577 }
578 
579 /**************************************************************
580  * PhysAddress
581  */
582 static char *
583 snmp_oct2physAddr(uint32_t len, char *octets, char *buf)
584 {
585 	char *ptr;
586 	uint32_t i;
587 
588 	if (len != SNMP_PHYSADDR_OCTETS || octets == NULL || buf == NULL)
589 		return (NULL);
590 
591 	buf[0]= '\0';
592 
593 	ptr = buf;
594 	ptr += sprintf(ptr, "%2.2x", octets[0]);
595 	for (i = 1; i < 6; i++)
596 		ptr += sprintf(ptr, ":%2.2x", octets[i]);
597 
598 	return (buf);
599 }
600 
601 static char *
602 snmp_addr2asn_oid(char *str, struct asn_oid *oid)
603 {
604 	char *endptr, *ptr;
605 	uint32_t v, i;
606 	int saved_errno;
607 
608 	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_PHYSADDR_OCTETS) < 0)
609 		return (NULL);
610 
611 	ptr = str;
612 	for (i = 0; i < 5; i++) {
613 		saved_errno = errno;
614 		v = strtoul(ptr, &endptr, 16);
615 		errno = saved_errno;
616 		if (v > 0xff) {
617 			warnx("Integer value %s not supported", str);
618 			return (NULL);
619 		}
620 		if (*endptr != ':') {
621 			warnx("Failed adding oid - %s",str);
622 			return (NULL);
623 		}
624 		if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
625 			return (NULL);
626 		ptr = endptr + 1;
627 	}
628 
629 	/* The last one - don't check the ending char here. */
630 	saved_errno = errno;
631 	v = strtoul(ptr, &endptr, 16);
632 	errno = saved_errno;
633 	if (v > 0xff) {
634 		warnx("Integer value %s not supported", str);
635 		return (NULL);
636 	}
637 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
638 		return (NULL);
639 
640 	return (endptr);
641 }
642 
643 static int32_t
644 parse_physaddress(struct snmp_value *sv, char *val)
645 {
646 	char *endptr;
647 	int32_t i;
648 	uint32_t v;
649 	uint8_t	phys_addr[SNMP_PHYSADDR_OCTETS];
650 
651 	for (i = 0; i < 5; i++) {
652 		v = strtoul(val, &endptr, 16);
653 		if (v > 0xff) {
654 			warnx("Integer value %s not supported", val);
655 			return (-1);
656 		}
657 		if(*endptr != ':') {
658 			warnx("Failed reading octet - %s", val);
659 			return (-1);
660 		}
661 		phys_addr[i] = v;
662 		val = endptr + 1;
663 	}
664 
665 	/* The last one - don't check the ending char here. */
666 	v = strtoul(val, &endptr, 16);
667 	if (v > 0xff) {
668 		warnx("Integer value %s not supported", val);
669 		return (-1);
670 	}
671 	phys_addr[5] = v;
672 
673 	if ((sv->v.octetstring.octets = malloc(SNMP_PHYSADDR_OCTETS)) == NULL) {
674 		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
675 		return (-1);
676 	}
677 
678 	sv->v.octetstring.len = SNMP_PHYSADDR_OCTETS;
679 	memcpy(sv->v.octetstring.octets, phys_addr, SNMP_PHYSADDR_OCTETS);
680 	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
681 	return (1);
682 }
683 
684 /**************************************************************
685  * NTPTimeStamp
686  **************************************************************
687  * NTP MIB, Revision 0.2, 7/25/97:
688  * NTPTimeStamp ::= TEXTUAL-CONVENTION
689  *    DISPLAY-HINT "4x.4x"
690  *    STATUS	current
691  *    DESCRIPTION
692  *	""
693  *    SYNTAX	OCTET STRING (SIZE(8))
694  */
695 static char *
696 snmp_oct2ntp_ts(uint32_t len, char *octets, char *buf)
697 {
698 	char *ptr;
699 	uint32_t i;
700 
701 	if (len != SNMP_NTP_TS_OCTETS || octets == NULL || buf == NULL)
702 		return (NULL);
703 
704 	buf[0]= '\0';
705 
706 	ptr = buf;
707 	i = octets[0] * 1000 + octets[1] * 100 + octets[2] * 10 + octets[3];
708 	ptr += sprintf(ptr, "%4.4d", i);
709 	i = octets[4] * 1000 + octets[5] * 100 + octets[6] * 10 + octets[7];
710 	ptr += sprintf(ptr, ".%4.4d", i);
711 
712 	return (buf);
713 }
714 
715 static char *
716 snmp_ntp_ts2asn_oid(char *str, struct asn_oid *oid)
717 {
718 	char *endptr, *ptr;
719 	uint32_t v, i, d;
720 	struct asn_oid suboid;
721 	int saved_errno;
722 
723 	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_NTP_TS_OCTETS) < 0)
724 		return (NULL);
725 
726 	ptr = str;
727 	saved_errno = errno;
728 	v = strtoul(ptr, &endptr, 10);
729 	if (errno != 0 || (v / 1000) > 9) {
730 		warnx("Integer value %s not supported", str);
731 		errno = saved_errno;
732 		return (NULL);
733 	} else
734 		errno = saved_errno;
735 
736 	if (*endptr != '.') {
737 		warnx("Failed adding oid - %s",str);
738 		return (NULL);
739 	}
740 
741 	memset(&suboid, 0, sizeof(struct asn_oid));
742 	suboid.len = SNMP_NTP_TS_OCTETS;
743 
744 	for (i = 0, d = 1000; i < 4; i++) {
745 		suboid.subs[i] = v / d;
746 		v = v % d;
747 		d = d / 10;
748 	}
749 
750 	ptr = endptr + 1;
751 	saved_errno = errno;
752 	v = strtoul(ptr, &endptr, 10);
753 	if (errno != 0 || (v / 1000) > 9) {
754 		warnx("Integer value %s not supported", str);
755 		errno = saved_errno;
756 		return (NULL);
757 	} else
758 		errno = saved_errno;
759 
760 	for (i = 0, d = 1000; i < 4; i++) {
761 		suboid.subs[i + 4] = v / d;
762 		v = v % d;
763 		d = d / 10;
764 	}
765 
766 	asn_append_oid(oid, &suboid);
767 	return (endptr);
768 }
769 
770 static int32_t
771 parse_ntp_ts(struct snmp_value *sv, char *val)
772 {
773 	char *endptr;
774 	int32_t i, d, saved_errno;
775 	uint32_t v;
776 	uint8_t	ntp_ts[SNMP_NTP_TS_OCTETS];
777 
778 	saved_errno = errno;
779 	v = strtoul(val, &endptr, 10);
780 	if (errno != 0 || (v / 1000) > 9) {
781 		saved_errno = errno;
782 		warnx("Integer value %s not supported", val);
783 		return (-1);
784 	} else
785 		saved_errno = errno;
786 
787 	if (*endptr != '.') {
788 		warnx("Failed reading octet - %s", val);
789 		return (-1);
790 	}
791 
792 	for (i = 0, d = 1000; i < 4; i++) {
793 		ntp_ts[i] = v / d;
794 		v = v % d;
795 		d = d / 10;
796 	}
797 	val = endptr + 1;
798 
799 	saved_errno = errno;
800 	v = strtoul(val, &endptr, 10);
801 	if (errno != 0 || (v / 1000) > 9) {
802 		saved_errno = errno;
803 		warnx("Integer value %s not supported", val);
804 		return (-1);
805 	} else
806 		saved_errno = errno;
807 
808 	for (i = 0, d = 1000; i < 4; i++) {
809 		ntp_ts[i + 4] = v / d;
810 		v = v % d;
811 		d = d / 10;
812 	}
813 
814 	if ((sv->v.octetstring.octets = malloc(SNMP_NTP_TS_OCTETS)) == NULL) {
815 		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
816 		return (-1);
817 	}
818 
819 	sv->v.octetstring.len = SNMP_NTP_TS_OCTETS;
820 	memcpy(sv->v.octetstring.octets, ntp_ts, SNMP_NTP_TS_OCTETS);
821 	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
822 	return (1);
823 }
824 
825 /**************************************************************
826  * BridgeId
827  **************************************************************
828  * BRIDGE-MIB, REVISION		"200509190000Z"
829  * BridgeId ::= TEXTUAL-CONVENTION
830  *    STATUS	current
831  *    DESCRIPTION
832  *	"The Bridge-Identifier, as used in the Spanning Tree
833  *	Protocol, to uniquely identify a bridge.  Its first two
834  *	octets (in network byte order) contain a priority value,
835  *	and its last 6 octets contain the MAC address used to
836  *	refer to a bridge in a unique fashion (typically, the
837  *	numerically smallest MAC address of all ports on the
838  *	bridge)."
839  *    SYNTAX	OCTET STRING (SIZE (8))
840  */
841 static char *
842 snmp_oct2bridgeid(uint32_t len, char *octets, char *buf)
843 {
844 	char *ptr;
845 	uint32_t i, priority;
846 
847 	if (len != SNMP_BRIDGEID_OCTETS || octets == NULL || buf == NULL)
848 		return (NULL);
849 
850 	buf[0]= '\0';
851 	ptr = buf;
852 
853 	priority = octets[0] << 8;
854 	priority += octets[1];
855 	if (priority > SNMP_MAX_BRIDGE_PRIORITY) {
856 		warnx("Invalid bridge priority %d", priority);
857 		return (NULL);
858 	} else
859 		ptr += sprintf(ptr, "%d.", octets[0]);
860 
861 	ptr += sprintf(ptr, "%2.2x", octets[2]);
862 
863 	for (i = 1; i < 6; i++)
864 		ptr += sprintf(ptr, ":%2.2x", octets[i + 2]);
865 
866 	return (buf);
867 }
868 
869 static char *
870 snmp_bridgeid2oct(char *str, struct asn_oid *oid)
871 {
872 	char *endptr, *ptr;
873 	uint32_t v, i;
874 	int32_t saved_errno;
875 
876 	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BRIDGEID_OCTETS) < 0)
877 		return (NULL);
878 
879 	ptr = str;
880 	/* Read the priority. */
881 	saved_errno = errno;
882 	v = strtoul(ptr, &endptr, 10);
883 	errno = 0;
884 
885 	if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
886 		errno = saved_errno;
887 		warnx("Bad bridge priority value %d", v);
888 		return (NULL);
889 	}
890 
891 	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff00)) < 0)
892 		return (NULL);
893 
894 	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
895 		return (NULL);
896 
897 	ptr = endptr + 1;
898 	for (i = 0; i < 5; i++) {
899 		saved_errno = errno;
900 		v = strtoul(ptr, &endptr, 16);
901 		errno = saved_errno;
902 		if (v > 0xff) {
903 			warnx("Integer value %s not supported", str);
904 			return (NULL);
905 		}
906 		if (*endptr != ':') {
907 			warnx("Failed adding oid - %s",str);
908 			return (NULL);
909 		}
910 		if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
911 			return (NULL);
912 		ptr = endptr + 1;
913 	}
914 
915 	/* The last one - don't check the ending char here. */
916 	saved_errno = errno;
917 	v = strtoul(ptr, &endptr, 16);
918 	errno = saved_errno;
919 	if (v > 0xff) {
920 		warnx("Integer value %s not supported", str);
921 		return (NULL);
922 	}
923 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
924 		return (NULL);
925 
926 	return (endptr);
927 }
928 
929 static int32_t
930 parse_bridge_id(struct snmp_value *sv, char *string)
931 {
932 	char *ptr, *endptr;
933 	int32_t i, saved_errno;
934 	uint32_t v;
935 	uint8_t	bridge_id[SNMP_BRIDGEID_OCTETS];
936 
937 	ptr = string;
938 	/* Read the priority. */
939 	saved_errno = errno;
940 	errno = 0;
941 	v = strtoul(string, &endptr, 10);
942 	errno = saved_errno;
943 
944 	if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
945 		errno = saved_errno;
946 		warnx("Bad bridge priority value %d", v);
947 		return (-1);
948 	}
949 
950 	bridge_id[0] = (v & 0xff00);
951 	bridge_id[1] = (v & 0xff);
952 
953 	string = endptr + 1;
954 
955 	for (i = 0; i < 5; i++) {
956 		v = strtoul(string, &endptr, 16);
957 		if (v > 0xff) {
958 			warnx("Integer value %s not supported", string);
959 			return (-1);
960 		}
961 		if(*endptr != ':') {
962 			warnx("Failed reading octet - %s", string);
963 			return (-1);
964 		}
965 		bridge_id[i + 2] = v;
966 		string = endptr + 1;
967 	}
968 
969 	/* The last one - don't check the ending char here. */
970 	v = strtoul(string, &endptr, 16);
971 	if (v > 0xff) {
972 		warnx("Integer value %s not supported", string);
973 		return (-1);
974 	}
975 	bridge_id[7] = v;
976 
977 	if ((sv->v.octetstring.octets = malloc(SNMP_BRIDGEID_OCTETS)) == NULL) {
978 		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
979 		return (-1);
980 	}
981 
982 	sv->v.octetstring.len = SNMP_BRIDGEID_OCTETS;
983 	memcpy(sv->v.octetstring.octets, bridge_id, SNMP_BRIDGEID_OCTETS);
984 	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
985 	return (1);
986 }
987 
988 /**************************************************************
989  * BridgePortId
990  **************************************************************
991  * BEGEMOT-BRIDGE-MIB, LAST-UPDATED "200608100000Z"
992  * BridgePortId ::= TEXTUAL-CONVENTION
993  *    DISPLAY-HINT "1x.1x"
994  *    STATUS	current
995  *    DESCRIPTION
996  *	"A port identifier that contains a bridge port's STP priority
997  *	in the first octet and the port number in the second octet."
998  *    SYNTAX	OCTET STRING (SIZE(2))
999  */
1000 static char *
1001 snmp_oct2bport_id(uint32_t len, char *octets, char *buf)
1002 {
1003 	char *ptr;
1004 
1005 	if (len != SNMP_BPORT_OCTETS || octets == NULL || buf == NULL)
1006 		return (NULL);
1007 
1008 	buf[0]= '\0';
1009 	ptr = buf;
1010 
1011 	ptr += sprintf(ptr, "%d.", octets[0]);
1012 	ptr += sprintf(ptr, "%d", octets[1]);
1013 
1014 	return (buf);
1015 }
1016 
1017 static char *
1018 snmp_bport_id2oct(char *str, struct asn_oid *oid)
1019 {
1020 	char *endptr, *ptr;
1021 	uint32_t v;
1022 	int saved_errno;
1023 
1024 	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BPORT_OCTETS) < 0)
1025 		return (NULL);
1026 
1027 	ptr = str;
1028 	/* Read the priority. */
1029 	saved_errno = errno;
1030 	v = strtoul(ptr, &endptr, 10);
1031 	errno = 0;
1032 
1033 	if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
1034 		errno = saved_errno;
1035 		warnx("Bad bridge port priority value %d", v);
1036 		return (NULL);
1037 	}
1038 
1039 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1040 		return (NULL);
1041 
1042 	saved_errno = errno;
1043 	v = strtoul(ptr, &endptr, 16);
1044 	errno = saved_errno;
1045 
1046 	if (v > 0xff) {
1047 		warnx("Bad port number - %d", v);
1048 		return (NULL);
1049 	}
1050 
1051 	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1052 		return (NULL);
1053 
1054 	return (endptr);
1055 }
1056 
1057 static int32_t
1058 parse_bport_id(struct snmp_value *value, char *string)
1059 {
1060 	char *ptr, *endptr;
1061 	int saved_errno;
1062 	uint32_t v;
1063 	uint8_t	bport_id[SNMP_BPORT_OCTETS];
1064 
1065 	ptr = string;
1066 	/* Read the priority. */
1067 	saved_errno = errno;
1068 	errno = 0;
1069 	v = strtoul(string, &endptr, 10);
1070 	errno = saved_errno;
1071 
1072 	if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
1073 		errno = saved_errno;
1074 		warnx("Bad bridge port priority value %d", v);
1075 		return (-1);
1076 	}
1077 
1078 	bport_id[0] = v;
1079 
1080 	string = endptr + 1;
1081 	v = strtoul(string, &endptr, 16);
1082 	if (v > 0xff) {
1083 		warnx("Bad port number - %d", v);
1084 		return (-1);
1085 	}
1086 
1087 	bport_id[1] = v;
1088 
1089 	if ((value->v.octetstring.octets = malloc(SNMP_BPORT_OCTETS)) == NULL) {
1090 		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
1091 		return (-1);
1092 	}
1093 
1094 	value->v.octetstring.len = SNMP_BPORT_OCTETS;
1095 	memcpy(value->v.octetstring.octets, bport_id, SNMP_BPORT_OCTETS);
1096 	value->syntax = SNMP_SYNTAX_OCTETSTRING;
1097 	return (1);
1098 }
1099 /**************************************************************
1100  * InetAddress
1101  **************************************************************
1102  * INET-ADDRESS-MIB, REVISION     "200502040000Z"
1103  * InetAddress ::= TEXTUAL-CONVENTION
1104  *   STATUS      current
1105  *   DESCRIPTION
1106  *       "Denotes a generic Internet address.
1107  *
1108  *        An InetAddress value is always interpreted within the context
1109  *        of an InetAddressType value.  Every usage of the InetAddress
1110  *        textual convention is required to specify the InetAddressType
1111  *        object that provides the context.  It is suggested that the
1112  *        InetAddressType object be logically registered before the
1113  *        object(s) that use the InetAddress textual convention, if
1114  *        they appear in the same logical row.
1115  *
1116  *        The value of an InetAddress object must always be
1117  *        consistent with the value of the associated InetAddressType
1118  *        object.  Attempts to set an InetAddress object to a value
1119  *        inconsistent with the associated InetAddressType
1120  *        must fail with an inconsistentValue error.
1121  *
1122  *        When this textual convention is used as the syntax of an
1123  *        index object, there may be issues with the limit of 128
1124  *        sub-identifiers specified in SMIv2, STD 58.  In this case,
1125  *        the object definition MUST include a 'SIZE' clause to
1126  *        limit the number of potential instance sub-identifiers;
1127  *        otherwise the applicable constraints MUST be stated in
1128  *        the appropriate conceptual row DESCRIPTION clauses, or
1129  *        in the surrounding documentation if there is no single
1130  *        DESCRIPTION clause that is appropriate."
1131  *   SYNTAX       OCTET STRING (SIZE (0..255))
1132  **************************************************************
1133  * TODO: FIXME!!! syrinx: Since we do not support checking the
1134  * consistency of a varbinding based on the value of a previous
1135  * one, try to guess the type of address based on the
1136  * OctetString SIZE - 4 for IPv4, 16 for IPv6, others currently
1137  * not supported.
1138  */
1139 static char *
1140 snmp_oct2inetaddr(uint32_t len, char *octets, char *buf)
1141 {
1142 	int af;
1143 	void *ip;
1144 	struct in_addr	ipv4;
1145 	struct in6_addr	ipv6;
1146 
1147 	if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL)
1148 		return (NULL);
1149 
1150 	switch (len) {
1151 		/* XXX: FIXME - IPv4*/
1152 		case 4:
1153 			memcpy(&ipv4.s_addr, octets, sizeof(ipv4.s_addr));
1154 			af = AF_INET;
1155 			ip = &ipv4;
1156 			break;
1157 
1158 		/* XXX: FIXME - IPv4*/
1159 		case 16:
1160 			memcpy(ipv6.s6_addr, octets, sizeof(ipv6.s6_addr));
1161 			af = AF_INET6;
1162 			ip = &ipv6;
1163 			break;
1164 
1165 		default:
1166 			return (NULL);
1167 	}
1168 
1169 	if (inet_ntop(af, ip, buf, SNMP_INADDRS_STRSZ) == NULL) {
1170 		warnx("inet_ntop failed - %s", strerror(errno));
1171 		return (NULL);
1172 	}
1173 
1174 	return (buf);
1175 }
1176 
1177 static char *
1178 snmp_inetaddr2oct(char *str, struct asn_oid *oid)
1179 {
1180 	return (NULL);
1181 }
1182 
1183 static int32_t
1184 parse_inetaddr(struct snmp_value *value, char *string)
1185 {
1186 	return (-1);
1187 }
1188 
1189 /**************************************************************
1190  * SNMP BITS type - XXX: FIXME
1191  **************************************************************/
1192 static char *
1193 snmp_oct2bits(uint32_t len, char *octets, char *buf)
1194 {
1195 	int i, bits;
1196 	uint64_t value;
1197 
1198 	if (len > sizeof(value) || octets == NULL || buf == NULL)
1199 		return (NULL);
1200 
1201 	for (i = len, value = 0, bits = 0; i > 0; i--, bits += 8)
1202 		value += octets[i] << bits;
1203 
1204 	buf[0]= '\0';
1205 	sprintf(buf, "0x%llx.",(long long unsigned) value);
1206 
1207 	return (buf);
1208 }
1209 
1210 static char *
1211 snmp_bits2oct(char *str, struct asn_oid *oid)
1212 {
1213 	char *endptr;
1214 	int i, size, bits, saved_errno;
1215 	uint64_t v, mask = 0xFF00000000000000;
1216 
1217 	saved_errno = errno;
1218 	errno = 0;
1219 
1220 	v = strtoull(str, &endptr, 16);
1221 	if (errno != 0) {
1222 		warnx("Bad BITS value %s - %s", str, strerror(errno));
1223 		errno = saved_errno;
1224 		return (NULL);
1225 	}
1226 
1227 	bits = 8;
1228 	/* Determine length - up to 8 octets supported so far. */
1229 	for (size = sizeof(v); size > 0; size--) {
1230 		if ((v & mask) != 0)
1231 			break;
1232 		mask = mask >> bits;
1233 	}
1234 
1235 	if (size == 0)
1236 		size = 1;
1237 
1238 	if (snmp_suboid_append(oid, (asn_subid_t) size) < 0)
1239 		return (NULL);
1240 
1241 	for (i = 0, bits = 0; i < size; i++, bits += 8)
1242 		if (snmp_suboid_append(oid,
1243 		    (asn_subid_t)((v & mask) >> bits)) < 0)
1244 			return (NULL);
1245 
1246 	return (endptr);
1247 }
1248 
1249 static int32_t
1250 parse_bits(struct snmp_value *value, char *string)
1251 {
1252 	char *endptr;
1253 	int i, size, bits, saved_errno;
1254 	uint64_t v, mask = 0xFF00000000000000;
1255 
1256 	saved_errno = errno;
1257 	errno = 0;
1258 
1259 	v = strtoull(string, &endptr, 16);
1260 
1261 	if (errno != 0) {
1262 		warnx("Bad BITS value %s - %s", string, strerror(errno));
1263 		errno = saved_errno;
1264 		return (-1);
1265 	}
1266 
1267 	bits = 8;
1268 	/* Determine length - up to 8 octets supported so far. */
1269 	for (size = sizeof(v); size > 0; size--) {
1270 		if ((v & mask) != 0)
1271 			break;
1272 		mask = mask >> bits;
1273 	}
1274 
1275 	if (size == 0)
1276 		size = 1;
1277 
1278 	if ((value->v.octetstring.octets = malloc(size)) == NULL) {
1279 		syslog(LOG_ERR, "malloc failed: %s", strerror(errno));
1280 		return (-1);
1281 	}
1282 
1283 	value->v.octetstring.len = size;
1284 	for (i = 0, bits = 0; i < size; i++, bits += 8)
1285 		value->v.octetstring.octets[i] = (v & mask) >> bits;
1286 	value->syntax = SNMP_SYNTAX_OCTETSTRING;
1287 	return (1);
1288 }
1289