bsnmptc.c revision 272461
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: releng/10.1/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.c 216295 2010-12-08 14:30:25Z syrinx $
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 */
58static char *snmp_oct2str(uint32_t, char *, char *);
59static char *snmp_str2asn_oid(char *, struct asn_oid *);
60static int parse_octetstring(struct snmp_value *, char *);
61
62/* DateAndTime */
63static char *snmp_octstr2date(uint32_t, char *, char *);
64static char *snmp_date2asn_oid(char * , struct asn_oid *);
65static int parse_dateandtime(struct snmp_value *, char *);
66
67/* PhysAddress */
68static char *snmp_oct2physAddr(uint32_t, char *, char *);
69static char *snmp_addr2asn_oid(char *, struct asn_oid *);
70static int parse_physaddress(struct snmp_value *, char *);
71
72/* NTPTimeStamp */
73static char *snmp_oct2ntp_ts(uint32_t, char *, char *);
74static char *snmp_ntp_ts2asn_oid(char *, struct asn_oid *);
75static int parse_ntp_ts(struct snmp_value *, char *);
76
77/* BridgeId */
78static char *snmp_oct2bridgeid(uint32_t, char *, char *);
79static char *snmp_bridgeid2oct(char *, struct asn_oid *);
80static int parse_bridge_id(struct snmp_value *, char *);
81
82/* BridgePortId */
83static char *snmp_oct2bport_id(uint32_t, char *, char *);
84static char *snmp_bport_id2oct(char *, struct asn_oid *);
85static int parse_bport_id(struct snmp_value *, char *);
86
87/* InetAddress */
88static char *snmp_oct2inetaddr(uint32_t len, char *octets, char *buf);
89static char *snmp_inetaddr2oct(char *str, struct asn_oid *oid);
90static int32_t parse_inetaddr(struct snmp_value *value, char *string);
91
92static char *snmp_oct2bits(uint32_t len, char *octets, char *buf);
93static char *snmp_bits2oct(char *str, struct asn_oid *oid);
94static int32_t parse_bits(struct snmp_value *value, char *string);
95
96struct 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 */
142enum snmp_tc
143snmp_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
155char *
156snmp_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
183char *
184snmp_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
192int32_t
193snmp_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*/
204static char *
205snmp_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
230static char *
231snmp_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
258static int32_t
259parse_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 */
315static char *
316snmp_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
337static char *
338snmp_date2asn_oid(char *str, struct asn_oid *oid)
339{
340	char *endptr, *ptr;
341	uint32_t v;
342	int32_t saved_errno;
343
344	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_DATETIME_OCTETS) < 0)
345		return (NULL);
346
347	/* Read 'YYYY-' and write it in two subs. */
348	ptr = str;
349	saved_errno = errno;
350	errno = 0;
351	v = strtoul(ptr, &endptr, 10);
352	if (v > 0xffff)
353		goto error;
354	else
355		errno = saved_errno;
356	if (*endptr != '-')
357		goto error1;
358	if (snmp_suboid_append(oid, (asn_subid_t) ((v & 0xff00) >> 8)) < 0)
359		return (NULL);
360	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
361		return (NULL);
362
363	/* 'MM-' */
364	ptr = endptr + 1;
365	saved_errno = errno;
366	v = strtoul(ptr, &endptr, 10);
367	if (errno != 0)
368		goto error;
369	else
370		errno = saved_errno;
371	if (*endptr != '-')
372		goto error1;
373	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
374		return (NULL);
375
376	/* 'DD,' */
377	ptr = endptr + 1;
378	saved_errno = errno;
379	v = strtoul(ptr, &endptr, 10);
380	if (errno != 0)
381		goto error;
382	else
383		errno = saved_errno;
384	if (*endptr != '-')
385		goto error1;
386	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
387		return (NULL);
388
389	/* 'HH:' */
390	ptr = endptr + 1;
391	saved_errno = errno;
392	v = strtoul(ptr, &endptr, 10);
393	if (errno != 0)
394		goto error;
395	else
396		errno = saved_errno;
397	if (*endptr != ':')
398		goto error1;
399	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
400		return (NULL);
401
402	/* 'MM:' */
403	ptr = endptr + 1;
404	saved_errno = errno;
405	v = strtoul(ptr, &endptr, 10);
406	if (errno != 0)
407		goto error;
408	else
409		errno = saved_errno;
410	if (*endptr != ':')
411		goto error1;
412	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
413		return (NULL);
414
415	/* 'SS.' */
416	ptr = endptr + 1;
417	saved_errno = errno;
418	v = strtoul(ptr, &endptr, 10);
419	if (errno != 0)
420		goto error;
421	else
422		errno = saved_errno;
423	if (*endptr != '.')
424		goto error1;
425	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
426		return (NULL);
427
428	/* 'M(mseconds),' */
429	ptr = endptr + 1;
430	saved_errno = errno;
431	v = strtoul(ptr, &endptr, 10);
432	if (errno != 0)
433		goto error;
434	else
435		errno = saved_errno;
436	if (*endptr != ',')
437		goto error1;
438	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
439		return (NULL);
440
441	/* 'UTC' - optional */
442	ptr = endptr + 1;
443	if (*ptr == 'U' && *(ptr + 1) == 'T' && *(ptr + 1) == 'C')
444		ptr += 3;
445
446	/* '+/-' */
447	if (*ptr == '-' || *ptr == '+') {
448		if (snmp_suboid_append(oid, (asn_subid_t) (*ptr)) < 0)
449			return (NULL);
450	} else
451		goto error1;
452
453	/* 'HH:' */
454	ptr = endptr + 1;
455	saved_errno = errno;
456	v = strtoul(ptr, &endptr, 10);
457	if (errno != 0)
458		goto error;
459	else
460		errno = saved_errno;
461	if (*endptr != ':')
462		goto error1;
463	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
464		return (NULL);
465
466	/* 'MM' - last one - ignore endptr here. */
467	ptr = endptr + 1;
468	saved_errno = errno;
469	v = strtoul(ptr, &endptr, 10);
470	if (errno != 0)
471		goto error;
472	else
473		errno = saved_errno;
474	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
475		return (NULL);
476
477	return (endptr);
478
479  error:
480	errno = saved_errno;
481  error1:
482	warnx("Date value %s not supported", str);
483	return (NULL);
484}
485
486/* Read a DateAndTime string eg. 1992-5-26,13:30:15.0,-4:0. */
487static int32_t
488parse_dateandtime(struct snmp_value *sv, char *val)
489{
490	char *endptr;
491	uint32_t v;
492	uint8_t	date[SNMP_DATETIME_OCTETS];
493
494	/* 'YYYY-' */
495	v = strtoul(val, &endptr, 10);
496	if (v > 0xffff || *endptr != '-')
497		goto error;
498	date[0] = ((v & 0xff00) >> 8);
499	date[1] = (v & 0xff);
500	val = endptr + 1;
501
502	/* 'MM-' */
503	v = strtoul(val, &endptr, 10);
504	if (v == 0 || v > 12 || *endptr != '-')
505		goto error;
506	date[2] = v;
507	val = endptr + 1;
508
509	/* 'DD,' */
510	v = strtoul(val, &endptr, 10);
511	if (v == 0 || v > 31 || *endptr != ',')
512		goto error;
513	date[3] = v;
514	val = endptr + 1;
515
516	/* 'HH:' */
517	v = strtoul(val, &endptr, 10);
518	if (v > 23 || *endptr != ':')
519		goto error;
520	date[4] = v;
521	val = endptr + 1;
522
523	/* 'MM:' */
524	v = strtoul(val, &endptr, 10);
525	if (v > 59 || *endptr != ':')
526		goto error;
527	date[5] = v;
528	val = endptr + 1;
529
530	/* 'SS.' */
531	v = strtoul(val, &endptr, 10);
532	if (v > 60 || *endptr != '.')
533		goto error;
534	date[6] = v;
535	val = endptr + 1;
536
537	/* '(deci-)s,' */
538	v = strtoul(val, &endptr, 10);
539	if (v > 9 || *endptr != ',')
540		goto error;
541	date[7] = v;
542	val = endptr + 1;
543
544	/* offset - '+/-' */
545	if (*val != '-' && *val != '+')
546		goto error;
547	date[8] = (uint8_t) *val;
548	val = endptr + 1;
549
550	/* 'HH:' - offset from UTC */
551	v = strtoul(val, &endptr, 10);
552	if (v > 13 || *endptr != ':')
553		goto error;
554	date[9] = v;
555	val = endptr + 1;
556
557	/* 'MM'\0''  offset from UTC */
558	v = strtoul(val, &endptr, 10);
559	if (v > 59 || *endptr != '\0')
560		goto error;
561	date[10] = v;
562
563	if ((sv->v.octetstring.octets = malloc(SNMP_DATETIME_OCTETS)) == NULL) {
564		warnx("malloc() failed - %s", strerror(errno));
565		return (-1);
566	}
567
568	sv->v.octetstring.len = SNMP_DATETIME_OCTETS;
569	memcpy(sv->v.octetstring.octets, date, SNMP_DATETIME_OCTETS);
570	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
571	return (1);
572
573  error:
574	warnx("Date value %s not supported", val);
575	return (-1);
576}
577
578/**************************************************************
579 * PhysAddress
580 */
581static char *
582snmp_oct2physAddr(uint32_t len, char *octets, char *buf)
583{
584	char *ptr;
585	uint32_t i;
586
587	if (len != SNMP_PHYSADDR_OCTETS || octets == NULL || buf == NULL)
588		return (NULL);
589
590	buf[0]= '\0';
591
592	ptr = buf;
593	ptr += sprintf(ptr, "%2.2x", octets[0]);
594	for (i = 1; i < 6; i++)
595		ptr += sprintf(ptr, ":%2.2x", octets[i]);
596
597	return (buf);
598}
599
600static char *
601snmp_addr2asn_oid(char *str, struct asn_oid *oid)
602{
603	char *endptr, *ptr;
604	uint32_t v, i;
605	int saved_errno;
606
607	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_PHYSADDR_OCTETS) < 0)
608		return (NULL);
609
610	ptr = str;
611	for (i = 0; i < 5; i++) {
612		saved_errno = errno;
613		v = strtoul(ptr, &endptr, 16);
614		errno = saved_errno;
615		if (v > 0xff) {
616			warnx("Integer value %s not supported", str);
617			return (NULL);
618		}
619		if (*endptr != ':') {
620			warnx("Failed adding oid - %s",str);
621			return (NULL);
622		}
623		if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
624			return (NULL);
625		ptr = endptr + 1;
626	}
627
628	/* The last one - don't check the ending char here. */
629	saved_errno = errno;
630	v = strtoul(ptr, &endptr, 16);
631	errno = saved_errno;
632	if (v > 0xff) {
633		warnx("Integer value %s not supported", str);
634		return (NULL);
635	}
636	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
637		return (NULL);
638
639	return (endptr);
640}
641
642static int32_t
643parse_physaddress(struct snmp_value *sv, char *val)
644{
645	char *endptr;
646	int32_t i;
647	uint32_t v;
648	uint8_t	phys_addr[SNMP_PHYSADDR_OCTETS];
649
650	for (i = 0; i < 5; i++) {
651		v = strtoul(val, &endptr, 16);
652		if (v > 0xff) {
653			warnx("Integer value %s not supported", val);
654			return (-1);
655		}
656		if(*endptr != ':') {
657			warnx("Failed reading octet - %s", val);
658			return (-1);
659		}
660		phys_addr[i] = v;
661		val = endptr + 1;
662	}
663
664	/* The last one - don't check the ending char here. */
665	v = strtoul(val, &endptr, 16);
666	if (v > 0xff) {
667		warnx("Integer value %s not supported", val);
668		return (-1);
669	}
670	phys_addr[5] = v;
671
672	if ((sv->v.octetstring.octets = malloc(SNMP_PHYSADDR_OCTETS)) == NULL) {
673		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
674		return (-1);
675	}
676
677	sv->v.octetstring.len = SNMP_PHYSADDR_OCTETS;
678	memcpy(sv->v.octetstring.octets, phys_addr, SNMP_PHYSADDR_OCTETS);
679	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
680	return (1);
681}
682
683/**************************************************************
684 * NTPTimeStamp
685 **************************************************************
686 * NTP MIB, Revision 0.2, 7/25/97:
687 * NTPTimeStamp ::= TEXTUAL-CONVENTION
688 *    DISPLAY-HINT "4x.4x"
689 *    STATUS	current
690 *    DESCRIPTION
691 *	""
692 *    SYNTAX	OCTET STRING (SIZE(8))
693 */
694static char *
695snmp_oct2ntp_ts(uint32_t len, char *octets, char *buf)
696{
697	char *ptr;
698	uint32_t i;
699
700	if (len != SNMP_NTP_TS_OCTETS || octets == NULL || buf == NULL)
701		return (NULL);
702
703	buf[0]= '\0';
704
705	ptr = buf;
706	i = octets[0] * 1000 + octets[1] * 100 + octets[2] * 10 + octets[3];
707	ptr += sprintf(ptr, "%4.4d", i);
708	i = octets[4] * 1000 + octets[5] * 100 + octets[6] * 10 + octets[7];
709	ptr += sprintf(ptr, ".%4.4d", i);
710
711	return (buf);
712}
713
714static char *
715snmp_ntp_ts2asn_oid(char *str, struct asn_oid *oid)
716{
717	char *endptr, *ptr;
718	uint32_t v, i, d;
719	struct asn_oid suboid;
720	int saved_errno;
721
722	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_NTP_TS_OCTETS) < 0)
723		return (NULL);
724
725	ptr = str;
726	saved_errno = errno;
727	v = strtoul(ptr, &endptr, 10);
728	if (errno != 0 || (v / 1000) > 9) {
729		warnx("Integer value %s not supported", str);
730		errno = saved_errno;
731		return (NULL);
732	} else
733		errno = saved_errno;
734
735	if (*endptr != '.') {
736		warnx("Failed adding oid - %s",str);
737		return (NULL);
738	}
739
740	memset(&suboid, 0, sizeof(struct asn_oid));
741	suboid.len = SNMP_NTP_TS_OCTETS;
742
743	for (i = 0, d = 1000; i < 4; i++) {
744		suboid.subs[i] = v / d;
745		v = v % d;
746		d = d / 10;
747	}
748
749	ptr = endptr + 1;
750	saved_errno = errno;
751	v = strtoul(ptr, &endptr, 10);
752	if (errno != 0 || (v / 1000) > 9) {
753		warnx("Integer value %s not supported", str);
754		errno = saved_errno;
755		return (NULL);
756	} else
757		errno = saved_errno;
758
759	for (i = 0, d = 1000; i < 4; i++) {
760		suboid.subs[i + 4] = v / d;
761		v = v % d;
762		d = d / 10;
763	}
764
765	asn_append_oid(oid, &suboid);
766	return (endptr);
767}
768
769static int32_t
770parse_ntp_ts(struct snmp_value *sv, char *val)
771{
772	char *endptr;
773	int32_t i, d, saved_errno;
774	uint32_t v;
775	uint8_t	ntp_ts[SNMP_NTP_TS_OCTETS];
776
777	saved_errno = errno;
778	v = strtoul(val, &endptr, 10);
779	if (errno != 0 || (v / 1000) > 9) {
780		saved_errno = errno;
781		warnx("Integer value %s not supported", val);
782		return (-1);
783	} else
784		saved_errno = errno;
785
786	if (*endptr != '.') {
787		warnx("Failed reading octet - %s", val);
788		return (-1);
789	}
790
791	for (i = 0, d = 1000; i < 4; i++) {
792		ntp_ts[i] = v / d;
793		v = v % d;
794		d = d / 10;
795	}
796	val = endptr + 1;
797
798	saved_errno = errno;
799	v = strtoul(val, &endptr, 10);
800	if (errno != 0 || (v / 1000) > 9) {
801		saved_errno = errno;
802		warnx("Integer value %s not supported", val);
803		return (-1);
804	} else
805		saved_errno = errno;
806
807	for (i = 0, d = 1000; i < 4; i++) {
808		ntp_ts[i + 4] = v / d;
809		v = v % d;
810		d = d / 10;
811	}
812
813	if ((sv->v.octetstring.octets = malloc(SNMP_NTP_TS_OCTETS)) == NULL) {
814		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
815		return (-1);
816	}
817
818	sv->v.octetstring.len = SNMP_NTP_TS_OCTETS;
819	memcpy(sv->v.octetstring.octets, ntp_ts, SNMP_NTP_TS_OCTETS);
820	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
821	return (1);
822}
823
824/**************************************************************
825 * BridgeId
826 **************************************************************
827 * BRIDGE-MIB, REVISION		"200509190000Z"
828 * BridgeId ::= TEXTUAL-CONVENTION
829 *    STATUS	current
830 *    DESCRIPTION
831 *	"The Bridge-Identifier, as used in the Spanning Tree
832 *	Protocol, to uniquely identify a bridge.  Its first two
833 *	octets (in network byte order) contain a priority value,
834 *	and its last 6 octets contain the MAC address used to
835 *	refer to a bridge in a unique fashion (typically, the
836 *	numerically smallest MAC address of all ports on the
837 *	bridge)."
838 *    SYNTAX	OCTET STRING (SIZE (8))
839 */
840static char *
841snmp_oct2bridgeid(uint32_t len, char *octets, char *buf)
842{
843	char *ptr;
844	uint32_t i, priority;
845
846	if (len != SNMP_BRIDGEID_OCTETS || octets == NULL || buf == NULL)
847		return (NULL);
848
849	buf[0]= '\0';
850	ptr = buf;
851
852	priority = octets[0] << 8;
853	priority += octets[1];
854	if (priority > SNMP_MAX_BRIDGE_PRIORITY) {
855		warnx("Invalid bridge priority %d", priority);
856		return (NULL);
857	} else
858		ptr += sprintf(ptr, "%d.", octets[0]);
859
860	ptr += sprintf(ptr, "%2.2x", octets[2]);
861
862	for (i = 1; i < 6; i++)
863		ptr += sprintf(ptr, ":%2.2x", octets[i + 2]);
864
865	return (buf);
866}
867
868static char *
869snmp_bridgeid2oct(char *str, struct asn_oid *oid)
870{
871	char *endptr, *ptr;
872	uint32_t v, i;
873	int32_t saved_errno;
874
875	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BRIDGEID_OCTETS) < 0)
876		return (NULL);
877
878	ptr = str;
879	/* Read the priority. */
880	saved_errno = errno;
881	v = strtoul(ptr, &endptr, 10);
882	errno = 0;
883
884	if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
885		errno = saved_errno;
886		warnx("Bad bridge priority value %d", v);
887		return (NULL);
888	}
889
890	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff00)) < 0)
891		return (NULL);
892
893	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
894		return (NULL);
895
896	ptr = endptr + 1;
897	for (i = 0; i < 5; i++) {
898		saved_errno = errno;
899		v = strtoul(ptr, &endptr, 16);
900		errno = saved_errno;
901		if (v > 0xff) {
902			warnx("Integer value %s not supported", str);
903			return (NULL);
904		}
905		if (*endptr != ':') {
906			warnx("Failed adding oid - %s",str);
907			return (NULL);
908		}
909		if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
910			return (NULL);
911		ptr = endptr + 1;
912	}
913
914	/* The last one - don't check the ending char here. */
915	saved_errno = errno;
916	v = strtoul(ptr, &endptr, 16);
917	errno = saved_errno;
918	if (v > 0xff) {
919		warnx("Integer value %s not supported", str);
920		return (NULL);
921	}
922	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
923		return (NULL);
924
925	return (endptr);
926}
927
928static int32_t
929parse_bridge_id(struct snmp_value *sv, char *string)
930{
931	char *ptr, *endptr;
932	int32_t i, saved_errno;
933	uint32_t v;
934	uint8_t	bridge_id[SNMP_BRIDGEID_OCTETS];
935
936	ptr = string;
937	/* Read the priority. */
938	saved_errno = errno;
939	errno = 0;
940	v = strtoul(string, &endptr, 10);
941	errno = saved_errno;
942
943	if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
944		errno = saved_errno;
945		warnx("Bad bridge priority value %d", v);
946		return (-1);
947	}
948
949	bridge_id[0] = (v & 0xff00);
950	bridge_id[1] = (v & 0xff);
951
952	string = endptr + 1;
953
954	for (i = 0; i < 5; i++) {
955		v = strtoul(string, &endptr, 16);
956		if (v > 0xff) {
957			warnx("Integer value %s not supported", string);
958			return (-1);
959		}
960		if(*endptr != ':') {
961			warnx("Failed reading octet - %s", string);
962			return (-1);
963		}
964		bridge_id[i + 2] = v;
965		string = endptr + 1;
966	}
967
968	/* The last one - don't check the ending char here. */
969	v = strtoul(string, &endptr, 16);
970	if (v > 0xff) {
971		warnx("Integer value %s not supported", string);
972		return (-1);
973	}
974	bridge_id[7] = v;
975
976	if ((sv->v.octetstring.octets = malloc(SNMP_BRIDGEID_OCTETS)) == NULL) {
977		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
978		return (-1);
979	}
980
981	sv->v.octetstring.len = SNMP_BRIDGEID_OCTETS;
982	memcpy(sv->v.octetstring.octets, bridge_id, SNMP_BRIDGEID_OCTETS);
983	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
984	return (1);
985}
986
987/**************************************************************
988 * BridgePortId
989 **************************************************************
990 * BEGEMOT-BRIDGE-MIB, LAST-UPDATED "200608100000Z"
991 * BridgePortId ::= TEXTUAL-CONVENTION
992 *    DISPLAY-HINT "1x.1x"
993 *    STATUS	current
994 *    DESCRIPTION
995 *	"A port identifier that contains a bridge port's STP priority
996 *	in the first octet and the port number in the second octet."
997 *    SYNTAX	OCTET STRING (SIZE(2))
998 */
999static char *
1000snmp_oct2bport_id(uint32_t len, char *octets, char *buf)
1001{
1002	char *ptr;
1003
1004	if (len != SNMP_BPORT_OCTETS || octets == NULL || buf == NULL)
1005		return (NULL);
1006
1007	buf[0]= '\0';
1008	ptr = buf;
1009
1010	ptr += sprintf(ptr, "%d.", octets[0]);
1011	ptr += sprintf(ptr, "%d", octets[1]);
1012
1013	return (buf);
1014}
1015
1016static char *
1017snmp_bport_id2oct(char *str, struct asn_oid *oid)
1018{
1019	char *endptr, *ptr;
1020	uint32_t v;
1021	int saved_errno;
1022
1023	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BPORT_OCTETS) < 0)
1024		return (NULL);
1025
1026	ptr = str;
1027	/* Read the priority. */
1028	saved_errno = errno;
1029	v = strtoul(ptr, &endptr, 10);
1030	errno = 0;
1031
1032	if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
1033		errno = saved_errno;
1034		warnx("Bad bridge port priority value %d", v);
1035		return (NULL);
1036	}
1037
1038	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1039		return (NULL);
1040
1041	saved_errno = errno;
1042	v = strtoul(ptr, &endptr, 16);
1043	errno = saved_errno;
1044
1045	if (v > 0xff) {
1046		warnx("Bad port number - %d", v);
1047		return (NULL);
1048	}
1049
1050	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1051		return (NULL);
1052
1053	return (endptr);
1054}
1055
1056static int32_t
1057parse_bport_id(struct snmp_value *value, char *string)
1058{
1059	char *ptr, *endptr;
1060	int saved_errno;
1061	uint32_t v;
1062	uint8_t	bport_id[SNMP_BPORT_OCTETS];
1063
1064	ptr = string;
1065	/* Read the priority. */
1066	saved_errno = errno;
1067	errno = 0;
1068	v = strtoul(string, &endptr, 10);
1069	errno = saved_errno;
1070
1071	if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
1072		errno = saved_errno;
1073		warnx("Bad bridge port priority value %d", v);
1074		return (-1);
1075	}
1076
1077	bport_id[0] = v;
1078
1079	string = endptr + 1;
1080	v = strtoul(string, &endptr, 16);
1081	if (v > 0xff) {
1082		warnx("Bad port number - %d", v);
1083		return (-1);
1084	}
1085
1086	bport_id[1] = v;
1087
1088	if ((value->v.octetstring.octets = malloc(SNMP_BPORT_OCTETS)) == NULL) {
1089		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
1090		return (-1);
1091	}
1092
1093	value->v.octetstring.len = SNMP_BPORT_OCTETS;
1094	memcpy(value->v.octetstring.octets, bport_id, SNMP_BPORT_OCTETS);
1095	value->syntax = SNMP_SYNTAX_OCTETSTRING;
1096	return (1);
1097}
1098/**************************************************************
1099 * InetAddress
1100 **************************************************************
1101 * INET-ADDRESS-MIB, REVISION     "200502040000Z"
1102 * InetAddress ::= TEXTUAL-CONVENTION
1103 *   STATUS      current
1104 *   DESCRIPTION
1105 *       "Denotes a generic Internet address.
1106 *
1107 *        An InetAddress value is always interpreted within the context
1108 *        of an InetAddressType value.  Every usage of the InetAddress
1109 *        textual convention is required to specify the InetAddressType
1110 *        object that provides the context.  It is suggested that the
1111 *        InetAddressType object be logically registered before the
1112 *        object(s) that use the InetAddress textual convention, if
1113 *        they appear in the same logical row.
1114 *
1115 *        The value of an InetAddress object must always be
1116 *        consistent with the value of the associated InetAddressType
1117 *        object.  Attempts to set an InetAddress object to a value
1118 *        inconsistent with the associated InetAddressType
1119 *        must fail with an inconsistentValue error.
1120 *
1121 *        When this textual convention is used as the syntax of an
1122 *        index object, there may be issues with the limit of 128
1123 *        sub-identifiers specified in SMIv2, STD 58.  In this case,
1124 *        the object definition MUST include a 'SIZE' clause to
1125 *        limit the number of potential instance sub-identifiers;
1126 *        otherwise the applicable constraints MUST be stated in
1127 *        the appropriate conceptual row DESCRIPTION clauses, or
1128 *        in the surrounding documentation if there is no single
1129 *        DESCRIPTION clause that is appropriate."
1130 *   SYNTAX       OCTET STRING (SIZE (0..255))
1131 **************************************************************
1132 * TODO: FIXME!!! syrinx: Since we do not support checking the
1133 * consistency of a varbinding based on the value of a previous
1134 * one, try to guess the type of address based on the
1135 * OctetString SIZE - 4 for IPv4, 16 for IPv6, others currently
1136 * not supported.
1137 */
1138static char *
1139snmp_oct2inetaddr(uint32_t len, char *octets, char *buf)
1140{
1141	int af;
1142	void *ip;
1143	struct in_addr	ipv4;
1144	struct in6_addr	ipv6;
1145
1146	if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL)
1147		return (NULL);
1148
1149	switch (len) {
1150		/* XXX: FIXME - IPv4*/
1151		case 4:
1152			memcpy(&ipv4.s_addr, octets, sizeof(ipv4.s_addr));
1153			af = AF_INET;
1154			ip = &ipv4;
1155			break;
1156
1157		/* XXX: FIXME - IPv4*/
1158		case 16:
1159			memcpy(ipv6.s6_addr, octets, sizeof(ipv6.s6_addr));
1160			af = AF_INET6;
1161			ip = &ipv6;
1162			break;
1163
1164		default:
1165			return (NULL);
1166	}
1167
1168	if (inet_ntop(af, ip, buf, SNMP_INADDRS_STRSZ) == NULL) {
1169		warnx("inet_ntop failed - %s", strerror(errno));
1170		return (NULL);
1171	}
1172
1173	return (buf);
1174}
1175
1176static char *
1177snmp_inetaddr2oct(char *str, struct asn_oid *oid)
1178{
1179	return (NULL);
1180}
1181
1182static int32_t
1183parse_inetaddr(struct snmp_value *value, char *string)
1184{
1185	return (-1);
1186}
1187
1188/**************************************************************
1189 * SNMP BITS type - XXX: FIXME
1190 **************************************************************/
1191static char *
1192snmp_oct2bits(uint32_t len, char *octets, char *buf)
1193{
1194	int i, bits;
1195	uint64_t value;
1196
1197	if (len > sizeof(value) || octets == NULL || buf == NULL)
1198		return (NULL);
1199
1200	for (i = len, value = 0, bits = 0; i > 0; i--, bits += 8)
1201		value += octets[i] << bits;
1202
1203	buf[0]= '\0';
1204	sprintf(buf, "0x%llx.",(long long unsigned) value);
1205
1206	return (buf);
1207}
1208
1209static char *
1210snmp_bits2oct(char *str, struct asn_oid *oid)
1211{
1212	char *endptr;
1213	int i, size, bits, saved_errno;
1214	uint64_t v, mask = 0xFF00000000000000;
1215
1216	saved_errno = errno;
1217	errno = 0;
1218
1219	v = strtoull(str, &endptr, 16);
1220	if (errno != 0) {
1221		warnx("Bad BITS value %s - %s", str, strerror(errno));
1222		errno = saved_errno;
1223		return (NULL);
1224	}
1225
1226	bits = 8;
1227	/* Determine length - up to 8 octets supported so far. */
1228	for (size = sizeof(v); size > 0; size--) {
1229		if ((v & mask) != 0)
1230			break;
1231		mask = mask >> bits;
1232	}
1233
1234	if (size == 0)
1235		size = 1;
1236
1237	if (snmp_suboid_append(oid, (asn_subid_t) size) < 0)
1238		return (NULL);
1239
1240	for (i = 0, bits = 0; i < size; i++, bits += 8)
1241		if (snmp_suboid_append(oid,
1242		    (asn_subid_t)((v & mask) >> bits)) < 0)
1243			return (NULL);
1244
1245	return (endptr);
1246}
1247
1248static int32_t
1249parse_bits(struct snmp_value *value, char *string)
1250{
1251	char *endptr;
1252	int i, size, bits, saved_errno;
1253	uint64_t v, mask = 0xFF00000000000000;
1254
1255	saved_errno = errno;
1256	errno = 0;
1257
1258	v = strtoull(string, &endptr, 16);
1259
1260	if (errno != 0) {
1261		warnx("Bad BITS value %s - %s", string, strerror(errno));
1262		errno = saved_errno;
1263		return (-1);
1264	}
1265
1266	bits = 8;
1267	/* Determine length - up to 8 octets supported so far. */
1268	for (size = sizeof(v); size > 0; size--) {
1269		if ((v & mask) != 0)
1270			break;
1271		mask = mask >> bits;
1272	}
1273
1274	if (size == 0)
1275		size = 1;
1276
1277	if ((value->v.octetstring.octets = malloc(size)) == NULL) {
1278		syslog(LOG_ERR, "malloc failed: %s", strerror(errno));
1279		return (-1);
1280	}
1281
1282	value->v.octetstring.len = size;
1283	for (i = 0, bits = 0; i < size; i++, bits += 8)
1284		value->v.octetstring.octets[i] = (v & mask) >> bits;
1285	value->syntax = SNMP_SYNTAX_OCTETSTRING;
1286	return (1);
1287}
1288