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_enc.c
1 /**
2  * @file
3  * Abstract Syntax Notation One (ISO 8824, 8825) encoding
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  * Returns octet count for length.
45  *
46  * @param length
47  * @param octets_needed points to the return value
48  */
49 void
50 snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
51 {
52   if (length < 0x80U)
53   {
54     *octets_needed = 1;
55   }
56   else if (length < 0x100U)
57   {
58     *octets_needed = 2;
59   }
60   else
61   {
62     *octets_needed = 3;
63   }
64 }
65
66 /**
67  * Returns octet count for an u32_t.
68  *
69  * @param value
70  * @param octets_needed points to the return value
71  *
72  * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
73  * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
74  * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
75  */
76 void
77 snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
78 {
79   if (value < 0x80UL)
80   {
81     *octets_needed = 1;
82   }
83   else if (value < 0x8000UL)
84   {
85     *octets_needed = 2;
86   }
87   else if (value < 0x800000UL)
88   {
89     *octets_needed = 3;
90   }
91   else if (value < 0x80000000UL)
92   {
93     *octets_needed = 4;
94   }
95   else
96   {
97     *octets_needed = 5;
98   }
99 }
100
101 /**
102  * Returns octet count for an s32_t.
103  *
104  * @param value
105  * @param octets_needed points to the return value
106  *
107  * @note ASN coded integers are _always_ signed.
108  */
109 void
110 snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
111 {
112   if (value < 0)
113   {
114     value = ~value;
115   }
116   if (value < 0x80L)
117   {
118     *octets_needed = 1;
119   }
120   else if (value < 0x8000L)
121   {
122     *octets_needed = 2;
123   }
124   else if (value < 0x800000L)
125   {
126     *octets_needed = 3;
127   }
128   else
129   {
130     *octets_needed = 4;
131   }
132 }
133
134 /**
135  * Returns octet count for an object identifier.
136  *
137  * @param ident_len object identifier array length
138  * @param ident points to object identifier array
139  * @param octets_needed points to the return value
140  */
141 void
142 snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed)
143 {
144   s32_t sub_id;
145   u8_t cnt;
146
147   cnt = 0;
148   if (ident_len > 1)
149   {
150     /* compressed prefix in one octet */
151     cnt++;
152     ident_len -= 2;
153     ident += 2;
154   }
155   while(ident_len > 0)
156   {
157     ident_len--;
158     sub_id = *ident;
159
160     sub_id >>= 7;
161     cnt++;
162     while(sub_id > 0)
163     {
164       sub_id >>= 7;
165       cnt++;
166     }
167     ident++;
168   }
169   *octets_needed = cnt;
170 }
171
172 /**
173  * Encodes ASN type field into a pbuf chained ASN1 msg.
174  *
175  * @param p points to output pbuf to encode value into
176  * @param ofs points to the offset within the pbuf chain
177  * @param type input ASN1 type
178  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
179  */
180 err_t
181 snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type)
182 {
183   u16_t plen, base;
184   u8_t *msg_ptr;
185
186   plen = 0;
187   while (p != NULL)
188   {
189     base = plen;
190     plen += p->len;
191     if (ofs < plen)
192     {
193       msg_ptr = p->payload;
194       msg_ptr += ofs - base;
195       *msg_ptr = type;
196       return ERR_OK;
197     }
198     p = p->next;
199   }
200   /* p == NULL, ofs >= plen */
201   return ERR_ARG;
202 }
203
204 /**
205  * Encodes host order length field into a pbuf chained ASN1 msg.
206  *
207  * @param p points to output pbuf to encode length into
208  * @param ofs points to the offset within the pbuf chain
209  * @param length is the host order length to be encoded
210  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
211  */
212 err_t
213 snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
214 {
215   u16_t plen, base;
216   u8_t *msg_ptr;
217
218   plen = 0;
219   while (p != NULL)
220   {
221     base = plen;
222     plen += p->len;
223     if (ofs < plen)
224     {
225       msg_ptr = p->payload;
226       msg_ptr += ofs - base;
227
228       if (length < 0x80)
229       {
230         *msg_ptr = length;
231         return ERR_OK;
232       }
233       else if (length < 0x100)
234       {
235         *msg_ptr = 0x81;
236         ofs += 1;
237         if (ofs >= plen)
238         {
239           /* next octet in next pbuf */
240           p = p->next;
241           if (p == NULL) { return ERR_ARG; }
242           msg_ptr = p->payload;
243         }
244         else
245         {
246           /* next octet in same pbuf */
247           msg_ptr++;
248         }
249         *msg_ptr = length;
250         return ERR_OK;
251       }
252       else
253       {
254         u8_t i;
255
256         /* length >= 0x100 && length <= 0xFFFF */
257         *msg_ptr = 0x82;
258         i = 2;
259         while (i > 0)
260         {
261           i--;
262           ofs += 1;
263           if (ofs >= plen)
264           {
265             /* next octet in next pbuf */
266             p = p->next;
267             if (p == NULL) { return ERR_ARG; }
268             msg_ptr = p->payload;
269             plen += p->len;
270           }
271           else
272           {
273             /* next octet in same pbuf */
274             msg_ptr++;
275           }
276           if (i == 0)
277           {
278             /* least significant length octet */
279             *msg_ptr = length;
280           }
281           else
282           {
283             /* most significant length octet */
284             *msg_ptr = length >> 8;
285           }
286         }
287         return ERR_OK;
288       }
289     }
290     p = p->next;
291   }
292   /* p == NULL, ofs >= plen */
293   return ERR_ARG;
294 }
295
296 /**
297  * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.
298  *
299  * @param p points to output pbuf to encode value into
300  * @param ofs points to the offset within the pbuf chain
301  * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
302  * @param value is the host order u32_t value to be encoded
303  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
304  *
305  * @see snmp_asn1_enc_u32t_cnt()
306  */
307 err_t
308 snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)
309 {
310   u16_t plen, base;
311   u8_t *msg_ptr;
312
313   plen = 0;
314   while (p != NULL)
315   {
316     base = plen;
317     plen += p->len;
318     if (ofs < plen)
319     {
320       msg_ptr = p->payload;
321       msg_ptr += ofs - base;
322
323       if (octets_needed == 5)
324       {
325         /* not enough bits in 'value' add leading 0x00 */
326         octets_needed--;
327         *msg_ptr = 0x00;
328         ofs += 1;
329         if (ofs >= plen)
330         {
331           /* next octet in next pbuf */
332           p = p->next;
333           if (p == NULL) { return ERR_ARG; }
334           msg_ptr = p->payload;
335           plen += p->len;
336         }
337         else
338         {
339           /* next octet in same pbuf */
340           msg_ptr++;
341         }
342       }
343       while (octets_needed > 1)
344       {
345         octets_needed--;
346         *msg_ptr = value >> (octets_needed << 3);
347         ofs += 1;
348         if (ofs >= plen)
349         {
350           /* next octet in next pbuf */
351           p = p->next;
352           if (p == NULL) { return ERR_ARG; }
353           msg_ptr = p->payload;
354           plen += p->len;
355         }
356         else
357         {
358           /* next octet in same pbuf */
359           msg_ptr++;
360         }
361       }
362       /* (only) one least significant octet */
363       *msg_ptr = value;
364       return ERR_OK;
365     }
366     p = p->next;
367   }
368   /* p == NULL, ofs >= plen */
369   return ERR_ARG;
370 }
371
372 /**
373  * Encodes s32_t integer into a pbuf chained ASN1 msg.
374  *
375  * @param p points to output pbuf to encode value into
376  * @param ofs points to the offset within the pbuf chain
377  * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())
378  * @param value is the host order s32_t value to be encoded
379  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
380  *
381  * @see snmp_asn1_enc_s32t_cnt()
382  */
383 err_t
384 snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value)
385 {
386   u16_t plen, base;
387   u8_t *msg_ptr;
388
389   plen = 0;
390   while (p != NULL)
391   {
392     base = plen;
393     plen += p->len;
394     if (ofs < plen)
395     {
396       msg_ptr = p->payload;
397       msg_ptr += ofs - base;
398
399       while (octets_needed > 1)
400       {
401         octets_needed--;
402         *msg_ptr = value >> (octets_needed << 3);
403         ofs += 1;
404         if (ofs >= plen)
405         {
406           /* next octet in next pbuf */
407           p = p->next;
408           if (p == NULL) { return ERR_ARG; }
409           msg_ptr = p->payload;
410           plen += p->len;
411         }
412         else
413         {
414           /* next octet in same pbuf */
415           msg_ptr++;
416         }
417       }
418       /* (only) one least significant octet */
419       *msg_ptr = value;
420       return ERR_OK;
421     }
422     p = p->next;
423   }
424   /* p == NULL, ofs >= plen */
425   return ERR_ARG;
426 }
427
428 /**
429  * Encodes object identifier into a pbuf chained ASN1 msg.
430  *
431  * @param p points to output pbuf to encode oid into
432  * @param ofs points to the offset within the pbuf chain
433  * @param ident_len object identifier array length
434  * @param ident points to object identifier array
435  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
436  */
437 err_t
438 snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
439 {
440   u16_t plen, base;
441   u8_t *msg_ptr;
442
443   plen = 0;
444   while (p != NULL)
445   {
446     base = plen;
447     plen += p->len;
448     if (ofs < plen)
449     {
450       msg_ptr = p->payload;
451       msg_ptr += ofs - base;
452
453       if (ident_len > 1)
454       {
455         if ((ident[0] == 1) && (ident[1] == 3))
456         {
457           /* compressed (most common) prefix .iso.org */
458           *msg_ptr = 0x2b;
459         }
460         else
461         {
462           /* calculate prefix */
463           *msg_ptr = (ident[0] * 40) + ident[1];
464         }
465         ofs += 1;
466         if (ofs >= plen)
467         {
468           /* next octet in next pbuf */
469           p = p->next;
470           if (p == NULL) { return ERR_ARG; }
471           msg_ptr = p->payload;
472           plen += p->len;
473         }
474         else
475         {
476           /* next octet in same pbuf */
477           msg_ptr++;
478         }
479         ident_len -= 2;
480         ident += 2;
481       }
482       else
483       {
484 /* @bug:  allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression??  */
485         /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
486         return ERR_ARG;
487       }
488       while (ident_len > 0)
489       {
490         s32_t sub_id;
491         u8_t shift, tail;
492
493         ident_len--;
494         sub_id = *ident;
495         tail = 0;
496         shift = 28;
497         while(shift > 0)
498         {
499           u8_t code;
500
501           code = sub_id >> shift;
502           if ((code != 0) || (tail != 0))
503           {
504             tail = 1;
505             *msg_ptr = code | 0x80;
506             ofs += 1;
507             if (ofs >= plen)
508             {
509               /* next octet in next pbuf */
510               p = p->next;
511               if (p == NULL) { return ERR_ARG; }
512               msg_ptr = p->payload;
513               plen += p->len;
514             }
515             else
516             {
517               /* next octet in same pbuf */
518               msg_ptr++;
519             }
520           }
521           shift -= 7;
522         }
523         *msg_ptr = (u8_t)sub_id & 0x7F;
524         if (ident_len > 0)
525         {
526           ofs += 1;
527           if (ofs >= plen)
528           {
529             /* next octet in next pbuf */
530             p = p->next;
531             if (p == NULL) { return ERR_ARG; }
532             msg_ptr = p->payload;
533             plen += p->len;
534           }
535           else
536           {
537             /* next octet in same pbuf */
538             msg_ptr++;
539           }
540         }
541         /* proceed to next sub-identifier */
542         ident++;
543       }
544       return ERR_OK;
545     }
546     p = p->next;
547   }
548   /* p == NULL, ofs >= plen */
549   return ERR_ARG;
550 }
551
552 /**
553  * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.
554  *
555  * @param p points to output pbuf to encode raw data into
556  * @param ofs points to the offset within the pbuf chain
557  * @param raw_len raw data length
558  * @param raw points raw data
559  * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
560  */
561 err_t
562 snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw)
563 {
564   u16_t plen, base;
565   u8_t *msg_ptr;
566
567   plen = 0;
568   while (p != NULL)
569   {
570     base = plen;
571     plen += p->len;
572     if (ofs < plen)
573     {
574       msg_ptr = p->payload;
575       msg_ptr += ofs - base;
576
577       while (raw_len > 1)
578       {
579         /* copy raw_len - 1 octets */
580         raw_len--;
581         *msg_ptr = *raw;
582         raw++;
583         ofs += 1;
584         if (ofs >= plen)
585         {
586           /* next octet in next pbuf */
587           p = p->next;
588           if (p == NULL) { return ERR_ARG; }
589           msg_ptr = p->payload;
590           plen += p->len;
591         }
592         else
593         {
594           /* next octet in same pbuf */
595           msg_ptr++;
596         }
597       }
598       if (raw_len > 0)
599       {
600         /* copy last or single octet */
601         *msg_ptr = *raw;
602       }
603       return ERR_OK;
604     }
605     p = p->next;
606   }
607   /* p == NULL, ofs >= plen */
608   return ERR_ARG;
609 }
610
611 #endif /* LWIP_SNMP */