1216295Ssyrinx/*-
2216295Ssyrinx * Copyright (c) 2006 The FreeBSD Project
3216295Ssyrinx * All rights reserved.
4216295Ssyrinx *
5216295Ssyrinx * Author: Shteryana Shopova <syrinx@FreeBSD.org>
6216295Ssyrinx *
7216295Ssyrinx * Redistribution of this software and documentation and use in source and
8216295Ssyrinx * binary forms, with or without modification, are permitted provided that
9216295Ssyrinx * the following conditions are met:
10216295Ssyrinx *
11216295Ssyrinx * 1. Redistributions of source code or documentation must retain the above
12216295Ssyrinx *    copyright notice, this list of conditions and the following disclaimer.
13216295Ssyrinx * 2. Redistributions in binary form must reproduce the above copyright
14216295Ssyrinx *    notice, this list of conditions and the following disclaimer in the
15216295Ssyrinx *    documentation and/or other materials provided with the distribution.
16216295Ssyrinx *
17216295Ssyrinx * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18216295Ssyrinx * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19216295Ssyrinx * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20216295Ssyrinx * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21216295Ssyrinx * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22216295Ssyrinx * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23216295Ssyrinx * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24216295Ssyrinx * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25216295Ssyrinx * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26216295Ssyrinx * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27216295Ssyrinx * SUCH DAMAGE.
28216295Ssyrinx *
29216295Ssyrinx * Textual conventions for OctetStrings
30216295Ssyrinx *
31216295Ssyrinx * $FreeBSD: stable/10/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.c 311595 2017-01-07 08:46:16Z ngie $
32216295Ssyrinx */
33216295Ssyrinx
34310903Sngie#include <sys/param.h>
35216295Ssyrinx#include <sys/queue.h>
36216295Ssyrinx#include <sys/socket.h>
37216295Ssyrinx#include <sys/uio.h>
38216295Ssyrinx
39216295Ssyrinx#include <ctype.h>
40216295Ssyrinx#include <err.h>
41216295Ssyrinx#include <errno.h>
42216295Ssyrinx#include <fcntl.h>
43216295Ssyrinx#include <stdio.h>
44216295Ssyrinx#include <stdlib.h>
45216295Ssyrinx#include <string.h>
46216295Ssyrinx#include <syslog.h>
47216295Ssyrinx#include <unistd.h>
48216295Ssyrinx
49216295Ssyrinx#include <arpa/inet.h>
50216295Ssyrinx#include <netinet/in.h>
51216295Ssyrinx
52216295Ssyrinx#include <bsnmp/asn1.h>
53216295Ssyrinx#include <bsnmp/snmp.h>
54216295Ssyrinx#include "bsnmptc.h"
55216295Ssyrinx#include "bsnmptools.h"
56216295Ssyrinx
57216295Ssyrinx/* OctetString, DisplayString */
58216295Ssyrinxstatic char *snmp_oct2str(uint32_t, char *, char *);
59216295Ssyrinxstatic char *snmp_str2asn_oid(char *, struct asn_oid *);
60216295Ssyrinxstatic int parse_octetstring(struct snmp_value *, char *);
61216295Ssyrinx
62216295Ssyrinx/* DateAndTime */
63216295Ssyrinxstatic char *snmp_octstr2date(uint32_t, char *, char *);
64216295Ssyrinxstatic char *snmp_date2asn_oid(char * , struct asn_oid *);
65216295Ssyrinxstatic int parse_dateandtime(struct snmp_value *, char *);
66216295Ssyrinx
67216295Ssyrinx/* PhysAddress */
68216295Ssyrinxstatic char *snmp_oct2physAddr(uint32_t, char *, char *);
69216295Ssyrinxstatic char *snmp_addr2asn_oid(char *, struct asn_oid *);
70216295Ssyrinxstatic int parse_physaddress(struct snmp_value *, char *);
71216295Ssyrinx
72216295Ssyrinx/* NTPTimeStamp */
73216295Ssyrinxstatic char *snmp_oct2ntp_ts(uint32_t, char *, char *);
74216295Ssyrinxstatic char *snmp_ntp_ts2asn_oid(char *, struct asn_oid *);
75216295Ssyrinxstatic int parse_ntp_ts(struct snmp_value *, char *);
76216295Ssyrinx
77216295Ssyrinx/* BridgeId */
78216295Ssyrinxstatic char *snmp_oct2bridgeid(uint32_t, char *, char *);
79216295Ssyrinxstatic char *snmp_bridgeid2oct(char *, struct asn_oid *);
80216295Ssyrinxstatic int parse_bridge_id(struct snmp_value *, char *);
81216295Ssyrinx
82216295Ssyrinx/* BridgePortId */
83216295Ssyrinxstatic char *snmp_oct2bport_id(uint32_t, char *, char *);
84216295Ssyrinxstatic char *snmp_bport_id2oct(char *, struct asn_oid *);
85216295Ssyrinxstatic int parse_bport_id(struct snmp_value *, char *);
86216295Ssyrinx
87216295Ssyrinx/* InetAddress */
88216295Ssyrinxstatic char *snmp_oct2inetaddr(uint32_t len, char *octets, char *buf);
89216295Ssyrinxstatic char *snmp_inetaddr2oct(char *str, struct asn_oid *oid);
90216295Ssyrinxstatic int32_t parse_inetaddr(struct snmp_value *value, char *string);
91216295Ssyrinx
92216295Ssyrinxstatic char *snmp_oct2bits(uint32_t len, char *octets, char *buf);
93216295Ssyrinxstatic char *snmp_bits2oct(char *str, struct asn_oid *oid);
94216295Ssyrinxstatic int32_t parse_bits(struct snmp_value *value, char *string);
95216295Ssyrinx
96300471Sngiestatic struct snmp_text_conv {
97216295Ssyrinx	enum snmp_tc	tc;
98216295Ssyrinx	const char	*tc_str;
99216295Ssyrinx	int32_t		len;
100216295Ssyrinx	snmp_oct2tc_f	oct2tc;
101216295Ssyrinx	snmp_tc2oid_f	tc2oid;
102216295Ssyrinx	snmp_tc2oct_f	tc2oct;
103216295Ssyrinx} text_convs[] = {
104216295Ssyrinx	{ SNMP_STRING, "OctetString", SNMP_VAR_STRSZ,
105216295Ssyrinx	  snmp_oct2str, snmp_str2asn_oid, parse_octetstring },
106216295Ssyrinx
107216295Ssyrinx	{ SNMP_DISPLAYSTRING, "DisplayString" , SNMP_VAR_STRSZ,
108216295Ssyrinx	  snmp_oct2str, snmp_str2asn_oid, parse_octetstring },
109216295Ssyrinx
110216295Ssyrinx	{ SNMP_DATEANDTIME, "DateAndTime", SNMP_DATETIME_STRSZ,
111216295Ssyrinx	  snmp_octstr2date, snmp_date2asn_oid, parse_dateandtime },
112216295Ssyrinx
113216295Ssyrinx	{ SNMP_PHYSADDR, "PhysAddress", SNMP_PHYSADDR_STRSZ,
114216295Ssyrinx	  snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },
115216295Ssyrinx
116216295Ssyrinx	{ SNMP_ATMESI, "AtmESI", SNMP_PHYSADDR_STRSZ,
117216295Ssyrinx	  snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },
118216295Ssyrinx
119216295Ssyrinx	{ SNMP_NTP_TIMESTAMP, "NTPTimeStamp", SNMP_NTP_TS_STRSZ,
120216295Ssyrinx	  snmp_oct2ntp_ts, snmp_ntp_ts2asn_oid, parse_ntp_ts },
121216295Ssyrinx
122216295Ssyrinx	{ SNMP_MACADDRESS, "MacAddress", SNMP_PHYSADDR_STRSZ,
123216295Ssyrinx	  snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },
124216295Ssyrinx
125216295Ssyrinx	{ SNMP_BRIDGE_ID, "BridgeId", SNMP_BRIDGEID_STRSZ,
126216295Ssyrinx	  snmp_oct2bridgeid, snmp_bridgeid2oct, parse_bridge_id },
127216295Ssyrinx
128216295Ssyrinx	{ SNMP_BPORT_ID, "BridgePortId", SNMP_BPORT_STRSZ,
129216295Ssyrinx	  snmp_oct2bport_id, snmp_bport_id2oct, parse_bport_id },
130216295Ssyrinx
131216295Ssyrinx	{ SNMP_INETADDRESS, "InetAddress", SNMP_INADDRS_STRSZ,
132216295Ssyrinx	  snmp_oct2inetaddr, snmp_inetaddr2oct, parse_inetaddr },
133216295Ssyrinx
134216295Ssyrinx	{ SNMP_TC_OWN, "BITS", SNMP_VAR_STRSZ,
135216295Ssyrinx	  snmp_oct2bits, snmp_bits2oct, parse_bits },
136216295Ssyrinx
137216295Ssyrinx	{ SNMP_UNKNOWN, "Unknown", SNMP_VAR_STRSZ, snmp_oct2str,
138216295Ssyrinx	  snmp_str2asn_oid, parse_octetstring }	/* keep last */
139216295Ssyrinx};
140216295Ssyrinx
141216295Ssyrinx/* Common API */
142216295Ssyrinxenum snmp_tc
143216295Ssyrinxsnmp_get_tc(char *str)
144216295Ssyrinx{
145216295Ssyrinx	int i;
146216295Ssyrinx	for (i = 0; i < SNMP_UNKNOWN; i++) {
147216295Ssyrinx		if (!strncmp(text_convs[i].tc_str, str,
148216295Ssyrinx		    strlen(text_convs[i].tc_str)))
149216295Ssyrinx			return (text_convs[i].tc);
150216295Ssyrinx	}
151216295Ssyrinx
152216295Ssyrinx	return (SNMP_STRING);
153216295Ssyrinx}
154216295Ssyrinx
155216295Ssyrinxchar *
156216295Ssyrinxsnmp_oct2tc(enum snmp_tc tc, uint32_t len, char *octets)
157216295Ssyrinx{
158216295Ssyrinx	uint32_t tc_len;
159216295Ssyrinx	char * buf;
160216295Ssyrinx
161300471Sngie	if (tc > SNMP_UNKNOWN)
162216295Ssyrinx		tc = SNMP_UNKNOWN;
163216295Ssyrinx
164216295Ssyrinx	if (text_convs[tc].len > 0)
165216295Ssyrinx		tc_len = text_convs[tc].len;
166216295Ssyrinx	else
167216295Ssyrinx		tc_len = 2 * len + 3;
168216295Ssyrinx
169216295Ssyrinx	if ((buf = malloc(tc_len)) == NULL ) {
170216295Ssyrinx		syslog(LOG_ERR, "malloc failed - %s", strerror(errno));
171216295Ssyrinx		return (NULL);
172216295Ssyrinx	}
173216295Ssyrinx
174216295Ssyrinx	memset(buf, 0, tc_len);
175216295Ssyrinx	if (text_convs[tc].oct2tc(len, octets, buf) == NULL) {
176216295Ssyrinx		free(buf);
177216295Ssyrinx		return (NULL);
178216295Ssyrinx	}
179216295Ssyrinx
180216295Ssyrinx	return (buf);
181216295Ssyrinx}
182216295Ssyrinx
183216295Ssyrinxchar *
184216295Ssyrinxsnmp_tc2oid(enum snmp_tc tc, char *str, struct asn_oid *oid)
185216295Ssyrinx{
186300471Sngie	if (tc > SNMP_UNKNOWN)
187216295Ssyrinx		tc = SNMP_UNKNOWN;
188216295Ssyrinx
189216295Ssyrinx	return (text_convs[tc].tc2oid(str, oid));
190216295Ssyrinx}
191216295Ssyrinx
192216295Ssyrinxint32_t
193216295Ssyrinxsnmp_tc2oct(enum snmp_tc tc, struct snmp_value *value, char *string)
194216295Ssyrinx{
195300471Sngie	if (tc > SNMP_UNKNOWN)
196216295Ssyrinx		tc = SNMP_UNKNOWN;
197216295Ssyrinx
198216295Ssyrinx	return (text_convs[tc].tc2oct(value, string));
199216295Ssyrinx}
200216295Ssyrinx
201216295Ssyrinx/*****************************************************
202216295Ssyrinx* Basic OctetString type.
203216295Ssyrinx*/
204216295Ssyrinxstatic char *
205216295Ssyrinxsnmp_oct2str(uint32_t len, char *octets, char *buf)
206216295Ssyrinx{
207216295Ssyrinx	uint8_t binary = 0;
208216295Ssyrinx	uint32_t i;
209216295Ssyrinx	char *ptr;
210216295Ssyrinx
211216295Ssyrinx	if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL)
212216295Ssyrinx		return (NULL);
213216295Ssyrinx
214216295Ssyrinx	for (ptr = buf, i = 0; i < len; i++)
215216295Ssyrinx		if (!isprint(octets[i])) {
216216295Ssyrinx			binary = 1;
217216295Ssyrinx			buf += sprintf(buf, "0x");
218216295Ssyrinx			break;
219216295Ssyrinx		}
220216295Ssyrinx
221216295Ssyrinx	for (ptr = buf, i = 0; i < len; i++)
222216295Ssyrinx		if (!binary)
223216295Ssyrinx			ptr += sprintf(ptr, "%c", octets[i]);
224216295Ssyrinx		else
225216295Ssyrinx			ptr += sprintf(ptr, "%2.2x", (u_char)octets[i]);
226216295Ssyrinx
227216295Ssyrinx	return (buf);
228216295Ssyrinx}
229216295Ssyrinx
230216295Ssyrinxstatic char *
231216295Ssyrinxsnmp_str2asn_oid(char *str, struct asn_oid *oid)
232216295Ssyrinx{
233216295Ssyrinx	uint32_t i, len = 0;
234216295Ssyrinx
235216295Ssyrinx	/*
236216295Ssyrinx	 * OctetStrings are allowed max length of ASN_MAXOCTETSTRING,
237216295Ssyrinx	 * but trying to index an entry with such a long OctetString
238216295Ssyrinx	 * will fail anyway.
239216295Ssyrinx	 */
240216295Ssyrinx	for (len = 0; len < ASN_MAXOIDLEN; len++) {
241216295Ssyrinx		if (strchr(",]", *(str + len)) != NULL)
242216295Ssyrinx			break;
243216295Ssyrinx	}
244216295Ssyrinx
245216295Ssyrinx	if (len >= ASN_MAXOIDLEN)
246216295Ssyrinx		return (NULL);
247216295Ssyrinx
248216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) len) < 0)
249216295Ssyrinx		return (NULL);
250216295Ssyrinx
251216295Ssyrinx	for (i = 0; i < len; i++)
252216295Ssyrinx		if (snmp_suboid_append(oid, (asn_subid_t) *(str + i)) < 0)
253216295Ssyrinx			return (NULL);
254216295Ssyrinx
255216295Ssyrinx	return (str + len);
256216295Ssyrinx}
257216295Ssyrinx
258216295Ssyrinxstatic int32_t
259216295Ssyrinxparse_octetstring(struct snmp_value *value, char *val)
260216295Ssyrinx{
261216295Ssyrinx	size_t len;
262216295Ssyrinx
263216295Ssyrinx	if ((len = strlen(val)) >= MAX_OCTSTRING_LEN) {
264216295Ssyrinx		warnx("Octetstring too long - %d is max allowed",
265216295Ssyrinx		    MAX_OCTSTRING_LEN - 1);
266216295Ssyrinx		return (-1);
267216295Ssyrinx	}
268216295Ssyrinx
269311590Sngie	if ((value->v.octetstring.octets = malloc(len)) == NULL) {
270311590Sngie		value->v.octetstring.len = 0;
271311595Sngie		syslog(LOG_ERR, "malloc failed: %s", strerror(errno));
272216295Ssyrinx		return (-1);
273216295Ssyrinx	}
274216295Ssyrinx
275311590Sngie	value->v.octetstring.len = len;
276216295Ssyrinx	memcpy(value->v.octetstring.octets, val, len);
277216295Ssyrinx	value->syntax = SNMP_SYNTAX_OCTETSTRING;
278216295Ssyrinx
279216295Ssyrinx	return (0);
280216295Ssyrinx}
281216295Ssyrinx
282216295Ssyrinx/*************************************************************
283216295Ssyrinx * DateAndTime
284216295Ssyrinx *************************************************************
285216295Ssyrinx * rfc 2579 specification:
286216295Ssyrinx * DateAndTime ::= TEXTUAL-CONVENTION
287216295Ssyrinx *   DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
288216295Ssyrinx *   STATUS	  current
289216295Ssyrinx *   DESCRIPTION
290216295Ssyrinx *	"A date-time specification.
291216295Ssyrinx *
292216295Ssyrinx *	field	octets	contents		range
293216295Ssyrinx *	-----	------	--------		-----
294216295Ssyrinx *	1	1-2	year*			0..65536
295216295Ssyrinx *	2	3	month			1..12
296216295Ssyrinx *	3	4	day			1..31
297216295Ssyrinx *	4	5	hour			0..23
298216295Ssyrinx *	5	6	minutes			0..59
299216295Ssyrinx *	6	7	seconds			0..60
300216295Ssyrinx *			(use 60 for leap-second)
301216295Ssyrinx *	7	8	deci-seconds		0..9
302216295Ssyrinx *	8	9	direction from UTC	'+' / '-'
303216295Ssyrinx *	9	10	hours from UTC*		0..13
304216295Ssyrinx *	10	11	minutes from UTC	0..59
305216295Ssyrinx *
306216295Ssyrinx *	* Notes:
307216295Ssyrinx *	    - the value of year is in network-byte order
308216295Ssyrinx *	    - daylight saving time in New Zealand is +13
309216295Ssyrinx *
310216295Ssyrinx *	For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
311216295Ssyrinx *	displayed as:
312216295Ssyrinx *
313216295Ssyrinx *		1992-5-26,13:30:15.0,-4:0
314216295Ssyrinx */
315216295Ssyrinxstatic char *
316216295Ssyrinxsnmp_octstr2date(uint32_t len, char *octets, char *buf)
317216295Ssyrinx{
318216295Ssyrinx	int year;
319216295Ssyrinx	char *ptr;
320216295Ssyrinx
321216295Ssyrinx	if (len != SNMP_DATETIME_OCTETS || octets == NULL || buf == NULL)
322216295Ssyrinx		return (NULL);
323216295Ssyrinx
324216295Ssyrinx	buf[0]= '\0';
325216295Ssyrinx	year = (octets[0] << 8);
326216295Ssyrinx	year += (octets[1]);
327216295Ssyrinx
328216295Ssyrinx	ptr = buf;
329216295Ssyrinx	ptr += sprintf(ptr, "%4.4d-%.2d-%.2d, ", year, octets[2],octets[3]);
330216295Ssyrinx	ptr += sprintf(ptr, "%2.2d:%2.2d:%2.2d.%.2d, ", octets[4],octets[5],
331216295Ssyrinx	    octets[6],octets[7]);
332216295Ssyrinx	ptr += sprintf(ptr, "%c%.2d:%.2d", octets[8],octets[9],octets[10]);
333216295Ssyrinx
334216295Ssyrinx	return (buf);
335216295Ssyrinx}
336216295Ssyrinx
337216295Ssyrinxstatic char *
338216295Ssyrinxsnmp_date2asn_oid(char *str, struct asn_oid *oid)
339216295Ssyrinx{
340216295Ssyrinx	char *endptr, *ptr;
341299016Sngie	static const char UTC[3] = "UTC";
342299016Sngie	int32_t saved_errno;
343216295Ssyrinx	uint32_t v;
344216295Ssyrinx
345216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_DATETIME_OCTETS) < 0)
346216295Ssyrinx		return (NULL);
347216295Ssyrinx
348216295Ssyrinx	/* Read 'YYYY-' and write it in two subs. */
349216295Ssyrinx	ptr = str;
350216295Ssyrinx	saved_errno = errno;
351216295Ssyrinx	errno = 0;
352216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
353216295Ssyrinx	if (v > 0xffff)
354216295Ssyrinx		goto error;
355216295Ssyrinx	else
356216295Ssyrinx		errno = saved_errno;
357216295Ssyrinx	if (*endptr != '-')
358216295Ssyrinx		goto error1;
359216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) ((v & 0xff00) >> 8)) < 0)
360216295Ssyrinx		return (NULL);
361216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
362216295Ssyrinx		return (NULL);
363216295Ssyrinx
364216295Ssyrinx	/* 'MM-' */
365216295Ssyrinx	ptr = endptr + 1;
366216295Ssyrinx	saved_errno = errno;
367301656Sngie	errno = 0;
368216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
369216295Ssyrinx	if (errno != 0)
370216295Ssyrinx		goto error;
371216295Ssyrinx	else
372216295Ssyrinx		errno = saved_errno;
373216295Ssyrinx	if (*endptr != '-')
374216295Ssyrinx		goto error1;
375216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
376216295Ssyrinx		return (NULL);
377216295Ssyrinx
378216295Ssyrinx	/* 'DD,' */
379216295Ssyrinx	ptr = endptr + 1;
380216295Ssyrinx	saved_errno = errno;
381301656Sngie	errno = 0;
382216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
383216295Ssyrinx	if (errno != 0)
384216295Ssyrinx		goto error;
385216295Ssyrinx	else
386216295Ssyrinx		errno = saved_errno;
387216295Ssyrinx	if (*endptr != '-')
388216295Ssyrinx		goto error1;
389216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
390216295Ssyrinx		return (NULL);
391216295Ssyrinx
392216295Ssyrinx	/* 'HH:' */
393216295Ssyrinx	ptr = endptr + 1;
394216295Ssyrinx	saved_errno = errno;
395301656Sngie	errno = 0;
396216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
397216295Ssyrinx	if (errno != 0)
398216295Ssyrinx		goto error;
399216295Ssyrinx	else
400216295Ssyrinx		errno = saved_errno;
401216295Ssyrinx	if (*endptr != ':')
402216295Ssyrinx		goto error1;
403216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
404216295Ssyrinx		return (NULL);
405216295Ssyrinx
406216295Ssyrinx	/* 'MM:' */
407216295Ssyrinx	ptr = endptr + 1;
408216295Ssyrinx	saved_errno = errno;
409301656Sngie	errno = 0;
410216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
411216295Ssyrinx	if (errno != 0)
412216295Ssyrinx		goto error;
413216295Ssyrinx	else
414216295Ssyrinx		errno = saved_errno;
415216295Ssyrinx	if (*endptr != ':')
416216295Ssyrinx		goto error1;
417216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
418216295Ssyrinx		return (NULL);
419216295Ssyrinx
420216295Ssyrinx	/* 'SS.' */
421216295Ssyrinx	ptr = endptr + 1;
422216295Ssyrinx	saved_errno = errno;
423301656Sngie	errno = 0;
424216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
425216295Ssyrinx	if (errno != 0)
426216295Ssyrinx		goto error;
427216295Ssyrinx	else
428216295Ssyrinx		errno = saved_errno;
429216295Ssyrinx	if (*endptr != '.')
430216295Ssyrinx		goto error1;
431216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
432216295Ssyrinx		return (NULL);
433216295Ssyrinx
434216295Ssyrinx	/* 'M(mseconds),' */
435216295Ssyrinx	ptr = endptr + 1;
436216295Ssyrinx	saved_errno = errno;
437301656Sngie	errno = 0;
438216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
439216295Ssyrinx	if (errno != 0)
440216295Ssyrinx		goto error;
441216295Ssyrinx	else
442216295Ssyrinx		errno = saved_errno;
443216295Ssyrinx	if (*endptr != ',')
444216295Ssyrinx		goto error1;
445216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
446216295Ssyrinx		return (NULL);
447216295Ssyrinx
448216295Ssyrinx	/* 'UTC' - optional */
449216295Ssyrinx	ptr = endptr + 1;
450299016Sngie	if (strncmp(ptr, UTC, sizeof(UTC)) == 0)
451299016Sngie		ptr += sizeof(UTC);
452216295Ssyrinx
453216295Ssyrinx	/* '+/-' */
454216295Ssyrinx	if (*ptr == '-' || *ptr == '+') {
455216295Ssyrinx		if (snmp_suboid_append(oid, (asn_subid_t) (*ptr)) < 0)
456216295Ssyrinx			return (NULL);
457216295Ssyrinx	} else
458216295Ssyrinx		goto error1;
459216295Ssyrinx
460216295Ssyrinx	/* 'HH:' */
461216295Ssyrinx	ptr = endptr + 1;
462216295Ssyrinx	saved_errno = errno;
463301656Sngie	errno = 0;
464216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
465216295Ssyrinx	if (errno != 0)
466216295Ssyrinx		goto error;
467216295Ssyrinx	else
468216295Ssyrinx		errno = saved_errno;
469216295Ssyrinx	if (*endptr != ':')
470216295Ssyrinx		goto error1;
471216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
472216295Ssyrinx		return (NULL);
473216295Ssyrinx
474216295Ssyrinx	/* 'MM' - last one - ignore endptr here. */
475216295Ssyrinx	ptr = endptr + 1;
476216295Ssyrinx	saved_errno = errno;
477301656Sngie	errno = 0;
478216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
479216295Ssyrinx	if (errno != 0)
480216295Ssyrinx		goto error;
481216295Ssyrinx	else
482216295Ssyrinx		errno = saved_errno;
483216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
484216295Ssyrinx		return (NULL);
485216295Ssyrinx
486216295Ssyrinx	return (endptr);
487216295Ssyrinx
488216295Ssyrinx  error:
489216295Ssyrinx	errno = saved_errno;
490216295Ssyrinx  error1:
491216295Ssyrinx	warnx("Date value %s not supported", str);
492216295Ssyrinx	return (NULL);
493216295Ssyrinx}
494216295Ssyrinx
495216295Ssyrinx/* Read a DateAndTime string eg. 1992-5-26,13:30:15.0,-4:0. */
496216295Ssyrinxstatic int32_t
497216295Ssyrinxparse_dateandtime(struct snmp_value *sv, char *val)
498216295Ssyrinx{
499216295Ssyrinx	char *endptr;
500216295Ssyrinx	uint32_t v;
501216295Ssyrinx	uint8_t	date[SNMP_DATETIME_OCTETS];
502216295Ssyrinx
503216295Ssyrinx	/* 'YYYY-' */
504216295Ssyrinx	v = strtoul(val, &endptr, 10);
505216295Ssyrinx	if (v > 0xffff || *endptr != '-')
506216295Ssyrinx		goto error;
507216295Ssyrinx	date[0] = ((v & 0xff00) >> 8);
508216295Ssyrinx	date[1] = (v & 0xff);
509216295Ssyrinx	val = endptr + 1;
510216295Ssyrinx
511216295Ssyrinx	/* 'MM-' */
512216295Ssyrinx	v = strtoul(val, &endptr, 10);
513216295Ssyrinx	if (v == 0 || v > 12 || *endptr != '-')
514216295Ssyrinx		goto error;
515216295Ssyrinx	date[2] = v;
516216295Ssyrinx	val = endptr + 1;
517216295Ssyrinx
518216295Ssyrinx	/* 'DD,' */
519216295Ssyrinx	v = strtoul(val, &endptr, 10);
520216295Ssyrinx	if (v == 0 || v > 31 || *endptr != ',')
521216295Ssyrinx		goto error;
522216295Ssyrinx	date[3] = v;
523216295Ssyrinx	val = endptr + 1;
524216295Ssyrinx
525216295Ssyrinx	/* 'HH:' */
526216295Ssyrinx	v = strtoul(val, &endptr, 10);
527216295Ssyrinx	if (v > 23 || *endptr != ':')
528216295Ssyrinx		goto error;
529216295Ssyrinx	date[4] = v;
530216295Ssyrinx	val = endptr + 1;
531216295Ssyrinx
532216295Ssyrinx	/* 'MM:' */
533216295Ssyrinx	v = strtoul(val, &endptr, 10);
534216295Ssyrinx	if (v > 59 || *endptr != ':')
535216295Ssyrinx		goto error;
536216295Ssyrinx	date[5] = v;
537216295Ssyrinx	val = endptr + 1;
538216295Ssyrinx
539216295Ssyrinx	/* 'SS.' */
540216295Ssyrinx	v = strtoul(val, &endptr, 10);
541216295Ssyrinx	if (v > 60 || *endptr != '.')
542216295Ssyrinx		goto error;
543216295Ssyrinx	date[6] = v;
544216295Ssyrinx	val = endptr + 1;
545216295Ssyrinx
546216295Ssyrinx	/* '(deci-)s,' */
547216295Ssyrinx	v = strtoul(val, &endptr, 10);
548216295Ssyrinx	if (v > 9 || *endptr != ',')
549216295Ssyrinx		goto error;
550216295Ssyrinx	date[7] = v;
551216295Ssyrinx	val = endptr + 1;
552216295Ssyrinx
553216295Ssyrinx	/* offset - '+/-' */
554216295Ssyrinx	if (*val != '-' && *val != '+')
555216295Ssyrinx		goto error;
556216295Ssyrinx	date[8] = (uint8_t) *val;
557216295Ssyrinx	val = endptr + 1;
558216295Ssyrinx
559216295Ssyrinx	/* 'HH:' - offset from UTC */
560216295Ssyrinx	v = strtoul(val, &endptr, 10);
561216295Ssyrinx	if (v > 13 || *endptr != ':')
562216295Ssyrinx		goto error;
563216295Ssyrinx	date[9] = v;
564216295Ssyrinx	val = endptr + 1;
565216295Ssyrinx
566216295Ssyrinx	/* 'MM'\0''  offset from UTC */
567216295Ssyrinx	v = strtoul(val, &endptr, 10);
568216295Ssyrinx	if (v > 59 || *endptr != '\0')
569216295Ssyrinx		goto error;
570216295Ssyrinx	date[10] = v;
571216295Ssyrinx
572216295Ssyrinx	if ((sv->v.octetstring.octets = malloc(SNMP_DATETIME_OCTETS)) == NULL) {
573311595Sngie		warn("malloc() failed");
574216295Ssyrinx		return (-1);
575216295Ssyrinx	}
576216295Ssyrinx
577216295Ssyrinx	sv->v.octetstring.len = SNMP_DATETIME_OCTETS;
578216295Ssyrinx	memcpy(sv->v.octetstring.octets, date, SNMP_DATETIME_OCTETS);
579216295Ssyrinx	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
580216295Ssyrinx	return (1);
581216295Ssyrinx
582216295Ssyrinx  error:
583216295Ssyrinx	warnx("Date value %s not supported", val);
584216295Ssyrinx	return (-1);
585216295Ssyrinx}
586216295Ssyrinx
587216295Ssyrinx/**************************************************************
588216295Ssyrinx * PhysAddress
589216295Ssyrinx */
590216295Ssyrinxstatic char *
591216295Ssyrinxsnmp_oct2physAddr(uint32_t len, char *octets, char *buf)
592216295Ssyrinx{
593216295Ssyrinx	char *ptr;
594216295Ssyrinx	uint32_t i;
595216295Ssyrinx
596216295Ssyrinx	if (len != SNMP_PHYSADDR_OCTETS || octets == NULL || buf == NULL)
597216295Ssyrinx		return (NULL);
598216295Ssyrinx
599216295Ssyrinx	buf[0]= '\0';
600216295Ssyrinx
601216295Ssyrinx	ptr = buf;
602216295Ssyrinx	ptr += sprintf(ptr, "%2.2x", octets[0]);
603216295Ssyrinx	for (i = 1; i < 6; i++)
604216295Ssyrinx		ptr += sprintf(ptr, ":%2.2x", octets[i]);
605216295Ssyrinx
606216295Ssyrinx	return (buf);
607216295Ssyrinx}
608216295Ssyrinx
609216295Ssyrinxstatic char *
610216295Ssyrinxsnmp_addr2asn_oid(char *str, struct asn_oid *oid)
611216295Ssyrinx{
612216295Ssyrinx	char *endptr, *ptr;
613216295Ssyrinx	uint32_t v, i;
614216295Ssyrinx	int saved_errno;
615216295Ssyrinx
616216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_PHYSADDR_OCTETS) < 0)
617216295Ssyrinx		return (NULL);
618216295Ssyrinx
619216295Ssyrinx	ptr = str;
620216295Ssyrinx	for (i = 0; i < 5; i++) {
621216295Ssyrinx		saved_errno = errno;
622216295Ssyrinx		v = strtoul(ptr, &endptr, 16);
623216295Ssyrinx		errno = saved_errno;
624216295Ssyrinx		if (v > 0xff) {
625216295Ssyrinx			warnx("Integer value %s not supported", str);
626216295Ssyrinx			return (NULL);
627216295Ssyrinx		}
628216295Ssyrinx		if (*endptr != ':') {
629311595Sngie			warnx("Failed adding oid - %s", str);
630216295Ssyrinx			return (NULL);
631216295Ssyrinx		}
632216295Ssyrinx		if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
633216295Ssyrinx			return (NULL);
634216295Ssyrinx		ptr = endptr + 1;
635216295Ssyrinx	}
636216295Ssyrinx
637216295Ssyrinx	/* The last one - don't check the ending char here. */
638216295Ssyrinx	saved_errno = errno;
639216295Ssyrinx	v = strtoul(ptr, &endptr, 16);
640216295Ssyrinx	errno = saved_errno;
641216295Ssyrinx	if (v > 0xff) {
642216295Ssyrinx		warnx("Integer value %s not supported", str);
643216295Ssyrinx		return (NULL);
644216295Ssyrinx	}
645216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
646216295Ssyrinx		return (NULL);
647216295Ssyrinx
648216295Ssyrinx	return (endptr);
649216295Ssyrinx}
650216295Ssyrinx
651216295Ssyrinxstatic int32_t
652216295Ssyrinxparse_physaddress(struct snmp_value *sv, char *val)
653216295Ssyrinx{
654216295Ssyrinx	char *endptr;
655216295Ssyrinx	int32_t i;
656216295Ssyrinx	uint32_t v;
657216295Ssyrinx	uint8_t	phys_addr[SNMP_PHYSADDR_OCTETS];
658216295Ssyrinx
659216295Ssyrinx	for (i = 0; i < 5; i++) {
660216295Ssyrinx		v = strtoul(val, &endptr, 16);
661216295Ssyrinx		if (v > 0xff) {
662216295Ssyrinx			warnx("Integer value %s not supported", val);
663216295Ssyrinx			return (-1);
664216295Ssyrinx		}
665216295Ssyrinx		if(*endptr != ':') {
666216295Ssyrinx			warnx("Failed reading octet - %s", val);
667216295Ssyrinx			return (-1);
668216295Ssyrinx		}
669216295Ssyrinx		phys_addr[i] = v;
670216295Ssyrinx		val = endptr + 1;
671216295Ssyrinx	}
672216295Ssyrinx
673216295Ssyrinx	/* The last one - don't check the ending char here. */
674216295Ssyrinx	v = strtoul(val, &endptr, 16);
675216295Ssyrinx	if (v > 0xff) {
676216295Ssyrinx		warnx("Integer value %s not supported", val);
677216295Ssyrinx		return (-1);
678216295Ssyrinx	}
679216295Ssyrinx	phys_addr[5] = v;
680216295Ssyrinx
681216295Ssyrinx	if ((sv->v.octetstring.octets = malloc(SNMP_PHYSADDR_OCTETS)) == NULL) {
682311595Sngie		syslog(LOG_ERR, "malloc failed: %s", strerror(errno));
683216295Ssyrinx		return (-1);
684216295Ssyrinx	}
685216295Ssyrinx
686216295Ssyrinx	sv->v.octetstring.len = SNMP_PHYSADDR_OCTETS;
687216295Ssyrinx	memcpy(sv->v.octetstring.octets, phys_addr, SNMP_PHYSADDR_OCTETS);
688216295Ssyrinx	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
689216295Ssyrinx	return (1);
690216295Ssyrinx}
691216295Ssyrinx
692216295Ssyrinx/**************************************************************
693216295Ssyrinx * NTPTimeStamp
694216295Ssyrinx **************************************************************
695216295Ssyrinx * NTP MIB, Revision 0.2, 7/25/97:
696216295Ssyrinx * NTPTimeStamp ::= TEXTUAL-CONVENTION
697216295Ssyrinx *    DISPLAY-HINT "4x.4x"
698216295Ssyrinx *    STATUS	current
699216295Ssyrinx *    DESCRIPTION
700216295Ssyrinx *	""
701216295Ssyrinx *    SYNTAX	OCTET STRING (SIZE(8))
702216295Ssyrinx */
703216295Ssyrinxstatic char *
704216295Ssyrinxsnmp_oct2ntp_ts(uint32_t len, char *octets, char *buf)
705216295Ssyrinx{
706216295Ssyrinx	char *ptr;
707216295Ssyrinx	uint32_t i;
708216295Ssyrinx
709216295Ssyrinx	if (len != SNMP_NTP_TS_OCTETS || octets == NULL || buf == NULL)
710216295Ssyrinx		return (NULL);
711216295Ssyrinx
712216295Ssyrinx	buf[0]= '\0';
713216295Ssyrinx
714216295Ssyrinx	ptr = buf;
715216295Ssyrinx	i = octets[0] * 1000 + octets[1] * 100 + octets[2] * 10 + octets[3];
716216295Ssyrinx	ptr += sprintf(ptr, "%4.4d", i);
717216295Ssyrinx	i = octets[4] * 1000 + octets[5] * 100 + octets[6] * 10 + octets[7];
718216295Ssyrinx	ptr += sprintf(ptr, ".%4.4d", i);
719216295Ssyrinx
720216295Ssyrinx	return (buf);
721216295Ssyrinx}
722216295Ssyrinx
723216295Ssyrinxstatic char *
724216295Ssyrinxsnmp_ntp_ts2asn_oid(char *str, struct asn_oid *oid)
725216295Ssyrinx{
726216295Ssyrinx	char *endptr, *ptr;
727216295Ssyrinx	uint32_t v, i, d;
728216295Ssyrinx	struct asn_oid suboid;
729216295Ssyrinx	int saved_errno;
730216295Ssyrinx
731216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_NTP_TS_OCTETS) < 0)
732216295Ssyrinx		return (NULL);
733216295Ssyrinx
734216295Ssyrinx	ptr = str;
735216295Ssyrinx	saved_errno = errno;
736301656Sngie	errno = 0;
737216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
738216295Ssyrinx	if (errno != 0 || (v / 1000) > 9) {
739216295Ssyrinx		warnx("Integer value %s not supported", str);
740216295Ssyrinx		errno = saved_errno;
741216295Ssyrinx		return (NULL);
742216295Ssyrinx	} else
743216295Ssyrinx		errno = saved_errno;
744216295Ssyrinx
745216295Ssyrinx	if (*endptr != '.') {
746311595Sngie		warnx("Failed adding oid - %s", str);
747216295Ssyrinx		return (NULL);
748216295Ssyrinx	}
749216295Ssyrinx
750216295Ssyrinx	memset(&suboid, 0, sizeof(struct asn_oid));
751216295Ssyrinx	suboid.len = SNMP_NTP_TS_OCTETS;
752216295Ssyrinx
753216295Ssyrinx	for (i = 0, d = 1000; i < 4; i++) {
754216295Ssyrinx		suboid.subs[i] = v / d;
755216295Ssyrinx		v = v % d;
756216295Ssyrinx		d = d / 10;
757216295Ssyrinx	}
758216295Ssyrinx
759216295Ssyrinx	ptr = endptr + 1;
760216295Ssyrinx	saved_errno = errno;
761301656Sngie	errno = 0;
762216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
763216295Ssyrinx	if (errno != 0 || (v / 1000) > 9) {
764216295Ssyrinx		warnx("Integer value %s not supported", str);
765216295Ssyrinx		errno = saved_errno;
766216295Ssyrinx		return (NULL);
767216295Ssyrinx	} else
768216295Ssyrinx		errno = saved_errno;
769216295Ssyrinx
770216295Ssyrinx	for (i = 0, d = 1000; i < 4; i++) {
771216295Ssyrinx		suboid.subs[i + 4] = v / d;
772216295Ssyrinx		v = v % d;
773216295Ssyrinx		d = d / 10;
774216295Ssyrinx	}
775216295Ssyrinx
776216295Ssyrinx	asn_append_oid(oid, &suboid);
777216295Ssyrinx	return (endptr);
778216295Ssyrinx}
779216295Ssyrinx
780216295Ssyrinxstatic int32_t
781216295Ssyrinxparse_ntp_ts(struct snmp_value *sv, char *val)
782216295Ssyrinx{
783216295Ssyrinx	char *endptr;
784216295Ssyrinx	int32_t i, d, saved_errno;
785216295Ssyrinx	uint32_t v;
786216295Ssyrinx	uint8_t	ntp_ts[SNMP_NTP_TS_OCTETS];
787216295Ssyrinx
788216295Ssyrinx	saved_errno = errno;
789301656Sngie	errno = 0;
790216295Ssyrinx	v = strtoul(val, &endptr, 10);
791216295Ssyrinx	if (errno != 0 || (v / 1000) > 9) {
792300559Sngie		errno = saved_errno;
793216295Ssyrinx		warnx("Integer value %s not supported", val);
794216295Ssyrinx		return (-1);
795216295Ssyrinx	} else
796300559Sngie		errno = saved_errno;
797216295Ssyrinx
798216295Ssyrinx	if (*endptr != '.') {
799216295Ssyrinx		warnx("Failed reading octet - %s", val);
800216295Ssyrinx		return (-1);
801216295Ssyrinx	}
802216295Ssyrinx
803216295Ssyrinx	for (i = 0, d = 1000; i < 4; i++) {
804216295Ssyrinx		ntp_ts[i] = v / d;
805216295Ssyrinx		v = v % d;
806216295Ssyrinx		d = d / 10;
807216295Ssyrinx	}
808216295Ssyrinx	val = endptr + 1;
809216295Ssyrinx
810216295Ssyrinx	saved_errno = errno;
811301656Sngie	errno = 0;
812216295Ssyrinx	v = strtoul(val, &endptr, 10);
813216295Ssyrinx	if (errno != 0 || (v / 1000) > 9) {
814300559Sngie		errno = saved_errno;
815216295Ssyrinx		warnx("Integer value %s not supported", val);
816216295Ssyrinx		return (-1);
817216295Ssyrinx	} else
818300559Sngie		errno = saved_errno;
819216295Ssyrinx
820216295Ssyrinx	for (i = 0, d = 1000; i < 4; i++) {
821216295Ssyrinx		ntp_ts[i + 4] = v / d;
822216295Ssyrinx		v = v % d;
823216295Ssyrinx		d = d / 10;
824216295Ssyrinx	}
825216295Ssyrinx
826216295Ssyrinx	if ((sv->v.octetstring.octets = malloc(SNMP_NTP_TS_OCTETS)) == NULL) {
827311595Sngie		syslog(LOG_ERR, "malloc failed: %s", strerror(errno));
828216295Ssyrinx		return (-1);
829216295Ssyrinx	}
830216295Ssyrinx
831216295Ssyrinx	sv->v.octetstring.len = SNMP_NTP_TS_OCTETS;
832216295Ssyrinx	memcpy(sv->v.octetstring.octets, ntp_ts, SNMP_NTP_TS_OCTETS);
833216295Ssyrinx	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
834216295Ssyrinx	return (1);
835216295Ssyrinx}
836216295Ssyrinx
837216295Ssyrinx/**************************************************************
838216295Ssyrinx * BridgeId
839216295Ssyrinx **************************************************************
840216295Ssyrinx * BRIDGE-MIB, REVISION		"200509190000Z"
841216295Ssyrinx * BridgeId ::= TEXTUAL-CONVENTION
842216295Ssyrinx *    STATUS	current
843216295Ssyrinx *    DESCRIPTION
844216295Ssyrinx *	"The Bridge-Identifier, as used in the Spanning Tree
845216295Ssyrinx *	Protocol, to uniquely identify a bridge.  Its first two
846216295Ssyrinx *	octets (in network byte order) contain a priority value,
847216295Ssyrinx *	and its last 6 octets contain the MAC address used to
848216295Ssyrinx *	refer to a bridge in a unique fashion (typically, the
849216295Ssyrinx *	numerically smallest MAC address of all ports on the
850216295Ssyrinx *	bridge)."
851216295Ssyrinx *    SYNTAX	OCTET STRING (SIZE (8))
852216295Ssyrinx */
853216295Ssyrinxstatic char *
854216295Ssyrinxsnmp_oct2bridgeid(uint32_t len, char *octets, char *buf)
855216295Ssyrinx{
856216295Ssyrinx	char *ptr;
857216295Ssyrinx	uint32_t i, priority;
858216295Ssyrinx
859216295Ssyrinx	if (len != SNMP_BRIDGEID_OCTETS || octets == NULL || buf == NULL)
860216295Ssyrinx		return (NULL);
861216295Ssyrinx
862216295Ssyrinx	buf[0]= '\0';
863216295Ssyrinx	ptr = buf;
864216295Ssyrinx
865216295Ssyrinx	priority = octets[0] << 8;
866216295Ssyrinx	priority += octets[1];
867216295Ssyrinx	if (priority > SNMP_MAX_BRIDGE_PRIORITY) {
868216295Ssyrinx		warnx("Invalid bridge priority %d", priority);
869216295Ssyrinx		return (NULL);
870216295Ssyrinx	} else
871216295Ssyrinx		ptr += sprintf(ptr, "%d.", octets[0]);
872216295Ssyrinx
873216295Ssyrinx	ptr += sprintf(ptr, "%2.2x", octets[2]);
874216295Ssyrinx
875216295Ssyrinx	for (i = 1; i < 6; i++)
876216295Ssyrinx		ptr += sprintf(ptr, ":%2.2x", octets[i + 2]);
877216295Ssyrinx
878216295Ssyrinx	return (buf);
879216295Ssyrinx}
880216295Ssyrinx
881216295Ssyrinxstatic char *
882216295Ssyrinxsnmp_bridgeid2oct(char *str, struct asn_oid *oid)
883216295Ssyrinx{
884216295Ssyrinx	char *endptr, *ptr;
885216295Ssyrinx	uint32_t v, i;
886216295Ssyrinx	int32_t saved_errno;
887216295Ssyrinx
888216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BRIDGEID_OCTETS) < 0)
889216295Ssyrinx		return (NULL);
890216295Ssyrinx
891216295Ssyrinx	ptr = str;
892216295Ssyrinx	/* Read the priority. */
893216295Ssyrinx	saved_errno = errno;
894301656Sngie	errno = 0;
895216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
896216295Ssyrinx
897216295Ssyrinx	if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
898216295Ssyrinx		errno = saved_errno;
899216295Ssyrinx		warnx("Bad bridge priority value %d", v);
900216295Ssyrinx		return (NULL);
901216295Ssyrinx	}
902216295Ssyrinx
903216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff00)) < 0)
904216295Ssyrinx		return (NULL);
905216295Ssyrinx
906216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
907216295Ssyrinx		return (NULL);
908216295Ssyrinx
909216295Ssyrinx	ptr = endptr + 1;
910216295Ssyrinx	for (i = 0; i < 5; i++) {
911216295Ssyrinx		saved_errno = errno;
912301656Sngie		errno = 0;
913216295Ssyrinx		v = strtoul(ptr, &endptr, 16);
914216295Ssyrinx		errno = saved_errno;
915216295Ssyrinx		if (v > 0xff) {
916216295Ssyrinx			warnx("Integer value %s not supported", str);
917216295Ssyrinx			return (NULL);
918216295Ssyrinx		}
919216295Ssyrinx		if (*endptr != ':') {
920216295Ssyrinx			warnx("Failed adding oid - %s",str);
921216295Ssyrinx			return (NULL);
922216295Ssyrinx		}
923216295Ssyrinx		if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
924216295Ssyrinx			return (NULL);
925216295Ssyrinx		ptr = endptr + 1;
926216295Ssyrinx	}
927216295Ssyrinx
928216295Ssyrinx	/* The last one - don't check the ending char here. */
929216295Ssyrinx	saved_errno = errno;
930301656Sngie	errno = 0;
931216295Ssyrinx	v = strtoul(ptr, &endptr, 16);
932216295Ssyrinx	errno = saved_errno;
933216295Ssyrinx	if (v > 0xff) {
934216295Ssyrinx		warnx("Integer value %s not supported", str);
935216295Ssyrinx		return (NULL);
936216295Ssyrinx	}
937216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
938216295Ssyrinx		return (NULL);
939216295Ssyrinx
940216295Ssyrinx	return (endptr);
941216295Ssyrinx}
942216295Ssyrinx
943216295Ssyrinxstatic int32_t
944216295Ssyrinxparse_bridge_id(struct snmp_value *sv, char *string)
945216295Ssyrinx{
946300471Sngie	char *endptr;
947216295Ssyrinx	int32_t i, saved_errno;
948216295Ssyrinx	uint32_t v;
949216295Ssyrinx	uint8_t	bridge_id[SNMP_BRIDGEID_OCTETS];
950216295Ssyrinx
951216295Ssyrinx	/* Read the priority. */
952216295Ssyrinx	saved_errno = errno;
953216295Ssyrinx	errno = 0;
954216295Ssyrinx	v = strtoul(string, &endptr, 10);
955216295Ssyrinx
956216295Ssyrinx	if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
957216295Ssyrinx		errno = saved_errno;
958216295Ssyrinx		warnx("Bad bridge priority value %d", v);
959216295Ssyrinx		return (-1);
960216295Ssyrinx	}
961216295Ssyrinx
962216295Ssyrinx	bridge_id[0] = (v & 0xff00);
963216295Ssyrinx	bridge_id[1] = (v & 0xff);
964216295Ssyrinx
965216295Ssyrinx	string = endptr + 1;
966216295Ssyrinx
967216295Ssyrinx	for (i = 0; i < 5; i++) {
968216295Ssyrinx		v = strtoul(string, &endptr, 16);
969216295Ssyrinx		if (v > 0xff) {
970216295Ssyrinx			warnx("Integer value %s not supported", string);
971216295Ssyrinx			return (-1);
972216295Ssyrinx		}
973216295Ssyrinx		if(*endptr != ':') {
974216295Ssyrinx			warnx("Failed reading octet - %s", string);
975216295Ssyrinx			return (-1);
976216295Ssyrinx		}
977216295Ssyrinx		bridge_id[i + 2] = v;
978216295Ssyrinx		string = endptr + 1;
979216295Ssyrinx	}
980216295Ssyrinx
981216295Ssyrinx	/* The last one - don't check the ending char here. */
982216295Ssyrinx	v = strtoul(string, &endptr, 16);
983216295Ssyrinx	if (v > 0xff) {
984216295Ssyrinx		warnx("Integer value %s not supported", string);
985216295Ssyrinx		return (-1);
986216295Ssyrinx	}
987216295Ssyrinx	bridge_id[7] = v;
988216295Ssyrinx
989216295Ssyrinx	if ((sv->v.octetstring.octets = malloc(SNMP_BRIDGEID_OCTETS)) == NULL) {
990311595Sngie		syslog(LOG_ERR, "malloc failed: %s", strerror(errno));
991216295Ssyrinx		return (-1);
992216295Ssyrinx	}
993216295Ssyrinx
994216295Ssyrinx	sv->v.octetstring.len = SNMP_BRIDGEID_OCTETS;
995216295Ssyrinx	memcpy(sv->v.octetstring.octets, bridge_id, SNMP_BRIDGEID_OCTETS);
996216295Ssyrinx	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
997216295Ssyrinx	return (1);
998216295Ssyrinx}
999216295Ssyrinx
1000216295Ssyrinx/**************************************************************
1001216295Ssyrinx * BridgePortId
1002216295Ssyrinx **************************************************************
1003216295Ssyrinx * BEGEMOT-BRIDGE-MIB, LAST-UPDATED "200608100000Z"
1004216295Ssyrinx * BridgePortId ::= TEXTUAL-CONVENTION
1005216295Ssyrinx *    DISPLAY-HINT "1x.1x"
1006216295Ssyrinx *    STATUS	current
1007216295Ssyrinx *    DESCRIPTION
1008216295Ssyrinx *	"A port identifier that contains a bridge port's STP priority
1009216295Ssyrinx *	in the first octet and the port number in the second octet."
1010216295Ssyrinx *    SYNTAX	OCTET STRING (SIZE(2))
1011216295Ssyrinx */
1012216295Ssyrinxstatic char *
1013216295Ssyrinxsnmp_oct2bport_id(uint32_t len, char *octets, char *buf)
1014216295Ssyrinx{
1015216295Ssyrinx	char *ptr;
1016216295Ssyrinx
1017216295Ssyrinx	if (len != SNMP_BPORT_OCTETS || octets == NULL || buf == NULL)
1018216295Ssyrinx		return (NULL);
1019216295Ssyrinx
1020216295Ssyrinx	buf[0]= '\0';
1021216295Ssyrinx	ptr = buf;
1022216295Ssyrinx
1023216295Ssyrinx	ptr += sprintf(ptr, "%d.", octets[0]);
1024216295Ssyrinx	ptr += sprintf(ptr, "%d", octets[1]);
1025216295Ssyrinx
1026216295Ssyrinx	return (buf);
1027216295Ssyrinx}
1028216295Ssyrinx
1029216295Ssyrinxstatic char *
1030216295Ssyrinxsnmp_bport_id2oct(char *str, struct asn_oid *oid)
1031216295Ssyrinx{
1032216295Ssyrinx	char *endptr, *ptr;
1033216295Ssyrinx	uint32_t v;
1034216295Ssyrinx	int saved_errno;
1035216295Ssyrinx
1036216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BPORT_OCTETS) < 0)
1037216295Ssyrinx		return (NULL);
1038216295Ssyrinx
1039216295Ssyrinx	ptr = str;
1040216295Ssyrinx	/* Read the priority. */
1041216295Ssyrinx	saved_errno = errno;
1042301656Sngie	errno = 0;
1043216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
1044216295Ssyrinx
1045216295Ssyrinx	if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
1046216295Ssyrinx		errno = saved_errno;
1047216295Ssyrinx		warnx("Bad bridge port priority value %d", v);
1048216295Ssyrinx		return (NULL);
1049216295Ssyrinx	}
1050216295Ssyrinx
1051216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1052216295Ssyrinx		return (NULL);
1053216295Ssyrinx
1054216295Ssyrinx	saved_errno = errno;
1055301656Sngie	errno = 0;
1056216295Ssyrinx	v = strtoul(ptr, &endptr, 16);
1057216295Ssyrinx	errno = saved_errno;
1058216295Ssyrinx
1059216295Ssyrinx	if (v > 0xff) {
1060216295Ssyrinx		warnx("Bad port number - %d", v);
1061216295Ssyrinx		return (NULL);
1062216295Ssyrinx	}
1063216295Ssyrinx
1064216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1065216295Ssyrinx		return (NULL);
1066216295Ssyrinx
1067216295Ssyrinx	return (endptr);
1068216295Ssyrinx}
1069216295Ssyrinx
1070216295Ssyrinxstatic int32_t
1071216295Ssyrinxparse_bport_id(struct snmp_value *value, char *string)
1072216295Ssyrinx{
1073300471Sngie	char *endptr;
1074216295Ssyrinx	int saved_errno;
1075216295Ssyrinx	uint32_t v;
1076216295Ssyrinx	uint8_t	bport_id[SNMP_BPORT_OCTETS];
1077216295Ssyrinx
1078216295Ssyrinx	/* Read the priority. */
1079216295Ssyrinx	saved_errno = errno;
1080216295Ssyrinx	errno = 0;
1081216295Ssyrinx	v = strtoul(string, &endptr, 10);
1082216295Ssyrinx
1083216295Ssyrinx	if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
1084216295Ssyrinx		errno = saved_errno;
1085216295Ssyrinx		warnx("Bad bridge port priority value %d", v);
1086216295Ssyrinx		return (-1);
1087216295Ssyrinx	}
1088216295Ssyrinx
1089216295Ssyrinx	bport_id[0] = v;
1090216295Ssyrinx
1091216295Ssyrinx	string = endptr + 1;
1092216295Ssyrinx	v = strtoul(string, &endptr, 16);
1093216295Ssyrinx	if (v > 0xff) {
1094216295Ssyrinx		warnx("Bad port number - %d", v);
1095216295Ssyrinx		return (-1);
1096216295Ssyrinx	}
1097216295Ssyrinx
1098216295Ssyrinx	bport_id[1] = v;
1099216295Ssyrinx
1100216295Ssyrinx	if ((value->v.octetstring.octets = malloc(SNMP_BPORT_OCTETS)) == NULL) {
1101311595Sngie		syslog(LOG_ERR, "malloc failed: %s", strerror(errno));
1102216295Ssyrinx		return (-1);
1103216295Ssyrinx	}
1104216295Ssyrinx
1105216295Ssyrinx	value->v.octetstring.len = SNMP_BPORT_OCTETS;
1106216295Ssyrinx	memcpy(value->v.octetstring.octets, bport_id, SNMP_BPORT_OCTETS);
1107216295Ssyrinx	value->syntax = SNMP_SYNTAX_OCTETSTRING;
1108216295Ssyrinx	return (1);
1109216295Ssyrinx}
1110216295Ssyrinx/**************************************************************
1111216295Ssyrinx * InetAddress
1112216295Ssyrinx **************************************************************
1113216295Ssyrinx * INET-ADDRESS-MIB, REVISION     "200502040000Z"
1114216295Ssyrinx * InetAddress ::= TEXTUAL-CONVENTION
1115216295Ssyrinx *   STATUS      current
1116216295Ssyrinx *   DESCRIPTION
1117216295Ssyrinx *       "Denotes a generic Internet address.
1118216295Ssyrinx *
1119216295Ssyrinx *        An InetAddress value is always interpreted within the context
1120216295Ssyrinx *        of an InetAddressType value.  Every usage of the InetAddress
1121216295Ssyrinx *        textual convention is required to specify the InetAddressType
1122216295Ssyrinx *        object that provides the context.  It is suggested that the
1123216295Ssyrinx *        InetAddressType object be logically registered before the
1124216295Ssyrinx *        object(s) that use the InetAddress textual convention, if
1125216295Ssyrinx *        they appear in the same logical row.
1126216295Ssyrinx *
1127216295Ssyrinx *        The value of an InetAddress object must always be
1128216295Ssyrinx *        consistent with the value of the associated InetAddressType
1129216295Ssyrinx *        object.  Attempts to set an InetAddress object to a value
1130216295Ssyrinx *        inconsistent with the associated InetAddressType
1131216295Ssyrinx *        must fail with an inconsistentValue error.
1132216295Ssyrinx *
1133216295Ssyrinx *        When this textual convention is used as the syntax of an
1134216295Ssyrinx *        index object, there may be issues with the limit of 128
1135216295Ssyrinx *        sub-identifiers specified in SMIv2, STD 58.  In this case,
1136216295Ssyrinx *        the object definition MUST include a 'SIZE' clause to
1137216295Ssyrinx *        limit the number of potential instance sub-identifiers;
1138216295Ssyrinx *        otherwise the applicable constraints MUST be stated in
1139216295Ssyrinx *        the appropriate conceptual row DESCRIPTION clauses, or
1140216295Ssyrinx *        in the surrounding documentation if there is no single
1141216295Ssyrinx *        DESCRIPTION clause that is appropriate."
1142216295Ssyrinx *   SYNTAX       OCTET STRING (SIZE (0..255))
1143216295Ssyrinx **************************************************************
1144216295Ssyrinx * TODO: FIXME!!! syrinx: Since we do not support checking the
1145216295Ssyrinx * consistency of a varbinding based on the value of a previous
1146310903Sngie * one, try to guess the type of address based on the
1147216295Ssyrinx * OctetString SIZE - 4 for IPv4, 16 for IPv6, others currently
1148216295Ssyrinx * not supported.
1149216295Ssyrinx */
1150216295Ssyrinxstatic char *
1151216295Ssyrinxsnmp_oct2inetaddr(uint32_t len, char *octets, char *buf)
1152216295Ssyrinx{
1153216295Ssyrinx	int af;
1154216295Ssyrinx	void *ip;
1155216295Ssyrinx	struct in_addr	ipv4;
1156216295Ssyrinx	struct in6_addr	ipv6;
1157216295Ssyrinx
1158216295Ssyrinx	if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL)
1159216295Ssyrinx		return (NULL);
1160216295Ssyrinx
1161216295Ssyrinx	switch (len) {
1162216295Ssyrinx		/* XXX: FIXME - IPv4*/
1163216295Ssyrinx		case 4:
1164216295Ssyrinx			memcpy(&ipv4.s_addr, octets, sizeof(ipv4.s_addr));
1165216295Ssyrinx			af = AF_INET;
1166216295Ssyrinx			ip = &ipv4;
1167216295Ssyrinx			break;
1168216295Ssyrinx
1169216295Ssyrinx		/* XXX: FIXME - IPv4*/
1170216295Ssyrinx		case 16:
1171216295Ssyrinx			memcpy(ipv6.s6_addr, octets, sizeof(ipv6.s6_addr));
1172216295Ssyrinx			af = AF_INET6;
1173216295Ssyrinx			ip = &ipv6;
1174216295Ssyrinx			break;
1175216295Ssyrinx
1176216295Ssyrinx		default:
1177216295Ssyrinx			return (NULL);
1178216295Ssyrinx	}
1179216295Ssyrinx
1180216295Ssyrinx	if (inet_ntop(af, ip, buf, SNMP_INADDRS_STRSZ) == NULL) {
1181311595Sngie		warn("inet_ntop failed");
1182216295Ssyrinx		return (NULL);
1183216295Ssyrinx	}
1184216295Ssyrinx
1185216295Ssyrinx	return (buf);
1186216295Ssyrinx}
1187216295Ssyrinx
1188216295Ssyrinxstatic char *
1189300471Sngiesnmp_inetaddr2oct(char *str __unused, struct asn_oid *oid __unused)
1190216295Ssyrinx{
1191216295Ssyrinx	return (NULL);
1192216295Ssyrinx}
1193216295Ssyrinx
1194216295Ssyrinxstatic int32_t
1195300471Sngieparse_inetaddr(struct snmp_value *value __unused, char *string __unused)
1196216295Ssyrinx{
1197216295Ssyrinx	return (-1);
1198216295Ssyrinx}
1199216295Ssyrinx
1200216295Ssyrinx/**************************************************************
1201216295Ssyrinx * SNMP BITS type - XXX: FIXME
1202216295Ssyrinx **************************************************************/
1203216295Ssyrinxstatic char *
1204216295Ssyrinxsnmp_oct2bits(uint32_t len, char *octets, char *buf)
1205216295Ssyrinx{
1206216295Ssyrinx	int i, bits;
1207216295Ssyrinx	uint64_t value;
1208216295Ssyrinx
1209216295Ssyrinx	if (len > sizeof(value) || octets == NULL || buf == NULL)
1210216295Ssyrinx		return (NULL);
1211216295Ssyrinx
1212216295Ssyrinx	for (i = len, value = 0, bits = 0; i > 0; i--, bits += 8)
1213216295Ssyrinx		value += octets[i] << bits;
1214216295Ssyrinx
1215216295Ssyrinx	buf[0]= '\0';
1216216295Ssyrinx	sprintf(buf, "0x%llx.",(long long unsigned) value);
1217216295Ssyrinx
1218216295Ssyrinx	return (buf);
1219216295Ssyrinx}
1220216295Ssyrinx
1221216295Ssyrinxstatic char *
1222216295Ssyrinxsnmp_bits2oct(char *str, struct asn_oid *oid)
1223216295Ssyrinx{
1224216295Ssyrinx	char *endptr;
1225216295Ssyrinx	int i, size, bits, saved_errno;
1226216295Ssyrinx	uint64_t v, mask = 0xFF00000000000000;
1227216295Ssyrinx
1228216295Ssyrinx	saved_errno = errno;
1229216295Ssyrinx	errno = 0;
1230216295Ssyrinx
1231216295Ssyrinx	v = strtoull(str, &endptr, 16);
1232216295Ssyrinx	if (errno != 0) {
1233311595Sngie		warn("Bad BITS value %s", str);
1234216295Ssyrinx		errno = saved_errno;
1235216295Ssyrinx		return (NULL);
1236216295Ssyrinx	}
1237216295Ssyrinx
1238216295Ssyrinx	bits = 8;
1239216295Ssyrinx	/* Determine length - up to 8 octets supported so far. */
1240216295Ssyrinx	for (size = sizeof(v); size > 0; size--) {
1241216295Ssyrinx		if ((v & mask) != 0)
1242216295Ssyrinx			break;
1243216295Ssyrinx		mask = mask >> bits;
1244216295Ssyrinx	}
1245216295Ssyrinx
1246216295Ssyrinx	if (size == 0)
1247216295Ssyrinx		size = 1;
1248216295Ssyrinx
1249216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) size) < 0)
1250216295Ssyrinx		return (NULL);
1251216295Ssyrinx
1252216295Ssyrinx	for (i = 0, bits = 0; i < size; i++, bits += 8)
1253216295Ssyrinx		if (snmp_suboid_append(oid,
1254216295Ssyrinx		    (asn_subid_t)((v & mask) >> bits)) < 0)
1255216295Ssyrinx			return (NULL);
1256216295Ssyrinx
1257216295Ssyrinx	return (endptr);
1258216295Ssyrinx}
1259216295Ssyrinx
1260216295Ssyrinxstatic int32_t
1261216295Ssyrinxparse_bits(struct snmp_value *value, char *string)
1262216295Ssyrinx{
1263216295Ssyrinx	char *endptr;
1264216295Ssyrinx	int i, size, bits, saved_errno;
1265216295Ssyrinx	uint64_t v, mask = 0xFF00000000000000;
1266216295Ssyrinx
1267216295Ssyrinx	saved_errno = errno;
1268216295Ssyrinx	errno = 0;
1269216295Ssyrinx
1270216295Ssyrinx	v = strtoull(string, &endptr, 16);
1271216295Ssyrinx
1272216295Ssyrinx	if (errno != 0) {
1273311595Sngie		warn("Bad BITS value %s", string);
1274216295Ssyrinx		errno = saved_errno;
1275216295Ssyrinx		return (-1);
1276216295Ssyrinx	}
1277216295Ssyrinx
1278216295Ssyrinx	bits = 8;
1279216295Ssyrinx	/* Determine length - up to 8 octets supported so far. */
1280216295Ssyrinx	for (size = sizeof(v); size > 0; size--) {
1281216295Ssyrinx		if ((v & mask) != 0)
1282216295Ssyrinx			break;
1283216295Ssyrinx		mask = mask >> bits;
1284216295Ssyrinx	}
1285216295Ssyrinx
1286216295Ssyrinx	if (size == 0)
1287216295Ssyrinx		size = 1;
1288216295Ssyrinx
1289216295Ssyrinx	if ((value->v.octetstring.octets = malloc(size)) == NULL) {
1290216295Ssyrinx		syslog(LOG_ERR, "malloc failed: %s", strerror(errno));
1291216295Ssyrinx		return (-1);
1292216295Ssyrinx	}
1293216295Ssyrinx
1294216295Ssyrinx	value->v.octetstring.len = size;
1295216295Ssyrinx	for (i = 0, bits = 0; i < size; i++, bits += 8)
1296216295Ssyrinx		value->v.octetstring.octets[i] = (v & mask) >> bits;
1297216295Ssyrinx	value->syntax = SNMP_SYNTAX_OCTETSTRING;
1298216295Ssyrinx	return (1);
1299216295Ssyrinx}
1300