2 * Copyright (c) 2001-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Author: Harti Brandt <harti@freebsd.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * $Begemot: bsnmp/lib/snmp.c,v 1.40 2005/10/04 14:32:42 brandt_h Exp $
33 #include <sys/types.h>
34 #include <sys/socket.h>
41 #elif defined(HAVE_INTTYPES_H)
53 static void snmp_error_func(const char *, ...);
54 static void snmp_printf_func(const char *, ...);
56 void (*snmp_error)(const char *, ...) = snmp_error_func;
57 void (*snmp_printf)(const char *, ...) = snmp_printf_func;
60 * Get the next variable binding from the list.
61 * ASN errors on the sequence or the OID are always fatal.
64 get_var_binding(struct asn_buf *b, struct snmp_value *binding)
67 asn_len_t len, trailer;
70 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
71 snmp_error("cannot parse varbind header");
72 return (ASN_ERR_FAILED);
75 /* temporary truncate the length so that the parser does not
76 * eat up bytes behind the sequence in the case the encoding is
77 * wrong of inner elements. */
78 trailer = b->asn_len - len;
81 if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) {
82 snmp_error("cannot parse binding objid");
83 return (ASN_ERR_FAILED);
85 if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
86 snmp_error("cannot parse binding value header");
87 return (ASN_ERR_FAILED);
93 binding->syntax = SNMP_SYNTAX_NULL;
94 err = asn_get_null_raw(b, len);
97 case ASN_TYPE_INTEGER:
98 binding->syntax = SNMP_SYNTAX_INTEGER;
99 err = asn_get_integer_raw(b, len, &binding->v.integer);
102 case ASN_TYPE_OCTETSTRING:
103 binding->syntax = SNMP_SYNTAX_OCTETSTRING;
104 binding->v.octetstring.octets = malloc(len);
105 if (binding->v.octetstring.octets == NULL) {
106 snmp_error("%s", strerror(errno));
107 return (ASN_ERR_FAILED);
109 binding->v.octetstring.len = len;
110 err = asn_get_octetstring_raw(b, len,
111 binding->v.octetstring.octets,
112 &binding->v.octetstring.len);
113 if (ASN_ERR_STOPPED(err)) {
114 free(binding->v.octetstring.octets);
115 binding->v.octetstring.octets = NULL;
120 binding->syntax = SNMP_SYNTAX_OID;
121 err = asn_get_objid_raw(b, len, &binding->v.oid);
124 case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS:
125 binding->syntax = SNMP_SYNTAX_IPADDRESS;
126 err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress);
129 case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS:
130 binding->syntax = SNMP_SYNTAX_TIMETICKS;
131 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
134 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER:
135 binding->syntax = SNMP_SYNTAX_COUNTER;
136 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
139 case ASN_CLASS_APPLICATION|ASN_APP_GAUGE:
140 binding->syntax = SNMP_SYNTAX_GAUGE;
141 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
144 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64:
145 binding->syntax = SNMP_SYNTAX_COUNTER64;
146 err = asn_get_counter64_raw(b, len, &binding->v.counter64);
149 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT:
150 binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT;
151 err = asn_get_null_raw(b, len);
154 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE:
155 binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
156 err = asn_get_null_raw(b, len);
159 case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW:
160 binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
161 err = asn_get_null_raw(b, len);
165 if ((err = asn_skip(b, len)) == ASN_ERR_OK)
167 snmp_error("bad binding value type 0x%x", type);
171 if (ASN_ERR_STOPPED(err)) {
172 snmp_error("cannot parse binding value");
177 snmp_error("ignoring junk at end of binding");
179 b->asn_len = trailer;
185 * Parse the different PDUs contents. Any ASN error in the outer components
186 * are fatal. Only errors in variable values may be tolerated. If all
187 * components can be parsed it returns either ASN_ERR_OK or the first
188 * error that was found.
191 snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
193 if (pdu->type == SNMP_PDU_TRAP) {
194 if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) {
195 snmp_error("cannot parse trap enterprise");
196 return (ASN_ERR_FAILED);
198 if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) {
199 snmp_error("cannot parse trap agent address");
200 return (ASN_ERR_FAILED);
202 if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) {
203 snmp_error("cannot parse 'generic-trap'");
204 return (ASN_ERR_FAILED);
206 if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) {
207 snmp_error("cannot parse 'specific-trap'");
208 return (ASN_ERR_FAILED);
210 if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) {
211 snmp_error("cannot parse trap 'time-stamp'");
212 return (ASN_ERR_FAILED);
215 if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) {
216 snmp_error("cannot parse 'request-id'");
217 return (ASN_ERR_FAILED);
219 if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) {
220 snmp_error("cannot parse 'error_status'");
221 return (ASN_ERR_FAILED);
223 if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) {
224 snmp_error("cannot parse 'error_index'");
225 return (ASN_ERR_FAILED);
229 if (asn_get_sequence(b, lenp) != ASN_ERR_OK) {
230 snmp_error("cannot get varlist header");
231 return (ASN_ERR_FAILED);
238 parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
240 asn_len_t len, trailer;
241 struct snmp_value *v;
242 enum asn_err err, err1;
244 err = snmp_parse_pdus_hdr(b, pdu, &len);
245 if (ASN_ERR_STOPPED(err))
248 trailer = b->asn_len - len;
252 while (b->asn_len != 0) {
253 if (pdu->nbindings == SNMP_MAX_BINDINGS) {
254 snmp_error("too many bindings (> %u) in PDU",
256 return (ASN_ERR_FAILED);
258 err1 = get_var_binding(b, v);
259 if (ASN_ERR_STOPPED(err1))
260 return (ASN_ERR_FAILED);
261 if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) {
263 *ip = pdu->nbindings + 1;
269 b->asn_len = trailer;
275 * Parse the outer SEQUENCE value. ASN_ERR_TAG means 'bad version'.
278 snmp_parse_message_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
284 if (asn_get_integer(b, &version) != ASN_ERR_OK) {
285 snmp_error("cannot decode version");
286 return (ASN_ERR_FAILED);
290 pdu->version = SNMP_V1;
291 } else if (version == 1) {
292 pdu->version = SNMP_V2c;
294 pdu->version = SNMP_Verr;
295 snmp_error("unsupported SNMP version");
296 return (ASN_ERR_TAG);
299 comm_len = SNMP_COMMUNITY_MAXLEN;
300 if (asn_get_octetstring(b, (u_char *)pdu->community,
301 &comm_len) != ASN_ERR_OK) {
302 snmp_error("cannot decode community");
303 return (ASN_ERR_FAILED);
305 pdu->community[comm_len] = '\0';
307 if (asn_get_header(b, &type, lenp) != ASN_ERR_OK) {
308 snmp_error("cannot get pdu header");
309 return (ASN_ERR_FAILED);
311 if ((type & ~ASN_TYPE_MASK) !=
312 (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
313 snmp_error("bad pdu header tag");
314 return (ASN_ERR_FAILED);
316 pdu->type = type & ASN_TYPE_MASK;
321 case SNMP_PDU_GETNEXT:
322 case SNMP_PDU_RESPONSE:
327 if (pdu->version != SNMP_V1) {
328 snmp_error("bad pdu type %u", pdu->type);
329 return (ASN_ERR_FAILED);
333 case SNMP_PDU_GETBULK:
334 case SNMP_PDU_INFORM:
336 case SNMP_PDU_REPORT:
337 if (pdu->version == SNMP_V1) {
338 snmp_error("bad pdu type %u", pdu->type);
339 return (ASN_ERR_FAILED);
344 snmp_error("bad pdu type %u", pdu->type);
345 return (ASN_ERR_FAILED);
349 if (*lenp > b->asn_len) {
350 snmp_error("pdu length too long");
351 return (ASN_ERR_FAILED);
358 parse_message(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
361 asn_len_t len, trailer;
363 err = snmp_parse_message_hdr(b, pdu, &len);
364 if (ASN_ERR_STOPPED(err))
367 trailer = b->asn_len - len;
370 err = parse_pdus(b, pdu, ip);
371 if (ASN_ERR_STOPPED(err))
372 return (ASN_ERR_FAILED);
375 snmp_error("ignoring trailing junk after pdu");
377 b->asn_len = trailer;
383 * Decode the PDU except for the variable bindings itself.
384 * If decoding fails because of a bad binding, but the rest can be
385 * decoded, ip points to the index of the failed variable (errors
386 * OORANGE, BADLEN or BADVERS).
389 snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
393 memset(pdu, 0, sizeof(*pdu));
395 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
396 snmp_error("cannot decode pdu header");
397 return (SNMP_CODE_FAILED);
399 if (b->asn_len < len) {
400 snmp_error("outer sequence value too short");
401 return (SNMP_CODE_FAILED);
403 if (b->asn_len != len) {
404 snmp_error("ignoring trailing junk in message");
408 switch (parse_message(b, pdu, ip)) {
411 return (SNMP_CODE_OK);
416 return (SNMP_CODE_FAILED);
419 return (SNMP_CODE_BADLEN);
422 return (SNMP_CODE_OORANGE);
425 if (pdu->version == SNMP_Verr)
426 return (SNMP_CODE_BADVERS);
428 return (SNMP_CODE_BADENC);
431 return (SNMP_CODE_OK);
435 * Check whether what we have is the complete PDU by snooping at the
436 * enclosing structure header. This returns:
437 * -1 if there are ASN.1 errors
438 * 0 if we need more data
439 * > 0 the length of this PDU
442 snmp_pdu_snoop(const struct asn_buf *b0)
446 struct asn_buf b = *b0;
448 /* <0x10|0x20> <len> <data...> */
452 if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) {
453 asn_error(&b, "bad sequence type %u", b.asn_cptr[0]);
462 if (*b.asn_cptr & 0x80) {
464 length = *b.asn_cptr++ & 0x7f;
467 asn_error(&b, "indefinite length not supported");
470 if (length > ASN_MAXLENLEN) {
471 asn_error(&b, "long length too long (%u)", length);
474 if (length > b.asn_len)
478 len = (len << 8) | *b.asn_cptr++;
489 return (len + b.asn_cptr - b0->asn_cptr);
493 * Encode the SNMP PDU without the variable bindings field.
494 * We do this the rather uneffective way by
495 * moving things around and assuming that the length field will never
496 * use more than 2 bytes.
497 * We need a number of pointers to apply the fixes afterwards.
500 snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
504 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
505 &pdu->outer_ptr) != ASN_ERR_OK)
506 return (SNMP_CODE_FAILED);
508 if (pdu->version == SNMP_V1)
509 err = asn_put_integer(b, 0);
510 else if (pdu->version == SNMP_V2c)
511 err = asn_put_integer(b, 1);
513 return (SNMP_CODE_BADVERS);
514 if (err != ASN_ERR_OK)
515 return (SNMP_CODE_FAILED);
517 if (asn_put_octetstring(b, (u_char *)pdu->community,
518 strlen(pdu->community)) != ASN_ERR_OK)
519 return (SNMP_CODE_FAILED);
521 if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT |
522 pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
523 return (SNMP_CODE_FAILED);
525 if (pdu->type == SNMP_PDU_TRAP) {
526 if (pdu->version != SNMP_V1 ||
527 asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK ||
528 asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK ||
529 asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK ||
530 asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK ||
531 asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK)
532 return (SNMP_CODE_FAILED);
534 if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK ||
535 pdu->type == SNMP_PDU_INFORM ||
536 pdu->type == SNMP_PDU_TRAP2 ||
537 pdu->type == SNMP_PDU_REPORT))
538 return (SNMP_CODE_FAILED);
540 if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK ||
541 asn_put_integer(b, pdu->error_status) != ASN_ERR_OK ||
542 asn_put_integer(b, pdu->error_index) != ASN_ERR_OK)
543 return (SNMP_CODE_FAILED);
546 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
547 &pdu->vars_ptr) != ASN_ERR_OK)
548 return (SNMP_CODE_FAILED);
550 return (SNMP_CODE_OK);
554 snmp_fix_encoding(struct asn_buf *b, const struct snmp_pdu *pdu)
556 if (asn_commit_header(b, pdu->vars_ptr) != ASN_ERR_OK ||
557 asn_commit_header(b, pdu->pdu_ptr) != ASN_ERR_OK ||
558 asn_commit_header(b, pdu->outer_ptr) != ASN_ERR_OK)
559 return (SNMP_CODE_FAILED);
560 return (SNMP_CODE_OK);
564 * Encode a binding. Caller must ensure, that the syntax is ok for that version.
565 * Be sure not to cobber b, when something fails.
568 snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding)
572 struct asn_buf save = *b;
574 if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
575 ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) {
580 if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) {
585 switch (binding->syntax) {
587 case SNMP_SYNTAX_NULL:
588 err = asn_put_null(b);
591 case SNMP_SYNTAX_INTEGER:
592 err = asn_put_integer(b, binding->v.integer);
595 case SNMP_SYNTAX_OCTETSTRING:
596 err = asn_put_octetstring(b, binding->v.octetstring.octets,
597 binding->v.octetstring.len);
600 case SNMP_SYNTAX_OID:
601 err = asn_put_objid(b, &binding->v.oid);
604 case SNMP_SYNTAX_IPADDRESS:
605 err = asn_put_ipaddress(b, binding->v.ipaddress);
608 case SNMP_SYNTAX_TIMETICKS:
609 err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32);
612 case SNMP_SYNTAX_COUNTER:
613 err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32);
616 case SNMP_SYNTAX_GAUGE:
617 err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32);
620 case SNMP_SYNTAX_COUNTER64:
621 err = asn_put_counter64(b, binding->v.counter64);
624 case SNMP_SYNTAX_NOSUCHOBJECT:
625 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT);
628 case SNMP_SYNTAX_NOSUCHINSTANCE:
629 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE);
632 case SNMP_SYNTAX_ENDOFMIBVIEW:
633 err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW);
637 if (err != ASN_ERR_OK) {
642 err = asn_commit_header(b, ptr);
643 if (err != ASN_ERR_OK) {
655 snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b)
660 if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK)
662 for (idx = 0; idx < pdu->nbindings; idx++)
663 if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx]))
665 return (SNMP_CODE_FAILED);
667 return (snmp_fix_encoding(resp_b, pdu));
671 dump_binding(const struct snmp_value *b)
674 char buf[ASN_OIDSTRLEN];
676 snmp_printf("%s=", asn_oid2str_r(&b->var, buf));
679 case SNMP_SYNTAX_NULL:
683 case SNMP_SYNTAX_INTEGER:
684 snmp_printf("INTEGER %d", b->v.integer);
687 case SNMP_SYNTAX_OCTETSTRING:
688 snmp_printf("OCTET STRING %lu:", b->v.octetstring.len);
689 for (i = 0; i < b->v.octetstring.len; i++)
690 snmp_printf(" %02x", b->v.octetstring.octets[i]);
693 case SNMP_SYNTAX_OID:
694 snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf));
697 case SNMP_SYNTAX_IPADDRESS:
698 snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0],
699 b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]);
702 case SNMP_SYNTAX_COUNTER:
703 snmp_printf("COUNTER %u", b->v.uint32);
706 case SNMP_SYNTAX_GAUGE:
707 snmp_printf("GAUGE %u", b->v.uint32);
710 case SNMP_SYNTAX_TIMETICKS:
711 snmp_printf("TIMETICKS %u", b->v.uint32);
714 case SNMP_SYNTAX_COUNTER64:
715 snmp_printf("COUNTER64 %lld", b->v.counter64);
718 case SNMP_SYNTAX_NOSUCHOBJECT:
719 snmp_printf("NoSuchObject");
722 case SNMP_SYNTAX_NOSUCHINSTANCE:
723 snmp_printf("NoSuchInstance");
726 case SNMP_SYNTAX_ENDOFMIBVIEW:
727 snmp_printf("EndOfMibView");
731 snmp_printf("UNKNOWN SYNTAX %u", b->syntax);
737 dump_bindings(const struct snmp_pdu *pdu)
741 for (i = 0; i < pdu->nbindings; i++) {
742 snmp_printf(" [%u]: ", i);
743 dump_binding(&pdu->bindings[i]);
749 dump_notrap(const struct snmp_pdu *pdu)
751 snmp_printf(" request_id=%d", pdu->request_id);
752 snmp_printf(" error_status=%d", pdu->error_status);
753 snmp_printf(" error_index=%d\n", pdu->error_index);
758 snmp_pdu_dump(const struct snmp_pdu *pdu)
760 char buf[ASN_OIDSTRLEN];
762 static const char *types[] = {
763 [SNMP_PDU_GET] = "GET",
764 [SNMP_PDU_GETNEXT] = "GETNEXT",
765 [SNMP_PDU_RESPONSE] = "RESPONSE",
766 [SNMP_PDU_SET] = "SET",
767 [SNMP_PDU_TRAP] = "TRAPv1",
768 [SNMP_PDU_GETBULK] = "GETBULK",
769 [SNMP_PDU_INFORM] = "INFORM",
770 [SNMP_PDU_TRAP2] = "TRAPv2",
771 [SNMP_PDU_REPORT] = "REPORT",
774 if (pdu->version == SNMP_V1)
776 else if (pdu->version == SNMP_V2c)
783 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
784 snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf));
785 snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0],
786 pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]);
787 snmp_printf(" generic_trap=%d", pdu->generic_trap);
788 snmp_printf(" specific_trap=%d", pdu->specific_trap);
789 snmp_printf(" time-stamp=%u\n", pdu->time_stamp);
794 case SNMP_PDU_GETNEXT:
795 case SNMP_PDU_RESPONSE:
797 case SNMP_PDU_GETBULK:
798 case SNMP_PDU_INFORM:
800 case SNMP_PDU_REPORT:
801 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
806 snmp_printf("bad pdu type %u\n", pdu->type);
812 snmp_value_free(struct snmp_value *value)
814 if (value->syntax == SNMP_SYNTAX_OCTETSTRING)
815 free(value->v.octetstring.octets);
816 value->syntax = SNMP_SYNTAX_NULL;
820 snmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
823 to->syntax = from->syntax;
825 if (from->syntax == SNMP_SYNTAX_OCTETSTRING) {
826 if ((to->v.octetstring.len = from->v.octetstring.len) == 0)
827 to->v.octetstring.octets = NULL;
829 to->v.octetstring.octets = malloc(to->v.octetstring.len);
830 if (to->v.octetstring.octets == NULL)
832 (void)memcpy(to->v.octetstring.octets,
833 from->v.octetstring.octets, to->v.octetstring.len);
841 snmp_pdu_free(struct snmp_pdu *pdu)
845 for (i = 0; i < pdu->nbindings; i++)
846 snmp_value_free(&pdu->bindings[i]);
850 * Parse an ASCII SNMP value into the binary form
853 snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v)
859 case SNMP_SYNTAX_NULL:
860 case SNMP_SYNTAX_NOSUCHOBJECT:
861 case SNMP_SYNTAX_NOSUCHINSTANCE:
862 case SNMP_SYNTAX_ENDOFMIBVIEW:
867 case SNMP_SYNTAX_INTEGER:
868 v->integer = strtoll(str, &end, 0);
873 case SNMP_SYNTAX_OCTETSTRING:
875 u_long len; /* actual length of string */
876 u_long alloc; /* allocate length of string */
877 u_char *octs; /* actual octets */
878 u_long oct; /* actual octet */
879 u_char *nocts; /* to avoid memory leak */
880 u_char c; /* actual character */
883 if (alloc == len) { \
885 if ((nocts = realloc(octs, alloc)) == NULL) { \
898 while((c = *str++) != '\0') {
907 switch (c = *str++) {
938 else if (isupper(*str))
939 c = *str++ - 'A' + 10;
941 c = *str++ - 'a' + 10;
946 else if (isupper(*str))
947 c += *str++ - 'A' + 10;
949 c += *str++ - 'a' + 10;
951 case '0': case '1': case '2':
952 case '3': case '4': case '5':
955 if (*str < '0' || *str > '7')
958 if (*str < '0' || *str > '7')
969 while (*str != '\0') {
970 oct = strtoul(str, &end, 16);
979 else if(*str != '\0') {
985 v->octetstring.octets = octs;
986 v->octetstring.len = len;
991 case SNMP_SYNTAX_OID:
998 if (v->oid.len == ASN_MAXOIDLEN)
1000 subid = strtoul(str, &end, 10);
1002 if (subid > ASN_MAXID)
1004 v->oid.subs[v->oid.len++] = (asn_subid_t)subid;
1014 case SNMP_SYNTAX_IPADDRESS:
1020 if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2],
1021 &ip[3], &n) == 4 && (size_t)n == strlen(str) &&
1022 ip[0] <= 0xff && ip[1] <= 0xff &&
1023 ip[2] <= 0xff && ip[3] <= 0xff) {
1024 v->ipaddress[0] = (u_char)ip[0];
1025 v->ipaddress[1] = (u_char)ip[1];
1026 v->ipaddress[2] = (u_char)ip[2];
1027 v->ipaddress[3] = (u_char)ip[3];
1031 if ((he = gethostbyname(str)) == NULL)
1033 if (he->h_addrtype != AF_INET)
1036 v->ipaddress[0] = he->h_addr[0];
1037 v->ipaddress[1] = he->h_addr[1];
1038 v->ipaddress[2] = he->h_addr[2];
1039 v->ipaddress[3] = he->h_addr[3];
1043 case SNMP_SYNTAX_COUNTER:
1044 case SNMP_SYNTAX_GAUGE:
1045 case SNMP_SYNTAX_TIMETICKS:
1049 sub = strtoull(str, &end, 0);
1050 if (*end != '\0' || sub > 0xffffffff)
1052 v->uint32 = (uint32_t)sub;
1056 case SNMP_SYNTAX_COUNTER64:
1057 v->counter64 = strtoull(str, &end, 0);
1066 snmp_error_func(const char *fmt, ...)
1071 fprintf(stderr, "SNMP: ");
1072 vfprintf(stderr, fmt, ap);
1073 fprintf(stderr, "\n");
1078 snmp_printf_func(const char *fmt, ...)
1083 vfprintf(stderr, fmt, ap);