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$
32216295Ssyrinx */
33216295Ssyrinx
34216295Ssyrinx#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
96216295Ssyrinxstruct 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
161216295Ssyrinx	if (tc < 0 || 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{
186216295Ssyrinx	if (tc < 0 || 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{
195216295Ssyrinx	if (tc < 0 || 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
269216295Ssyrinx	value->v.octetstring.len = len;
270216295Ssyrinx
271216295Ssyrinx	if((value->v.octetstring.octets = malloc(len)) == NULL) {
272216295Ssyrinx		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
273216295Ssyrinx		return (-1);
274216295Ssyrinx	}
275216295Ssyrinx
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;
341216295Ssyrinx	uint32_t v;
342216295Ssyrinx	int32_t saved_errno;
343216295Ssyrinx
344216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_DATETIME_OCTETS) < 0)
345216295Ssyrinx		return (NULL);
346216295Ssyrinx
347216295Ssyrinx	/* Read 'YYYY-' and write it in two subs. */
348216295Ssyrinx	ptr = str;
349216295Ssyrinx	saved_errno = errno;
350216295Ssyrinx	errno = 0;
351216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
352216295Ssyrinx	if (v > 0xffff)
353216295Ssyrinx		goto error;
354216295Ssyrinx	else
355216295Ssyrinx		errno = saved_errno;
356216295Ssyrinx	if (*endptr != '-')
357216295Ssyrinx		goto error1;
358216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) ((v & 0xff00) >> 8)) < 0)
359216295Ssyrinx		return (NULL);
360216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
361216295Ssyrinx		return (NULL);
362216295Ssyrinx
363216295Ssyrinx	/* 'MM-' */
364216295Ssyrinx	ptr = endptr + 1;
365216295Ssyrinx	saved_errno = errno;
366216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
367216295Ssyrinx	if (errno != 0)
368216295Ssyrinx		goto error;
369216295Ssyrinx	else
370216295Ssyrinx		errno = saved_errno;
371216295Ssyrinx	if (*endptr != '-')
372216295Ssyrinx		goto error1;
373216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
374216295Ssyrinx		return (NULL);
375216295Ssyrinx
376216295Ssyrinx	/* 'DD,' */
377216295Ssyrinx	ptr = endptr + 1;
378216295Ssyrinx	saved_errno = errno;
379216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
380216295Ssyrinx	if (errno != 0)
381216295Ssyrinx		goto error;
382216295Ssyrinx	else
383216295Ssyrinx		errno = saved_errno;
384216295Ssyrinx	if (*endptr != '-')
385216295Ssyrinx		goto error1;
386216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
387216295Ssyrinx		return (NULL);
388216295Ssyrinx
389216295Ssyrinx	/* 'HH:' */
390216295Ssyrinx	ptr = endptr + 1;
391216295Ssyrinx	saved_errno = errno;
392216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
393216295Ssyrinx	if (errno != 0)
394216295Ssyrinx		goto error;
395216295Ssyrinx	else
396216295Ssyrinx		errno = saved_errno;
397216295Ssyrinx	if (*endptr != ':')
398216295Ssyrinx		goto error1;
399216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
400216295Ssyrinx		return (NULL);
401216295Ssyrinx
402216295Ssyrinx	/* 'MM:' */
403216295Ssyrinx	ptr = endptr + 1;
404216295Ssyrinx	saved_errno = errno;
405216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
406216295Ssyrinx	if (errno != 0)
407216295Ssyrinx		goto error;
408216295Ssyrinx	else
409216295Ssyrinx		errno = saved_errno;
410216295Ssyrinx	if (*endptr != ':')
411216295Ssyrinx		goto error1;
412216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
413216295Ssyrinx		return (NULL);
414216295Ssyrinx
415216295Ssyrinx	/* 'SS.' */
416216295Ssyrinx	ptr = endptr + 1;
417216295Ssyrinx	saved_errno = errno;
418216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
419216295Ssyrinx	if (errno != 0)
420216295Ssyrinx		goto error;
421216295Ssyrinx	else
422216295Ssyrinx		errno = saved_errno;
423216295Ssyrinx	if (*endptr != '.')
424216295Ssyrinx		goto error1;
425216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
426216295Ssyrinx		return (NULL);
427216295Ssyrinx
428216295Ssyrinx	/* 'M(mseconds),' */
429216295Ssyrinx	ptr = endptr + 1;
430216295Ssyrinx	saved_errno = errno;
431216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
432216295Ssyrinx	if (errno != 0)
433216295Ssyrinx		goto error;
434216295Ssyrinx	else
435216295Ssyrinx		errno = saved_errno;
436216295Ssyrinx	if (*endptr != ',')
437216295Ssyrinx		goto error1;
438216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
439216295Ssyrinx		return (NULL);
440216295Ssyrinx
441216295Ssyrinx	/* 'UTC' - optional */
442216295Ssyrinx	ptr = endptr + 1;
443216295Ssyrinx	if (*ptr == 'U' && *(ptr + 1) == 'T' && *(ptr + 1) == 'C')
444216295Ssyrinx		ptr += 3;
445216295Ssyrinx
446216295Ssyrinx	/* '+/-' */
447216295Ssyrinx	if (*ptr == '-' || *ptr == '+') {
448216295Ssyrinx		if (snmp_suboid_append(oid, (asn_subid_t) (*ptr)) < 0)
449216295Ssyrinx			return (NULL);
450216295Ssyrinx	} else
451216295Ssyrinx		goto error1;
452216295Ssyrinx
453216295Ssyrinx	/* 'HH:' */
454216295Ssyrinx	ptr = endptr + 1;
455216295Ssyrinx	saved_errno = errno;
456216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
457216295Ssyrinx	if (errno != 0)
458216295Ssyrinx		goto error;
459216295Ssyrinx	else
460216295Ssyrinx		errno = saved_errno;
461216295Ssyrinx	if (*endptr != ':')
462216295Ssyrinx		goto error1;
463216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
464216295Ssyrinx		return (NULL);
465216295Ssyrinx
466216295Ssyrinx	/* 'MM' - last one - ignore endptr here. */
467216295Ssyrinx	ptr = endptr + 1;
468216295Ssyrinx	saved_errno = errno;
469216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
470216295Ssyrinx	if (errno != 0)
471216295Ssyrinx		goto error;
472216295Ssyrinx	else
473216295Ssyrinx		errno = saved_errno;
474216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
475216295Ssyrinx		return (NULL);
476216295Ssyrinx
477216295Ssyrinx	return (endptr);
478216295Ssyrinx
479216295Ssyrinx  error:
480216295Ssyrinx	errno = saved_errno;
481216295Ssyrinx  error1:
482216295Ssyrinx	warnx("Date value %s not supported", str);
483216295Ssyrinx	return (NULL);
484216295Ssyrinx}
485216295Ssyrinx
486216295Ssyrinx/* Read a DateAndTime string eg. 1992-5-26,13:30:15.0,-4:0. */
487216295Ssyrinxstatic int32_t
488216295Ssyrinxparse_dateandtime(struct snmp_value *sv, char *val)
489216295Ssyrinx{
490216295Ssyrinx	char *endptr;
491216295Ssyrinx	uint32_t v;
492216295Ssyrinx	uint8_t	date[SNMP_DATETIME_OCTETS];
493216295Ssyrinx
494216295Ssyrinx	/* 'YYYY-' */
495216295Ssyrinx	v = strtoul(val, &endptr, 10);
496216295Ssyrinx	if (v > 0xffff || *endptr != '-')
497216295Ssyrinx		goto error;
498216295Ssyrinx	date[0] = ((v & 0xff00) >> 8);
499216295Ssyrinx	date[1] = (v & 0xff);
500216295Ssyrinx	val = endptr + 1;
501216295Ssyrinx
502216295Ssyrinx	/* 'MM-' */
503216295Ssyrinx	v = strtoul(val, &endptr, 10);
504216295Ssyrinx	if (v == 0 || v > 12 || *endptr != '-')
505216295Ssyrinx		goto error;
506216295Ssyrinx	date[2] = v;
507216295Ssyrinx	val = endptr + 1;
508216295Ssyrinx
509216295Ssyrinx	/* 'DD,' */
510216295Ssyrinx	v = strtoul(val, &endptr, 10);
511216295Ssyrinx	if (v == 0 || v > 31 || *endptr != ',')
512216295Ssyrinx		goto error;
513216295Ssyrinx	date[3] = v;
514216295Ssyrinx	val = endptr + 1;
515216295Ssyrinx
516216295Ssyrinx	/* 'HH:' */
517216295Ssyrinx	v = strtoul(val, &endptr, 10);
518216295Ssyrinx	if (v > 23 || *endptr != ':')
519216295Ssyrinx		goto error;
520216295Ssyrinx	date[4] = v;
521216295Ssyrinx	val = endptr + 1;
522216295Ssyrinx
523216295Ssyrinx	/* 'MM:' */
524216295Ssyrinx	v = strtoul(val, &endptr, 10);
525216295Ssyrinx	if (v > 59 || *endptr != ':')
526216295Ssyrinx		goto error;
527216295Ssyrinx	date[5] = v;
528216295Ssyrinx	val = endptr + 1;
529216295Ssyrinx
530216295Ssyrinx	/* 'SS.' */
531216295Ssyrinx	v = strtoul(val, &endptr, 10);
532216295Ssyrinx	if (v > 60 || *endptr != '.')
533216295Ssyrinx		goto error;
534216295Ssyrinx	date[6] = v;
535216295Ssyrinx	val = endptr + 1;
536216295Ssyrinx
537216295Ssyrinx	/* '(deci-)s,' */
538216295Ssyrinx	v = strtoul(val, &endptr, 10);
539216295Ssyrinx	if (v > 9 || *endptr != ',')
540216295Ssyrinx		goto error;
541216295Ssyrinx	date[7] = v;
542216295Ssyrinx	val = endptr + 1;
543216295Ssyrinx
544216295Ssyrinx	/* offset - '+/-' */
545216295Ssyrinx	if (*val != '-' && *val != '+')
546216295Ssyrinx		goto error;
547216295Ssyrinx	date[8] = (uint8_t) *val;
548216295Ssyrinx	val = endptr + 1;
549216295Ssyrinx
550216295Ssyrinx	/* 'HH:' - offset from UTC */
551216295Ssyrinx	v = strtoul(val, &endptr, 10);
552216295Ssyrinx	if (v > 13 || *endptr != ':')
553216295Ssyrinx		goto error;
554216295Ssyrinx	date[9] = v;
555216295Ssyrinx	val = endptr + 1;
556216295Ssyrinx
557216295Ssyrinx	/* 'MM'\0''  offset from UTC */
558216295Ssyrinx	v = strtoul(val, &endptr, 10);
559216295Ssyrinx	if (v > 59 || *endptr != '\0')
560216295Ssyrinx		goto error;
561216295Ssyrinx	date[10] = v;
562216295Ssyrinx
563216295Ssyrinx	if ((sv->v.octetstring.octets = malloc(SNMP_DATETIME_OCTETS)) == NULL) {
564216295Ssyrinx		warnx("malloc() failed - %s", strerror(errno));
565216295Ssyrinx		return (-1);
566216295Ssyrinx	}
567216295Ssyrinx
568216295Ssyrinx	sv->v.octetstring.len = SNMP_DATETIME_OCTETS;
569216295Ssyrinx	memcpy(sv->v.octetstring.octets, date, SNMP_DATETIME_OCTETS);
570216295Ssyrinx	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
571216295Ssyrinx	return (1);
572216295Ssyrinx
573216295Ssyrinx  error:
574216295Ssyrinx	warnx("Date value %s not supported", val);
575216295Ssyrinx	return (-1);
576216295Ssyrinx}
577216295Ssyrinx
578216295Ssyrinx/**************************************************************
579216295Ssyrinx * PhysAddress
580216295Ssyrinx */
581216295Ssyrinxstatic char *
582216295Ssyrinxsnmp_oct2physAddr(uint32_t len, char *octets, char *buf)
583216295Ssyrinx{
584216295Ssyrinx	char *ptr;
585216295Ssyrinx	uint32_t i;
586216295Ssyrinx
587216295Ssyrinx	if (len != SNMP_PHYSADDR_OCTETS || octets == NULL || buf == NULL)
588216295Ssyrinx		return (NULL);
589216295Ssyrinx
590216295Ssyrinx	buf[0]= '\0';
591216295Ssyrinx
592216295Ssyrinx	ptr = buf;
593216295Ssyrinx	ptr += sprintf(ptr, "%2.2x", octets[0]);
594216295Ssyrinx	for (i = 1; i < 6; i++)
595216295Ssyrinx		ptr += sprintf(ptr, ":%2.2x", octets[i]);
596216295Ssyrinx
597216295Ssyrinx	return (buf);
598216295Ssyrinx}
599216295Ssyrinx
600216295Ssyrinxstatic char *
601216295Ssyrinxsnmp_addr2asn_oid(char *str, struct asn_oid *oid)
602216295Ssyrinx{
603216295Ssyrinx	char *endptr, *ptr;
604216295Ssyrinx	uint32_t v, i;
605216295Ssyrinx	int saved_errno;
606216295Ssyrinx
607216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_PHYSADDR_OCTETS) < 0)
608216295Ssyrinx		return (NULL);
609216295Ssyrinx
610216295Ssyrinx	ptr = str;
611216295Ssyrinx	for (i = 0; i < 5; i++) {
612216295Ssyrinx		saved_errno = errno;
613216295Ssyrinx		v = strtoul(ptr, &endptr, 16);
614216295Ssyrinx		errno = saved_errno;
615216295Ssyrinx		if (v > 0xff) {
616216295Ssyrinx			warnx("Integer value %s not supported", str);
617216295Ssyrinx			return (NULL);
618216295Ssyrinx		}
619216295Ssyrinx		if (*endptr != ':') {
620216295Ssyrinx			warnx("Failed adding oid - %s",str);
621216295Ssyrinx			return (NULL);
622216295Ssyrinx		}
623216295Ssyrinx		if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
624216295Ssyrinx			return (NULL);
625216295Ssyrinx		ptr = endptr + 1;
626216295Ssyrinx	}
627216295Ssyrinx
628216295Ssyrinx	/* The last one - don't check the ending char here. */
629216295Ssyrinx	saved_errno = errno;
630216295Ssyrinx	v = strtoul(ptr, &endptr, 16);
631216295Ssyrinx	errno = saved_errno;
632216295Ssyrinx	if (v > 0xff) {
633216295Ssyrinx		warnx("Integer value %s not supported", str);
634216295Ssyrinx		return (NULL);
635216295Ssyrinx	}
636216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
637216295Ssyrinx		return (NULL);
638216295Ssyrinx
639216295Ssyrinx	return (endptr);
640216295Ssyrinx}
641216295Ssyrinx
642216295Ssyrinxstatic int32_t
643216295Ssyrinxparse_physaddress(struct snmp_value *sv, char *val)
644216295Ssyrinx{
645216295Ssyrinx	char *endptr;
646216295Ssyrinx	int32_t i;
647216295Ssyrinx	uint32_t v;
648216295Ssyrinx	uint8_t	phys_addr[SNMP_PHYSADDR_OCTETS];
649216295Ssyrinx
650216295Ssyrinx	for (i = 0; i < 5; i++) {
651216295Ssyrinx		v = strtoul(val, &endptr, 16);
652216295Ssyrinx		if (v > 0xff) {
653216295Ssyrinx			warnx("Integer value %s not supported", val);
654216295Ssyrinx			return (-1);
655216295Ssyrinx		}
656216295Ssyrinx		if(*endptr != ':') {
657216295Ssyrinx			warnx("Failed reading octet - %s", val);
658216295Ssyrinx			return (-1);
659216295Ssyrinx		}
660216295Ssyrinx		phys_addr[i] = v;
661216295Ssyrinx		val = endptr + 1;
662216295Ssyrinx	}
663216295Ssyrinx
664216295Ssyrinx	/* The last one - don't check the ending char here. */
665216295Ssyrinx	v = strtoul(val, &endptr, 16);
666216295Ssyrinx	if (v > 0xff) {
667216295Ssyrinx		warnx("Integer value %s not supported", val);
668216295Ssyrinx		return (-1);
669216295Ssyrinx	}
670216295Ssyrinx	phys_addr[5] = v;
671216295Ssyrinx
672216295Ssyrinx	if ((sv->v.octetstring.octets = malloc(SNMP_PHYSADDR_OCTETS)) == NULL) {
673216295Ssyrinx		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
674216295Ssyrinx		return (-1);
675216295Ssyrinx	}
676216295Ssyrinx
677216295Ssyrinx	sv->v.octetstring.len = SNMP_PHYSADDR_OCTETS;
678216295Ssyrinx	memcpy(sv->v.octetstring.octets, phys_addr, SNMP_PHYSADDR_OCTETS);
679216295Ssyrinx	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
680216295Ssyrinx	return (1);
681216295Ssyrinx}
682216295Ssyrinx
683216295Ssyrinx/**************************************************************
684216295Ssyrinx * NTPTimeStamp
685216295Ssyrinx **************************************************************
686216295Ssyrinx * NTP MIB, Revision 0.2, 7/25/97:
687216295Ssyrinx * NTPTimeStamp ::= TEXTUAL-CONVENTION
688216295Ssyrinx *    DISPLAY-HINT "4x.4x"
689216295Ssyrinx *    STATUS	current
690216295Ssyrinx *    DESCRIPTION
691216295Ssyrinx *	""
692216295Ssyrinx *    SYNTAX	OCTET STRING (SIZE(8))
693216295Ssyrinx */
694216295Ssyrinxstatic char *
695216295Ssyrinxsnmp_oct2ntp_ts(uint32_t len, char *octets, char *buf)
696216295Ssyrinx{
697216295Ssyrinx	char *ptr;
698216295Ssyrinx	uint32_t i;
699216295Ssyrinx
700216295Ssyrinx	if (len != SNMP_NTP_TS_OCTETS || octets == NULL || buf == NULL)
701216295Ssyrinx		return (NULL);
702216295Ssyrinx
703216295Ssyrinx	buf[0]= '\0';
704216295Ssyrinx
705216295Ssyrinx	ptr = buf;
706216295Ssyrinx	i = octets[0] * 1000 + octets[1] * 100 + octets[2] * 10 + octets[3];
707216295Ssyrinx	ptr += sprintf(ptr, "%4.4d", i);
708216295Ssyrinx	i = octets[4] * 1000 + octets[5] * 100 + octets[6] * 10 + octets[7];
709216295Ssyrinx	ptr += sprintf(ptr, ".%4.4d", i);
710216295Ssyrinx
711216295Ssyrinx	return (buf);
712216295Ssyrinx}
713216295Ssyrinx
714216295Ssyrinxstatic char *
715216295Ssyrinxsnmp_ntp_ts2asn_oid(char *str, struct asn_oid *oid)
716216295Ssyrinx{
717216295Ssyrinx	char *endptr, *ptr;
718216295Ssyrinx	uint32_t v, i, d;
719216295Ssyrinx	struct asn_oid suboid;
720216295Ssyrinx	int saved_errno;
721216295Ssyrinx
722216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_NTP_TS_OCTETS) < 0)
723216295Ssyrinx		return (NULL);
724216295Ssyrinx
725216295Ssyrinx	ptr = str;
726216295Ssyrinx	saved_errno = errno;
727216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
728216295Ssyrinx	if (errno != 0 || (v / 1000) > 9) {
729216295Ssyrinx		warnx("Integer value %s not supported", str);
730216295Ssyrinx		errno = saved_errno;
731216295Ssyrinx		return (NULL);
732216295Ssyrinx	} else
733216295Ssyrinx		errno = saved_errno;
734216295Ssyrinx
735216295Ssyrinx	if (*endptr != '.') {
736216295Ssyrinx		warnx("Failed adding oid - %s",str);
737216295Ssyrinx		return (NULL);
738216295Ssyrinx	}
739216295Ssyrinx
740216295Ssyrinx	memset(&suboid, 0, sizeof(struct asn_oid));
741216295Ssyrinx	suboid.len = SNMP_NTP_TS_OCTETS;
742216295Ssyrinx
743216295Ssyrinx	for (i = 0, d = 1000; i < 4; i++) {
744216295Ssyrinx		suboid.subs[i] = v / d;
745216295Ssyrinx		v = v % d;
746216295Ssyrinx		d = d / 10;
747216295Ssyrinx	}
748216295Ssyrinx
749216295Ssyrinx	ptr = endptr + 1;
750216295Ssyrinx	saved_errno = errno;
751216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
752216295Ssyrinx	if (errno != 0 || (v / 1000) > 9) {
753216295Ssyrinx		warnx("Integer value %s not supported", str);
754216295Ssyrinx		errno = saved_errno;
755216295Ssyrinx		return (NULL);
756216295Ssyrinx	} else
757216295Ssyrinx		errno = saved_errno;
758216295Ssyrinx
759216295Ssyrinx	for (i = 0, d = 1000; i < 4; i++) {
760216295Ssyrinx		suboid.subs[i + 4] = v / d;
761216295Ssyrinx		v = v % d;
762216295Ssyrinx		d = d / 10;
763216295Ssyrinx	}
764216295Ssyrinx
765216295Ssyrinx	asn_append_oid(oid, &suboid);
766216295Ssyrinx	return (endptr);
767216295Ssyrinx}
768216295Ssyrinx
769216295Ssyrinxstatic int32_t
770216295Ssyrinxparse_ntp_ts(struct snmp_value *sv, char *val)
771216295Ssyrinx{
772216295Ssyrinx	char *endptr;
773216295Ssyrinx	int32_t i, d, saved_errno;
774216295Ssyrinx	uint32_t v;
775216295Ssyrinx	uint8_t	ntp_ts[SNMP_NTP_TS_OCTETS];
776216295Ssyrinx
777216295Ssyrinx	saved_errno = errno;
778216295Ssyrinx	v = strtoul(val, &endptr, 10);
779216295Ssyrinx	if (errno != 0 || (v / 1000) > 9) {
780216295Ssyrinx		saved_errno = errno;
781216295Ssyrinx		warnx("Integer value %s not supported", val);
782216295Ssyrinx		return (-1);
783216295Ssyrinx	} else
784216295Ssyrinx		saved_errno = errno;
785216295Ssyrinx
786216295Ssyrinx	if (*endptr != '.') {
787216295Ssyrinx		warnx("Failed reading octet - %s", val);
788216295Ssyrinx		return (-1);
789216295Ssyrinx	}
790216295Ssyrinx
791216295Ssyrinx	for (i = 0, d = 1000; i < 4; i++) {
792216295Ssyrinx		ntp_ts[i] = v / d;
793216295Ssyrinx		v = v % d;
794216295Ssyrinx		d = d / 10;
795216295Ssyrinx	}
796216295Ssyrinx	val = endptr + 1;
797216295Ssyrinx
798216295Ssyrinx	saved_errno = errno;
799216295Ssyrinx	v = strtoul(val, &endptr, 10);
800216295Ssyrinx	if (errno != 0 || (v / 1000) > 9) {
801216295Ssyrinx		saved_errno = errno;
802216295Ssyrinx		warnx("Integer value %s not supported", val);
803216295Ssyrinx		return (-1);
804216295Ssyrinx	} else
805216295Ssyrinx		saved_errno = errno;
806216295Ssyrinx
807216295Ssyrinx	for (i = 0, d = 1000; i < 4; i++) {
808216295Ssyrinx		ntp_ts[i + 4] = v / d;
809216295Ssyrinx		v = v % d;
810216295Ssyrinx		d = d / 10;
811216295Ssyrinx	}
812216295Ssyrinx
813216295Ssyrinx	if ((sv->v.octetstring.octets = malloc(SNMP_NTP_TS_OCTETS)) == NULL) {
814216295Ssyrinx		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
815216295Ssyrinx		return (-1);
816216295Ssyrinx	}
817216295Ssyrinx
818216295Ssyrinx	sv->v.octetstring.len = SNMP_NTP_TS_OCTETS;
819216295Ssyrinx	memcpy(sv->v.octetstring.octets, ntp_ts, SNMP_NTP_TS_OCTETS);
820216295Ssyrinx	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
821216295Ssyrinx	return (1);
822216295Ssyrinx}
823216295Ssyrinx
824216295Ssyrinx/**************************************************************
825216295Ssyrinx * BridgeId
826216295Ssyrinx **************************************************************
827216295Ssyrinx * BRIDGE-MIB, REVISION		"200509190000Z"
828216295Ssyrinx * BridgeId ::= TEXTUAL-CONVENTION
829216295Ssyrinx *    STATUS	current
830216295Ssyrinx *    DESCRIPTION
831216295Ssyrinx *	"The Bridge-Identifier, as used in the Spanning Tree
832216295Ssyrinx *	Protocol, to uniquely identify a bridge.  Its first two
833216295Ssyrinx *	octets (in network byte order) contain a priority value,
834216295Ssyrinx *	and its last 6 octets contain the MAC address used to
835216295Ssyrinx *	refer to a bridge in a unique fashion (typically, the
836216295Ssyrinx *	numerically smallest MAC address of all ports on the
837216295Ssyrinx *	bridge)."
838216295Ssyrinx *    SYNTAX	OCTET STRING (SIZE (8))
839216295Ssyrinx */
840216295Ssyrinxstatic char *
841216295Ssyrinxsnmp_oct2bridgeid(uint32_t len, char *octets, char *buf)
842216295Ssyrinx{
843216295Ssyrinx	char *ptr;
844216295Ssyrinx	uint32_t i, priority;
845216295Ssyrinx
846216295Ssyrinx	if (len != SNMP_BRIDGEID_OCTETS || octets == NULL || buf == NULL)
847216295Ssyrinx		return (NULL);
848216295Ssyrinx
849216295Ssyrinx	buf[0]= '\0';
850216295Ssyrinx	ptr = buf;
851216295Ssyrinx
852216295Ssyrinx	priority = octets[0] << 8;
853216295Ssyrinx	priority += octets[1];
854216295Ssyrinx	if (priority > SNMP_MAX_BRIDGE_PRIORITY) {
855216295Ssyrinx		warnx("Invalid bridge priority %d", priority);
856216295Ssyrinx		return (NULL);
857216295Ssyrinx	} else
858216295Ssyrinx		ptr += sprintf(ptr, "%d.", octets[0]);
859216295Ssyrinx
860216295Ssyrinx	ptr += sprintf(ptr, "%2.2x", octets[2]);
861216295Ssyrinx
862216295Ssyrinx	for (i = 1; i < 6; i++)
863216295Ssyrinx		ptr += sprintf(ptr, ":%2.2x", octets[i + 2]);
864216295Ssyrinx
865216295Ssyrinx	return (buf);
866216295Ssyrinx}
867216295Ssyrinx
868216295Ssyrinxstatic char *
869216295Ssyrinxsnmp_bridgeid2oct(char *str, struct asn_oid *oid)
870216295Ssyrinx{
871216295Ssyrinx	char *endptr, *ptr;
872216295Ssyrinx	uint32_t v, i;
873216295Ssyrinx	int32_t saved_errno;
874216295Ssyrinx
875216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BRIDGEID_OCTETS) < 0)
876216295Ssyrinx		return (NULL);
877216295Ssyrinx
878216295Ssyrinx	ptr = str;
879216295Ssyrinx	/* Read the priority. */
880216295Ssyrinx	saved_errno = errno;
881216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
882216295Ssyrinx	errno = 0;
883216295Ssyrinx
884216295Ssyrinx	if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
885216295Ssyrinx		errno = saved_errno;
886216295Ssyrinx		warnx("Bad bridge priority value %d", v);
887216295Ssyrinx		return (NULL);
888216295Ssyrinx	}
889216295Ssyrinx
890216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff00)) < 0)
891216295Ssyrinx		return (NULL);
892216295Ssyrinx
893216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
894216295Ssyrinx		return (NULL);
895216295Ssyrinx
896216295Ssyrinx	ptr = endptr + 1;
897216295Ssyrinx	for (i = 0; i < 5; i++) {
898216295Ssyrinx		saved_errno = errno;
899216295Ssyrinx		v = strtoul(ptr, &endptr, 16);
900216295Ssyrinx		errno = saved_errno;
901216295Ssyrinx		if (v > 0xff) {
902216295Ssyrinx			warnx("Integer value %s not supported", str);
903216295Ssyrinx			return (NULL);
904216295Ssyrinx		}
905216295Ssyrinx		if (*endptr != ':') {
906216295Ssyrinx			warnx("Failed adding oid - %s",str);
907216295Ssyrinx			return (NULL);
908216295Ssyrinx		}
909216295Ssyrinx		if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
910216295Ssyrinx			return (NULL);
911216295Ssyrinx		ptr = endptr + 1;
912216295Ssyrinx	}
913216295Ssyrinx
914216295Ssyrinx	/* The last one - don't check the ending char here. */
915216295Ssyrinx	saved_errno = errno;
916216295Ssyrinx	v = strtoul(ptr, &endptr, 16);
917216295Ssyrinx	errno = saved_errno;
918216295Ssyrinx	if (v > 0xff) {
919216295Ssyrinx		warnx("Integer value %s not supported", str);
920216295Ssyrinx		return (NULL);
921216295Ssyrinx	}
922216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
923216295Ssyrinx		return (NULL);
924216295Ssyrinx
925216295Ssyrinx	return (endptr);
926216295Ssyrinx}
927216295Ssyrinx
928216295Ssyrinxstatic int32_t
929216295Ssyrinxparse_bridge_id(struct snmp_value *sv, char *string)
930216295Ssyrinx{
931216295Ssyrinx	char *ptr, *endptr;
932216295Ssyrinx	int32_t i, saved_errno;
933216295Ssyrinx	uint32_t v;
934216295Ssyrinx	uint8_t	bridge_id[SNMP_BRIDGEID_OCTETS];
935216295Ssyrinx
936216295Ssyrinx	ptr = string;
937216295Ssyrinx	/* Read the priority. */
938216295Ssyrinx	saved_errno = errno;
939216295Ssyrinx	errno = 0;
940216295Ssyrinx	v = strtoul(string, &endptr, 10);
941216295Ssyrinx	errno = saved_errno;
942216295Ssyrinx
943216295Ssyrinx	if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
944216295Ssyrinx		errno = saved_errno;
945216295Ssyrinx		warnx("Bad bridge priority value %d", v);
946216295Ssyrinx		return (-1);
947216295Ssyrinx	}
948216295Ssyrinx
949216295Ssyrinx	bridge_id[0] = (v & 0xff00);
950216295Ssyrinx	bridge_id[1] = (v & 0xff);
951216295Ssyrinx
952216295Ssyrinx	string = endptr + 1;
953216295Ssyrinx
954216295Ssyrinx	for (i = 0; i < 5; i++) {
955216295Ssyrinx		v = strtoul(string, &endptr, 16);
956216295Ssyrinx		if (v > 0xff) {
957216295Ssyrinx			warnx("Integer value %s not supported", string);
958216295Ssyrinx			return (-1);
959216295Ssyrinx		}
960216295Ssyrinx		if(*endptr != ':') {
961216295Ssyrinx			warnx("Failed reading octet - %s", string);
962216295Ssyrinx			return (-1);
963216295Ssyrinx		}
964216295Ssyrinx		bridge_id[i + 2] = v;
965216295Ssyrinx		string = endptr + 1;
966216295Ssyrinx	}
967216295Ssyrinx
968216295Ssyrinx	/* The last one - don't check the ending char here. */
969216295Ssyrinx	v = strtoul(string, &endptr, 16);
970216295Ssyrinx	if (v > 0xff) {
971216295Ssyrinx		warnx("Integer value %s not supported", string);
972216295Ssyrinx		return (-1);
973216295Ssyrinx	}
974216295Ssyrinx	bridge_id[7] = v;
975216295Ssyrinx
976216295Ssyrinx	if ((sv->v.octetstring.octets = malloc(SNMP_BRIDGEID_OCTETS)) == NULL) {
977216295Ssyrinx		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
978216295Ssyrinx		return (-1);
979216295Ssyrinx	}
980216295Ssyrinx
981216295Ssyrinx	sv->v.octetstring.len = SNMP_BRIDGEID_OCTETS;
982216295Ssyrinx	memcpy(sv->v.octetstring.octets, bridge_id, SNMP_BRIDGEID_OCTETS);
983216295Ssyrinx	sv->syntax = SNMP_SYNTAX_OCTETSTRING;
984216295Ssyrinx	return (1);
985216295Ssyrinx}
986216295Ssyrinx
987216295Ssyrinx/**************************************************************
988216295Ssyrinx * BridgePortId
989216295Ssyrinx **************************************************************
990216295Ssyrinx * BEGEMOT-BRIDGE-MIB, LAST-UPDATED "200608100000Z"
991216295Ssyrinx * BridgePortId ::= TEXTUAL-CONVENTION
992216295Ssyrinx *    DISPLAY-HINT "1x.1x"
993216295Ssyrinx *    STATUS	current
994216295Ssyrinx *    DESCRIPTION
995216295Ssyrinx *	"A port identifier that contains a bridge port's STP priority
996216295Ssyrinx *	in the first octet and the port number in the second octet."
997216295Ssyrinx *    SYNTAX	OCTET STRING (SIZE(2))
998216295Ssyrinx */
999216295Ssyrinxstatic char *
1000216295Ssyrinxsnmp_oct2bport_id(uint32_t len, char *octets, char *buf)
1001216295Ssyrinx{
1002216295Ssyrinx	char *ptr;
1003216295Ssyrinx
1004216295Ssyrinx	if (len != SNMP_BPORT_OCTETS || octets == NULL || buf == NULL)
1005216295Ssyrinx		return (NULL);
1006216295Ssyrinx
1007216295Ssyrinx	buf[0]= '\0';
1008216295Ssyrinx	ptr = buf;
1009216295Ssyrinx
1010216295Ssyrinx	ptr += sprintf(ptr, "%d.", octets[0]);
1011216295Ssyrinx	ptr += sprintf(ptr, "%d", octets[1]);
1012216295Ssyrinx
1013216295Ssyrinx	return (buf);
1014216295Ssyrinx}
1015216295Ssyrinx
1016216295Ssyrinxstatic char *
1017216295Ssyrinxsnmp_bport_id2oct(char *str, struct asn_oid *oid)
1018216295Ssyrinx{
1019216295Ssyrinx	char *endptr, *ptr;
1020216295Ssyrinx	uint32_t v;
1021216295Ssyrinx	int saved_errno;
1022216295Ssyrinx
1023216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BPORT_OCTETS) < 0)
1024216295Ssyrinx		return (NULL);
1025216295Ssyrinx
1026216295Ssyrinx	ptr = str;
1027216295Ssyrinx	/* Read the priority. */
1028216295Ssyrinx	saved_errno = errno;
1029216295Ssyrinx	v = strtoul(ptr, &endptr, 10);
1030216295Ssyrinx	errno = 0;
1031216295Ssyrinx
1032216295Ssyrinx	if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
1033216295Ssyrinx		errno = saved_errno;
1034216295Ssyrinx		warnx("Bad bridge port priority value %d", v);
1035216295Ssyrinx		return (NULL);
1036216295Ssyrinx	}
1037216295Ssyrinx
1038216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1039216295Ssyrinx		return (NULL);
1040216295Ssyrinx
1041216295Ssyrinx	saved_errno = errno;
1042216295Ssyrinx	v = strtoul(ptr, &endptr, 16);
1043216295Ssyrinx	errno = saved_errno;
1044216295Ssyrinx
1045216295Ssyrinx	if (v > 0xff) {
1046216295Ssyrinx		warnx("Bad port number - %d", v);
1047216295Ssyrinx		return (NULL);
1048216295Ssyrinx	}
1049216295Ssyrinx
1050216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1051216295Ssyrinx		return (NULL);
1052216295Ssyrinx
1053216295Ssyrinx	return (endptr);
1054216295Ssyrinx}
1055216295Ssyrinx
1056216295Ssyrinxstatic int32_t
1057216295Ssyrinxparse_bport_id(struct snmp_value *value, char *string)
1058216295Ssyrinx{
1059216295Ssyrinx	char *ptr, *endptr;
1060216295Ssyrinx	int saved_errno;
1061216295Ssyrinx	uint32_t v;
1062216295Ssyrinx	uint8_t	bport_id[SNMP_BPORT_OCTETS];
1063216295Ssyrinx
1064216295Ssyrinx	ptr = string;
1065216295Ssyrinx	/* Read the priority. */
1066216295Ssyrinx	saved_errno = errno;
1067216295Ssyrinx	errno = 0;
1068216295Ssyrinx	v = strtoul(string, &endptr, 10);
1069216295Ssyrinx	errno = saved_errno;
1070216295Ssyrinx
1071216295Ssyrinx	if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
1072216295Ssyrinx		errno = saved_errno;
1073216295Ssyrinx		warnx("Bad bridge port priority value %d", v);
1074216295Ssyrinx		return (-1);
1075216295Ssyrinx	}
1076216295Ssyrinx
1077216295Ssyrinx	bport_id[0] = v;
1078216295Ssyrinx
1079216295Ssyrinx	string = endptr + 1;
1080216295Ssyrinx	v = strtoul(string, &endptr, 16);
1081216295Ssyrinx	if (v > 0xff) {
1082216295Ssyrinx		warnx("Bad port number - %d", v);
1083216295Ssyrinx		return (-1);
1084216295Ssyrinx	}
1085216295Ssyrinx
1086216295Ssyrinx	bport_id[1] = v;
1087216295Ssyrinx
1088216295Ssyrinx	if ((value->v.octetstring.octets = malloc(SNMP_BPORT_OCTETS)) == NULL) {
1089216295Ssyrinx		syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
1090216295Ssyrinx		return (-1);
1091216295Ssyrinx	}
1092216295Ssyrinx
1093216295Ssyrinx	value->v.octetstring.len = SNMP_BPORT_OCTETS;
1094216295Ssyrinx	memcpy(value->v.octetstring.octets, bport_id, SNMP_BPORT_OCTETS);
1095216295Ssyrinx	value->syntax = SNMP_SYNTAX_OCTETSTRING;
1096216295Ssyrinx	return (1);
1097216295Ssyrinx}
1098216295Ssyrinx/**************************************************************
1099216295Ssyrinx * InetAddress
1100216295Ssyrinx **************************************************************
1101216295Ssyrinx * INET-ADDRESS-MIB, REVISION     "200502040000Z"
1102216295Ssyrinx * InetAddress ::= TEXTUAL-CONVENTION
1103216295Ssyrinx *   STATUS      current
1104216295Ssyrinx *   DESCRIPTION
1105216295Ssyrinx *       "Denotes a generic Internet address.
1106216295Ssyrinx *
1107216295Ssyrinx *        An InetAddress value is always interpreted within the context
1108216295Ssyrinx *        of an InetAddressType value.  Every usage of the InetAddress
1109216295Ssyrinx *        textual convention is required to specify the InetAddressType
1110216295Ssyrinx *        object that provides the context.  It is suggested that the
1111216295Ssyrinx *        InetAddressType object be logically registered before the
1112216295Ssyrinx *        object(s) that use the InetAddress textual convention, if
1113216295Ssyrinx *        they appear in the same logical row.
1114216295Ssyrinx *
1115216295Ssyrinx *        The value of an InetAddress object must always be
1116216295Ssyrinx *        consistent with the value of the associated InetAddressType
1117216295Ssyrinx *        object.  Attempts to set an InetAddress object to a value
1118216295Ssyrinx *        inconsistent with the associated InetAddressType
1119216295Ssyrinx *        must fail with an inconsistentValue error.
1120216295Ssyrinx *
1121216295Ssyrinx *        When this textual convention is used as the syntax of an
1122216295Ssyrinx *        index object, there may be issues with the limit of 128
1123216295Ssyrinx *        sub-identifiers specified in SMIv2, STD 58.  In this case,
1124216295Ssyrinx *        the object definition MUST include a 'SIZE' clause to
1125216295Ssyrinx *        limit the number of potential instance sub-identifiers;
1126216295Ssyrinx *        otherwise the applicable constraints MUST be stated in
1127216295Ssyrinx *        the appropriate conceptual row DESCRIPTION clauses, or
1128216295Ssyrinx *        in the surrounding documentation if there is no single
1129216295Ssyrinx *        DESCRIPTION clause that is appropriate."
1130216295Ssyrinx *   SYNTAX       OCTET STRING (SIZE (0..255))
1131216295Ssyrinx **************************************************************
1132216295Ssyrinx * TODO: FIXME!!! syrinx: Since we do not support checking the
1133216295Ssyrinx * consistency of a varbinding based on the value of a previous
1134216295Ssyrinx * one, try to guess the type of address based on the
1135216295Ssyrinx * OctetString SIZE - 4 for IPv4, 16 for IPv6, others currently
1136216295Ssyrinx * not supported.
1137216295Ssyrinx */
1138216295Ssyrinxstatic char *
1139216295Ssyrinxsnmp_oct2inetaddr(uint32_t len, char *octets, char *buf)
1140216295Ssyrinx{
1141216295Ssyrinx	int af;
1142216295Ssyrinx	void *ip;
1143216295Ssyrinx	struct in_addr	ipv4;
1144216295Ssyrinx	struct in6_addr	ipv6;
1145216295Ssyrinx
1146216295Ssyrinx	if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL)
1147216295Ssyrinx		return (NULL);
1148216295Ssyrinx
1149216295Ssyrinx	switch (len) {
1150216295Ssyrinx		/* XXX: FIXME - IPv4*/
1151216295Ssyrinx		case 4:
1152216295Ssyrinx			memcpy(&ipv4.s_addr, octets, sizeof(ipv4.s_addr));
1153216295Ssyrinx			af = AF_INET;
1154216295Ssyrinx			ip = &ipv4;
1155216295Ssyrinx			break;
1156216295Ssyrinx
1157216295Ssyrinx		/* XXX: FIXME - IPv4*/
1158216295Ssyrinx		case 16:
1159216295Ssyrinx			memcpy(ipv6.s6_addr, octets, sizeof(ipv6.s6_addr));
1160216295Ssyrinx			af = AF_INET6;
1161216295Ssyrinx			ip = &ipv6;
1162216295Ssyrinx			break;
1163216295Ssyrinx
1164216295Ssyrinx		default:
1165216295Ssyrinx			return (NULL);
1166216295Ssyrinx	}
1167216295Ssyrinx
1168216295Ssyrinx	if (inet_ntop(af, ip, buf, SNMP_INADDRS_STRSZ) == NULL) {
1169216295Ssyrinx		warnx("inet_ntop failed - %s", strerror(errno));
1170216295Ssyrinx		return (NULL);
1171216295Ssyrinx	}
1172216295Ssyrinx
1173216295Ssyrinx	return (buf);
1174216295Ssyrinx}
1175216295Ssyrinx
1176216295Ssyrinxstatic char *
1177216295Ssyrinxsnmp_inetaddr2oct(char *str, struct asn_oid *oid)
1178216295Ssyrinx{
1179216295Ssyrinx	return (NULL);
1180216295Ssyrinx}
1181216295Ssyrinx
1182216295Ssyrinxstatic int32_t
1183216295Ssyrinxparse_inetaddr(struct snmp_value *value, char *string)
1184216295Ssyrinx{
1185216295Ssyrinx	return (-1);
1186216295Ssyrinx}
1187216295Ssyrinx
1188216295Ssyrinx/**************************************************************
1189216295Ssyrinx * SNMP BITS type - XXX: FIXME
1190216295Ssyrinx **************************************************************/
1191216295Ssyrinxstatic char *
1192216295Ssyrinxsnmp_oct2bits(uint32_t len, char *octets, char *buf)
1193216295Ssyrinx{
1194216295Ssyrinx	int i, bits;
1195216295Ssyrinx	uint64_t value;
1196216295Ssyrinx
1197216295Ssyrinx	if (len > sizeof(value) || octets == NULL || buf == NULL)
1198216295Ssyrinx		return (NULL);
1199216295Ssyrinx
1200216295Ssyrinx	for (i = len, value = 0, bits = 0; i > 0; i--, bits += 8)
1201216295Ssyrinx		value += octets[i] << bits;
1202216295Ssyrinx
1203216295Ssyrinx	buf[0]= '\0';
1204216295Ssyrinx	sprintf(buf, "0x%llx.",(long long unsigned) value);
1205216295Ssyrinx
1206216295Ssyrinx	return (buf);
1207216295Ssyrinx}
1208216295Ssyrinx
1209216295Ssyrinxstatic char *
1210216295Ssyrinxsnmp_bits2oct(char *str, struct asn_oid *oid)
1211216295Ssyrinx{
1212216295Ssyrinx	char *endptr;
1213216295Ssyrinx	int i, size, bits, saved_errno;
1214216295Ssyrinx	uint64_t v, mask = 0xFF00000000000000;
1215216295Ssyrinx
1216216295Ssyrinx	saved_errno = errno;
1217216295Ssyrinx	errno = 0;
1218216295Ssyrinx
1219216295Ssyrinx	v = strtoull(str, &endptr, 16);
1220216295Ssyrinx	if (errno != 0) {
1221216295Ssyrinx		warnx("Bad BITS value %s - %s", str, strerror(errno));
1222216295Ssyrinx		errno = saved_errno;
1223216295Ssyrinx		return (NULL);
1224216295Ssyrinx	}
1225216295Ssyrinx
1226216295Ssyrinx	bits = 8;
1227216295Ssyrinx	/* Determine length - up to 8 octets supported so far. */
1228216295Ssyrinx	for (size = sizeof(v); size > 0; size--) {
1229216295Ssyrinx		if ((v & mask) != 0)
1230216295Ssyrinx			break;
1231216295Ssyrinx		mask = mask >> bits;
1232216295Ssyrinx	}
1233216295Ssyrinx
1234216295Ssyrinx	if (size == 0)
1235216295Ssyrinx		size = 1;
1236216295Ssyrinx
1237216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) size) < 0)
1238216295Ssyrinx		return (NULL);
1239216295Ssyrinx
1240216295Ssyrinx	for (i = 0, bits = 0; i < size; i++, bits += 8)
1241216295Ssyrinx		if (snmp_suboid_append(oid,
1242216295Ssyrinx		    (asn_subid_t)((v & mask) >> bits)) < 0)
1243216295Ssyrinx			return (NULL);
1244216295Ssyrinx
1245216295Ssyrinx	return (endptr);
1246216295Ssyrinx}
1247216295Ssyrinx
1248216295Ssyrinxstatic int32_t
1249216295Ssyrinxparse_bits(struct snmp_value *value, char *string)
1250216295Ssyrinx{
1251216295Ssyrinx	char *endptr;
1252216295Ssyrinx	int i, size, bits, saved_errno;
1253216295Ssyrinx	uint64_t v, mask = 0xFF00000000000000;
1254216295Ssyrinx
1255216295Ssyrinx	saved_errno = errno;
1256216295Ssyrinx	errno = 0;
1257216295Ssyrinx
1258216295Ssyrinx	v = strtoull(string, &endptr, 16);
1259216295Ssyrinx
1260216295Ssyrinx	if (errno != 0) {
1261216295Ssyrinx		warnx("Bad BITS value %s - %s", string, strerror(errno));
1262216295Ssyrinx		errno = saved_errno;
1263216295Ssyrinx		return (-1);
1264216295Ssyrinx	}
1265216295Ssyrinx
1266216295Ssyrinx	bits = 8;
1267216295Ssyrinx	/* Determine length - up to 8 octets supported so far. */
1268216295Ssyrinx	for (size = sizeof(v); size > 0; size--) {
1269216295Ssyrinx		if ((v & mask) != 0)
1270216295Ssyrinx			break;
1271216295Ssyrinx		mask = mask >> bits;
1272216295Ssyrinx	}
1273216295Ssyrinx
1274216295Ssyrinx	if (size == 0)
1275216295Ssyrinx		size = 1;
1276216295Ssyrinx
1277216295Ssyrinx	if ((value->v.octetstring.octets = malloc(size)) == NULL) {
1278216295Ssyrinx		syslog(LOG_ERR, "malloc failed: %s", strerror(errno));
1279216295Ssyrinx		return (-1);
1280216295Ssyrinx	}
1281216295Ssyrinx
1282216295Ssyrinx	value->v.octetstring.len = size;
1283216295Ssyrinx	for (i = 0, bits = 0; i < size; i++, bits += 8)
1284216295Ssyrinx		value->v.octetstring.octets[i] = (v & mask) >> bits;
1285216295Ssyrinx	value->syntax = SNMP_SYNTAX_OCTETSTRING;
1286216295Ssyrinx	return (1);
1287216295Ssyrinx}
1288