Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / lwip / core / snmp / asn1_dec.c
1 /**
2  * @file
3  * Abstract Syntax Notation One (ISO 8824, 8825) decoding
4  *
5  * @todo not optimised (yet), favor correctness over speed, favor speed over size
6  */
7
8 /*
9  * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without modification,
13  * are permitted provided that the following conditions are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright notice,
16  *    this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright notice,
18  *    this list of conditions and the following disclaimer in the documentation
19  *    and/or other materials provided with the distribution.
20  * 3. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
24  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
26  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
28  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
31  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32  * OF SUCH DAMAGE.
33  *
34  * Author: Christiaan Simons <christiaan.simons@axon.tv>
35  */
36
37 #include "lwip/opt.h"
38
39 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
40
41 #include "lwip/snmp_asn1.h"
42
43 /**
44  * Retrieves type field from incoming pbuf chain.
45  *
46  * @param p points to a pbuf holding an ASN1 coded type field
47  * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field
48  * @param type return ASN1 type
49  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
50  */
51 err_t
52 snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)
53 {
54   u16_t plen, base;
55   u8_t *msg_ptr;
56
57   plen = 0;
58   while (p != NULL)
59   {
60     base = plen;
61     plen += p->len;
62     if (ofs < plen)
63     {
64       msg_ptr = p->payload;
65       msg_ptr += ofs - base;
66       *type = *msg_ptr;
67       return ERR_OK;
68     }
69     p = p->next;
70   }
71   /* p == NULL, ofs >= plen */
72   return ERR_ARG;
73 }
74
75 /**
76  * Decodes length field from incoming pbuf chain into host length.
77  *
78  * @param p points to a pbuf holding an ASN1 coded length
79  * @param ofs points to the offset within the pbuf chain of the ASN1 coded length
80  * @param octets_used returns number of octets used by the length code
81  * @param length return host order length, upto 64k
82  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
83  */
84 err_t
85 snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length)
86 {
87   u16_t plen, base;
88   u8_t *msg_ptr;
89
90   plen = 0;
91   while (p != NULL)
92   {
93     base = plen;
94     plen += p->len;
95     if (ofs < plen)
96     {
97       msg_ptr = p->payload;
98       msg_ptr += ofs - base;
99
100       if (*msg_ptr < 0x80)
101       {
102         /* primitive definite length format */
103         *octets_used = 1;
104         *length = *msg_ptr;
105         return ERR_OK;
106       }
107       else if (*msg_ptr == 0x80)
108       {
109         /* constructed indefinite length format, termination with two zero octets */
110         u8_t zeros;
111         u8_t i;
112
113         *length = 0;
114         zeros = 0;
115         while (zeros != 2)
116         {
117           i = 2;
118           while (i > 0)
119           {
120             i--;
121             (*length) += 1;
122             ofs += 1;
123             if (ofs >= plen)
124             {
125               /* next octet in next pbuf */
126               p = p->next;
127               if (p == NULL) { return ERR_ARG; }
128               msg_ptr = p->payload;
129               plen += p->len;
130             }
131             else
132             {
133               /* next octet in same pbuf */
134               msg_ptr++;
135             }
136             if (*msg_ptr == 0)
137             {
138               zeros++;
139               if (zeros == 2)
140               {
141                 /* stop while (i > 0) */
142                 i = 0;
143               }
144             }
145             else
146             {
147               zeros = 0;
148             }
149           }
150         }
151         *octets_used = 1;
152         return ERR_OK;
153       }
154       else if (*msg_ptr == 0x81)
155       {
156         /* constructed definite length format, one octet */
157         ofs += 1;
158         if (ofs >= plen)
159         {
160           /* next octet in next pbuf */
161           p = p->next;
162           if (p == NULL) { return ERR_ARG; }
163           msg_ptr = p->payload;
164         }
165         else
166         {
167           /* next octet in same pbuf */
168           msg_ptr++;
169         }
170         *length = *msg_ptr;
171         *octets_used = 2;
172         return ERR_OK;
173       }
174       else if (*msg_ptr == 0x82)
175       {
176         u8_t i;
177
178         /* constructed definite length format, two octets */
179         i = 2;
180         while (i > 0)
181         {
182           i--;
183           ofs += 1;
184           if (ofs >= plen)
185           {
186             /* next octet in next pbuf */
187             p = p->next;
188             if (p == NULL) { return ERR_ARG; }
189             msg_ptr = p->payload;
190             plen += p->len;
191           }
192           else
193           {
194             /* next octet in same pbuf */
195             msg_ptr++;
196           }
197           if (i == 0)
198           {
199             /* least significant length octet */
200             *length |= *msg_ptr;
201           }
202           else
203           {
204             /* most significant length octet */
205             *length = (*msg_ptr) << 8;
206           }
207         }
208         *octets_used = 3;
209         return ERR_OK;
210       }
211       else
212       {
213         /* constructed definite length format 3..127 octets, this is too big (>64k) */
214         /**  @todo: do we need to accept inefficient codings with many leading zero's? */
215         *octets_used = 1 + ((*msg_ptr) & 0x7f);
216         return ERR_ARG;
217       }
218     }
219     p = p->next;
220   }
221
222   /* p == NULL, ofs >= plen */
223   return ERR_ARG;
224 }
225
226 /**
227  * Decodes positive integer (counter, gauge, timeticks) into u32_t.
228  *
229  * @param p points to a pbuf holding an ASN1 coded integer
230  * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
231  * @param len length of the coded integer field
232  * @param value return host order integer
233  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
234  *
235  * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
236  * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
237  * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
238  */
239 err_t
240 snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
241 {
242   u16_t plen, base;
243   u8_t *msg_ptr;
244
245   plen = 0;
246   while (p != NULL)
247   {
248     base = plen;
249     plen += p->len;
250     if (ofs < plen)
251     {
252       msg_ptr = p->payload;
253       msg_ptr += ofs - base;
254       if ((len > 0) && (len < 6))
255       {
256         /* start from zero */
257         *value = 0;
258         if (*msg_ptr & 0x80)
259         {
260           /* negative, expecting zero sign bit! */
261           return ERR_ARG;
262         }
263         else
264         {
265           /* positive */
266           if ((len > 1) && (*msg_ptr == 0))
267           {
268             /* skip leading "sign byte" octet 0x00 */
269             len--;
270             ofs += 1;
271             if (ofs >= plen)
272             {
273               /* next octet in next pbuf */
274               p = p->next;
275               if (p == NULL) { return ERR_ARG; }
276               msg_ptr = p->payload;
277               plen += p->len;
278             }
279             else
280             {
281               /* next octet in same pbuf */
282               msg_ptr++;
283             }
284           }
285         }
286         /* OR octets with value */
287         while (len > 1)
288         {
289           len--;
290           *value |= *msg_ptr;
291           *value <<= 8;
292           ofs += 1;
293           if (ofs >= plen)
294           {
295             /* next octet in next pbuf */
296             p = p->next;
297             if (p == NULL) { return ERR_ARG; }
298             msg_ptr = p->payload;
299             plen += p->len;
300           }
301           else
302           {
303             /* next octet in same pbuf */
304             msg_ptr++;
305           }
306         }
307         *value |= *msg_ptr;
308         return ERR_OK;
309       }
310       else
311       {
312         return ERR_ARG;
313       }
314     }
315     p = p->next;
316   }
317   /* p == NULL, ofs >= plen */
318   return ERR_ARG;
319 }
320
321 /**
322  * Decodes integer into s32_t.
323  *
324  * @param p points to a pbuf holding an ASN1 coded integer
325  * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
326  * @param len length of the coded integer field
327  * @param value return host order integer
328  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
329  *
330  * @note ASN coded integers are _always_ signed!
331  */
332 err_t
333 snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)
334 {
335   u16_t plen, base;
336   u8_t *msg_ptr;
337 #if BYTE_ORDER == LITTLE_ENDIAN
338   u8_t *lsb_ptr = (u8_t*)value;
339 #endif
340 #if BYTE_ORDER == BIG_ENDIAN
341   u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;
342 #endif
343   u8_t sign;
344
345   plen = 0;
346   while (p != NULL)
347   {
348     base = plen;
349     plen += p->len;
350     if (ofs < plen)
351     {
352       msg_ptr = p->payload;
353       msg_ptr += ofs - base;
354       if ((len > 0) && (len < 5))
355       {
356         if (*msg_ptr & 0x80)
357         {
358           /* negative, start from -1 */
359           *value = -1;
360           sign = 1;
361         }
362         else
363         {
364           /* positive, start from 0 */
365           *value = 0;
366           sign = 0;
367         }
368         /* OR/AND octets with value */
369         while (len > 1)
370         {
371           len--;
372           if (sign)
373           {
374             *lsb_ptr &= *msg_ptr;
375             *value <<= 8;
376             *lsb_ptr |= 255;
377           }
378           else
379           {
380             *lsb_ptr |= *msg_ptr;
381             *value <<= 8;
382           }
383           ofs += 1;
384           if (ofs >= plen)
385           {
386             /* next octet in next pbuf */
387             p = p->next;
388             if (p == NULL) { return ERR_ARG; }
389             msg_ptr = p->payload;
390             plen += p->len;
391           }
392           else
393           {
394             /* next octet in same pbuf */
395             msg_ptr++;
396           }
397         }
398         if (sign)
399         {
400           *lsb_ptr &= *msg_ptr;
401         }
402         else
403         {
404           *lsb_ptr |= *msg_ptr;
405         }
406         return ERR_OK;
407       }
408       else
409       {
410         return ERR_ARG;
411       }
412     }
413     p = p->next;
414   }
415   /* p == NULL, ofs >= plen */
416   return ERR_ARG;
417 }
418
419 /**
420  * Decodes object identifier from incoming message into array of s32_t.
421  *
422  * @param p points to a pbuf holding an ASN1 coded object identifier
423  * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier
424  * @param len length of the coded object identifier
425  * @param oid return object identifier struct
426  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
427  */
428 err_t
429 snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
430 {
431   u16_t plen, base;
432   u8_t *msg_ptr;
433   s32_t *oid_ptr;
434
435   plen = 0;
436   while (p != NULL)
437   {
438     base = plen;
439     plen += p->len;
440     if (ofs < plen)
441     {
442       msg_ptr = p->payload;
443       msg_ptr += ofs - base;
444
445       oid->len = 0;
446       oid_ptr = &oid->id[0];
447       if (len > 0)
448       {
449         /* first compressed octet */
450         if (*msg_ptr == 0x2B)
451         {
452           /* (most) common case 1.3 (iso.org) */
453           *oid_ptr = 1;
454           oid_ptr++;
455           *oid_ptr = 3;
456           oid_ptr++;
457         }
458         else if (*msg_ptr < 40)
459         {
460           *oid_ptr = 0;
461           oid_ptr++;
462           *oid_ptr = *msg_ptr;
463           oid_ptr++;
464         }
465         else if (*msg_ptr < 80)
466         {
467           *oid_ptr = 1;
468           oid_ptr++;
469           *oid_ptr = (*msg_ptr) - 40;
470           oid_ptr++;
471         }
472         else
473         {
474           *oid_ptr = 2;
475           oid_ptr++;
476           *oid_ptr = (*msg_ptr) - 80;
477           oid_ptr++;
478         }
479         oid->len = 2;
480       }
481       else
482       {
483         /* accepting zero length identifiers e.g. for
484            getnext operation. uncommon but valid */
485         return ERR_OK;
486       }
487       len--;
488       if (len > 0)
489       {
490         ofs += 1;
491         if (ofs >= plen)
492         {
493           /* next octet in next pbuf */
494           p = p->next;
495           if (p == NULL) { return ERR_ARG; }
496           msg_ptr = p->payload;
497           plen += p->len;
498         }
499         else
500         {
501           /* next octet in same pbuf */
502           msg_ptr++;
503         }
504       }
505       while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN))
506       {
507         /* sub-identifier uses multiple octets */
508         if (*msg_ptr & 0x80)
509         {
510           s32_t sub_id = 0;
511
512           while ((*msg_ptr & 0x80) && (len > 1))
513           {
514             len--;
515             sub_id = (sub_id << 7) + (*msg_ptr & ~0x80);
516             ofs += 1;
517             if (ofs >= plen)
518             {
519               /* next octet in next pbuf */
520               p = p->next;
521               if (p == NULL) { return ERR_ARG; }
522               msg_ptr = p->payload;
523               plen += p->len;
524             }
525             else
526             {
527               /* next octet in same pbuf */
528               msg_ptr++;
529             }
530           }
531           if (!(*msg_ptr & 0x80) && (len > 0))
532           {
533             /* last octet sub-identifier */
534             len--;
535             sub_id = (sub_id << 7) + *msg_ptr;
536             *oid_ptr = sub_id;
537           }
538         }
539         else
540         {
541           /* !(*msg_ptr & 0x80) sub-identifier uses single octet */
542           len--;
543           *oid_ptr = *msg_ptr;
544         }
545         if (len > 0)
546         {
547           /* remaining oid bytes available ... */
548           ofs += 1;
549           if (ofs >= plen)
550           {
551             /* next octet in next pbuf */
552             p = p->next;
553             if (p == NULL) { return ERR_ARG; }
554             msg_ptr = p->payload;
555             plen += p->len;
556           }
557           else
558           {
559             /* next octet in same pbuf */
560             msg_ptr++;
561           }
562         }
563         oid_ptr++;
564         oid->len++;
565       }
566       if (len == 0)
567       {
568         /* len == 0, end of oid */
569         return ERR_OK;
570       }
571       else
572       {
573         /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */
574         return ERR_ARG;
575       }
576
577     }
578     p = p->next;
579   }
580   /* p == NULL, ofs >= plen */
581   return ERR_ARG;
582 }
583
584 /**
585  * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
586  * from incoming message into array.
587  *
588  * @param p points to a pbuf holding an ASN1 coded raw data
589  * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data
590  * @param len length of the coded raw data (zero is valid, e.g. empty string!)
591  * @param raw_len length of the raw return value
592  * @param raw return raw bytes
593  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
594  */
595 err_t
596 snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw)
597 {
598   u16_t plen, base;
599   u8_t *msg_ptr;
600
601   if (len > 0)
602   {
603     plen = 0;
604     while (p != NULL)
605     {
606       base = plen;
607       plen += p->len;
608       if (ofs < plen)
609       {
610         msg_ptr = p->payload;
611         msg_ptr += ofs - base;
612         if (raw_len >= len)
613         {
614           while (len > 1)
615           {
616             /* copy len - 1 octets */
617             len--;
618             *raw = *msg_ptr;
619             raw++;
620             ofs += 1;
621             if (ofs >= plen)
622             {
623               /* next octet in next pbuf */
624               p = p->next;
625               if (p == NULL) { return ERR_ARG; }
626               msg_ptr = p->payload;
627               plen += p->len;
628             }
629             else
630             {
631               /* next octet in same pbuf */
632               msg_ptr++;
633             }
634           }
635           /* copy last octet */
636           *raw = *msg_ptr;
637           return ERR_OK;
638         }
639         else
640         {
641           /* raw_len < len, not enough dst space */
642           return ERR_ARG;
643         }
644       }
645       p = p->next;
646     }
647     /* p == NULL, ofs >= plen */
648     return ERR_ARG;
649   }
650   else
651   {
652     /* len == 0, empty string */
653     return ERR_OK;
654   }
655 }
656
657 #endif /* LWIP_SNMP */