xref: /freebsd/contrib/bsnmp/lib/snmp.c (revision f06ca4af1879f1cb903660d2a12ba7edcf152938)
1f06ca4afSHartmut Brandt /*
2f06ca4afSHartmut Brandt  * Copyright (c) 2001-2003
3f06ca4afSHartmut Brandt  *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4f06ca4afSHartmut Brandt  *	All rights reserved.
5f06ca4afSHartmut Brandt  *
6f06ca4afSHartmut Brandt  * Author: Harti Brandt <harti@freebsd.org>
7f06ca4afSHartmut Brandt  *
8f06ca4afSHartmut Brandt  * Redistribution of this software and documentation and use in source and
9f06ca4afSHartmut Brandt  * binary forms, with or without modification, are permitted provided that
10f06ca4afSHartmut Brandt  * the following conditions are met:
11f06ca4afSHartmut Brandt  *
12f06ca4afSHartmut Brandt  * 1. Redistributions of source code or documentation must retain the above
13f06ca4afSHartmut Brandt  *    copyright notice, this list of conditions and the following disclaimer.
14f06ca4afSHartmut Brandt  * 2. Redistributions in binary form must reproduce the above copyright
15f06ca4afSHartmut Brandt  *    notice, this list of conditions and the following disclaimer in the
16f06ca4afSHartmut Brandt  *    documentation and/or other materials provided with the distribution.
17f06ca4afSHartmut Brandt  * 3. Neither the name of the Institute nor the names of its contributors
18f06ca4afSHartmut Brandt  *    may be used to endorse or promote products derived from this software
19f06ca4afSHartmut Brandt  *    without specific prior written permission.
20f06ca4afSHartmut Brandt  *
21f06ca4afSHartmut Brandt  * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
22f06ca4afSHartmut Brandt  * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23f06ca4afSHartmut Brandt  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24f06ca4afSHartmut Brandt  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
25f06ca4afSHartmut Brandt  * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
26f06ca4afSHartmut Brandt  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27f06ca4afSHartmut Brandt  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
28f06ca4afSHartmut Brandt  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29f06ca4afSHartmut Brandt  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30f06ca4afSHartmut Brandt  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31f06ca4afSHartmut Brandt  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32f06ca4afSHartmut Brandt  *
33f06ca4afSHartmut Brandt  * $Begemot: bsnmp/lib/snmp.c,v 1.34 2003/01/28 13:44:34 hbb Exp $
34f06ca4afSHartmut Brandt  *
35f06ca4afSHartmut Brandt  * SNMP
36f06ca4afSHartmut Brandt  */
37f06ca4afSHartmut Brandt #include <sys/types.h>
38f06ca4afSHartmut Brandt #include <sys/socket.h>
39f06ca4afSHartmut Brandt #include <stdio.h>
40f06ca4afSHartmut Brandt #include <stdlib.h>
41f06ca4afSHartmut Brandt #include <stddef.h>
42f06ca4afSHartmut Brandt #include <stdarg.h>
43f06ca4afSHartmut Brandt #include <string.h>
44f06ca4afSHartmut Brandt #include <ctype.h>
45f06ca4afSHartmut Brandt #include <netdb.h>
46f06ca4afSHartmut Brandt #include <errno.h>
47f06ca4afSHartmut Brandt 
48f06ca4afSHartmut Brandt #include "asn1.h"
49f06ca4afSHartmut Brandt #include "snmp.h"
50f06ca4afSHartmut Brandt #include "snmppriv.h"
51f06ca4afSHartmut Brandt 
52f06ca4afSHartmut Brandt static void snmp_error_func(const char *, ...);
53f06ca4afSHartmut Brandt static void snmp_printf_func(const char *, ...);
54f06ca4afSHartmut Brandt 
55f06ca4afSHartmut Brandt void (*snmp_error)(const char *, ...) = snmp_error_func;
56f06ca4afSHartmut Brandt void (*snmp_printf)(const char *, ...) = snmp_printf_func;
57f06ca4afSHartmut Brandt 
58f06ca4afSHartmut Brandt 
59f06ca4afSHartmut Brandt /*
60f06ca4afSHartmut Brandt  * Get the next variable binding from the list.
61f06ca4afSHartmut Brandt  * ASN errors on the sequence or the OID are always fatal.
62f06ca4afSHartmut Brandt  */
63f06ca4afSHartmut Brandt static enum asn_err
64f06ca4afSHartmut Brandt get_var_binding(struct asn_buf *b, struct snmp_value *binding)
65f06ca4afSHartmut Brandt {
66f06ca4afSHartmut Brandt 	u_char type;
67f06ca4afSHartmut Brandt 	asn_len_t len, trailer;
68f06ca4afSHartmut Brandt 	enum asn_err err;
69f06ca4afSHartmut Brandt 
70f06ca4afSHartmut Brandt 	if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
71f06ca4afSHartmut Brandt 		snmp_error("cannot parse varbind header");
72f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
73f06ca4afSHartmut Brandt 	}
74f06ca4afSHartmut Brandt 
75f06ca4afSHartmut Brandt 	/* temporary truncate the length so that the parser does not
76f06ca4afSHartmut Brandt 	 * eat up bytes behind the sequence in the case the encoding is
77f06ca4afSHartmut Brandt 	 * wrong of inner elements. */
78f06ca4afSHartmut Brandt 	trailer = b->asn_len - len;
79f06ca4afSHartmut Brandt 	b->asn_len = len;
80f06ca4afSHartmut Brandt 
81f06ca4afSHartmut Brandt 	if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) {
82f06ca4afSHartmut Brandt 		snmp_error("cannot parse binding objid");
83f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
84f06ca4afSHartmut Brandt 	}
85f06ca4afSHartmut Brandt 	if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
86f06ca4afSHartmut Brandt 		snmp_error("cannot parse binding value header");
87f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
88f06ca4afSHartmut Brandt 	}
89f06ca4afSHartmut Brandt 
90f06ca4afSHartmut Brandt 	switch (type) {
91f06ca4afSHartmut Brandt 
92f06ca4afSHartmut Brandt 	  case ASN_TYPE_NULL:
93f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_NULL;
94f06ca4afSHartmut Brandt 		err = asn_get_null_raw(b, len);
95f06ca4afSHartmut Brandt 		break;
96f06ca4afSHartmut Brandt 
97f06ca4afSHartmut Brandt 	  case ASN_TYPE_INTEGER:
98f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_INTEGER;
99f06ca4afSHartmut Brandt 		err = asn_get_integer_raw(b, len, &binding->v.integer);
100f06ca4afSHartmut Brandt 		break;
101f06ca4afSHartmut Brandt 
102f06ca4afSHartmut Brandt 	  case ASN_TYPE_OCTETSTRING:
103f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_OCTETSTRING;
104f06ca4afSHartmut Brandt 		binding->v.octetstring.octets = malloc(len);
105f06ca4afSHartmut Brandt 		if (binding->v.octetstring.octets == NULL) {
106f06ca4afSHartmut Brandt 			snmp_error("%s", strerror(errno));
107f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
108f06ca4afSHartmut Brandt 		}
109f06ca4afSHartmut Brandt 		binding->v.octetstring.len = len;
110f06ca4afSHartmut Brandt 		err = asn_get_octetstring_raw(b, len,
111f06ca4afSHartmut Brandt 		    binding->v.octetstring.octets,
112f06ca4afSHartmut Brandt 		    &binding->v.octetstring.len);
113f06ca4afSHartmut Brandt 		if (ASN_ERR_STOPPED(err)) {
114f06ca4afSHartmut Brandt 			free(binding->v.octetstring.octets);
115f06ca4afSHartmut Brandt 			binding->v.octetstring.octets = NULL;
116f06ca4afSHartmut Brandt 		}
117f06ca4afSHartmut Brandt 		break;
118f06ca4afSHartmut Brandt 
119f06ca4afSHartmut Brandt 	  case ASN_TYPE_OBJID:
120f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_OID;
121f06ca4afSHartmut Brandt 		err = asn_get_objid_raw(b, len, &binding->v.oid);
122f06ca4afSHartmut Brandt 		break;
123f06ca4afSHartmut Brandt 
124f06ca4afSHartmut Brandt 	  case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS:
125f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_IPADDRESS;
126f06ca4afSHartmut Brandt 		err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress);
127f06ca4afSHartmut Brandt 		break;
128f06ca4afSHartmut Brandt 
129f06ca4afSHartmut Brandt 	  case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS:
130f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_TIMETICKS;
131f06ca4afSHartmut Brandt 		err = asn_get_uint32_raw(b, len, &binding->v.uint32);
132f06ca4afSHartmut Brandt 		break;
133f06ca4afSHartmut Brandt 
134f06ca4afSHartmut Brandt 	  case ASN_CLASS_APPLICATION|ASN_APP_COUNTER:
135f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_COUNTER;
136f06ca4afSHartmut Brandt 		err = asn_get_uint32_raw(b, len, &binding->v.uint32);
137f06ca4afSHartmut Brandt 		break;
138f06ca4afSHartmut Brandt 
139f06ca4afSHartmut Brandt 	  case ASN_CLASS_APPLICATION|ASN_APP_GAUGE:
140f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_GAUGE;
141f06ca4afSHartmut Brandt 		err = asn_get_uint32_raw(b, len, &binding->v.uint32);
142f06ca4afSHartmut Brandt 		break;
143f06ca4afSHartmut Brandt 
144f06ca4afSHartmut Brandt 	  case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64:
145f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_COUNTER64;
146f06ca4afSHartmut Brandt 		err = asn_get_counter64_raw(b, len, &binding->v.counter64);
147f06ca4afSHartmut Brandt 		break;
148f06ca4afSHartmut Brandt 
149f06ca4afSHartmut Brandt 	  case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT:
150f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT;
151f06ca4afSHartmut Brandt 		err = asn_get_null_raw(b, len);
152f06ca4afSHartmut Brandt 		break;
153f06ca4afSHartmut Brandt 
154f06ca4afSHartmut Brandt 	  case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE:
155f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
156f06ca4afSHartmut Brandt 		err = asn_get_null_raw(b, len);
157f06ca4afSHartmut Brandt 		break;
158f06ca4afSHartmut Brandt 
159f06ca4afSHartmut Brandt 	  case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW:
160f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
161f06ca4afSHartmut Brandt 		err = asn_get_null_raw(b, len);
162f06ca4afSHartmut Brandt 		break;
163f06ca4afSHartmut Brandt 
164f06ca4afSHartmut Brandt 	  default:
165f06ca4afSHartmut Brandt 		if ((err = asn_skip(b, len)) == ASN_ERR_OK)
166f06ca4afSHartmut Brandt 			err = ASN_ERR_TAG;
167f06ca4afSHartmut Brandt 		snmp_error("bad binding value type 0x%x", type);
168f06ca4afSHartmut Brandt 		break;
169f06ca4afSHartmut Brandt 	}
170f06ca4afSHartmut Brandt 
171f06ca4afSHartmut Brandt 	if (ASN_ERR_STOPPED(err)) {
172f06ca4afSHartmut Brandt 		snmp_error("cannot parse binding value");
173f06ca4afSHartmut Brandt 		return (err);
174f06ca4afSHartmut Brandt 	}
175f06ca4afSHartmut Brandt 
176f06ca4afSHartmut Brandt 	if (b->asn_len != 0)
177f06ca4afSHartmut Brandt 		snmp_error("ignoring junk at end of binding");
178f06ca4afSHartmut Brandt 
179f06ca4afSHartmut Brandt 	b->asn_len = trailer;
180f06ca4afSHartmut Brandt 
181f06ca4afSHartmut Brandt 	return (err);
182f06ca4afSHartmut Brandt }
183f06ca4afSHartmut Brandt 
184f06ca4afSHartmut Brandt /*
185f06ca4afSHartmut Brandt  * Parse the different PDUs contents. Any ASN error in the outer components
186f06ca4afSHartmut Brandt  * are fatal. Only errors in variable values may be tolerated. If all
187f06ca4afSHartmut Brandt  * components can be parsed it returns either ASN_ERR_OK or the first
188f06ca4afSHartmut Brandt  * error that was found.
189f06ca4afSHartmut Brandt  */
190f06ca4afSHartmut Brandt enum asn_err
191f06ca4afSHartmut Brandt snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
192f06ca4afSHartmut Brandt {
193f06ca4afSHartmut Brandt 	if (pdu->type == SNMP_PDU_TRAP) {
194f06ca4afSHartmut Brandt 		if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) {
195f06ca4afSHartmut Brandt 			snmp_error("cannot parse trap enterprise");
196f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
197f06ca4afSHartmut Brandt 		}
198f06ca4afSHartmut Brandt 		if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) {
199f06ca4afSHartmut Brandt 			snmp_error("cannot parse trap agent address");
200f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
201f06ca4afSHartmut Brandt 		}
202f06ca4afSHartmut Brandt 		if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) {
203f06ca4afSHartmut Brandt 			snmp_error("cannot parse 'generic-trap'");
204f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
205f06ca4afSHartmut Brandt 		}
206f06ca4afSHartmut Brandt 		if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) {
207f06ca4afSHartmut Brandt 			snmp_error("cannot parse 'specific-trap'");
208f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
209f06ca4afSHartmut Brandt 		}
210f06ca4afSHartmut Brandt 		if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) {
211f06ca4afSHartmut Brandt 			snmp_error("cannot parse trap 'time-stamp'");
212f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
213f06ca4afSHartmut Brandt 		}
214f06ca4afSHartmut Brandt 	} else {
215f06ca4afSHartmut Brandt 		if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) {
216f06ca4afSHartmut Brandt 			snmp_error("cannot parse 'request-id'");
217f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
218f06ca4afSHartmut Brandt 		}
219f06ca4afSHartmut Brandt 		if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) {
220f06ca4afSHartmut Brandt 			snmp_error("cannot parse 'error_status'");
221f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
222f06ca4afSHartmut Brandt 		}
223f06ca4afSHartmut Brandt 		if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) {
224f06ca4afSHartmut Brandt 			snmp_error("cannot parse 'error_index'");
225f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
226f06ca4afSHartmut Brandt 		}
227f06ca4afSHartmut Brandt 	}
228f06ca4afSHartmut Brandt 
229f06ca4afSHartmut Brandt 	if (asn_get_sequence(b, lenp) != ASN_ERR_OK) {
230f06ca4afSHartmut Brandt 		snmp_error("cannot get varlist header");
231f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
232f06ca4afSHartmut Brandt 	}
233f06ca4afSHartmut Brandt 
234f06ca4afSHartmut Brandt 	return (ASN_ERR_OK);
235f06ca4afSHartmut Brandt }
236f06ca4afSHartmut Brandt 
237f06ca4afSHartmut Brandt static enum asn_err
238f06ca4afSHartmut Brandt parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
239f06ca4afSHartmut Brandt {
240f06ca4afSHartmut Brandt 	asn_len_t len, trailer;
241f06ca4afSHartmut Brandt 	struct snmp_value *v;
242f06ca4afSHartmut Brandt 	enum asn_err err, err1;
243f06ca4afSHartmut Brandt 
244f06ca4afSHartmut Brandt 	err = snmp_parse_pdus_hdr(b, pdu, &len);
245f06ca4afSHartmut Brandt 	if (ASN_ERR_STOPPED(err))
246f06ca4afSHartmut Brandt 		return (err);
247f06ca4afSHartmut Brandt 
248f06ca4afSHartmut Brandt 	trailer = b->asn_len - len;
249f06ca4afSHartmut Brandt 
250f06ca4afSHartmut Brandt 	v = pdu->bindings;
251f06ca4afSHartmut Brandt 	err = ASN_ERR_OK;
252f06ca4afSHartmut Brandt 	while (b->asn_len != 0) {
253f06ca4afSHartmut Brandt 		if (pdu->nbindings == SNMP_MAX_BINDINGS) {
254f06ca4afSHartmut Brandt 			snmp_error("too many bindings (> %u) in PDU",
255f06ca4afSHartmut Brandt 			    SNMP_MAX_BINDINGS);
256f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
257f06ca4afSHartmut Brandt 		}
258f06ca4afSHartmut Brandt 		err1 = get_var_binding(b, v);
259f06ca4afSHartmut Brandt 		if (ASN_ERR_STOPPED(err1))
260f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
261f06ca4afSHartmut Brandt 		if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) {
262f06ca4afSHartmut Brandt 			err = err1;
263f06ca4afSHartmut Brandt 			*ip = pdu->nbindings + 1;
264f06ca4afSHartmut Brandt 		}
265f06ca4afSHartmut Brandt 		pdu->nbindings++;
266f06ca4afSHartmut Brandt 		v++;
267f06ca4afSHartmut Brandt 	}
268f06ca4afSHartmut Brandt 
269f06ca4afSHartmut Brandt 	b->asn_len = trailer;
270f06ca4afSHartmut Brandt 
271f06ca4afSHartmut Brandt 	return (err);
272f06ca4afSHartmut Brandt }
273f06ca4afSHartmut Brandt 
274f06ca4afSHartmut Brandt /*
275f06ca4afSHartmut Brandt  * Parse the outer SEQUENCE value. ASN_ERR_TAG means 'bad version'.
276f06ca4afSHartmut Brandt  */
277f06ca4afSHartmut Brandt enum asn_err
278f06ca4afSHartmut Brandt snmp_parse_message_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
279f06ca4afSHartmut Brandt {
280f06ca4afSHartmut Brandt 	int32_t version;
281f06ca4afSHartmut Brandt 	u_char type;
282f06ca4afSHartmut Brandt 	u_int comm_len;
283f06ca4afSHartmut Brandt 
284f06ca4afSHartmut Brandt 	if (asn_get_integer(b, &version) != ASN_ERR_OK) {
285f06ca4afSHartmut Brandt 		snmp_error("cannot decode version");
286f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
287f06ca4afSHartmut Brandt 	}
288f06ca4afSHartmut Brandt 
289f06ca4afSHartmut Brandt 	if (version == 0) {
290f06ca4afSHartmut Brandt 		pdu->version = SNMP_V1;
291f06ca4afSHartmut Brandt 	} else if (version == 1) {
292f06ca4afSHartmut Brandt 		pdu->version = SNMP_V2c;
293f06ca4afSHartmut Brandt 	} else {
294f06ca4afSHartmut Brandt 		pdu->version = SNMP_Verr;
295f06ca4afSHartmut Brandt 		snmp_error("unsupported SNMP version");
296f06ca4afSHartmut Brandt 		return (ASN_ERR_TAG);
297f06ca4afSHartmut Brandt 	}
298f06ca4afSHartmut Brandt 
299f06ca4afSHartmut Brandt 	comm_len = SNMP_COMMUNITY_MAXLEN;
300f06ca4afSHartmut Brandt 	if (asn_get_octetstring(b, (u_char *)pdu->community,
301f06ca4afSHartmut Brandt 	    &comm_len) != ASN_ERR_OK) {
302f06ca4afSHartmut Brandt 		snmp_error("cannot decode community");
303f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
304f06ca4afSHartmut Brandt 	}
305f06ca4afSHartmut Brandt 	pdu->community[comm_len] = '\0';
306f06ca4afSHartmut Brandt 
307f06ca4afSHartmut Brandt 	if (asn_get_header(b, &type, lenp) != ASN_ERR_OK) {
308f06ca4afSHartmut Brandt 		snmp_error("cannot get pdu header");
309f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
310f06ca4afSHartmut Brandt 	}
311f06ca4afSHartmut Brandt 	if ((type & ~ASN_TYPE_MASK) !=
312f06ca4afSHartmut Brandt 	    (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
313f06ca4afSHartmut Brandt 		snmp_error("bad pdu header tag");
314f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
315f06ca4afSHartmut Brandt 	}
316f06ca4afSHartmut Brandt 	pdu->type = type & ASN_TYPE_MASK;
317f06ca4afSHartmut Brandt 
318f06ca4afSHartmut Brandt 	switch (pdu->type) {
319f06ca4afSHartmut Brandt 
320f06ca4afSHartmut Brandt 	  case SNMP_PDU_GET:
321f06ca4afSHartmut Brandt 	  case SNMP_PDU_GETNEXT:
322f06ca4afSHartmut Brandt 	  case SNMP_PDU_RESPONSE:
323f06ca4afSHartmut Brandt 	  case SNMP_PDU_SET:
324f06ca4afSHartmut Brandt 		break;
325f06ca4afSHartmut Brandt 
326f06ca4afSHartmut Brandt 	  case SNMP_PDU_TRAP:
327f06ca4afSHartmut Brandt 		if (pdu->version != SNMP_V1) {
328f06ca4afSHartmut Brandt 			snmp_error("bad pdu type %u", pdu->type);
329f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
330f06ca4afSHartmut Brandt 		}
331f06ca4afSHartmut Brandt 		break;
332f06ca4afSHartmut Brandt 
333f06ca4afSHartmut Brandt 	  case SNMP_PDU_GETBULK:
334f06ca4afSHartmut Brandt 	  case SNMP_PDU_INFORM:
335f06ca4afSHartmut Brandt 	  case SNMP_PDU_TRAP2:
336f06ca4afSHartmut Brandt 	  case SNMP_PDU_REPORT:
337f06ca4afSHartmut Brandt 		if (pdu->version == SNMP_V1) {
338f06ca4afSHartmut Brandt 			snmp_error("bad pdu type %u", pdu->type);
339f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
340f06ca4afSHartmut Brandt 		}
341f06ca4afSHartmut Brandt 		break;
342f06ca4afSHartmut Brandt 
343f06ca4afSHartmut Brandt 	  default:
344f06ca4afSHartmut Brandt 		snmp_error("bad pdu type %u", pdu->type);
345f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
346f06ca4afSHartmut Brandt 	}
347f06ca4afSHartmut Brandt 
348f06ca4afSHartmut Brandt 
349f06ca4afSHartmut Brandt 	if (*lenp > b->asn_len) {
350f06ca4afSHartmut Brandt 		snmp_error("pdu length too long");
351f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
352f06ca4afSHartmut Brandt 	}
353f06ca4afSHartmut Brandt 
354f06ca4afSHartmut Brandt 	return (ASN_ERR_OK);
355f06ca4afSHartmut Brandt }
356f06ca4afSHartmut Brandt 
357f06ca4afSHartmut Brandt static enum asn_err
358f06ca4afSHartmut Brandt parse_message(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
359f06ca4afSHartmut Brandt {
360f06ca4afSHartmut Brandt 	enum asn_err err;
361f06ca4afSHartmut Brandt 	asn_len_t len, trailer;
362f06ca4afSHartmut Brandt 
363f06ca4afSHartmut Brandt 	err = snmp_parse_message_hdr(b, pdu, &len);
364f06ca4afSHartmut Brandt 	if (ASN_ERR_STOPPED(err))
365f06ca4afSHartmut Brandt 		return (err);
366f06ca4afSHartmut Brandt 
367f06ca4afSHartmut Brandt 	trailer = b->asn_len - len;
368f06ca4afSHartmut Brandt 	b->asn_len = len;
369f06ca4afSHartmut Brandt 
370f06ca4afSHartmut Brandt 	err = parse_pdus(b, pdu, ip);
371f06ca4afSHartmut Brandt 	if (ASN_ERR_STOPPED(err))
372f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
373f06ca4afSHartmut Brandt 
374f06ca4afSHartmut Brandt 	if (b->asn_len != 0)
375f06ca4afSHartmut Brandt 		snmp_error("ignoring trailing junk after pdu");
376f06ca4afSHartmut Brandt 
377f06ca4afSHartmut Brandt 	b->asn_len = trailer;
378f06ca4afSHartmut Brandt 
379f06ca4afSHartmut Brandt 	return (err);
380f06ca4afSHartmut Brandt }
381f06ca4afSHartmut Brandt 
382f06ca4afSHartmut Brandt /*
383f06ca4afSHartmut Brandt  * Decode the PDU except for the variable bindings itself.
384f06ca4afSHartmut Brandt  * If decoding fails because of a bad binding, but the rest can be
385f06ca4afSHartmut Brandt  * decoded, ip points to the index of the failed variable (errors
386f06ca4afSHartmut Brandt  * OORANGE, BADLEN or BADVERS).
387f06ca4afSHartmut Brandt  */
388f06ca4afSHartmut Brandt enum snmp_code
389f06ca4afSHartmut Brandt snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
390f06ca4afSHartmut Brandt {
391f06ca4afSHartmut Brandt 	asn_len_t len;
392f06ca4afSHartmut Brandt 
393f06ca4afSHartmut Brandt 	memset(pdu, 0, sizeof(*pdu));
394f06ca4afSHartmut Brandt 
395f06ca4afSHartmut Brandt 	if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
396f06ca4afSHartmut Brandt 		snmp_error("cannot decode pdu header");
397f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
398f06ca4afSHartmut Brandt 	}
399f06ca4afSHartmut Brandt 	if (b->asn_len < len) {
400f06ca4afSHartmut Brandt 		snmp_error("outer sequence value too short");
401f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
402f06ca4afSHartmut Brandt 	}
403f06ca4afSHartmut Brandt 	if (b->asn_len != len) {
404f06ca4afSHartmut Brandt 		snmp_error("ignoring trailing junk in message");
405f06ca4afSHartmut Brandt 		b->asn_len = len;
406f06ca4afSHartmut Brandt 	}
407f06ca4afSHartmut Brandt 
408f06ca4afSHartmut Brandt 	switch (parse_message(b, pdu, ip)) {
409f06ca4afSHartmut Brandt 
410f06ca4afSHartmut Brandt 	  case ASN_ERR_OK:
411f06ca4afSHartmut Brandt 		return (SNMP_CODE_OK);
412f06ca4afSHartmut Brandt 
413f06ca4afSHartmut Brandt 	  case ASN_ERR_FAILED:
414f06ca4afSHartmut Brandt 	  case ASN_ERR_EOBUF:
415f06ca4afSHartmut Brandt 		snmp_pdu_free(pdu);
416f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
417f06ca4afSHartmut Brandt 
418f06ca4afSHartmut Brandt 	  case ASN_ERR_BADLEN:
419f06ca4afSHartmut Brandt 		return (SNMP_CODE_BADLEN);
420f06ca4afSHartmut Brandt 
421f06ca4afSHartmut Brandt 	  case ASN_ERR_RANGE:
422f06ca4afSHartmut Brandt 		return (SNMP_CODE_OORANGE);
423f06ca4afSHartmut Brandt 
424f06ca4afSHartmut Brandt 	  case ASN_ERR_TAG:
425f06ca4afSHartmut Brandt 		if (pdu->version == SNMP_Verr)
426f06ca4afSHartmut Brandt 			return (SNMP_CODE_BADVERS);
427f06ca4afSHartmut Brandt 		else
428f06ca4afSHartmut Brandt 			return (SNMP_CODE_BADENC);
429f06ca4afSHartmut Brandt 	}
430f06ca4afSHartmut Brandt 
431f06ca4afSHartmut Brandt 	return (SNMP_CODE_OK);
432f06ca4afSHartmut Brandt }
433f06ca4afSHartmut Brandt 
434f06ca4afSHartmut Brandt /*
435f06ca4afSHartmut Brandt  * Encode the SNMP PDU without the variable bindings field.
436f06ca4afSHartmut Brandt  * We do this the rather uneffective way by
437f06ca4afSHartmut Brandt  * moving things around and assuming that the length field will never
438f06ca4afSHartmut Brandt  * use more than 2 bytes.
439f06ca4afSHartmut Brandt  * We need a number of pointers to apply the fixes afterwards.
440f06ca4afSHartmut Brandt  */
441f06ca4afSHartmut Brandt enum snmp_code
442f06ca4afSHartmut Brandt snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
443f06ca4afSHartmut Brandt {
444f06ca4afSHartmut Brandt 	enum asn_err err;
445f06ca4afSHartmut Brandt 
446f06ca4afSHartmut Brandt 	if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
447f06ca4afSHartmut Brandt 	    &pdu->outer_ptr) != ASN_ERR_OK)
448f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
449f06ca4afSHartmut Brandt 
450f06ca4afSHartmut Brandt 	if (pdu->version == SNMP_V1)
451f06ca4afSHartmut Brandt 		err = asn_put_integer(b, 0);
452f06ca4afSHartmut Brandt 	else if (pdu->version == SNMP_V2c)
453f06ca4afSHartmut Brandt 		err = asn_put_integer(b, 1);
454f06ca4afSHartmut Brandt 	else
455f06ca4afSHartmut Brandt 		return (SNMP_CODE_BADVERS);
456f06ca4afSHartmut Brandt 	if (err != ASN_ERR_OK)
457f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
458f06ca4afSHartmut Brandt 
459f06ca4afSHartmut Brandt 	if (asn_put_octetstring(b, (u_char *)pdu->community,
460f06ca4afSHartmut Brandt 	    strlen(pdu->community)) != ASN_ERR_OK)
461f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
462f06ca4afSHartmut Brandt 
463f06ca4afSHartmut Brandt 	if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT |
464f06ca4afSHartmut Brandt 	    pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
465f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
466f06ca4afSHartmut Brandt 
467f06ca4afSHartmut Brandt 	if (pdu->type == SNMP_PDU_TRAP) {
468f06ca4afSHartmut Brandt 		if (pdu->version != SNMP_V1 ||
469f06ca4afSHartmut Brandt 		    asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK ||
470f06ca4afSHartmut Brandt 		    asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK ||
471f06ca4afSHartmut Brandt 		    asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK ||
472f06ca4afSHartmut Brandt 		    asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK ||
473f06ca4afSHartmut Brandt 		    asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK)
474f06ca4afSHartmut Brandt 			return (SNMP_CODE_FAILED);
475f06ca4afSHartmut Brandt 	} else {
476f06ca4afSHartmut Brandt 		if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK ||
477f06ca4afSHartmut Brandt 		    pdu->type == SNMP_PDU_INFORM ||
478f06ca4afSHartmut Brandt 		    pdu->type == SNMP_PDU_TRAP2 ||
479f06ca4afSHartmut Brandt 		    pdu->type == SNMP_PDU_REPORT))
480f06ca4afSHartmut Brandt 			return (SNMP_CODE_FAILED);
481f06ca4afSHartmut Brandt 
482f06ca4afSHartmut Brandt 		if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK ||
483f06ca4afSHartmut Brandt 		    asn_put_integer(b, pdu->error_status) != ASN_ERR_OK ||
484f06ca4afSHartmut Brandt 		    asn_put_integer(b, pdu->error_index) != ASN_ERR_OK)
485f06ca4afSHartmut Brandt 			return (SNMP_CODE_FAILED);
486f06ca4afSHartmut Brandt 	}
487f06ca4afSHartmut Brandt 
488f06ca4afSHartmut Brandt 	if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
489f06ca4afSHartmut Brandt 	    &pdu->vars_ptr) != ASN_ERR_OK)
490f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
491f06ca4afSHartmut Brandt 
492f06ca4afSHartmut Brandt 	return (SNMP_CODE_OK);
493f06ca4afSHartmut Brandt }
494f06ca4afSHartmut Brandt 
495f06ca4afSHartmut Brandt enum snmp_code
496f06ca4afSHartmut Brandt snmp_fix_encoding(struct asn_buf *b, const struct snmp_pdu *pdu)
497f06ca4afSHartmut Brandt {
498f06ca4afSHartmut Brandt 	if (asn_commit_header(b, pdu->vars_ptr) != ASN_ERR_OK ||
499f06ca4afSHartmut Brandt 	    asn_commit_header(b, pdu->pdu_ptr) != ASN_ERR_OK ||
500f06ca4afSHartmut Brandt 	    asn_commit_header(b, pdu->outer_ptr) != ASN_ERR_OK)
501f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
502f06ca4afSHartmut Brandt 	return (SNMP_CODE_OK);
503f06ca4afSHartmut Brandt }
504f06ca4afSHartmut Brandt 
505f06ca4afSHartmut Brandt /*
506f06ca4afSHartmut Brandt  * Encode a binding. Caller must ensure, that the syntax is ok for that version.
507f06ca4afSHartmut Brandt  * Be sure not to cobber b, when something fails.
508f06ca4afSHartmut Brandt  */
509f06ca4afSHartmut Brandt enum asn_err
510f06ca4afSHartmut Brandt snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding)
511f06ca4afSHartmut Brandt {
512f06ca4afSHartmut Brandt 	u_char *ptr;
513f06ca4afSHartmut Brandt 	enum asn_err err;
514f06ca4afSHartmut Brandt 	struct asn_buf save = *b;
515f06ca4afSHartmut Brandt 
516f06ca4afSHartmut Brandt 	if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
517f06ca4afSHartmut Brandt 	    ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) {
518f06ca4afSHartmut Brandt 		*b = save;
519f06ca4afSHartmut Brandt 		return (err);
520f06ca4afSHartmut Brandt 	}
521f06ca4afSHartmut Brandt 
522f06ca4afSHartmut Brandt 	if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) {
523f06ca4afSHartmut Brandt 		*b = save;
524f06ca4afSHartmut Brandt 		return (err);
525f06ca4afSHartmut Brandt 	}
526f06ca4afSHartmut Brandt 
527f06ca4afSHartmut Brandt 	switch (binding->syntax) {
528f06ca4afSHartmut Brandt 
529f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NULL:
530f06ca4afSHartmut Brandt 		err = asn_put_null(b);
531f06ca4afSHartmut Brandt 		break;
532f06ca4afSHartmut Brandt 
533f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_INTEGER:
534f06ca4afSHartmut Brandt 		err = asn_put_integer(b, binding->v.integer);
535f06ca4afSHartmut Brandt 		break;
536f06ca4afSHartmut Brandt 
537f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_OCTETSTRING:
538f06ca4afSHartmut Brandt 		err = asn_put_octetstring(b, binding->v.octetstring.octets,
539f06ca4afSHartmut Brandt 		    binding->v.octetstring.len);
540f06ca4afSHartmut Brandt 		break;
541f06ca4afSHartmut Brandt 
542f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_OID:
543f06ca4afSHartmut Brandt 		err = asn_put_objid(b, &binding->v.oid);
544f06ca4afSHartmut Brandt 		break;
545f06ca4afSHartmut Brandt 
546f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_IPADDRESS:
547f06ca4afSHartmut Brandt 		err = asn_put_ipaddress(b, binding->v.ipaddress);
548f06ca4afSHartmut Brandt 		break;
549f06ca4afSHartmut Brandt 
550f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_TIMETICKS:
551f06ca4afSHartmut Brandt 		err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32);
552f06ca4afSHartmut Brandt 		break;
553f06ca4afSHartmut Brandt 
554f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_COUNTER:
555f06ca4afSHartmut Brandt 		err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32);
556f06ca4afSHartmut Brandt 		break;
557f06ca4afSHartmut Brandt 
558f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_GAUGE:
559f06ca4afSHartmut Brandt 		err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32);
560f06ca4afSHartmut Brandt 		break;
561f06ca4afSHartmut Brandt 
562f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_COUNTER64:
563f06ca4afSHartmut Brandt 		err = asn_put_counter64(b, binding->v.counter64);
564f06ca4afSHartmut Brandt 		break;
565f06ca4afSHartmut Brandt 
566f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NOSUCHOBJECT:
567f06ca4afSHartmut Brandt 		err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT);
568f06ca4afSHartmut Brandt 		break;
569f06ca4afSHartmut Brandt 
570f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NOSUCHINSTANCE:
571f06ca4afSHartmut Brandt 		err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE);
572f06ca4afSHartmut Brandt 		break;
573f06ca4afSHartmut Brandt 
574f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_ENDOFMIBVIEW:
575f06ca4afSHartmut Brandt 		err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW);
576f06ca4afSHartmut Brandt 		break;
577f06ca4afSHartmut Brandt 	}
578f06ca4afSHartmut Brandt 
579f06ca4afSHartmut Brandt 	if (err != ASN_ERR_OK) {
580f06ca4afSHartmut Brandt 		*b = save;
581f06ca4afSHartmut Brandt 		return (err);
582f06ca4afSHartmut Brandt 	}
583f06ca4afSHartmut Brandt 
584f06ca4afSHartmut Brandt 	err = asn_commit_header(b, ptr);
585f06ca4afSHartmut Brandt 	if (err != ASN_ERR_OK) {
586f06ca4afSHartmut Brandt 		*b = save;
587f06ca4afSHartmut Brandt 		return (err);
588f06ca4afSHartmut Brandt 	}
589f06ca4afSHartmut Brandt 
590f06ca4afSHartmut Brandt 	return (ASN_ERR_OK);
591f06ca4afSHartmut Brandt }
592f06ca4afSHartmut Brandt 
593f06ca4afSHartmut Brandt /*
594f06ca4afSHartmut Brandt  * Encode an PDU.
595f06ca4afSHartmut Brandt  */
596f06ca4afSHartmut Brandt enum snmp_code
597f06ca4afSHartmut Brandt snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b)
598f06ca4afSHartmut Brandt {
599f06ca4afSHartmut Brandt 	u_int idx;
600f06ca4afSHartmut Brandt 	enum snmp_code err;
601f06ca4afSHartmut Brandt 
602f06ca4afSHartmut Brandt 	if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK)
603f06ca4afSHartmut Brandt 		return (err);
604f06ca4afSHartmut Brandt 	for (idx = 0; idx < pdu->nbindings; idx++)
605f06ca4afSHartmut Brandt 		if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx]))
606f06ca4afSHartmut Brandt 		    != ASN_ERR_OK)
607f06ca4afSHartmut Brandt 			return (SNMP_CODE_FAILED);
608f06ca4afSHartmut Brandt 
609f06ca4afSHartmut Brandt 	return (snmp_fix_encoding(resp_b, pdu));
610f06ca4afSHartmut Brandt }
611f06ca4afSHartmut Brandt 
612f06ca4afSHartmut Brandt static void
613f06ca4afSHartmut Brandt dump_binding(const struct snmp_value *b)
614f06ca4afSHartmut Brandt {
615f06ca4afSHartmut Brandt 	u_int i;
616f06ca4afSHartmut Brandt 	char buf[ASN_OIDSTRLEN];
617f06ca4afSHartmut Brandt 
618f06ca4afSHartmut Brandt 	snmp_printf("%s=", asn_oid2str_r(&b->var, buf));
619f06ca4afSHartmut Brandt 	switch (b->syntax) {
620f06ca4afSHartmut Brandt 
621f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NULL:
622f06ca4afSHartmut Brandt 		snmp_printf("NULL");
623f06ca4afSHartmut Brandt 		break;
624f06ca4afSHartmut Brandt 
625f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_INTEGER:
626f06ca4afSHartmut Brandt 		snmp_printf("INTEGER %d", b->v.integer);
627f06ca4afSHartmut Brandt 		break;
628f06ca4afSHartmut Brandt 
629f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_OCTETSTRING:
630f06ca4afSHartmut Brandt 		snmp_printf("OCTET STRING %lu:", b->v.octetstring.len);
631f06ca4afSHartmut Brandt 		for (i = 0; i < b->v.octetstring.len; i++)
632f06ca4afSHartmut Brandt 			snmp_printf(" %02x", b->v.octetstring.octets[i]);
633f06ca4afSHartmut Brandt 		break;
634f06ca4afSHartmut Brandt 
635f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_OID:
636f06ca4afSHartmut Brandt 		snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf));
637f06ca4afSHartmut Brandt 		break;
638f06ca4afSHartmut Brandt 
639f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_IPADDRESS:
640f06ca4afSHartmut Brandt 		snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0],
641f06ca4afSHartmut Brandt 		    b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]);
642f06ca4afSHartmut Brandt 		break;
643f06ca4afSHartmut Brandt 
644f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_COUNTER:
645f06ca4afSHartmut Brandt 		snmp_printf("COUNTER %u", b->v.uint32);
646f06ca4afSHartmut Brandt 		break;
647f06ca4afSHartmut Brandt 
648f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_GAUGE:
649f06ca4afSHartmut Brandt 		snmp_printf("GAUGE %u", b->v.uint32);
650f06ca4afSHartmut Brandt 		break;
651f06ca4afSHartmut Brandt 
652f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_TIMETICKS:
653f06ca4afSHartmut Brandt 		snmp_printf("TIMETICKS %u", b->v.uint32);
654f06ca4afSHartmut Brandt 		break;
655f06ca4afSHartmut Brandt 
656f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_COUNTER64:
657f06ca4afSHartmut Brandt 		snmp_printf("COUNTER64 %lld", b->v.counter64);
658f06ca4afSHartmut Brandt 		break;
659f06ca4afSHartmut Brandt 
660f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NOSUCHOBJECT:
661f06ca4afSHartmut Brandt 		snmp_printf("NoSuchObject");
662f06ca4afSHartmut Brandt 		break;
663f06ca4afSHartmut Brandt 
664f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NOSUCHINSTANCE:
665f06ca4afSHartmut Brandt 		snmp_printf("NoSuchInstance");
666f06ca4afSHartmut Brandt 		break;
667f06ca4afSHartmut Brandt 
668f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_ENDOFMIBVIEW:
669f06ca4afSHartmut Brandt 		snmp_printf("EndOfMibView");
670f06ca4afSHartmut Brandt 		break;
671f06ca4afSHartmut Brandt 
672f06ca4afSHartmut Brandt 	  default:
673f06ca4afSHartmut Brandt 		snmp_printf("UNKNOWN SYNTAX %u", b->syntax);
674f06ca4afSHartmut Brandt 		break;
675f06ca4afSHartmut Brandt 	}
676f06ca4afSHartmut Brandt }
677f06ca4afSHartmut Brandt 
678f06ca4afSHartmut Brandt static __inline void
679f06ca4afSHartmut Brandt dump_bindings(const struct snmp_pdu *pdu)
680f06ca4afSHartmut Brandt {
681f06ca4afSHartmut Brandt 	u_int i;
682f06ca4afSHartmut Brandt 
683f06ca4afSHartmut Brandt 	for (i = 0; i < pdu->nbindings; i++) {
684f06ca4afSHartmut Brandt 		snmp_printf(" [%u]: ", i);
685f06ca4afSHartmut Brandt 		dump_binding(&pdu->bindings[i]);
686f06ca4afSHartmut Brandt 		snmp_printf("\n");
687f06ca4afSHartmut Brandt 	}
688f06ca4afSHartmut Brandt }
689f06ca4afSHartmut Brandt 
690f06ca4afSHartmut Brandt static __inline void
691f06ca4afSHartmut Brandt dump_notrap(const struct snmp_pdu *pdu)
692f06ca4afSHartmut Brandt {
693f06ca4afSHartmut Brandt 	snmp_printf(" request_id=%d", pdu->request_id);
694f06ca4afSHartmut Brandt 	snmp_printf(" error_status=%d", pdu->error_status);
695f06ca4afSHartmut Brandt 	snmp_printf(" error_index=%d\n", pdu->error_index);
696f06ca4afSHartmut Brandt 	dump_bindings(pdu);
697f06ca4afSHartmut Brandt }
698f06ca4afSHartmut Brandt 
699f06ca4afSHartmut Brandt void
700f06ca4afSHartmut Brandt snmp_pdu_dump(const struct snmp_pdu *pdu)
701f06ca4afSHartmut Brandt {
702f06ca4afSHartmut Brandt 	char buf[ASN_OIDSTRLEN];
703f06ca4afSHartmut Brandt 	const char *vers;
704f06ca4afSHartmut Brandt 	static const char *types[] = {
705f06ca4afSHartmut Brandt 		[SNMP_PDU_GET] =	"GET",
706f06ca4afSHartmut Brandt 		[SNMP_PDU_GETNEXT] =	"GETNEXT",
707f06ca4afSHartmut Brandt 		[SNMP_PDU_RESPONSE] =	"RESPONSE",
708f06ca4afSHartmut Brandt 		[SNMP_PDU_SET] =	"SET",
709f06ca4afSHartmut Brandt 		[SNMP_PDU_TRAP] =	"TRAPv1",
710f06ca4afSHartmut Brandt 		[SNMP_PDU_GETBULK] =	"GETBULK",
711f06ca4afSHartmut Brandt 		[SNMP_PDU_INFORM] =	"INFORM",
712f06ca4afSHartmut Brandt 		[SNMP_PDU_TRAP2] =	"TRAPv2",
713f06ca4afSHartmut Brandt 		[SNMP_PDU_REPORT] =	"REPORT",
714f06ca4afSHartmut Brandt 	};
715f06ca4afSHartmut Brandt 
716f06ca4afSHartmut Brandt 	if (pdu->version == SNMP_V1)
717f06ca4afSHartmut Brandt 		vers = "SNMPv1";
718f06ca4afSHartmut Brandt 	else if (pdu->version == SNMP_V2c)
719f06ca4afSHartmut Brandt 		vers = "SNMPv2c";
720f06ca4afSHartmut Brandt 	else
721f06ca4afSHartmut Brandt 		vers = "v?";
722f06ca4afSHartmut Brandt 
723f06ca4afSHartmut Brandt 	switch (pdu->type) {
724f06ca4afSHartmut Brandt 	  case SNMP_PDU_TRAP:
725f06ca4afSHartmut Brandt 		snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
726f06ca4afSHartmut Brandt 		snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf));
727f06ca4afSHartmut Brandt 		snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0],
728f06ca4afSHartmut Brandt 		    pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]);
729f06ca4afSHartmut Brandt 		snmp_printf(" generic_trap=%d", pdu->generic_trap);
730f06ca4afSHartmut Brandt 		snmp_printf(" specific_trap=%d", pdu->specific_trap);
731f06ca4afSHartmut Brandt 		snmp_printf(" time-stamp=%u\n", pdu->time_stamp);
732f06ca4afSHartmut Brandt 		dump_bindings(pdu);
733f06ca4afSHartmut Brandt 		break;
734f06ca4afSHartmut Brandt 
735f06ca4afSHartmut Brandt 	  case SNMP_PDU_GET:
736f06ca4afSHartmut Brandt 	  case SNMP_PDU_GETNEXT:
737f06ca4afSHartmut Brandt 	  case SNMP_PDU_RESPONSE:
738f06ca4afSHartmut Brandt 	  case SNMP_PDU_SET:
739f06ca4afSHartmut Brandt 	  case SNMP_PDU_GETBULK:
740f06ca4afSHartmut Brandt 	  case SNMP_PDU_INFORM:
741f06ca4afSHartmut Brandt 	  case SNMP_PDU_TRAP2:
742f06ca4afSHartmut Brandt 	  case SNMP_PDU_REPORT:
743f06ca4afSHartmut Brandt 		snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
744f06ca4afSHartmut Brandt 		dump_notrap(pdu);
745f06ca4afSHartmut Brandt 		break;
746f06ca4afSHartmut Brandt 
747f06ca4afSHartmut Brandt 	  default:
748f06ca4afSHartmut Brandt 		snmp_printf("bad pdu type %u\n", pdu->type);
749f06ca4afSHartmut Brandt 		break;
750f06ca4afSHartmut Brandt 	}
751f06ca4afSHartmut Brandt }
752f06ca4afSHartmut Brandt 
753f06ca4afSHartmut Brandt void
754f06ca4afSHartmut Brandt snmp_value_free(struct snmp_value *value)
755f06ca4afSHartmut Brandt {
756f06ca4afSHartmut Brandt 	if (value->syntax == SNMP_SYNTAX_OCTETSTRING)
757f06ca4afSHartmut Brandt 		free(value->v.octetstring.octets);
758f06ca4afSHartmut Brandt 	value->syntax = SNMP_SYNTAX_NULL;
759f06ca4afSHartmut Brandt }
760f06ca4afSHartmut Brandt 
761f06ca4afSHartmut Brandt int
762f06ca4afSHartmut Brandt snmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
763f06ca4afSHartmut Brandt {
764f06ca4afSHartmut Brandt 	to->var = from->var;
765f06ca4afSHartmut Brandt 	to->syntax = from->syntax;
766f06ca4afSHartmut Brandt 
767f06ca4afSHartmut Brandt 	if (from->syntax == SNMP_SYNTAX_OCTETSTRING) {
768f06ca4afSHartmut Brandt 		if ((to->v.octetstring.len = from->v.octetstring.len) == 0)
769f06ca4afSHartmut Brandt 			to->v.octetstring.octets = NULL;
770f06ca4afSHartmut Brandt 		else {
771f06ca4afSHartmut Brandt 			to->v.octetstring.octets = malloc(to->v.octetstring.len);
772f06ca4afSHartmut Brandt 			if (to->v.octetstring.octets == NULL)
773f06ca4afSHartmut Brandt 				return (-1);
774f06ca4afSHartmut Brandt 			(void)memcpy(to->v.octetstring.octets,
775f06ca4afSHartmut Brandt 			    from->v.octetstring.octets, to->v.octetstring.len);
776f06ca4afSHartmut Brandt 		}
777f06ca4afSHartmut Brandt 	} else
778f06ca4afSHartmut Brandt 		to->v = from->v;
779f06ca4afSHartmut Brandt 	return (0);
780f06ca4afSHartmut Brandt }
781f06ca4afSHartmut Brandt 
782f06ca4afSHartmut Brandt void
783f06ca4afSHartmut Brandt snmp_pdu_free(struct snmp_pdu *pdu)
784f06ca4afSHartmut Brandt {
785f06ca4afSHartmut Brandt 	u_int i;
786f06ca4afSHartmut Brandt 
787f06ca4afSHartmut Brandt 	for (i = 0; i < pdu->nbindings; i++)
788f06ca4afSHartmut Brandt 		snmp_value_free(&pdu->bindings[i]);
789f06ca4afSHartmut Brandt }
790f06ca4afSHartmut Brandt 
791f06ca4afSHartmut Brandt /*
792f06ca4afSHartmut Brandt  * Parse an ASCII SNMP value into the binary form
793f06ca4afSHartmut Brandt  */
794f06ca4afSHartmut Brandt int
795f06ca4afSHartmut Brandt snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v)
796f06ca4afSHartmut Brandt {
797f06ca4afSHartmut Brandt 	char *end;
798f06ca4afSHartmut Brandt 
799f06ca4afSHartmut Brandt 	switch (syntax) {
800f06ca4afSHartmut Brandt 
801f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NULL:
802f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NOSUCHOBJECT:
803f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NOSUCHINSTANCE:
804f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_ENDOFMIBVIEW:
805f06ca4afSHartmut Brandt 		if (*str != '\0')
806f06ca4afSHartmut Brandt 			return (-1);
807f06ca4afSHartmut Brandt 		return (0);
808f06ca4afSHartmut Brandt 
809f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_INTEGER:
810f06ca4afSHartmut Brandt 		v->integer = strtoll(str, &end, 0);
811f06ca4afSHartmut Brandt 		if (*end != '\0')
812f06ca4afSHartmut Brandt 			return (-1);
813f06ca4afSHartmut Brandt 		return (0);
814f06ca4afSHartmut Brandt 
815f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_OCTETSTRING:
816f06ca4afSHartmut Brandt 	    {
817f06ca4afSHartmut Brandt 		u_long len;	/* actual length of string */
818f06ca4afSHartmut Brandt 		u_long alloc;	/* allocate length of string */
819f06ca4afSHartmut Brandt 		u_char *octs;	/* actual octets */
820f06ca4afSHartmut Brandt 		u_long oct;	/* actual octet */
821f06ca4afSHartmut Brandt 		u_char *nocts;	/* to avoid memory leak */
822f06ca4afSHartmut Brandt 		u_char c;	/* actual character */
823f06ca4afSHartmut Brandt 
824f06ca4afSHartmut Brandt # define STUFFC(C)							\
825f06ca4afSHartmut Brandt 		if (alloc == len) {					\
826f06ca4afSHartmut Brandt 			alloc += 100;					\
827f06ca4afSHartmut Brandt 			if ((nocts = realloc(octs, alloc)) == NULL) {	\
828f06ca4afSHartmut Brandt 				free(octs);				\
829f06ca4afSHartmut Brandt 				return (-1);				\
830f06ca4afSHartmut Brandt 			}						\
831f06ca4afSHartmut Brandt 			octs = nocts;					\
832f06ca4afSHartmut Brandt 		}							\
833f06ca4afSHartmut Brandt 		octs[len++] = (C);
834f06ca4afSHartmut Brandt 
835f06ca4afSHartmut Brandt 		len = alloc = 0;
836f06ca4afSHartmut Brandt 		octs = NULL;
837f06ca4afSHartmut Brandt 
838f06ca4afSHartmut Brandt 		if (*str == '"') {
839f06ca4afSHartmut Brandt 			str++;
840f06ca4afSHartmut Brandt 			while((c = *str++) != '\0') {
841f06ca4afSHartmut Brandt 				if (c == '"') {
842f06ca4afSHartmut Brandt 					if (*str != '\0') {
843f06ca4afSHartmut Brandt 						free(octs);
844f06ca4afSHartmut Brandt 						return (-1);
845f06ca4afSHartmut Brandt 					}
846f06ca4afSHartmut Brandt 					break;
847f06ca4afSHartmut Brandt 				}
848f06ca4afSHartmut Brandt 				if (c == '\\') {
849f06ca4afSHartmut Brandt 					switch (c = *str++) {
850f06ca4afSHartmut Brandt 
851f06ca4afSHartmut Brandt 					  case '\\':
852f06ca4afSHartmut Brandt 						break;
853f06ca4afSHartmut Brandt 					  case 'a':
854f06ca4afSHartmut Brandt 						c = '\a';
855f06ca4afSHartmut Brandt 						break;
856f06ca4afSHartmut Brandt 					  case 'b':
857f06ca4afSHartmut Brandt 						c = '\b';
858f06ca4afSHartmut Brandt 						break;
859f06ca4afSHartmut Brandt 					  case 'f':
860f06ca4afSHartmut Brandt 						c = '\f';
861f06ca4afSHartmut Brandt 						break;
862f06ca4afSHartmut Brandt 					  case 'n':
863f06ca4afSHartmut Brandt 						c = '\n';
864f06ca4afSHartmut Brandt 						break;
865f06ca4afSHartmut Brandt 					  case 'r':
866f06ca4afSHartmut Brandt 						c = '\r';
867f06ca4afSHartmut Brandt 						break;
868f06ca4afSHartmut Brandt 					  case 't':
869f06ca4afSHartmut Brandt 						c = '\t';
870f06ca4afSHartmut Brandt 						break;
871f06ca4afSHartmut Brandt 					  case 'v':
872f06ca4afSHartmut Brandt 						c = '\v';
873f06ca4afSHartmut Brandt 						break;
874f06ca4afSHartmut Brandt 					  case 'x':
875f06ca4afSHartmut Brandt 						c = 0;
876f06ca4afSHartmut Brandt 						if (!isxdigit(*str))
877f06ca4afSHartmut Brandt 							break;
878f06ca4afSHartmut Brandt 						if (isdigit(*str))
879f06ca4afSHartmut Brandt 							c = *str++ - '0';
880f06ca4afSHartmut Brandt 						else if (isupper(*str))
881f06ca4afSHartmut Brandt 							c = *str++ - 'A' + 10;
882f06ca4afSHartmut Brandt 						else
883f06ca4afSHartmut Brandt 							c = *str++ - 'a' + 10;
884f06ca4afSHartmut Brandt 						if (!isxdigit(*str))
885f06ca4afSHartmut Brandt 							break;
886f06ca4afSHartmut Brandt 						if (isdigit(*str))
887f06ca4afSHartmut Brandt 							c += *str++ - '0';
888f06ca4afSHartmut Brandt 						else if (isupper(*str))
889f06ca4afSHartmut Brandt 							c += *str++ - 'A' + 10;
890f06ca4afSHartmut Brandt 						else
891f06ca4afSHartmut Brandt 							c += *str++ - 'a' + 10;
892f06ca4afSHartmut Brandt 						break;
893f06ca4afSHartmut Brandt 					  case '0': case '1': case '2':
894f06ca4afSHartmut Brandt 					  case '3': case '4': case '5':
895f06ca4afSHartmut Brandt 					  case '6': case '7':
896f06ca4afSHartmut Brandt 						c = *str++ - '0';
897f06ca4afSHartmut Brandt 						if (*str < '0' || *str > '7')
898f06ca4afSHartmut Brandt 							break;
899f06ca4afSHartmut Brandt 						c = *str++ - '0';
900f06ca4afSHartmut Brandt 						if (*str < '0' || *str > '7')
901f06ca4afSHartmut Brandt 							break;
902f06ca4afSHartmut Brandt 						c = *str++ - '0';
903f06ca4afSHartmut Brandt 						break;
904f06ca4afSHartmut Brandt 					  default:
905f06ca4afSHartmut Brandt 						break;
906f06ca4afSHartmut Brandt 					}
907f06ca4afSHartmut Brandt 				}
908f06ca4afSHartmut Brandt 				STUFFC(c);
909f06ca4afSHartmut Brandt 			}
910f06ca4afSHartmut Brandt 		} else {
911f06ca4afSHartmut Brandt 			while (*str != '\0') {
912f06ca4afSHartmut Brandt 				oct = strtoul(str, &end, 16);
913f06ca4afSHartmut Brandt 				str = end;
914f06ca4afSHartmut Brandt 				if (oct > 0xff) {
915f06ca4afSHartmut Brandt 					free(octs);
916f06ca4afSHartmut Brandt 					return (-1);
917f06ca4afSHartmut Brandt 				}
918f06ca4afSHartmut Brandt 				STUFFC(oct);
919f06ca4afSHartmut Brandt 				if (*str == ':')
920f06ca4afSHartmut Brandt 					str++;
921f06ca4afSHartmut Brandt 				else if(*str != '\0') {
922f06ca4afSHartmut Brandt 					free(octs);
923f06ca4afSHartmut Brandt 					return (-1);
924f06ca4afSHartmut Brandt 				}
925f06ca4afSHartmut Brandt 			}
926f06ca4afSHartmut Brandt 		}
927f06ca4afSHartmut Brandt 		v->octetstring.octets = octs;
928f06ca4afSHartmut Brandt 		v->octetstring.len = len;
929f06ca4afSHartmut Brandt 		return (0);
930f06ca4afSHartmut Brandt # undef STUFFC
931f06ca4afSHartmut Brandt 	    }
932f06ca4afSHartmut Brandt 
933f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_OID:
934f06ca4afSHartmut Brandt 	    {
935f06ca4afSHartmut Brandt 		u_long subid;
936f06ca4afSHartmut Brandt 
937f06ca4afSHartmut Brandt 		v->oid.len = 0;
938f06ca4afSHartmut Brandt 
939f06ca4afSHartmut Brandt 		for (;;) {
940f06ca4afSHartmut Brandt 			if (v->oid.len == ASN_MAXOIDLEN)
941f06ca4afSHartmut Brandt 				return (-1);
942f06ca4afSHartmut Brandt 			subid = strtoul(str, &end, 10);
943f06ca4afSHartmut Brandt 			str = end;
944f06ca4afSHartmut Brandt 			if (subid > ASN_MAXID)
945f06ca4afSHartmut Brandt 				return (-1);
946f06ca4afSHartmut Brandt 			v->oid.subs[v->oid.len++] = (asn_subid_t)subid;
947f06ca4afSHartmut Brandt 			if (*str == '\0')
948f06ca4afSHartmut Brandt 				break;
949f06ca4afSHartmut Brandt 			if (*str != '.')
950f06ca4afSHartmut Brandt 				return (-1);
951f06ca4afSHartmut Brandt 			str++;
952f06ca4afSHartmut Brandt 		}
953f06ca4afSHartmut Brandt 		return (0);
954f06ca4afSHartmut Brandt 	    }
955f06ca4afSHartmut Brandt 
956f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_IPADDRESS:
957f06ca4afSHartmut Brandt 	    {
958f06ca4afSHartmut Brandt 		struct hostent *he;
959f06ca4afSHartmut Brandt 		u_long ip[4];
960f06ca4afSHartmut Brandt 		int n;
961f06ca4afSHartmut Brandt 
962f06ca4afSHartmut Brandt 		if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2],
963f06ca4afSHartmut Brandt 		    &ip[3], &n) == 4 && (size_t)n == strlen(str) &&
964f06ca4afSHartmut Brandt 		    ip[0] <= 0xff && ip[1] <= 0xff &&
965f06ca4afSHartmut Brandt 		    ip[2] <= 0xff && ip[3] <= 0xff) {
966f06ca4afSHartmut Brandt 			v->ipaddress[0] = (u_char)ip[0];
967f06ca4afSHartmut Brandt 			v->ipaddress[1] = (u_char)ip[1];
968f06ca4afSHartmut Brandt 			v->ipaddress[2] = (u_char)ip[2];
969f06ca4afSHartmut Brandt 			v->ipaddress[3] = (u_char)ip[3];
970f06ca4afSHartmut Brandt 			return (0);
971f06ca4afSHartmut Brandt 		}
972f06ca4afSHartmut Brandt 
973f06ca4afSHartmut Brandt 		if ((he = gethostbyname(str)) == NULL)
974f06ca4afSHartmut Brandt 			return (-1);
975f06ca4afSHartmut Brandt 		if (he->h_addrtype != AF_INET)
976f06ca4afSHartmut Brandt 			return (-1);
977f06ca4afSHartmut Brandt 
978f06ca4afSHartmut Brandt 		v->ipaddress[0] = he->h_addr[0];
979f06ca4afSHartmut Brandt 		v->ipaddress[1] = he->h_addr[1];
980f06ca4afSHartmut Brandt 		v->ipaddress[2] = he->h_addr[2];
981f06ca4afSHartmut Brandt 		v->ipaddress[3] = he->h_addr[3];
982f06ca4afSHartmut Brandt 		return (0);
983f06ca4afSHartmut Brandt 	    }
984f06ca4afSHartmut Brandt 
985f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_COUNTER:
986f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_GAUGE:
987f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_TIMETICKS:
988f06ca4afSHartmut Brandt 	    {
989f06ca4afSHartmut Brandt 		u_int64_t sub;
990f06ca4afSHartmut Brandt 
991f06ca4afSHartmut Brandt 		sub = strtoull(str, &end, 0);
992f06ca4afSHartmut Brandt 		if (*end != '\0' || sub > 0xffffffff)
993f06ca4afSHartmut Brandt 			return (-1);
994f06ca4afSHartmut Brandt 		v->uint32 = (u_int32_t)sub;
995f06ca4afSHartmut Brandt 		return (0);
996f06ca4afSHartmut Brandt 	    }
997f06ca4afSHartmut Brandt 
998f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_COUNTER64:
999f06ca4afSHartmut Brandt 		v->counter64 = strtoull(str, &end, 0);
1000f06ca4afSHartmut Brandt 		if (*end != '\0')
1001f06ca4afSHartmut Brandt 			return (-1);
1002f06ca4afSHartmut Brandt 		return (0);
1003f06ca4afSHartmut Brandt 	}
1004f06ca4afSHartmut Brandt 	abort();
1005f06ca4afSHartmut Brandt }
1006f06ca4afSHartmut Brandt 
1007f06ca4afSHartmut Brandt static void
1008f06ca4afSHartmut Brandt snmp_error_func(const char *fmt, ...)
1009f06ca4afSHartmut Brandt {
1010f06ca4afSHartmut Brandt 	va_list ap;
1011f06ca4afSHartmut Brandt 
1012f06ca4afSHartmut Brandt 	va_start(ap, fmt);
1013f06ca4afSHartmut Brandt 	fprintf(stderr, "SNMP: ");
1014f06ca4afSHartmut Brandt 	vfprintf(stderr, fmt, ap);
1015f06ca4afSHartmut Brandt 	fprintf(stderr, "\n");
1016f06ca4afSHartmut Brandt 	va_end(ap);
1017f06ca4afSHartmut Brandt }
1018f06ca4afSHartmut Brandt 
1019f06ca4afSHartmut Brandt static void
1020f06ca4afSHartmut Brandt snmp_printf_func(const char *fmt, ...)
1021f06ca4afSHartmut Brandt {
1022f06ca4afSHartmut Brandt 	va_list ap;
1023f06ca4afSHartmut Brandt 
1024f06ca4afSHartmut Brandt 	va_start(ap, fmt);
1025f06ca4afSHartmut Brandt 	vfprintf(stderr, fmt, ap);
1026f06ca4afSHartmut Brandt 	va_end(ap);
1027f06ca4afSHartmut Brandt }
1028