# BRCM_VERSION=3
[bcm963xx.git] / userapps / opensource / net-snmp / snmplib / asn1.c
1 /*
2  * Abstract Syntax Notation One, ASN.1
3  * As defined in ISO/IS 8824 and ISO/IS 8825
4  * This implements a subset of the above International Standards that
5  * is sufficient to implement SNMP.
6  *
7  * Encodes abstract data types into a machine independent stream of bytes.
8  *
9  */
10 /**********************************************************************
11         Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
12
13                       All Rights Reserved
14
15 Permission to use, copy, modify, and distribute this software and its 
16 documentation for any purpose and without fee is hereby granted, 
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in 
19 supporting documentation, and that the name of CMU not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.  
22
23 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 SOFTWARE.
30 ******************************************************************/
31 #include <net-snmp/net-snmp-config.h>
32
33 #ifdef KINETICS
34 #include "gw.h"
35 #endif
36
37 #if HAVE_STRING_H
38 #include <string.h>
39 #else
40 #include <strings.h>
41 #endif
42
43 #include <sys/types.h>
44 #include <stdio.h>
45 #ifdef HAVE_STDLIB_H
46 #include <stdlib.h>
47 #endif
48 #if HAVE_WINSOCK_H
49 #include <winsock.h>
50 #endif
51 #if HAVE_NETINET_IN_H
52 #include <netinet/in.h>
53 #endif
54
55 #ifdef vms
56 #include <in.h>
57 #endif
58
59 #if HAVE_DMALLOC_H
60 #include <dmalloc.h>
61 #endif
62
63 #include <net-snmp/output_api.h>
64 #include <net-snmp/utilities.h>
65
66 #include <net-snmp/library/asn1.h>
67 #include <net-snmp/library/int64.h>
68 #include <net-snmp/library/mib.h>
69
70 #ifndef NULL
71 #define NULL    0
72 #endif
73
74 #include <net-snmp/library/snmp_api.h>
75
76 static
77     void
78 _asn_size_err(const char *str, size_t wrongsize, size_t rightsize)
79 {
80     char            ebuf[128];
81
82     snprintf(ebuf, sizeof(ebuf),
83             "%s size %d: s/b %d", str, wrongsize, rightsize);
84     ebuf[ sizeof(ebuf)-1 ] = 0;
85     ERROR_MSG(ebuf);
86 }
87
88 static
89     void
90 _asn_length_err(const char *str, size_t wrongsize, size_t rightsize)
91 {
92     char            ebuf[128];
93
94     snprintf(ebuf, sizeof(ebuf),
95             "%s length %d too large: exceeds %d", str, wrongsize,
96             rightsize);
97     ebuf[ sizeof(ebuf)-1 ] = 0;
98     ERROR_MSG(ebuf);
99 }
100
101 /*
102  * call after asn_parse_length to verify result.
103  */
104 static
105     int
106 _asn_parse_length_check(const char *str,
107                         u_char * bufp, u_char * data,
108                         u_long plen, size_t dlen)
109 {
110     char            ebuf[128];
111     size_t          header_len;
112
113     if (bufp == NULL) {
114         /*
115          * error message is set 
116          */
117         return 1;
118     }
119     header_len = bufp - data;
120     if (plen > 0x7fffffff || header_len > 0x7fffffff ||
121         ((size_t) plen + header_len) > dlen) {
122         snprintf(ebuf, sizeof(ebuf),
123                 "%s: message overflow: %d len + %d delta > %d len",
124                 str, (int) plen, (int) header_len, (int) dlen);
125         ebuf[ sizeof(ebuf)-1 ] = 0;
126         ERROR_MSG(ebuf);
127         return 1;
128     }
129     return 0;
130 }
131
132 /*
133  * call after asn_build_header to verify result.
134  */
135 static
136     int
137 _asn_build_header_check(const char *str, u_char * data,
138                         size_t datalen, size_t typedlen)
139 {
140     char            ebuf[128];
141
142     if (data == NULL) {
143         /*
144          * error message is set 
145          */
146         return 1;
147     }
148     if (datalen < typedlen) {
149         snprintf(ebuf, sizeof(ebuf),
150                 "%s: bad header, length too short: %d < %d", str,
151                 datalen, typedlen);
152         ebuf[ sizeof(ebuf)-1 ] = 0;
153         ERROR_MSG(ebuf);
154         return 1;
155     }
156     return 0;
157 }
158
159 static
160     int
161 _asn_realloc_build_header_check(const char *str,
162                                 u_char ** pkt, size_t * pkt_len,
163                                 size_t typedlen)
164 {
165     char            ebuf[128];
166
167     if (pkt == NULL || *pkt == NULL) {
168         /*
169          * Error message is set.  
170          */
171         return 1;
172     }
173
174     if (*pkt_len < typedlen) {
175         snprintf(ebuf, sizeof(ebuf),
176                 "%s: bad header, length too short: %d < %d", str,
177                 *pkt_len, typedlen);
178         ebuf[ sizeof(ebuf)-1 ] = 0;
179         ERROR_MSG(ebuf);
180         return 1;
181     }
182     return 0;
183 }
184
185 /*
186  * checks the incoming packet for validity and returns its size or 0 
187  */
188 int
189 asn_check_packet(u_char * pkt, size_t len)
190 {
191     u_long          asn_length;
192
193     if (len < 2)
194         return 0;               /* always too short */
195
196     if (*pkt != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR))
197         return -1;              /* wrong type */
198
199     if (*(pkt + 1) & 0x80) {
200         /*
201          * long length 
202          */
203         if ((int) len < (int) (*(pkt + 1) & ~0x80) + 2)
204             return 0;           /* still to short, incomplete length */
205         asn_parse_length(pkt + 1, &asn_length);
206         return (asn_length + 2 + (*(pkt + 1) & ~0x80));
207     } else {
208         /*
209          * short length 
210          */
211         return (*(pkt + 1) + 2);
212     }
213 }
214
215 static
216     int
217 _asn_bitstring_check(const char *str, size_t asn_length, u_char datum)
218 {
219     char            ebuf[128];
220
221     if (asn_length < 1) {
222         snprintf(ebuf, sizeof(ebuf),
223                 "%s: length %d too small", str, (int) asn_length);
224         ebuf[ sizeof(ebuf)-1 ] = 0;
225         ERROR_MSG(ebuf);
226         return 1;
227     }
228     /*
229      * if (datum > 7){
230      * sprintf(ebuf,"%s: datum %d >7: too large", str, (int)(datum));
231      * ERROR_MSG(ebuf);
232      * return 1;
233      * }
234      */
235     return 0;
236 }
237
238 /*
239  * asn_parse_int - pulls a long out of an int type.
240  *  On entry, datalength is input as the number of valid bytes following
241  *   "data".  On exit, it is returned as the number of valid bytes
242  *   following the end of this object.
243  *
244  *  Returns a pointer to the first byte past the end
245  *   of this object (i.e. the start of the next object).
246  *  Returns NULL on any error.
247  
248  u_char * asn_parse_int(
249  u_char     *data         IN - pointer to start of object
250  int        *datalength   IN/OUT - number of valid bytes left in buffer
251  u_char     *type         OUT - asn type of object
252  long       *intp         IN/OUT - pointer to start of output buffer
253  int         intsize      IN - size of output buffer
254  */
255
256 u_char         *
257 asn_parse_int(u_char * data,
258               size_t * datalength,
259               u_char * type, long *intp, size_t intsize)
260 {
261     /*
262      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
263      */
264     static const char *errpre = "parse int";
265     register u_char *bufp = data;
266     u_long          asn_length;
267     register long   value = 0;
268
269     if (intsize != sizeof(long)) {
270         _asn_size_err(errpre, intsize, sizeof(long));
271         return NULL;
272     }
273     *type = *bufp++;
274     bufp = asn_parse_length(bufp, &asn_length);
275     if (_asn_parse_length_check
276         (errpre, bufp, data, asn_length, *datalength))
277         return NULL;
278
279     if ((size_t) asn_length > intsize) {
280         _asn_length_err(errpre, (size_t) asn_length, intsize);
281         return NULL;
282     }
283
284     *datalength -= (int) asn_length + (bufp - data);
285     if (*bufp & 0x80)
286         value = -1;             /* integer is negative */
287
288     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
289
290     while (asn_length--)
291         value = (value << 8) | *bufp++;
292
293     DEBUGMSG(("dumpv_recv", "  Integer:\t%ld (0x%.2X)\n", value, value));
294
295     *intp = value;
296     return bufp;
297 }
298
299
300 /*
301  * asn_parse_unsigned_int - pulls an unsigned long out of an ASN int type.
302  *  On entry, datalength is input as the number of valid bytes following
303  *   "data".  On exit, it is returned as the number of valid bytes
304  *   following the end of this object.
305  *
306  *  Returns a pointer to the first byte past the end
307  *   of this object (i.e. the start of the next object).
308  *  Returns NULL on any error.
309  
310  u_char * asn_parse_unsigned_int(
311  u_char     *data         IN - pointer to start of object
312  int        *datalength   IN/OUT - number of valid bytes left in buffer
313  u_char     *type         OUT - asn type of object
314  u_long     *intp         IN/OUT - pointer to start of output buffer
315  int         intsize      IN - size of output buffer
316  */
317 u_char         *
318 asn_parse_unsigned_int(u_char * data,
319                        size_t * datalength,
320                        u_char * type, u_long * intp, size_t intsize)
321 {
322     /*
323      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
324      */
325     static const char *errpre = "parse uint";
326     register u_char *bufp = data;
327     u_long          asn_length;
328     register u_long value = 0;
329
330     if (intsize != sizeof(long)) {
331         _asn_size_err(errpre, intsize, sizeof(long));
332         return NULL;
333     }
334     *type = *bufp++;
335     bufp = asn_parse_length(bufp, &asn_length);
336     if (_asn_parse_length_check
337         (errpre, bufp, data, asn_length, *datalength))
338         return NULL;
339
340     if (((int) asn_length > (intsize + 1)) ||
341         (((int) asn_length == intsize + 1) && *bufp != 0x00)) {
342         _asn_length_err(errpre, (size_t) asn_length, intsize);
343         return NULL;
344     }
345     *datalength -= (int) asn_length + (bufp - data);
346     if (*bufp & 0x80)
347         value = ~value;         /* integer is negative */
348
349     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
350
351     while (asn_length--)
352         value = (value << 8) | *bufp++;
353
354     DEBUGMSG(("dumpv_recv", "  UInteger:\t%ld (0x%.2X)\n", value, value));
355
356     *intp = value;
357     return bufp;
358 }
359
360
361 /*
362  * asn_build_int - builds an ASN object containing an integer.
363  *  On entry, datalength is input as the number of valid bytes following
364  *   "data".  On exit, it is returned as the number of valid bytes
365  *   following the end of this object.
366  *
367  *  Returns a pointer to the first byte past the end
368  *   of this object (i.e. the start of the next object).
369  *  Returns NULL on any error.
370  
371  u_char * asn_build_int(
372  u_char     *data         IN - pointer to start of output buffer
373  int        *datalength   IN/OUT - number of valid bytes left in buffer
374  int         type         IN  - asn type of object
375  long       *intp         IN - pointer to start of long integer
376  int         intsize      IN - size of input buffer
377  */
378 u_char         *
379 asn_build_int(u_char * data,
380               size_t * datalength, u_char type, long *intp, size_t intsize)
381 {
382     /*
383      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
384      */
385     static const char *errpre = "build int";
386     register long   integer;
387     register u_long mask;
388 #ifndef SNMP_NO_DEBUGGING
389     u_char         *initdatap = data;
390 #endif
391
392     if (intsize != sizeof(long)) {
393         _asn_size_err(errpre, intsize, sizeof(long));
394         return NULL;
395     }
396     integer = *intp;
397     /*
398      * Truncate "unnecessary" bytes off of the most significant end of this
399      * 2's complement integer.  There should be no sequence of 9
400      * consecutive 1's or 0's at the most significant end of the
401      * integer.
402      */
403     mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
404     /*
405      * mask is 0xFF800000 on a big-endian machine 
406      */
407     while ((((integer & mask) == 0) || ((integer & mask) == mask))
408            && intsize > 1) {
409         intsize--;
410         integer <<= 8;
411     }
412     data = asn_build_header(data, datalength, type, intsize);
413     if (_asn_build_header_check(errpre, data, *datalength, intsize))
414         return NULL;
415
416     *datalength -= intsize;
417     mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
418     /*
419      * mask is 0xFF000000 on a big-endian machine 
420      */
421     while (intsize--) {
422         *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1)));
423         integer <<= 8;
424     }
425     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
426     DEBUGMSG(("dumpv_send", "  Integer:\t%ld (0x%.2X)\n", *intp, *intp));
427     return data;
428 }
429
430
431 /*
432  * asn_build_unsigned_int - builds an ASN object containing an integer.
433  *  On entry, datalength is input as the number of valid bytes following
434  *   "data".  On exit, it is returned as the number of valid bytes
435  *   following the end of this object.
436  *
437  *  Returns a pointer to the first byte past the end
438  *   of this object (i.e. the start of the next object).
439  *  Returns NULL on any error.
440  
441  u_char * asn_build_unsigned_int(
442  u_char     *data         IN - pointer to start of output buffer
443  int        *datalength   IN/OUT - number of valid bytes left in buffer
444  u_char      type         IN  - asn type of object
445  u_long     *intp         IN - pointer to start of long integer
446  int         intsize      IN - size of input buffer
447  */
448 u_char         *
449 asn_build_unsigned_int(u_char * data,
450                        size_t * datalength,
451                        u_char type, u_long * intp, size_t intsize)
452 {
453     /*
454      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
455      */
456     static const char *errpre = "build uint";
457     register u_long integer;
458     register u_long mask;
459     int             add_null_byte = 0;
460 #ifndef SNMP_NO_DEBUGGING
461     u_char         *initdatap = data;
462 #endif
463
464     if (intsize != sizeof(long)) {
465         _asn_size_err(errpre, intsize, sizeof(long));
466         return NULL;
467     }
468     integer = *intp;
469     mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
470     /*
471      * mask is 0xFF000000 on a big-endian machine 
472      */
473     if ((u_char) ((integer & mask) >> (8 * (sizeof(long) - 1))) & 0x80) {
474         /*
475          * if MSB is set 
476          */
477         add_null_byte = 1;
478         intsize++;
479     } else {
480         /*
481          * Truncate "unnecessary" bytes off of the most significant end of this 2's complement integer.
482          * There should be no sequence of 9 consecutive 1's or 0's at the most significant end of the
483          * integer.
484          */
485         mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
486         /*
487          * mask is 0xFF800000 on a big-endian machine 
488          */
489         while ((((integer & mask) == 0) || ((integer & mask) == mask))
490                && intsize > 1) {
491             intsize--;
492             integer <<= 8;
493         }
494     }
495     data = asn_build_header(data, datalength, type, intsize);
496     if (_asn_build_header_check(errpre, data, *datalength, intsize))
497         return NULL;
498
499     *datalength -= intsize;
500     if (add_null_byte == 1) {
501         *data++ = '\0';
502         intsize--;
503     }
504     mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
505     /*
506      * mask is 0xFF000000 on a big-endian machine 
507      */
508     while (intsize--) {
509         *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1)));
510         integer <<= 8;
511     }
512     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
513     DEBUGMSG(("dumpv_send", "  UInteger:\t%ld (0x%.2X)\n", *intp, *intp));
514     return data;
515 }
516
517
518 /*
519  * asn_parse_string - pulls an octet string out of an ASN octet string type.
520  *  On entry, datalength is input as the number of valid bytes following
521  *   "data".  On exit, it is returned as the number of valid bytes
522  *   following the beginning of the next object.
523  *
524  *  "string" is filled with the octet string.
525  *
526  *  Returns a pointer to the first byte past the end
527  *   of this object (i.e. the start of the next object).
528  *  Returns NULL on any error.
529  *
530  * u_char * asn_parse_string(
531  *     u_char     *data         IN - pointer to start of object
532  *     int        *datalength   IN/OUT - number of valid bytes left in buffer
533  *     u_char     *type         OUT - asn type of object
534  *     u_char     *string       IN/OUT - pointer to start of output buffer
535  *     int        *strlength    IN/OUT - size of output buffer
536  *
537  *
538  * ASN.1 octet string   ::=      primstring | cmpdstring
539  * primstring           ::= 0x04 asnlength byte {byte}*
540  * cmpdstring           ::= 0x24 asnlength string {string}*
541  */
542 u_char         *
543 asn_parse_string(u_char * data,
544                  size_t * datalength,
545                  u_char * type, u_char * string, size_t * strlength)
546 {
547     static const char *errpre = "parse string";
548     u_char         *bufp = data;
549     u_long          asn_length;
550
551     *type = *bufp++;
552     bufp = asn_parse_length(bufp, &asn_length);
553     if (_asn_parse_length_check
554         (errpre, bufp, data, asn_length, *datalength)) {
555         return NULL;
556     }
557
558     if ((int) asn_length > *strlength) {
559         _asn_length_err(errpre, (size_t) asn_length, *strlength);
560         return NULL;
561     }
562
563     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
564
565     memmove(string, bufp, asn_length);
566     if (*strlength > (int) asn_length)
567         string[asn_length] = 0;
568     *strlength = (int) asn_length;
569     *datalength -= (int) asn_length + (bufp - data);
570
571     DEBUGIF("dumpv_recv") {
572         u_char         *buf = (u_char *) malloc(1 + asn_length);
573         size_t          l = (buf != NULL) ? (1 + asn_length) : 0, ol = 0;
574
575         if (sprint_realloc_asciistring
576             (&buf, &l, &ol, 1, string, asn_length)) {
577             DEBUGMSG(("dumpv_recv", "  String:\t%s\n", buf));
578         } else {
579             if (buf == NULL) {
580                 DEBUGMSG(("dumpv_recv", "  String:\t[TRUNCATED]\n"));
581             } else {
582                 DEBUGMSG(("dumpv_recv", "  String:\t%s [TRUNCATED]\n",
583                           buf));
584             }
585         }
586         if (buf != NULL) {
587             free(buf);
588         }
589     }
590
591     return bufp + asn_length;
592 }
593
594
595 /*
596  * asn_build_string - Builds an ASN octet string object containing the input string.
597  *  On entry, datalength is input as the number of valid bytes following
598  *   "data".  On exit, it is returned as the number of valid bytes
599  *   following the beginning of the next object.
600  *
601  *  Returns a pointer to the first byte past the end
602  *   of this object (i.e. the start of the next object).
603  *  Returns NULL on any error.
604  
605  u_char * asn_build_string(
606  u_char     *data         IN - pointer to start of object
607  int        *datalength   IN/OUT - number of valid bytes left in buffer
608  u_char      type         IN - asn type of object
609  u_char     *string       IN - pointer to start of input buffer
610  int         strlength    IN - size of input buffer
611  */
612 u_char         *
613 asn_build_string(u_char * data,
614                  size_t * datalength,
615                  u_char type, const u_char * string, size_t strlength)
616 {
617     /*
618      * ASN.1 octet string ::= primstring | cmpdstring
619      * primstring ::= 0x04 asnlength byte {byte}*
620      * cmpdstring ::= 0x24 asnlength string {string}*
621      * This code will never send a compound string.
622      */
623 #ifndef SNMP_NO_DEBUGGING
624     u_char         *initdatap = data;
625 #endif
626     data = asn_build_header(data, datalength, type, strlength);
627     if (_asn_build_header_check
628         ("build string", data, *datalength, strlength))
629         return NULL;
630
631     if (strlength) {
632         if (string == NULL) {
633             memset(data, 0, strlength);
634         } else {
635             memmove(data, string, strlength);
636         }
637     }
638     *datalength -= strlength;
639     DEBUGDUMPSETUP("send", initdatap, data - initdatap + strlength);
640     DEBUGIF("dumpv_send") {
641         u_char         *buf = (u_char *) malloc(1 + strlength);
642         size_t          l = (buf != NULL) ? (1 + strlength) : 0, ol = 0;
643
644         if (sprint_realloc_asciistring
645             (&buf, &l, &ol, 1, string, strlength)) {
646             DEBUGMSG(("dumpv_send", "  String:\t%s\n", buf));
647         } else {
648             if (buf == NULL) {
649                 DEBUGMSG(("dumpv_send", "  String:\t[TRUNCATED]\n"));
650             } else {
651                 DEBUGMSG(("dumpv_send", "  String:\t%s [TRUNCATED]\n",
652                           buf));
653             }
654         }
655         if (buf != NULL) {
656             free(buf);
657         }
658     }
659     return data + strlength;
660 }
661
662
663
664 /*
665  * asn_parse_header - interprets the ID and length of the current object.
666  *  On entry, datalength is input as the number of valid bytes following
667  *   "data".  On exit, it is returned as the number of valid bytes
668  *   in this object following the id and length.
669  *
670  *  Returns a pointer to the first byte of the contents of this object.
671  *  Returns NULL on any error.
672  
673  u_char * asn_parse_header(
674  u_char     *data         IN - pointer to start of object
675  int        *datalength   IN/OUT - number of valid bytes left in buffer
676  u_char     *type         OUT - asn type of object
677  */
678 u_char         *
679 asn_parse_header(u_char * data, size_t * datalength, u_char * type)
680 {
681     register u_char *bufp;
682     u_long          asn_length;
683
684     if (!data || !datalength || !type) {
685         ERROR_MSG("parse header: NULL pointer");
686         return NULL;
687     }
688     bufp = data;
689     /*
690      * this only works on data types < 30, i.e. no extension octets 
691      */
692     if (IS_EXTENSION_ID(*bufp)) {
693         ERROR_MSG("can't process ID >= 30");
694         return NULL;
695     }
696     *type = *bufp;
697     bufp = asn_parse_length(bufp + 1, &asn_length);
698
699     if (_asn_parse_length_check
700         ("parse header", bufp, data, asn_length, *datalength))
701         return NULL;
702
703 #ifdef DUMP_PRINT_HEADERS
704     DEBUGDUMPSETUP("recv", data, (bufp - data));
705     DEBUGMSG(("dumpv_recv", "  Header: 0x%.2X, len = %d (0x%X)\n", *data,
706               asn_length, asn_length));
707 #else
708     /*
709      * DEBUGMSGHEXTLI(("recv",data,(bufp-data)));
710      * DEBUGMSG(("dumpH_recv","\n"));
711      */
712 #endif
713
714 #ifdef OPAQUE_SPECIAL_TYPES
715
716     if ((*type == ASN_OPAQUE) && (*bufp == ASN_OPAQUE_TAG1)) {
717
718         /*
719          * check if 64-but counter 
720          */
721         switch (*(bufp + 1)) {
722         case ASN_OPAQUE_COUNTER64:
723         case ASN_OPAQUE_U64:
724         case ASN_OPAQUE_FLOAT:
725         case ASN_OPAQUE_DOUBLE:
726         case ASN_OPAQUE_I64:
727             *type = *(bufp + 1);
728             break;
729
730         default:
731             /*
732              * just an Opaque 
733              */
734             *datalength = (int) asn_length;
735             return bufp;
736         }
737         /*
738          * value is encoded as special format 
739          */
740         bufp = asn_parse_length(bufp + 2, &asn_length);
741         if (_asn_parse_length_check("parse opaque header", bufp, data,
742                                     asn_length, *datalength))
743             return NULL;
744     }
745 #endif                          /* OPAQUE_SPECIAL_TYPES */
746
747     *datalength = (int) asn_length;
748
749     return bufp;
750 }
751
752 /*
753  * same as asn_parse_header with test for expected type.
754  */
755 u_char         *
756 asn_parse_sequence(u_char * data, size_t * datalength, u_char * type, u_char expected_type,     /* must be this type */
757                    const char *estr)
758 {                               /* error message prefix */
759     data = asn_parse_header(data, datalength, type);
760     if (data && (*type != expected_type)) {
761         char            ebuf[128];
762         snprintf(ebuf, sizeof(ebuf),
763                  "%s header type %02X: s/b %02X", estr,
764                 (u_char) * type, (u_char) expected_type);
765         ebuf[ sizeof(ebuf)-1 ] = 0;
766         ERROR_MSG(ebuf);
767         return NULL;
768     }
769     return data;
770 }
771
772
773
774 /*
775  * asn_build_header - builds an ASN header for an object with the ID and
776  * length specified.
777  *  On entry, datalength is input as the number of valid bytes following
778  *   "data".  On exit, it is returned as the number of valid bytes
779  *   in this object following the id and length.
780  *
781  *  This only works on data types < 30, i.e. no extension octets.
782  *  The maximum length is 0xFFFF;
783  *
784  *  Returns a pointer to the first byte of the contents of this object.
785  *  Returns NULL on any error.
786  
787  u_char * asn_build_header(
788  u_char     *data         IN - pointer to start of object
789  size_t     *datalength   IN/OUT - number of valid bytes left in buffer
790  u_char      type         IN - asn type of object
791  size_t      length       IN - length of object
792  */
793 u_char         *
794 asn_build_header(u_char * data,
795                  size_t * datalength, u_char type, size_t length)
796 {
797     char            ebuf[128];
798
799     if (*datalength < 1) {
800         snprintf(ebuf, sizeof(ebuf),
801                 "bad header length < 1 :%d, %d", *datalength,
802                 length);
803         ebuf[ sizeof(ebuf)-1 ] = 0;
804         ERROR_MSG(ebuf);
805         return NULL;
806     }
807     *data++ = type;
808     (*datalength)--;
809     return asn_build_length(data, datalength, length);
810 }
811
812 /*
813  * asn_build_sequence - builds an ASN header for a sequence with the ID and
814  * length specified.
815  *  On entry, datalength is input as the number of valid bytes following
816  *   "data".  On exit, it is returned as the number of valid bytes
817  *   in this object following the id and length.
818  *
819  *  This only works on data types < 30, i.e. no extension octets.
820  *  The maximum length is 0xFFFF;
821  *
822  *  Returns a pointer to the first byte of the contents of this object.
823  *  Returns NULL on any error.
824  
825  u_char * asn_build_sequence(
826  u_char     *data         IN - pointer to start of object
827  int        *datalength   IN/OUT - number of valid bytes left in buffer
828  u_char      type         IN - asn type of object
829  int         length       IN - length of object
830  */
831 u_char         *
832 asn_build_sequence(u_char * data,
833                    size_t * datalength, u_char type, size_t length)
834 {
835     static const char *errpre = "build seq";
836     char            ebuf[128];
837
838     if (*datalength < 4) {
839         snprintf(ebuf, sizeof(ebuf),
840                 "%s: length %d < 4: PUNT", errpre,
841                 (int) *datalength);
842         ebuf[ sizeof(ebuf)-1 ] = 0;
843         ERROR_MSG(ebuf);
844         return NULL;
845     }
846     *datalength -= 4;
847     *data++ = type;
848     *data++ = (u_char) (0x02 | ASN_LONG_LEN);
849     *data++ = (u_char) ((length >> 8) & 0xFF);
850     *data++ = (u_char) (length & 0xFF);
851     return data;
852 }
853
854 /*
855  * asn_parse_length - interprets the length of the current object.
856  *  On exit, length contains the value of this length field.
857  *
858  *  Returns a pointer to the first byte after this length
859  *  field (aka: the start of the data field).
860  *  Returns NULL on any error.
861  
862  u_char * asn_parse_length(
863  u_char     *data         IN - pointer to start of length field
864  u_long     *length       OUT - value of length field
865  */
866 u_char         *
867 asn_parse_length(u_char * data, u_long * length)
868 {
869     static const char *errpre = "parse length";
870     char            ebuf[128];
871     register u_char lengthbyte;
872
873     if (!data || !length) {
874         ERROR_MSG("parse length: NULL pointer");
875         return NULL;
876     }
877     lengthbyte = *data;
878
879     if (lengthbyte & ASN_LONG_LEN) {
880         lengthbyte &= ~ASN_LONG_LEN;    /* turn MSb off */
881         if (lengthbyte == 0) {
882             snprintf(ebuf, sizeof(ebuf),
883                      "%s: indefinite length not supported", errpre);
884             ebuf[ sizeof(ebuf)-1 ] = 0;
885             ERROR_MSG(ebuf);
886             return NULL;
887         }
888         if (lengthbyte > sizeof(long)) {
889             snprintf(ebuf, sizeof(ebuf),
890                     "%s: data length %d > %d not supported", errpre,
891                     lengthbyte, sizeof(long));
892             ebuf[ sizeof(ebuf)-1 ] = 0;
893             ERROR_MSG(ebuf);
894             return NULL;
895         }
896         data++;
897         *length = 0;            /* protect against short lengths */
898         while (lengthbyte--) {
899             *length <<= 8;
900             *length |= *data++;
901         }
902         if ((long) *length < 0) {
903             snprintf(ebuf, sizeof(ebuf),
904                      "%s: negative data length %ld\n", errpre,
905                      (long) *length);
906             ebuf[ sizeof(ebuf)-1 ] = 0;
907             ERROR_MSG(ebuf);
908             return NULL;
909         }
910         return data;
911     } else {                    /* short asnlength */
912         *length = (long) lengthbyte;
913         return data + 1;
914     }
915 }
916
917 /*
918  * 
919  * u_char * asn_build_length(
920  * u_char     *data         IN - pointer to start of object
921  * int        *datalength   IN/OUT - number of valid bytes left in buffer
922  * int         length       IN - length of object
923  */
924 u_char         *
925 asn_build_length(u_char * data, size_t * datalength, size_t length)
926 {
927     static const char *errpre = "build length";
928     char            ebuf[128];
929
930     u_char         *start_data = data;
931
932     /*
933      * no indefinite lengths sent 
934      */
935     if (length < 0x80) {
936         if (*datalength < 1) {
937             snprintf(ebuf, sizeof(ebuf),
938                     "%s: bad length < 1 :%d, %d", errpre,
939                     *datalength, length);
940             ebuf[ sizeof(ebuf)-1 ] = 0;
941             ERROR_MSG(ebuf);
942             return NULL;
943         }
944         *data++ = (u_char) length;
945     } else if (length <= 0xFF) {
946         if (*datalength < 2) {
947             snprintf(ebuf, sizeof(ebuf),
948                     "%s: bad length < 2 :%d, %d", errpre,
949                     *datalength, length);
950             ebuf[ sizeof(ebuf)-1 ] = 0;
951             ERROR_MSG(ebuf);
952             return NULL;
953         }
954         *data++ = (u_char) (0x01 | ASN_LONG_LEN);
955         *data++ = (u_char) length;
956     } else {                    /* 0xFF < length <= 0xFFFF */
957         if (*datalength < 3) {
958             snprintf(ebuf, sizeof(ebuf),
959                     "%s: bad length < 3 :%d, %d", errpre,
960                     *datalength, length);
961             ebuf[ sizeof(ebuf)-1 ] = 0;
962             ERROR_MSG(ebuf);
963             return NULL;
964         }
965         *data++ = (u_char) (0x02 | ASN_LONG_LEN);
966         *data++ = (u_char) ((length >> 8) & 0xFF);
967         *data++ = (u_char) (length & 0xFF);
968     }
969     *datalength -= (data - start_data);
970     return data;
971
972 }
973
974 /*
975  * asn_parse_objid - pulls an object indentifier out of an ASN object identifier type.
976  *  On entry, datalength is input as the number of valid bytes following
977  *   "data".  On exit, it is returned as the number of valid bytes
978  *   following the beginning of the next object.
979  *
980  *  "objid" is filled with the object identifier.
981  *
982  *  Returns a pointer to the first byte past the end
983  *   of this object (i.e. the start of the next object).
984  *  Returns NULL on any error.
985  
986  u_char * asn_parse_objid(
987  u_char     *data         IN - pointer to start of object
988  int        *datalength   IN/OUT - number of valid bytes left in buffer
989  u_char     *type         OUT - asn type of object
990  oid        *objid        IN/OUT - pointer to start of output buffer
991  int        *objidlength  IN/OUT - number of sub-id's in objid
992  */
993 u_char         *
994 asn_parse_objid(u_char * data,
995                 size_t * datalength,
996                 u_char * type, oid * objid, size_t * objidlength)
997 {
998     /*
999      * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
1000      * subidentifier ::= {leadingbyte}* lastbyte
1001      * leadingbyte ::= 1 7bitvalue
1002      * lastbyte ::= 0 7bitvalue
1003      */
1004     register u_char *bufp = data;
1005     register oid   *oidp = objid + 1;
1006     register u_long subidentifier;
1007     register long   length;
1008     u_long          asn_length;
1009
1010     *type = *bufp++;
1011     bufp = asn_parse_length(bufp, &asn_length);
1012     if (_asn_parse_length_check("parse objid", bufp, data,
1013                                 asn_length, *datalength))
1014         return NULL;
1015
1016     *datalength -= (int) asn_length + (bufp - data);
1017
1018     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
1019
1020     /*
1021      * Handle invalid object identifier encodings of the form 06 00 robustly 
1022      */
1023     if (asn_length == 0)
1024         objid[0] = objid[1] = 0;
1025
1026     length = asn_length;
1027     (*objidlength)--;           /* account for expansion of first byte */
1028
1029     while (length > 0 && (*objidlength)-- > 0) {
1030         subidentifier = 0;
1031         do {                    /* shift and add in low order 7 bits */
1032             subidentifier =
1033                 (subidentifier << 7) + (*(u_char *) bufp & ~ASN_BIT8);
1034             length--;
1035         } while (*(u_char *) bufp++ & ASN_BIT8);        /* last byte has high bit clear */
1036         /*
1037          * ?? note, this test will never be true, since the largest value
1038          * of subidentifier is the value of MAX_SUBID! 
1039          */
1040         if (subidentifier > (u_long) MAX_SUBID) {
1041             ERROR_MSG("subidentifier too large");
1042             return NULL;
1043         }
1044         *oidp++ = (oid) subidentifier;
1045     }
1046
1047     /*
1048      * The first two subidentifiers are encoded into the first component
1049      * with the value (X * 40) + Y, where:
1050      *  X is the value of the first subidentifier.
1051      *  Y is the value of the second subidentifier.
1052      */
1053     subidentifier = (u_long) objid[1];
1054     if (subidentifier == 0x2B) {
1055         objid[0] = 1;
1056         objid[1] = 3;
1057     } else {
1058         if (subidentifier < 40) {
1059             objid[0] = 0;
1060             objid[1] = subidentifier;
1061         } else if (subidentifier < 80) {
1062             objid[0] = 1;
1063             objid[1] = subidentifier - 40;
1064         } else {
1065             objid[0] = 2;
1066             objid[1] = subidentifier - 80;
1067         }
1068     }
1069
1070     *objidlength = (int) (oidp - objid);
1071
1072     DEBUGMSG(("dumpv_recv", "  ObjID: "));
1073     DEBUGMSGOID(("dumpv_recv", objid, *objidlength));
1074     DEBUGMSG(("dumpv_recv", "\n"));
1075     return bufp;
1076 }
1077
1078 /*
1079  * asn_build_objid - Builds an ASN object identifier object containing the
1080  * input string.
1081  *  On entry, datalength is input as the number of valid bytes following
1082  *   "data".  On exit, it is returned as the number of valid bytes
1083  *   following the beginning of the next object.
1084  *
1085  *  Returns a pointer to the first byte past the end
1086  *   of this object (i.e. the start of the next object).
1087  *  Returns NULL on any error.
1088  
1089  u_char * asn_build_objid(
1090  u_char     *data         IN - pointer to start of object
1091  int        *datalength   IN/OUT - number of valid bytes left in buffer
1092  int        type         IN - asn type of object
1093  oid        *objid        IN - pointer to start of input buffer
1094  int         objidlength  IN - number of sub-id's in objid
1095  */
1096 u_char         *
1097 asn_build_objid(u_char * data,
1098                 size_t * datalength,
1099                 u_char type, oid * objid, size_t objidlength)
1100 {
1101     /*
1102      * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
1103      * subidentifier ::= {leadingbyte}* lastbyte
1104      * leadingbyte ::= 1 7bitvalue
1105      * lastbyte ::= 0 7bitvalue
1106      */
1107     size_t          asnlength;
1108     register oid   *op = objid;
1109     u_char          objid_size[MAX_OID_LEN];
1110     register u_long objid_val;
1111     u_long          first_objid_val;
1112     register int    i;
1113 #ifndef SNMP_NO_DEBUGGING
1114     u_char         *initdatap = data;
1115 #endif
1116
1117     /*
1118      * check if there are at least 2 sub-identifiers 
1119      */
1120     if (objidlength == 0) {
1121         /*
1122          * there are not, so make OID have two with value of zero 
1123          */
1124         objid_val = 0;
1125         objidlength = 2;
1126     } else if (objid[0] > 2) {
1127         ERROR_MSG("build objid: bad first subidentifier");
1128         return NULL;
1129     } else if (objidlength == 1) {
1130         /*
1131          * encode the first value 
1132          */
1133         objid_val = (op[0] * 40);
1134         objidlength = 2;
1135         op++;
1136     } else {
1137         /*
1138          * combine the first two values 
1139          */
1140         if ((op[1] > 40) &&
1141             (op[0] < 2)) {
1142             ERROR_MSG("build objid: bad second subidentifier");
1143             return NULL;
1144         }
1145         objid_val = (op[0] * 40) + op[1];
1146         op += 2;
1147     }
1148     first_objid_val = objid_val;
1149
1150     /*
1151      * ditch illegal calls now 
1152      */
1153     if (objidlength > MAX_OID_LEN)
1154         return NULL;
1155
1156     /*
1157      * calculate the number of bytes needed to store the encoded value 
1158      */
1159     for (i = 1, asnlength = 0;;) {
1160         if (objid_val < (unsigned) 0x80) {
1161             objid_size[i] = 1;
1162             asnlength += 1;
1163         } else if (objid_val < (unsigned) 0x4000) {
1164             objid_size[i] = 2;
1165             asnlength += 2;
1166         } else if (objid_val < (unsigned) 0x200000) {
1167             objid_size[i] = 3;
1168             asnlength += 3;
1169         } else if (objid_val < (unsigned) 0x10000000) {
1170             objid_size[i] = 4;
1171             asnlength += 4;
1172         } else {
1173             objid_size[i] = 5;
1174             asnlength += 5;
1175         }
1176         i++;
1177         if (i >= (int) objidlength)
1178             break;
1179         objid_val = *op++;      /* XXX - doesn't handle 2.X (X > 40) */
1180     }
1181
1182     /*
1183      * store the ASN.1 tag and length 
1184      */
1185     data = asn_build_header(data, datalength, type, asnlength);
1186     if (_asn_build_header_check
1187         ("build objid", data, *datalength, asnlength))
1188         return NULL;
1189
1190     /*
1191      * store the encoded OID value 
1192      */
1193     for (i = 1, objid_val = first_objid_val, op = objid + 2;
1194          i < (int) objidlength; i++) {
1195         if (i != 1)
1196             objid_val = *op++;
1197         switch (objid_size[i]) {
1198         case 1:
1199             *data++ = (u_char) objid_val;
1200             break;
1201
1202         case 2:
1203             *data++ = (u_char) ((objid_val >> 7) | 0x80);
1204             *data++ = (u_char) (objid_val & 0x07f);
1205             break;
1206
1207         case 3:
1208             *data++ = (u_char) ((objid_val >> 14) | 0x80);
1209             *data++ = (u_char) ((objid_val >> 7 & 0x7f) | 0x80);
1210             *data++ = (u_char) (objid_val & 0x07f);
1211             break;
1212
1213         case 4:
1214             *data++ = (u_char) ((objid_val >> 21) | 0x80);
1215             *data++ = (u_char) ((objid_val >> 14 & 0x7f) | 0x80);
1216             *data++ = (u_char) ((objid_val >> 7 & 0x7f) | 0x80);
1217             *data++ = (u_char) (objid_val & 0x07f);
1218             break;
1219
1220         case 5:
1221             *data++ = (u_char) ((objid_val >> 28) | 0x80);
1222             *data++ = (u_char) ((objid_val >> 21 & 0x7f) | 0x80);
1223             *data++ = (u_char) ((objid_val >> 14 & 0x7f) | 0x80);
1224             *data++ = (u_char) ((objid_val >> 7 & 0x7f) | 0x80);
1225             *data++ = (u_char) (objid_val & 0x07f);
1226             break;
1227         }
1228     }
1229
1230     /*
1231      * return the length and data ptr 
1232      */
1233     *datalength -= asnlength;
1234     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
1235     DEBUGMSG(("dumpv_send", "  ObjID: "));
1236     DEBUGMSGOID(("dumpv_send", objid, objidlength));
1237     DEBUGMSG(("dumpv_send", "\n"));
1238     return data;
1239 }
1240
1241 /*
1242  * asn_parse_null - Interprets an ASN null type.
1243  *  On entry, datalength is input as the number of valid bytes following
1244  *   "data".  On exit, it is returned as the number of valid bytes
1245  *   following the beginning of the next object.
1246  *
1247  *  Returns a pointer to the first byte past the end
1248  *   of this object (i.e. the start of the next object).
1249  *  Returns NULL on any error.
1250  
1251  u_char * asn_parse_null(
1252  u_char     *data         IN - pointer to start of object
1253  int        *datalength   IN/OUT - number of valid bytes left in buffer
1254  u_char     *type         OUT - asn type of object
1255  */
1256 u_char         *
1257 asn_parse_null(u_char * data, size_t * datalength, u_char * type)
1258 {
1259     /*
1260      * ASN.1 null ::= 0x05 0x00
1261      */
1262     register u_char *bufp = data;
1263     u_long          asn_length;
1264
1265     *type = *bufp++;
1266     bufp = asn_parse_length(bufp, &asn_length);
1267     if (bufp == NULL) {
1268         ERROR_MSG("parse null: bad length");
1269         return NULL;
1270     }
1271     if (asn_length != 0) {
1272         ERROR_MSG("parse null: malformed ASN.1 null");
1273         return NULL;
1274     }
1275
1276     *datalength -= (bufp - data);
1277
1278     DEBUGDUMPSETUP("recv", data, bufp - data);
1279     DEBUGMSG(("dumpv_recv", "  NULL\n"));
1280
1281     return bufp + asn_length;
1282 }
1283
1284
1285 /*
1286  * asn_build_null - Builds an ASN null object.
1287  *  On entry, datalength is input as the number of valid bytes following
1288  *   "data".  On exit, it is returned as the number of valid bytes
1289  *   following the beginning of the next object.
1290  *
1291  *  Returns a pointer to the first byte past the end
1292  *   of this object (i.e. the start of the next object).
1293  *  Returns NULL on any error.
1294  
1295  u_char * asn_build_null(
1296  u_char     *data         IN - pointer to start of object
1297  int        *datalength   IN/OUT - number of valid bytes left in buffer
1298  u_char      type         IN - asn type of object
1299  */
1300 u_char         *
1301 asn_build_null(u_char * data, size_t * datalength, u_char type)
1302 {
1303     /*
1304      * ASN.1 null ::= 0x05 0x00
1305      */
1306 #ifndef SNMP_NO_DEBUGGING
1307     u_char         *initdatap = data;
1308 #endif
1309     data = asn_build_header(data, datalength, type, 0);
1310     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
1311     DEBUGMSG(("dumpv_send", "  NULL\n"));
1312     return data;
1313 }
1314
1315 /*
1316  * asn_parse_bitstring - pulls a bitstring out of an ASN bitstring type.
1317  *  On entry, datalength is input as the number of valid bytes following
1318  *   "data".  On exit, it is returned as the number of valid bytes
1319  *   following the beginning of the next object.
1320  *
1321  *  "string" is filled with the bit string.
1322  *
1323  *  Returns a pointer to the first byte past the end
1324  *   of this object (i.e. the start of the next object).
1325  *  Returns NULL on any error.
1326  
1327  u_char * asn_parse_bitstring(
1328  u_char     *data         IN - pointer to start of object
1329  size_t     *datalength   IN/OUT - number of valid bytes left in buffer
1330  u_char     *type         OUT - asn type of object
1331  u_char     *string       IN/OUT - pointer to start of output buffer
1332  size_t     *strlength    IN/OUT - size of output buffer
1333  */
1334 u_char         *
1335 asn_parse_bitstring(u_char * data,
1336                     size_t * datalength,
1337                     u_char * type, u_char * string, size_t * strlength)
1338 {
1339     /*
1340      * bitstring ::= 0x03 asnlength unused {byte}*
1341      */
1342     static const char *errpre = "parse bitstring";
1343     register u_char *bufp = data;
1344     u_long          asn_length;
1345
1346     *type = *bufp++;
1347     bufp = asn_parse_length(bufp, &asn_length);
1348     if (_asn_parse_length_check(errpre, bufp, data,
1349                                 asn_length, *datalength))
1350         return NULL;
1351
1352     if ((size_t) asn_length > *strlength) {
1353         _asn_length_err(errpre, (size_t) asn_length, *strlength);
1354         return NULL;
1355     }
1356     if (_asn_bitstring_check(errpre, asn_length, *bufp))
1357         return NULL;
1358
1359     DEBUGDUMPSETUP("recv", data, bufp - data);
1360     DEBUGMSG(("dumpv_recv", "  Bitstring: "));
1361     DEBUGMSGHEX(("dumpv_recv", data, asn_length));
1362     DEBUGMSG(("dumpv_recv", "\n"));
1363
1364     memmove(string, bufp, asn_length);
1365     *strlength = (int) asn_length;
1366     *datalength -= (int) asn_length + (bufp - data);
1367     return bufp + asn_length;
1368 }
1369
1370
1371 /*
1372  * asn_build_bitstring - Builds an ASN bit string object containing the
1373  * input string.
1374  *  On entry, datalength is input as the number of valid bytes following
1375  *   "data".  On exit, it is returned as the number of valid bytes
1376  *   following the beginning of the next object.
1377  *
1378  *  Returns a pointer to the first byte past the end
1379  *   of this object (i.e. the start of the next object).
1380  *  Returns NULL on any error.
1381  
1382  u_char * asn_build_bitstring(
1383  u_char     *data         IN - pointer to start of object
1384  int        *datalength   IN/OUT - number of valid bytes left in buffer
1385  u_char      type         IN - asn type of object
1386  u_char     *string       IN - pointer to start of input buffer
1387  int         strlength    IN - size of input buffer
1388  */
1389 u_char         *
1390 asn_build_bitstring(u_char * data,
1391                     size_t * datalength,
1392                     u_char type, u_char * string, size_t strlength)
1393 {
1394     /*
1395      * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
1396      */
1397     static const char *errpre = "build bitstring";
1398     if (_asn_bitstring_check
1399         (errpre, strlength, ((string) ? *string : (u_char) 0)))
1400         return NULL;
1401
1402     data = asn_build_header(data, datalength, type, strlength);
1403     if (_asn_build_header_check(errpre, data, *datalength, strlength))
1404         return NULL;
1405
1406     if (strlength > 0 && string)
1407         memmove(data, string, strlength);
1408     else if (strlength > 0 && !string) {
1409         ERROR_MSG("no string passed into asn_build_bitstring\n");
1410         return NULL;
1411     }
1412
1413     *datalength -= strlength;
1414     DEBUGDUMPSETUP("send", data, strlength);
1415     DEBUGMSG(("dumpv_send", "  Bitstring: "));
1416     DEBUGMSGHEX(("dumpv_send", data, strlength));
1417     DEBUGMSG(("dumpv_send", "\n"));
1418     return data + strlength;
1419 }
1420
1421 #ifdef BRCM_SNMP_SUPPORT
1422 /*
1423  * asn_parse_unsigned_int64 - pulls a 64 bit unsigned long out of an ASN int
1424  * type.
1425  *  On entry, datalength is input as the number of valid bytes following
1426  *   "data".  On exit, it is returned as the number of valid bytes
1427  *   following the end of this object.
1428  *
1429  *  Returns a pointer to the first byte past the end
1430  *   of this object (i.e. the start of the next object).
1431  *  Returns NULL on any error.
1432  
1433  u_char * asn_parse_unsigned_int64(
1434  u_char     *data         IN - pointer to start of object
1435  int        *datalength   IN/OUT - number of valid bytes left in buffer
1436  u_char     *type         OUT - asn type of object
1437  struct counter64 *cp     IN/OUT - pointer to counter struct
1438  int         countersize  IN - size of output buffer
1439  */
1440 u_char         *
1441 asn_parse_unsigned_int64(u_char * data,
1442                          size_t * datalength,
1443                          u_char * type,
1444                          struct counter64 * cp, size_t countersize)
1445 {
1446     /*
1447      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
1448      */
1449     static const char *errpre = "parse uint64";
1450     const int       uint64sizelimit = (4 * 2) + 1;
1451     register u_char *bufp = data;
1452     u_long          asn_length;
1453     register u_long low = 0, high = 0;
1454
1455     if (countersize != sizeof(struct counter64)) {
1456         _asn_size_err(errpre, countersize, sizeof(struct counter64));
1457         return NULL;
1458     }
1459     *type = *bufp++;
1460     bufp = asn_parse_length(bufp, &asn_length);
1461     if (_asn_parse_length_check
1462         (errpre, bufp, data, asn_length, *datalength))
1463         return NULL;
1464
1465     DEBUGDUMPSETUP("recv", data, bufp - data);
1466 #ifdef OPAQUE_SPECIAL_TYPES
1467     /*
1468      * 64 bit counters as opaque 
1469      */
1470     if ((*type == ASN_OPAQUE) &&
1471         (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
1472         (*bufp == ASN_OPAQUE_TAG1) &&
1473         ((*(bufp + 1) == ASN_OPAQUE_COUNTER64) ||
1474          (*(bufp + 1) == ASN_OPAQUE_U64))) {
1475         /*
1476          * change type to Counter64 or U64 
1477          */
1478         *type = *(bufp + 1);
1479         /*
1480          * value is encoded as special format 
1481          */
1482         bufp = asn_parse_length(bufp + 2, &asn_length);
1483         if (_asn_parse_length_check("parse opaque uint64", bufp, data,
1484                                     asn_length, *datalength))
1485             return NULL;
1486     }
1487 #endif                          /* OPAQUE_SPECIAL_TYPES */
1488     if (((int) asn_length > uint64sizelimit) ||
1489         (((int) asn_length == uint64sizelimit) && *bufp != 0x00)) {
1490         _asn_length_err(errpre, (size_t) asn_length, uint64sizelimit);
1491         return NULL;
1492     }
1493     *datalength -= (int) asn_length + (bufp - data);
1494     if (*bufp & 0x80) {
1495         low = ~low;             /* integer is negative */
1496         high = ~high;
1497     }
1498
1499     while (asn_length--) {
1500         high = (high << 8) | ((low & 0xFF000000) >> 24);
1501         low = (low << 8) | *bufp++;
1502     }
1503
1504     cp->low = low;
1505     cp->high = high;
1506
1507     DEBUGIF("dumpv_recv") {
1508         char            i64buf[I64CHARSZ + 1];
1509         printU64(i64buf, cp);
1510         DEBUGMSG(("dumpv_recv", "Counter64: ", i64buf));
1511     }
1512
1513     return bufp;
1514 }
1515
1516
1517 /*
1518  * asn_build_unsigned_int64 - builds an ASN object containing a 64 bit integer.
1519  *  On entry, datalength is input as the number of valid bytes following
1520  *   "data".  On exit, it is returned as the number of valid bytes
1521  *   following the end of this object.
1522  *
1523  *  Returns a pointer to the first byte past the end
1524  *   of this object (i.e. the start of the next object).
1525  *  Returns NULL on any error.
1526  
1527  u_char * asn_build_unsigned_int64(
1528  u_char     *data         IN - pointer to start of output buffer
1529  size_t     *datalength   IN/OUT - number of valid bytes left in buffer
1530  u_char      type         IN  - asn type of object
1531  struct counter64 *cp     IN - pointer to counter struct
1532  size_t      countersize  IN - size of input buffer
1533  */
1534 u_char         *
1535 asn_build_unsigned_int64(u_char * data,
1536                          size_t * datalength,
1537                          u_char type,
1538                          struct counter64 * cp, size_t countersize)
1539 {
1540     /*
1541      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
1542      */
1543
1544     register u_long low, high;
1545     register u_long mask, mask2;
1546     int             add_null_byte = 0;
1547     size_t          intsize;
1548 #ifndef SNMP_NO_DEBUGGING
1549     u_char         *initdatap = data;
1550 #endif
1551
1552     if (countersize != sizeof(struct counter64)) {
1553         _asn_size_err("build uint64", countersize,
1554                       sizeof(struct counter64));
1555         return NULL;
1556     }
1557     intsize = 8;
1558     low = cp->low;
1559     high = cp->high;
1560     mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
1561     /*
1562      * mask is 0xFF000000 on a big-endian machine 
1563      */
1564     if ((u_char) ((high & mask) >> (8 * (sizeof(long) - 1))) & 0x80) {
1565         /*
1566          * if MSB is set 
1567          */
1568         add_null_byte = 1;
1569         intsize++;
1570     } else {
1571         /*
1572          * Truncate "unnecessary" bytes off of the most significant end of this 2's
1573          * complement integer.
1574          * There should be no sequence of 9 consecutive 1's or 0's at the most
1575          * significant end of the integer.
1576          */
1577         mask2 = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
1578         /*
1579          * mask2 is 0xFF800000 on a big-endian machine 
1580          */
1581         while ((((high & mask2) == 0) || ((high & mask2) == mask2))
1582                && intsize > 1) {
1583             intsize--;
1584             high = (high << 8)
1585                 | ((low & mask) >> (8 * (sizeof(long) - 1)));
1586             low <<= 8;
1587         }
1588     }
1589 #ifdef OPAQUE_SPECIAL_TYPES
1590     /*
1591      * encode a Counter64 as an opaque (it also works in SNMPv1) 
1592      */
1593     /*
1594      * turn into Opaque holding special tagged value 
1595      */
1596     if (type == ASN_OPAQUE_COUNTER64) {
1597         /*
1598          * put the tag and length for the Opaque wrapper 
1599          */
1600         data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
1601         if (_asn_build_header_check
1602             ("build counter u64", data, *datalength, intsize + 3))
1603             return NULL;
1604
1605         /*
1606          * put the special tag and length 
1607          */
1608         *data++ = ASN_OPAQUE_TAG1;
1609         *data++ = ASN_OPAQUE_COUNTER64;
1610         *data++ = (u_char) intsize;
1611         *datalength = *datalength - 3;
1612     } else
1613         /*
1614          * Encode the Unsigned int64 in an opaque 
1615          */
1616         /*
1617          * turn into Opaque holding special tagged value 
1618          */
1619     if (type == ASN_OPAQUE_U64) {
1620         /*
1621          * put the tag and length for the Opaque wrapper 
1622          */
1623         data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
1624         if (_asn_build_header_check
1625             ("build opaque u64", data, *datalength, intsize + 3))
1626             return NULL;
1627
1628         /*
1629          * put the special tag and length 
1630          */
1631         *data++ = ASN_OPAQUE_TAG1;
1632         *data++ = ASN_OPAQUE_U64;
1633         *data++ = (u_char) intsize;
1634         *datalength = *datalength - 3;
1635     } else {
1636 #endif                          /* OPAQUE_SPECIAL_TYPES */
1637         data = asn_build_header(data, datalength, type, intsize);
1638         if (_asn_build_header_check
1639             ("build uint64", data, *datalength, intsize))
1640             return NULL;
1641
1642 #ifdef OPAQUE_SPECIAL_TYPES
1643     }
1644 #endif                          /* OPAQUE_SPECIAL_TYPES */
1645     *datalength -= intsize;
1646     if (add_null_byte == 1) {
1647         *data++ = '\0';
1648         intsize--;
1649     }
1650     while (intsize--) {
1651         *data++ = (u_char) ((high & mask) >> (8 * (sizeof(long) - 1)));
1652         high = (high << 8)
1653             | ((low & mask) >> (8 * (sizeof(long) - 1)));
1654         low <<= 8;
1655
1656     }
1657     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
1658     DEBUGIF("dumpv_send") {
1659         char            i64buf[I64CHARSZ + 1];
1660         printU64(i64buf, cp);
1661         DEBUGMSG(("dumpv_send", i64buf));
1662     }
1663     return data;
1664 }
1665
1666 #ifdef OPAQUE_SPECIAL_TYPES
1667
1668 /*
1669  * 
1670  * u_char * asn_parse_signed_int64(
1671  * u_char     *data         IN - pointer to start of object
1672  * int        *datalength   IN/OUT - number of valid bytes left in buffer
1673  * u_char     *type         OUT - asn type of object
1674  * struct counter64 *cp     IN/OUT - pointer to counter struct
1675  * int         countersize  IN - size of output buffer
1676  */
1677
1678 u_char         *
1679 asn_parse_signed_int64(u_char * data,
1680                        size_t * datalength,
1681                        u_char * type,
1682                        struct counter64 * cp, size_t countersize)
1683 {
1684     static const char *errpre = "parse int64";
1685     const int       int64sizelimit = (4 * 2) + 1;
1686     char            ebuf[128];
1687     register u_char *bufp = data;
1688     u_long          asn_length;
1689     register u_int  low = 0, high = 0;
1690
1691     if (countersize != sizeof(struct counter64)) {
1692         _asn_size_err(errpre, countersize, sizeof(struct counter64));
1693         return NULL;
1694     }
1695     *type = *bufp++;
1696     bufp = asn_parse_length(bufp, &asn_length);
1697     if (_asn_parse_length_check
1698         (errpre, bufp, data, asn_length, *datalength))
1699         return NULL;
1700
1701     DEBUGDUMPSETUP("recv", data, bufp - data);
1702     if ((*type == ASN_OPAQUE) &&
1703         (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
1704         (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_I64)) {
1705         /*
1706          * change type to Int64 
1707          */
1708         *type = *(bufp + 1);
1709         /*
1710          * value is encoded as special format 
1711          */
1712         bufp = asn_parse_length(bufp + 2, &asn_length);
1713         if (_asn_parse_length_check("parse opaque int64", bufp, data,
1714                                     asn_length, *datalength))
1715             return NULL;
1716     }
1717     /*
1718      * this should always have been true until snmp gets int64 PDU types 
1719      */
1720     else {
1721         snprintf(ebuf, sizeof(ebuf),
1722                 "%s: wrong type: %d, len %d, buf bytes (%02X,%02X)",
1723                 errpre, *type, (int) asn_length, *bufp, *(bufp + 1));
1724         ebuf[ sizeof(ebuf)-1 ] = 0;
1725         ERROR_MSG(ebuf);
1726         return NULL;
1727     }
1728     if (((int) asn_length > int64sizelimit) ||
1729         (((int) asn_length == int64sizelimit) && *bufp != 0x00)) {
1730         _asn_length_err(errpre, (size_t) asn_length, int64sizelimit);
1731         return NULL;
1732     }
1733     *datalength -= (int) asn_length + (bufp - data);
1734     if (*bufp & 0x80) {
1735         low = ~low;             /* integer is negative */
1736         high = ~high;
1737     }
1738
1739     while (asn_length--) {
1740         high = (high << 8) | ((low & 0xFF000000) >> 24);
1741         low = (low << 8) | *bufp++;
1742     }
1743
1744     cp->low = low;
1745     cp->high = high;
1746
1747     DEBUGIF("dumpv_recv") {
1748         char            i64buf[I64CHARSZ + 1];
1749         printI64(i64buf, cp);
1750         DEBUGMSG(("dumpv_recv", "Integer64: %s", i64buf));
1751     }
1752
1753     return bufp;
1754 }
1755
1756
1757 /*
1758  * 
1759  * u_char * asn_build_signed_int64(
1760  * u_char     *data         IN - pointer to start of object
1761  * int        *datalength   IN/OUT - number of valid bytes left in buffer
1762  * u_char      type         IN - asn type of object
1763  * struct counter64 *cp     IN - pointer to counter struct
1764  * int         countersize  IN - size of input buffer
1765  */
1766 u_char         *
1767 asn_build_signed_int64(u_char * data,
1768                        size_t * datalength,
1769                        u_char type,
1770                        struct counter64 * cp, size_t countersize)
1771 {
1772     /*
1773      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
1774      */
1775
1776     struct counter64 c64;
1777     register u_int  mask, mask2;
1778     u_long          low, high;
1779     size_t          intsize;
1780 #ifndef SNMP_NO_DEBUGGING
1781     u_char         *initdatap = data;
1782 #endif
1783
1784     if (countersize != sizeof(struct counter64)) {
1785         _asn_size_err("build int64", countersize,
1786                       sizeof(struct counter64));
1787         return NULL;
1788     }
1789     intsize = 8;
1790     memcpy(&c64, cp, sizeof(struct counter64)); /* we're may modify it */
1791     low = c64.low;
1792     high = c64.high;
1793
1794     /*
1795      * Truncate "unnecessary" bytes off of the most significant end of this
1796      * 2's complement integer.  There should be no sequence of 9
1797      * consecutive 1's or 0's at the most significant end of the
1798      * integer.
1799      */
1800     mask = ((u_int) 0xFF) << (8 * (sizeof(u_int) - 1));
1801     mask2 = ((u_int) 0x1FF) << ((8 * (sizeof(u_int) - 1)) - 1);
1802     /*
1803      * mask is 0xFF800000 on a big-endian machine 
1804      */
1805     while ((((high & mask2) == 0) || ((high & mask2) == mask2))
1806            && intsize > 1) {
1807         intsize--;
1808         high = (high << 8)
1809             | ((low & mask) >> (8 * (sizeof(u_int) - 1)));
1810         low <<= 8;
1811     }
1812     /*
1813      * until a real int64 gets incorperated into SNMP, we are going to
1814      * encode it as an opaque instead.  First, we build the opaque
1815      * header and then the int64 tag type we use to mark it as an
1816      * int64 in the opaque string. 
1817      */
1818     data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
1819     if (_asn_build_header_check
1820         ("build int64", data, *datalength, intsize + 3))
1821         return NULL;
1822
1823     *data++ = ASN_OPAQUE_TAG1;
1824     *data++ = ASN_OPAQUE_I64;
1825     *data++ = (u_char) intsize;
1826     *datalength -= (3 + intsize);
1827
1828     while (intsize--) {
1829         *data++ = (u_char) ((high & mask) >> (8 * (sizeof(u_int) - 1)));
1830         high = (high << 8)
1831             | ((low & mask) >> (8 * (sizeof(u_int) - 1)));
1832         low <<= 8;
1833     }
1834     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
1835     DEBUGIF("dumpv_send") {
1836         char            i64buf[I64CHARSZ + 1];
1837         printU64(i64buf, cp);
1838         DEBUGMSG(("dumpv_send", i64buf));
1839     }
1840     return data;
1841 }
1842
1843
1844 /*
1845  * asn_parse_float - pulls a single precision floating-point out of an opaque type.
1846  *
1847  *  On entry, datalength is input as the number of valid bytes following
1848  *   "data".  On exit, it is returned as the number of valid bytes
1849  *   following the end of this object.
1850  *
1851  *  Returns a pointer to the first byte past the end
1852  *   of this object (i.e. the start of the next object).
1853  *  Returns NULL on any error.
1854  
1855  u_char * asn_parse_float(
1856  u_char     *data         IN - pointer to start of object
1857  int        *datalength   IN/OUT - number of valid bytes left in buffer
1858  u_char     *type         OUT - asn type of object
1859  float      *floatp       IN/OUT - pointer to float
1860  int         floatsize    IN - size of output buffer
1861  */
1862 u_char         *
1863 asn_parse_float(u_char * data,
1864                 size_t * datalength,
1865                 u_char * type, float *floatp, size_t floatsize)
1866 {
1867     register u_char *bufp = data;
1868     u_long          asn_length;
1869     union {
1870         float           floatVal;
1871         long            longVal;
1872         u_char          c[sizeof(float)];
1873     } fu;
1874
1875     if (floatsize != sizeof(float)) {
1876         _asn_size_err("parse float", floatsize, sizeof(float));
1877         return NULL;
1878     }
1879     *type = *bufp++;
1880     bufp = asn_parse_length(bufp, &asn_length);
1881     if (_asn_parse_length_check("parse float", bufp, data,
1882                                 asn_length, *datalength))
1883         return NULL;
1884
1885     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
1886     /*
1887      * the float is encoded as an opaque 
1888      */
1889     if ((*type == ASN_OPAQUE) &&
1890         (asn_length == ASN_OPAQUE_FLOAT_BER_LEN) &&
1891         (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_FLOAT)) {
1892
1893         /*
1894          * value is encoded as special format 
1895          */
1896         bufp = asn_parse_length(bufp + 2, &asn_length);
1897         if (_asn_parse_length_check("parse opaque float", bufp, data,
1898                                     asn_length, *datalength))
1899             return NULL;
1900
1901         /*
1902          * change type to Float 
1903          */
1904         *type = ASN_OPAQUE_FLOAT;
1905     }
1906
1907     if (asn_length != sizeof(float)) {
1908         _asn_size_err("parse seq float", asn_length, sizeof(float));
1909         return NULL;
1910     }
1911
1912     *datalength -= (int) asn_length + (bufp - data);
1913     memcpy(&fu.c[0], bufp, asn_length);
1914
1915     /*
1916      * correct for endian differences 
1917      */
1918     fu.longVal = ntohl(fu.longVal);
1919
1920     *floatp = fu.floatVal;
1921
1922     DEBUGMSG(("dumpv_recv", "Opaque float: %f\n", *floatp));
1923     return bufp;
1924 }
1925
1926 /*
1927  * asn_build_float - builds an ASN object containing a single precision floating-point
1928  *                    number in an Opaque value.
1929  *
1930  *  On entry, datalength is input as the number of valid bytes following
1931  *   "data".  On exit, it is returned as the number of valid bytes
1932  *   following the end of this object.
1933  *
1934  *  Returns a pointer to the first byte past the end
1935  *   of this object (i.e. the start of the next object).
1936  *  Returns NULL on any error.
1937  
1938  u_char * asn_build_float(
1939  u_char     *data         IN - pointer to start of object
1940  int        *datalength   IN/OUT - number of valid bytes left in buffer
1941  u_char      type         IN - asn type of object
1942  float      *floatp       IN - pointer to float
1943  int         floatsize    IN - size of input buffer
1944  */
1945 u_char         *
1946 asn_build_float(u_char * data,
1947                 size_t * datalength,
1948                 u_char type, float *floatp, size_t floatsize)
1949 {
1950     union {
1951         float           floatVal;
1952         int             intVal;
1953         u_char          c[sizeof(float)];
1954     } fu;
1955 #ifndef SNMP_NO_DEBUGGING
1956     u_char         *initdatap = data;
1957 #endif
1958
1959     if (floatsize != sizeof(float)) {
1960         _asn_size_err("build float", floatsize, sizeof(float));
1961         return NULL;
1962     }
1963     /*
1964      * encode the float as an opaque 
1965      */
1966     /*
1967      * turn into Opaque holding special tagged value 
1968      */
1969
1970     /*
1971      * put the tag and length for the Opaque wrapper 
1972      */
1973     data = asn_build_header(data, datalength, ASN_OPAQUE, floatsize + 3);
1974     if (_asn_build_header_check
1975         ("build float", data, *datalength, (floatsize + 3)))
1976         return NULL;
1977
1978     /*
1979      * put the special tag and length 
1980      */
1981     *data++ = ASN_OPAQUE_TAG1;
1982     *data++ = ASN_OPAQUE_FLOAT;
1983     *data++ = (u_char) floatsize;
1984     *datalength = *datalength - 3;
1985
1986     fu.floatVal = *floatp;
1987     /*
1988      * correct for endian differences 
1989      */
1990     fu.intVal = htonl(fu.intVal);
1991
1992     *datalength -= floatsize;
1993     memcpy(data, &fu.c[0], floatsize);
1994
1995     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
1996     DEBUGMSG(("dumpv_send", "Opaque float: %f\n", *floatp));
1997     data += floatsize;
1998     return data;
1999 }
2000
2001 /*
2002  * 
2003  * u_char * asn_parse_double(
2004  * u_char     *data         IN - pointer to start of object
2005  * int        *datalength   IN/OUT - number of valid bytes left in buffer
2006  * u_char     *type         OUT - asn type of object
2007  * double     *doublep      IN/OUT - pointer to double
2008  * int         doublesize   IN - size of output buffer
2009  */
2010 u_char         *
2011 asn_parse_double(u_char * data,
2012                  size_t * datalength,
2013                  u_char * type, double *doublep, size_t doublesize)
2014 {
2015     register u_char *bufp = data;
2016     u_long          asn_length;
2017     long            tmp;
2018     union {
2019         double          doubleVal;
2020         int             intVal[2];
2021         u_char          c[sizeof(double)];
2022     } fu;
2023
2024
2025     if (doublesize != sizeof(double)) {
2026         _asn_size_err("parse double", doublesize, sizeof(double));
2027         return NULL;
2028     }
2029     *type = *bufp++;
2030     bufp = asn_parse_length(bufp, &asn_length);
2031     if (_asn_parse_length_check("parse double", bufp, data,
2032                                 asn_length, *datalength))
2033         return NULL;
2034
2035     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2036     /*
2037      * the double is encoded as an opaque 
2038      */
2039     if ((*type == ASN_OPAQUE) &&
2040         (asn_length == ASN_OPAQUE_DOUBLE_BER_LEN) &&
2041         (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_DOUBLE)) {
2042
2043         /*
2044          * value is encoded as special format 
2045          */
2046         bufp = asn_parse_length(bufp + 2, &asn_length);
2047         if (_asn_parse_length_check("parse opaque double", bufp, data,
2048                                     asn_length, *datalength))
2049             return NULL;
2050
2051         /*
2052          * change type to Double 
2053          */
2054         *type = ASN_OPAQUE_DOUBLE;
2055     }
2056
2057     if (asn_length != sizeof(double)) {
2058         _asn_size_err("parse seq double", asn_length, sizeof(double));
2059         return NULL;
2060     }
2061     *datalength -= (int) asn_length + (bufp - data);
2062     memcpy(&fu.c[0], bufp, asn_length);
2063
2064     /*
2065      * correct for endian differences 
2066      */
2067
2068     tmp = ntohl(fu.intVal[0]);
2069     fu.intVal[0] = ntohl(fu.intVal[1]);
2070     fu.intVal[1] = tmp;
2071
2072     *doublep = fu.doubleVal;
2073     DEBUGMSG(("dumpv_recv", "  Opaque Double:\t%f\n", *doublep));
2074
2075     return bufp;
2076 }
2077 #endif /* BRCM_SNMP_SUPPORT */
2078
2079 /*
2080  * 
2081  * u_char * asn_build_double(
2082  * u_char     *data         IN - pointer to start of object
2083  * int        *datalength   IN/OUT - number of valid bytes left in buffer
2084  * u_char      type         IN - asn type of object
2085  * double     *doublep      IN - pointer to double
2086  * int         doublesize   IN - size of input buffer
2087  */
2088 u_char         *
2089 asn_build_double(u_char * data,
2090                  size_t * datalength,
2091                  u_char type, double *doublep, size_t doublesize)
2092 {
2093     long            tmp;
2094     union {
2095         double          doubleVal;
2096         int             intVal[2];
2097         u_char          c[sizeof(double)];
2098     } fu;
2099 #ifndef SNMP_NO_DEBUGGING
2100     u_char         *initdatap = data;
2101 #endif
2102
2103     if (doublesize != sizeof(double)) {
2104         _asn_size_err("build double", doublesize, sizeof(double));
2105         return NULL;
2106     }
2107
2108     /*
2109      * encode the double as an opaque 
2110      */
2111     /*
2112      * turn into Opaque holding special tagged value 
2113      */
2114
2115     /*
2116      * put the tag and length for the Opaque wrapper 
2117      */
2118     data = asn_build_header(data, datalength, ASN_OPAQUE, doublesize + 3);
2119     if (_asn_build_header_check
2120         ("build double", data, *datalength, doublesize + 3))
2121         return NULL;
2122
2123     /*
2124      * put the special tag and length 
2125      */
2126     *data++ = ASN_OPAQUE_TAG1;
2127     *data++ = ASN_OPAQUE_DOUBLE;
2128     *data++ = (u_char) doublesize;
2129     *datalength = *datalength - 3;
2130
2131     fu.doubleVal = *doublep;
2132     /*
2133      * correct for endian differences 
2134      */
2135     tmp = htonl(fu.intVal[0]);
2136     fu.intVal[0] = htonl(fu.intVal[1]);
2137     fu.intVal[1] = tmp;
2138     *datalength -= doublesize;
2139     memcpy(data, &fu.c[0], doublesize);
2140
2141     data += doublesize;
2142     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2143     DEBUGMSG(("dumpv_send", "  Opaque double: %f", *doublep));
2144     return data;
2145 }
2146
2147 #endif                          /* OPAQUE_SPECIAL_TYPES */
2148
2149
2150 /*
2151  * This function increases the size of the buffer pointed to by *pkt, which
2152  * is initially of size *pkt_len.  Contents are preserved **AT THE TOP END OF 
2153  * THE BUFFER** (hence making this function useful for reverse encoding).
2154  * You can change the reallocation scheme, but you **MUST** guarantee to
2155  * allocate **AT LEAST** one extra byte.  If memory cannot be reallocated,
2156  * then return 0; otherwise return 1.  
2157  */
2158
2159 int
2160 asn_realloc(u_char ** pkt, size_t * pkt_len)
2161 {
2162     if (pkt != NULL && pkt_len != NULL) {
2163         size_t          old_pkt_len = *pkt_len;
2164
2165         DEBUGMSGTL(("asn_realloc", " old_pkt %08p, old_pkt_len %08x\n",
2166                     *pkt, old_pkt_len));
2167
2168         if (snmp_realloc(pkt, pkt_len)) {
2169             DEBUGMSGTL(("asn_realloc", " new_pkt %08p, new_pkt_len %08x\n",
2170                         *pkt, *pkt_len));
2171             DEBUGMSGTL(("asn_realloc",
2172                         " memmove(%08p + %08x, %08p, %08x)\n", *pkt,
2173                         (*pkt_len - old_pkt_len), *pkt, old_pkt_len));
2174             memmove(*pkt + (*pkt_len - old_pkt_len), *pkt, old_pkt_len);
2175             memset(*pkt, (int) ' ', *pkt_len - old_pkt_len);
2176             return 1;
2177         } else {
2178             DEBUGMSG(("asn_realloc", " CANNOT REALLOC()\n"));
2179         }
2180     }
2181     return 0;
2182 }
2183
2184 #ifdef USE_REVERSE_ASNENCODING
2185
2186 int
2187 asn_realloc_rbuild_length(u_char ** pkt, size_t * pkt_len,
2188                           size_t * offset, int r, size_t length)
2189 {
2190     static const char *errpre = "build length";
2191     char            ebuf[128];
2192     int             tmp_int;
2193     size_t          start_offset = *offset;
2194
2195     if (length <= 0x7f) {
2196         if (((*pkt_len - *offset) < 1)
2197             && !(r && asn_realloc(pkt, pkt_len))) {
2198             snprintf(ebuf, sizeof(ebuf),
2199                     "%s: bad length < 1 :%d, %d", errpre,
2200                     *pkt_len - *offset, length);
2201             ebuf[ sizeof(ebuf)-1 ] = 0;
2202             ERROR_MSG(ebuf);
2203             return 0;
2204         }
2205         *(*pkt + *pkt_len - (++*offset)) = length;
2206     } else {
2207         while (length > 0xff) {
2208             if (((*pkt_len - *offset) < 1)
2209                 && !(r && asn_realloc(pkt, pkt_len))) {
2210                 snprintf(ebuf, sizeof(ebuf),
2211                         "%s: bad length < 1 :%d, %d", errpre,
2212                         *pkt_len - *offset, length);
2213                 ebuf[ sizeof(ebuf)-1 ] = 0;
2214                 ERROR_MSG(ebuf);
2215                 return 0;
2216             }
2217             *(*pkt + *pkt_len - (++*offset)) = length & 0xff;
2218             length >>= 8;
2219         }
2220
2221         while ((*pkt_len - *offset) < 2) {
2222             if (!(r && asn_realloc(pkt, pkt_len))) {
2223                 snprintf(ebuf, sizeof(ebuf),
2224                         "%s: bad length < 1 :%d, %d", errpre,
2225                         *pkt_len - *offset, length);
2226                 ebuf[ sizeof(ebuf)-1 ] = 0;
2227                 ERROR_MSG(ebuf);
2228                 return 0;
2229             }
2230         }
2231
2232         *(*pkt + *pkt_len - (++*offset)) = length & 0xff;
2233         tmp_int = *offset - start_offset;
2234         *(*pkt + *pkt_len - (++*offset)) = tmp_int | 0x80;
2235     }
2236
2237     return 1;
2238 }
2239
2240 int
2241 asn_realloc_rbuild_header(u_char ** pkt, size_t * pkt_len,
2242                           size_t * offset, int r,
2243                           u_char type, size_t length)
2244 {
2245     char            ebuf[128];
2246
2247     if (asn_realloc_rbuild_length(pkt, pkt_len, offset, r, length)) {
2248         if (((*pkt_len - *offset) < 1)
2249             && !(r && asn_realloc(pkt, pkt_len))) {
2250             snprintf(ebuf, sizeof(ebuf),
2251                     "bad header length < 1 :%d, %d",
2252                     *pkt_len - *offset, length);
2253             ebuf[ sizeof(ebuf)-1 ] = 0;
2254             ERROR_MSG(ebuf);
2255             return 0;
2256         }
2257         *(*pkt + *pkt_len - (++*offset)) = type;
2258         return 1;
2259     }
2260     return 0;
2261 }
2262
2263 int
2264 asn_realloc_rbuild_int(u_char ** pkt, size_t * pkt_len,
2265                        size_t * offset, int r,
2266                        u_char type, long *intp, size_t intsize)
2267 {
2268     static const char *errpre = "build int";
2269     register long   integer = *intp;
2270     int             testvalue = (*intp < 0) ? -1 : 0;
2271     size_t          start_offset = *offset;
2272
2273     if (intsize != sizeof(long)) {
2274         _asn_size_err(errpre, intsize, sizeof(long));
2275         return 0;
2276     }
2277
2278     if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
2279         return 0;
2280     }
2281     *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
2282     integer >>= 8;
2283
2284     while (integer != testvalue) {
2285         if (((*pkt_len - *offset) < 1)
2286             && !(r && asn_realloc(pkt, pkt_len))) {
2287             return 0;
2288         }
2289         *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
2290         integer >>= 8;
2291     }
2292
2293     if ((*(*pkt + *pkt_len - *offset) & 0x80) != (testvalue & 0x80)) {
2294         /*
2295          * Make sure left most bit is representational of the rest of the bits
2296          * that aren't encoded.  
2297          */
2298         if (((*pkt_len - *offset) < 1)
2299             && !(r && asn_realloc(pkt, pkt_len))) {
2300             return 0;
2301         }
2302         *(*pkt + *pkt_len - (++*offset)) = testvalue & 0xff;
2303     }
2304
2305     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
2306                                   (*offset - start_offset))) {
2307         if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
2308                                             (*offset - start_offset))) {
2309             return 0;
2310         } else {
2311             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
2312                            (*offset - start_offset));
2313             DEBUGMSG(("dumpv_send", "  Integer:\t%ld (0x%.2X)\n", *intp,
2314                       *intp));
2315             return 1;
2316         }
2317     }
2318
2319     return 0;
2320 }
2321
2322 int
2323 asn_realloc_rbuild_string(u_char ** pkt, size_t * pkt_len,
2324                           size_t * offset, int r,
2325                           u_char type,
2326                           const u_char * string, size_t strlength)
2327 {
2328     static const char *errpre = "build string";
2329     size_t          start_offset = *offset;
2330
2331     while ((*pkt_len - *offset) < strlength) {
2332         if (!(r && asn_realloc(pkt, pkt_len))) {
2333             return 0;
2334         }
2335     }
2336
2337     *offset += strlength;
2338     memcpy(*pkt + *pkt_len - *offset, string, strlength);
2339
2340     if (asn_realloc_rbuild_header
2341         (pkt, pkt_len, offset, r, type, strlength)) {
2342         if (_asn_realloc_build_header_check
2343             (errpre, pkt, pkt_len, strlength)) {
2344             return 0;
2345         } else {
2346             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
2347                            *offset - start_offset);
2348             DEBUGIF("dumpv_send") {
2349                 if (strlength == 0) {
2350                     DEBUGMSG(("dumpv_send", "  String: [NULL]\n"));
2351                 } else {
2352                     u_char         *buf = (u_char *) malloc(2 * strlength);
2353                     size_t          l =
2354                         (buf != NULL) ? (2 * strlength) : 0, ol = 0;
2355
2356                     if (sprint_realloc_asciistring
2357                         (&buf, &l, &ol, 1, string, strlength)) {
2358                         DEBUGMSG(("dumpv_send", "  String:\t%s\n", buf));
2359                     } else {
2360                         if (buf == NULL) {
2361                             DEBUGMSG(("dumpv_send",
2362                                       "  String:\t[TRUNCATED]\n"));
2363                         } else {
2364                             DEBUGMSG(("dumpv_send",
2365                                       "  String:\t%s [TRUNCATED]\n", buf));
2366                         }
2367                     }
2368                     if (buf != NULL) {
2369                         free(buf);
2370                     }
2371                 }
2372             }
2373         }
2374         return 1;
2375     }
2376
2377     return 0;
2378 }
2379
2380 int
2381 asn_realloc_rbuild_unsigned_int(u_char ** pkt, size_t * pkt_len,
2382                                 size_t * offset, int r,
2383                                 u_char type, u_long * intp, size_t intsize)
2384 {
2385     static const char *errpre = "build uint";
2386     register u_long integer = *intp;
2387     size_t          start_offset = *offset;
2388
2389     if (intsize != sizeof(unsigned long)) {
2390         _asn_size_err(errpre, intsize, sizeof(unsigned long));
2391         return 0;
2392     }
2393
2394     if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
2395         return 0;
2396     }
2397     *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
2398     integer >>= 8;
2399
2400     while (integer != 0) {
2401         if (((*pkt_len - *offset) < 1)
2402             && !(r && asn_realloc(pkt, pkt_len))) {
2403             return 0;
2404         }
2405         *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
2406         integer >>= 8;
2407     }
2408
2409     if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
2410         /*
2411          * Make sure left most bit is representational of the rest of the bits
2412          * that aren't encoded.  
2413          */
2414         if (((*pkt_len - *offset) < 1)
2415             && !(r && asn_realloc(pkt, pkt_len))) {
2416             return 0;
2417         }
2418         *(*pkt + *pkt_len - (++*offset)) = 0;
2419     }
2420
2421     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
2422                                   (*offset - start_offset))) {
2423         if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
2424                                             (*offset - start_offset))) {
2425             return 0;
2426         } else {
2427             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
2428                            (*offset - start_offset));
2429             DEBUGMSG(("dumpv_send", "  UInteger:\t%lu (0x%.2X)\n", *intp,
2430                       *intp));
2431             return 1;
2432         }
2433     }
2434
2435     return 0;
2436 }
2437
2438 int
2439 asn_realloc_rbuild_sequence(u_char ** pkt, size_t * pkt_len,
2440                             size_t * offset, int r,
2441                             u_char type, size_t length)
2442 {
2443     return asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
2444                                      length);
2445 }
2446
2447 int
2448 asn_realloc_rbuild_objid(u_char ** pkt, size_t * pkt_len,
2449                          size_t * offset, int r,
2450                          u_char type,
2451                          const oid * objid, size_t objidlength)
2452 {
2453     /*
2454      * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
2455      * subidentifier ::= {leadingbyte}* lastbyte
2456      * leadingbyte ::= 1 7bitvalue
2457      * lastbyte ::= 0 7bitvalue
2458      */
2459     register size_t i;
2460     register oid    tmpint;
2461     size_t          start_offset = *offset;
2462     const char     *errpre = "build objid";
2463
2464     /*
2465      * Check if there are at least 2 sub-identifiers.  
2466      */
2467     if (objidlength == 0) {
2468         /*
2469          * There are not, so make OID have two with value of zero.  
2470          */
2471         while ((*pkt_len - *offset) < 2) {
2472             if (!(r && asn_realloc(pkt, pkt_len))) {
2473                 return 0;
2474             }
2475         }
2476
2477         *(*pkt + *pkt_len - (++*offset)) = 0;
2478         *(*pkt + *pkt_len - (++*offset)) = 0;
2479     } else if (objid[0] > 2) {
2480         ERROR_MSG("build objid: bad first subidentifier");
2481         return 0;
2482     } else if (objidlength == 1) {
2483         /*
2484          * Encode the first value.  
2485          */
2486         if (((*pkt_len - *offset) < 1)
2487             && !(r && asn_realloc(pkt, pkt_len))) {
2488             return 0;
2489         }
2490         *(*pkt + *pkt_len - (++*offset)) = (u_char) objid[0];
2491     } else {
2492         for (i = objidlength; i > 2; i--) {
2493             tmpint = objid[i - 1];
2494
2495             if (((*pkt_len - *offset) < 1)
2496                 && !(r && asn_realloc(pkt, pkt_len))) {
2497                 return 0;
2498             }
2499             *(*pkt + *pkt_len - (++*offset)) = (u_char) tmpint & 0x7f;
2500             tmpint >>= 7;
2501
2502             while (tmpint > 0) {
2503                 if (((*pkt_len - *offset) < 1)
2504                     && !(r && asn_realloc(pkt, pkt_len))) {
2505                     return 0;
2506                 }
2507                 *(*pkt + *pkt_len - (++*offset)) =
2508                     (u_char) ((tmpint & 0x7f) | 0x80);
2509                 tmpint >>= 7;
2510             }
2511         }
2512
2513         /*
2514          * Combine the first two values.  
2515          */
2516         if ((objid[1] > 40) &&
2517             (objid[0] < 2)) {
2518             ERROR_MSG("build objid: bad second subidentifier");
2519             return 0;
2520         }
2521         tmpint = ((objid[0] * 40) + objid[1]);
2522         if (((*pkt_len - *offset) < 1)
2523             && !(r && asn_realloc(pkt, pkt_len))) {
2524             return 0;
2525         }
2526         *(*pkt + *pkt_len - (++*offset)) = (u_char) tmpint & 0x7f;
2527         tmpint >>= 7;
2528
2529         while (tmpint > 0) {
2530             if (((*pkt_len - *offset) < 1)
2531                 && !(r && asn_realloc(pkt, pkt_len))) {
2532                 return 0;
2533             }
2534             *(*pkt + *pkt_len - (++*offset)) =
2535                 (u_char) ((tmpint & 0x7f) | 0x80);
2536             tmpint >>= 7;
2537         }
2538     }
2539
2540     tmpint = *offset - start_offset;
2541     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
2542                                   (*offset - start_offset))) {
2543         if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
2544                                             (*offset - start_offset))) {
2545             return 0;
2546         } else {
2547             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
2548                            (*offset - start_offset));
2549             DEBUGMSG(("dumpv_send", "  ObjID: "));
2550             DEBUGMSGOID(("dumpv_send", objid, objidlength));
2551             DEBUGMSG(("dumpv_send", "\n"));
2552             return 1;
2553         }
2554     }
2555
2556     return 0;
2557 }
2558
2559 int
2560 asn_realloc_rbuild_null(u_char ** pkt, size_t * pkt_len,
2561                         size_t * offset, int r, u_char type)
2562 {
2563     /*
2564      * ASN.1 null ::= 0x05 0x00
2565      */
2566     size_t          start_offset = *offset;
2567
2568     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, 0)) {
2569         DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
2570                        (*offset - start_offset));
2571         DEBUGMSG(("dumpv_send", "  NULL\n"));
2572         return 1;
2573     } else {
2574         return 0;
2575     }
2576 }
2577
2578 int
2579 asn_realloc_rbuild_bitstring(u_char ** pkt, size_t * pkt_len,
2580                              size_t * offset, int r,
2581                              u_char type,
2582                              u_char * string, size_t strlength)
2583 {
2584     /*
2585      * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
2586      */
2587     static const char *errpre = "build bitstring";
2588     size_t          start_offset = *offset;
2589
2590     while ((*pkt_len - *offset) < strlength) {
2591         if (!(r && asn_realloc(pkt, pkt_len))) {
2592             return 0;
2593         }
2594     }
2595
2596     *offset += strlength;
2597     memcpy(*pkt + *pkt_len - *offset, string, strlength);
2598
2599     if (asn_realloc_rbuild_header
2600         (pkt, pkt_len, offset, r, type, strlength)) {
2601         if (_asn_realloc_build_header_check
2602             (errpre, pkt, pkt_len, strlength)) {
2603             return 0;
2604         } else {
2605             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
2606                            *offset - start_offset);
2607             DEBUGIF("dumpv_send") {
2608                 if (strlength == 0) {
2609                     DEBUGMSG(("dumpv_send", "  Bitstring: [NULL]\n"));
2610                 } else {
2611                     u_char         *buf = (u_char *) malloc(2 * strlength);
2612                     size_t          l =
2613                         (buf != NULL) ? (2 * strlength) : 0, ol = 0;
2614
2615                     if (sprint_realloc_asciistring
2616                         (&buf, &l, &ol, 1, string, strlength)) {
2617                         DEBUGMSG(("dumpv_send", "  Bitstring:\t%s\n",
2618                                   buf));
2619                     } else {
2620                         if (buf == NULL) {
2621                             DEBUGMSG(("dumpv_send",
2622                                       "  Bitstring:\t[TRUNCATED]\n"));
2623                         } else {
2624                             DEBUGMSG(("dumpv_send",
2625                                       "  Bitstring:\t%s [TRUNCATED]\n",
2626                                       buf));
2627                         }
2628                     }
2629                     if (buf != NULL) {
2630                         free(buf);
2631                     }
2632                 }
2633             }
2634         }
2635         return 1;
2636     }
2637
2638     return 0;
2639 }
2640
2641 #ifdef BRCM_SNMP_SUPPORT
2642 int
2643 asn_realloc_rbuild_unsigned_int64(u_char ** pkt, size_t * pkt_len,
2644                                   size_t * offset, int r,
2645                                   u_char type,
2646                                   struct counter64 *cp, size_t countersize)
2647 {
2648     /*
2649      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
2650      */
2651     register u_long low = cp->low, high = cp->high;
2652     size_t          intsize, start_offset = *offset;
2653     int             count;
2654
2655     if (countersize != sizeof(struct counter64)) {
2656         _asn_size_err("build uint64", countersize,
2657                       sizeof(struct counter64));
2658         return 0;
2659     }
2660
2661     /*
2662      * Encode the low 4 bytes first.  
2663      */
2664     if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
2665         return 0;
2666     }
2667     *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
2668     low >>= 8;
2669     count = 1;
2670
2671     while (low != 0) {
2672         count++;
2673         if (((*pkt_len - *offset) < 1)
2674             && !(r && asn_realloc(pkt, pkt_len))) {
2675             return 0;
2676         }
2677         *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
2678         low >>= 8;
2679     }
2680
2681     /*
2682      * Then the high byte if present.  
2683      */
2684     if (high) {
2685         /*
2686          * Do the rest of the low byte.  
2687          */
2688         for (; count < 4; count++) {
2689             if (((*pkt_len - *offset) < 1)
2690                 && !(r && asn_realloc(pkt, pkt_len))) {
2691                 return 0;
2692             }
2693             *(*pkt + *pkt_len - (++*offset)) = 0;
2694         }
2695
2696         /*
2697          * Do high byte.  
2698          */
2699         if (((*pkt_len - *offset) < 1)
2700             && !(r && asn_realloc(pkt, pkt_len))) {
2701             return 0;
2702         }
2703         *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
2704         high >>= 8;
2705
2706         while (high != 0) {
2707             if (((*pkt_len - *offset) < 1)
2708                 && !(r && asn_realloc(pkt, pkt_len))) {
2709                 return 0;
2710             }
2711             *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
2712             high >>= 8;
2713         }
2714     }
2715
2716     if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
2717         /*
2718          * Make sure left most bit is representational of the rest of the bits
2719          * that aren't encoded.  
2720          */
2721         if (((*pkt_len - *offset) < 1)
2722             && !(r && asn_realloc(pkt, pkt_len))) {
2723             return 0;
2724         }
2725         *(*pkt + *pkt_len - (++*offset)) = 0;
2726     }
2727
2728     intsize = *offset - start_offset;
2729
2730 #ifdef OPAQUE_SPECIAL_TYPES
2731     /*
2732      * Encode a Counter64 as an opaque (it also works in SNMPv1).  
2733      */
2734     if (type == ASN_OPAQUE_COUNTER64) {
2735         while ((*pkt_len - *offset) < 5) {
2736             if (!(r && asn_realloc(pkt, pkt_len))) {
2737                 return 0;
2738             }
2739         }
2740
2741         *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
2742         *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_COUNTER64;
2743         *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
2744
2745         /*
2746          * Put the tag and length for the Opaque wrapper.  
2747          */
2748         if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
2749                                       ASN_OPAQUE, intsize + 3)) {
2750             if (_asn_realloc_build_header_check
2751                 ("build counter u64", pkt, pkt_len, intsize + 3)) {
2752                 return 0;
2753             }
2754         } else {
2755             return 0;
2756         }
2757     } else if (type == ASN_OPAQUE_U64) {
2758         /*
2759          * Encode the Unsigned int64 in an opaque.  
2760          */
2761         while ((*pkt_len - *offset) < 5) {
2762             if (!(r && asn_realloc(pkt, pkt_len))) {
2763                 return 0;
2764             }
2765         }
2766
2767         *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
2768         *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_U64;
2769         *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
2770
2771         /*
2772          * Put the tag and length for the Opaque wrapper.  
2773          */
2774         if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
2775                                       ASN_OPAQUE, intsize + 3)) {
2776             if (_asn_realloc_build_header_check
2777                 ("build counter u64", pkt, pkt_len, intsize + 3)) {
2778                 return 0;
2779             }
2780         } else {
2781             return 0;
2782         }
2783     } else {
2784
2785 #endif                          /* OPAQUE_SPECIAL_TYPES */
2786         if (asn_realloc_rbuild_header
2787             (pkt, pkt_len, offset, r, type, intsize)) {
2788             if (_asn_realloc_build_header_check
2789                 ("build uint64", pkt, pkt_len, intsize)) {
2790                 return 0;
2791             }
2792         } else {
2793             return 0;
2794         }
2795 #ifdef OPAQUE_SPECIAL_TYPES
2796     }
2797 #endif                          /* OPAQUE_SPECIAL_TYPES */
2798
2799     DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
2800     DEBUGMSG(("dumpv_send", "  U64:\t%lu %lu\n", cp->high, cp->low));
2801     return 1;
2802 }
2803
2804 #ifdef OPAQUE_SPECIAL_TYPES
2805 int
2806 asn_realloc_rbuild_signed_int64(u_char ** pkt, size_t * pkt_len,
2807                                 size_t * offset, int r,
2808                                 u_char type,
2809                                 struct counter64 *cp, size_t countersize)
2810 {
2811     /*
2812      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
2813      */
2814     register u_long low = cp->low, high = cp->high;
2815     size_t          intsize, start_offset = *offset;
2816     int             count, testvalue = (high & 0x80000000) ? -1 : 0;
2817
2818     if (countersize != sizeof(struct counter64)) {
2819         _asn_size_err("build uint64", countersize,
2820                       sizeof(struct counter64));
2821         return 0;
2822     }
2823
2824     /*
2825      * Encode the low 4 bytes first.  
2826      */
2827     if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
2828         return 0;
2829     }
2830     *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
2831     low >>= 8;
2832     count = 1;
2833
2834     while ((int) low != testvalue) {
2835         count++;
2836         if (((*pkt_len - *offset) < 1)
2837             && !(r && asn_realloc(pkt, pkt_len))) {
2838             return 0;
2839         }
2840         *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
2841         low >>= 8;
2842     }
2843
2844     /*
2845      * Then the high byte if present.  
2846      */
2847     if (high) {
2848         /*
2849          * Do the rest of the low byte.  
2850          */
2851         for (; count < 4; count++) {
2852             if (((*pkt_len - *offset) < 1)
2853                 && !(r && asn_realloc(pkt, pkt_len))) {
2854                 return 0;
2855             }
2856             *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
2857         }
2858
2859         /*
2860          * Do high byte.  
2861          */
2862         if (((*pkt_len - *offset) < 1)
2863             && !(r && asn_realloc(pkt, pkt_len))) {
2864             return 0;
2865         }
2866         *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
2867         high >>= 8;
2868
2869         while ((int) high != testvalue) {
2870             if (((*pkt_len - *offset) < 1)
2871                 && !(r && asn_realloc(pkt, pkt_len))) {
2872                 return 0;
2873             }
2874             *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
2875             high >>= 8;
2876         }
2877     }
2878
2879     if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
2880         /*
2881          * Make sure left most bit is representational of the rest of the bits
2882          * that aren't encoded.  
2883          */
2884         if (((*pkt_len - *offset) < 1)
2885             && !(r && asn_realloc(pkt, pkt_len))) {
2886             return 0;
2887         }
2888         *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
2889     }
2890
2891     intsize = *offset - start_offset;
2892
2893     while ((*pkt_len - *offset) < 5) {
2894         if (!(r && asn_realloc(pkt, pkt_len))) {
2895             return 0;
2896         }
2897     }
2898
2899     *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
2900     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_I64;
2901     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
2902
2903     /*
2904      * Put the tag and length for the Opaque wrapper.  
2905      */
2906     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
2907                                   ASN_OPAQUE, intsize + 3)) {
2908         if (_asn_realloc_build_header_check
2909             ("build counter u64", pkt, pkt_len, intsize + 3)) {
2910             return 0;
2911         }
2912     } else {
2913         return 0;
2914     }
2915
2916     DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
2917     DEBUGMSG(("dumpv_send", "  UInt64:\t%lu %lu\n", cp->high, cp->low));
2918     return 1;
2919 }
2920
2921 int
2922 asn_realloc_rbuild_float(u_char ** pkt, size_t * pkt_len,
2923                          size_t * offset, int r,
2924                          u_char type, float *floatp, size_t floatsize)
2925 {
2926     size_t          start_offset = *offset;
2927     union {
2928         float           floatVal;
2929         int             intVal;
2930         u_char          c[sizeof(float)];
2931     } fu;
2932
2933     /*
2934      * Floatsize better not be larger than realistic.  
2935      */
2936     if (floatsize != sizeof(float) || floatsize > 122) {
2937         return 0;
2938     }
2939
2940     while ((*pkt_len - *offset) < floatsize + 3) {
2941         if (!(r && asn_realloc(pkt, pkt_len))) {
2942             return 0;
2943         }
2944     }
2945
2946     /*
2947      * Correct for endian differences and copy value.  
2948      */
2949     fu.floatVal = *floatp;
2950     fu.intVal = htonl(fu.intVal);
2951     *offset += floatsize;
2952     memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), floatsize);
2953
2954     /*
2955      * Put the special tag and length (3 bytes).  
2956      */
2957     *(*pkt + *pkt_len - (++*offset)) = (u_char) floatsize;
2958     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_FLOAT;
2959     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
2960
2961     /*
2962      * Put the tag and length for the Opaque wrapper.  
2963      */
2964     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
2965                                   ASN_OPAQUE, floatsize + 3)) {
2966         if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
2967                                             floatsize + 3)) {
2968             return 0;
2969         } else {
2970             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
2971                            *offset - start_offset);
2972             DEBUGMSG(("dumpv_send", "Opaque Float:\t%f\n", *floatp));
2973             return 1;
2974         }
2975     }
2976
2977     return 0;
2978 }
2979 #endif /* BRCM_SNMP_SUPPORT */
2980
2981 int
2982 asn_realloc_rbuild_double(u_char ** pkt, size_t * pkt_len,
2983                           size_t * offset, int r,
2984                           u_char type, double *doublep, size_t doublesize)
2985 {
2986     size_t          start_offset = *offset;
2987     long            tmp;
2988     union {
2989         double          doubleVal;
2990         int             intVal[2];
2991         u_char          c[sizeof(double)];
2992     } fu;
2993
2994     /*
2995      * Doublesize better not be larger than realistic.  
2996      */
2997     if (doublesize != sizeof(double) || doublesize > 122) {
2998         return 0;
2999     }
3000
3001     while ((*pkt_len - *offset) < doublesize + 3) {
3002         if (!(r && asn_realloc(pkt, pkt_len))) {
3003             return 0;
3004         }
3005     }
3006
3007     /*
3008      * Correct for endian differences and copy value.  
3009      */
3010     fu.doubleVal = *doublep;
3011     tmp = htonl(fu.intVal[0]);
3012     fu.intVal[0] = htonl(fu.intVal[1]);
3013     fu.intVal[1] = tmp;
3014     *offset += doublesize;
3015     memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), doublesize);
3016
3017     /*
3018      * Put the special tag and length (3 bytes).  
3019      */
3020     *(*pkt + *pkt_len - (++*offset)) = (u_char) doublesize;
3021     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_DOUBLE;
3022     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3023
3024     /*
3025      * Put the tag and length for the Opaque wrapper.  
3026      */
3027     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3028                                   ASN_OPAQUE, doublesize + 3)) {
3029         if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
3030                                             doublesize + 3)) {
3031             return 0;
3032         } else {
3033             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3034                            *offset - start_offset);
3035             DEBUGMSG(("dumpv_send", "  Opaque Double:\t%f\n", *doublep));
3036             return 1;
3037         }
3038     }
3039
3040     return 0;
3041 }
3042
3043 #endif                          /* OPAQUE_SPECIAL_TYPES */
3044 #endif                          /*  USE_REVERSE_ASNENCODING  */