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 / msg_out.c
1 /**
2  * @file
3  * SNMP output message processing (RFC1157).
4  *
5  * Output responses and traps are build in two passes:
6  *
7  * Pass 0: iterate over the output message backwards to determine encoding lengths
8  * Pass 1: the actual forward encoding of internal form into ASN1
9  *
10  * The single-pass encoding method described by Comer & Stevens
11  * requires extra buffer space and copying for reversal of the packet.
12  * The buffer requirement can be prohibitively large for big payloads
13  * (>= 484) therefore we use the two encoding passes.
14  */
15
16 /*
17  * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
18  * All rights reserved.
19  *
20  * Redistribution and use in source and binary forms, with or without modification,
21  * are permitted provided that the following conditions are met:
22  *
23  * 1. Redistributions of source code must retain the above copyright notice,
24  *    this list of conditions and the following disclaimer.
25  * 2. Redistributions in binary form must reproduce the above copyright notice,
26  *    this list of conditions and the following disclaimer in the documentation
27  *    and/or other materials provided with the distribution.
28  * 3. The name of the author may not be used to endorse or promote products
29  *    derived from this software without specific prior written permission.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
32  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
33  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
34  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
35  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
36  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
39  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
40  * OF SUCH DAMAGE.
41  *
42  * Author: Christiaan Simons <christiaan.simons@axon.tv>
43  */
44
45 #include "lwip/opt.h"
46
47 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
48
49 #include "lwip/udp.h"
50 #include "lwip/netif.h"
51 #include "lwip/snmp.h"
52 #include "lwip/snmp_asn1.h"
53 #include "lwip/snmp_msg.h"
54
55 struct snmp_trap_dst
56 {
57   /* destination IP address in network order */
58   struct ip_addr dip;
59   /* set to 0 when disabled, >0 when enabled */
60   u8_t enable;
61 };
62 struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS];
63
64 /** TRAP message structure */
65 struct snmp_msg_trap trap_msg;
66
67 static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len);
68 static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len);
69 static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root);
70
71 static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p);
72 static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p);
73 static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs);
74
75 /**
76  * Sets enable switch for this trap destination.
77  * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
78  * @param enable switch if 0 destination is disabled >0 enabled.
79  */
80 void
81 snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)
82 {
83   if (dst_idx < SNMP_TRAP_DESTINATIONS)
84   {
85     trap_dst[dst_idx].enable = enable;
86   }
87 }
88
89 /**
90  * Sets IPv4 address for this trap destination.
91  * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
92  * @param dst IPv4 address in host order.
93  */
94 void
95 snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst)
96 {
97   if (dst_idx < SNMP_TRAP_DESTINATIONS)
98   {
99     trap_dst[dst_idx].dip.addr = htonl(dst->addr);
100   }
101 }
102
103 /**
104  * Sends a 'getresponse' message to the request originator.
105  *
106  * @param m_stat points to the current message request state source
107  * @return ERR_OK when success, ERR_MEM if we're out of memory
108  *
109  * @note the caller is responsible for filling in outvb in the m_stat
110  * and provide error-status and index (except for tooBig errors) ...
111  */
112 err_t
113 snmp_send_response(struct snmp_msg_pstat *m_stat)
114 {
115   struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0};
116   struct pbuf *p;
117   u16_t tot_len;
118   err_t err;
119
120   /* pass 0, calculate length fields */
121   tot_len = snmp_varbind_list_sum(&m_stat->outvb);
122   tot_len = snmp_resp_header_sum(m_stat, tot_len);
123
124   /* try allocating pbuf(s) for complete response */
125   p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
126   if (p == NULL)
127   {
128     LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n"));
129
130     /* can't construct reply, return error-status tooBig */
131     m_stat->error_status = SNMP_ES_TOOBIG;
132     m_stat->error_index = 0;
133     /* pass 0, recalculate lengths, for empty varbind-list */
134     tot_len = snmp_varbind_list_sum(&emptyvb);
135     tot_len = snmp_resp_header_sum(m_stat, tot_len);
136     /* retry allocation once for header and empty varbind-list */
137     p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
138   }
139   if (p != NULL)
140   {
141     /* first pbuf alloc try or retry alloc success */
142     u16_t ofs;
143
144     LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n"));
145
146     /* pass 1, size error, encode packet ino the pbuf(s) */
147     ofs = snmp_resp_header_enc(m_stat, p);
148     if (m_stat->error_status == SNMP_ES_TOOBIG)
149     {
150       snmp_varbind_list_enc(&emptyvb, p, ofs);
151     }
152     else
153     {
154       snmp_varbind_list_enc(&m_stat->outvb, p, ofs);
155     }
156
157     switch (m_stat->error_status)
158     {
159       case SNMP_ES_TOOBIG:
160         snmp_inc_snmpouttoobigs();
161         break;
162       case SNMP_ES_NOSUCHNAME:
163         snmp_inc_snmpoutnosuchnames();
164         break;
165       case SNMP_ES_BADVALUE:
166         snmp_inc_snmpoutbadvalues();
167         break;
168       case SNMP_ES_GENERROR:
169         snmp_inc_snmpoutgenerrs();
170         break;
171     }
172     snmp_inc_snmpoutgetresponses();
173     snmp_inc_snmpoutpkts();
174
175     /** @todo do we need separate rx and tx pcbs for threaded case? */
176     /** connect to the originating source */
177     udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp);
178     err = udp_send(m_stat->pcb, p);
179     if (err == ERR_MEM)
180     {
181       /** @todo release some memory, retry and return tooBig? tooMuchHassle? */
182       err = ERR_MEM;
183     }
184     else
185     {
186       err = ERR_OK;
187     }
188     /** disassociate remote address and port with this pcb */
189     udp_disconnect(m_stat->pcb);
190
191     pbuf_free(p);
192     LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n"));
193     return err;
194   }
195   else
196   {
197     /* first pbuf alloc try or retry alloc failed
198        very low on memory, couldn't return tooBig */
199     return ERR_MEM;
200   }
201 }
202
203
204 /**
205  * Sends an generic or enterprise specific trap message.
206  *
207  * @param generic_trap is the trap code
208  * @param eoid points to enterprise object identifier
209  * @param specific_trap used for enterprise traps when generic_trap == 6
210  * @return ERR_OK when success, ERR_MEM if we're out of memory
211  *
212  * @note the caller is responsible for filling in outvb in the trap_msg
213  * @note the use of the enterpise identifier field
214  * is per RFC1215.
215  * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps
216  * and .iso.org.dod.internet.private.enterprises.yourenterprise
217  * (sysObjectID) for specific traps.
218  */
219 err_t
220 snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)
221 {
222   struct snmp_trap_dst *td;
223   struct netif *dst_if;
224   struct ip_addr dst_ip;
225   struct pbuf *p;
226   u16_t i,tot_len;
227
228   for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++)
229   {
230     if ((td->enable != 0) && (td->dip.addr != 0))
231     {
232       /* network order trap destination */
233       trap_msg.dip.addr = td->dip.addr;
234       /* lookup current source address for this dst */
235       dst_if = ip_route(&td->dip);
236       dst_ip.addr = ntohl(dst_if->ip_addr.addr);
237       trap_msg.sip_raw[0] = dst_ip.addr >> 24;
238       trap_msg.sip_raw[1] = dst_ip.addr >> 16;
239       trap_msg.sip_raw[2] = dst_ip.addr >> 8;
240       trap_msg.sip_raw[3] = dst_ip.addr;
241       trap_msg.gen_trap = generic_trap;
242       trap_msg.spc_trap = specific_trap;
243       if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC)
244       {
245         /* enterprise-Specific trap */
246         trap_msg.enterprise = eoid;
247       }
248       else
249       {
250         /* generic (MIB-II) trap */
251         snmp_get_snmpgrpid_ptr(&trap_msg.enterprise);
252       }
253       snmp_get_sysuptime(&trap_msg.ts);
254
255       /* pass 0, calculate length fields */
256       tot_len = snmp_varbind_list_sum(&trap_msg.outvb);
257       tot_len = snmp_trap_header_sum(&trap_msg, tot_len);
258
259       /* allocate pbuf(s) */
260       p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
261       if (p != NULL)
262       {
263         u16_t ofs;
264
265         /* pass 1, encode packet ino the pbuf(s) */
266         ofs = snmp_trap_header_enc(&trap_msg, p);
267         snmp_varbind_list_enc(&trap_msg.outvb, p, ofs);
268
269         snmp_inc_snmpouttraps();
270         snmp_inc_snmpoutpkts();
271
272         /** connect to the TRAP destination */
273         udp_connect(trap_msg.pcb, &trap_msg.dip, SNMP_TRAP_PORT);
274         udp_send(trap_msg.pcb, p);
275         /** disassociate remote address and port with this pcb */
276         udp_disconnect(trap_msg.pcb);
277
278         pbuf_free(p);
279       }
280       else
281       {
282         return ERR_MEM;
283       }
284     }
285   }
286   return ERR_OK;
287 }
288
289 void
290 snmp_coldstart_trap(void)
291 {
292   trap_msg.outvb.head = NULL;
293   trap_msg.outvb.tail = NULL;
294   trap_msg.outvb.count = 0;
295   snmp_send_trap(SNMP_GENTRAP_COLDSTART, NULL, 0);
296 }
297
298 void
299 snmp_authfail_trap(void)
300 {
301   u8_t enable;
302   snmp_get_snmpenableauthentraps(&enable);
303   if (enable == 1)
304   {
305     trap_msg.outvb.head = NULL;
306     trap_msg.outvb.tail = NULL;
307     trap_msg.outvb.count = 0;
308     snmp_send_trap(SNMP_GENTRAP_AUTHFAIL, NULL, 0);
309   }
310 }
311
312 /**
313  * Sums response header field lengths from tail to head and
314  * returns resp_header_lengths for second encoding pass.
315  *
316  * @param vb_len varbind-list length
317  * @param rhl points to returned header lengths
318  * @return the required lenght for encoding the response header
319  */
320 static u16_t
321 snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len)
322 {
323   u16_t tot_len;
324   struct snmp_resp_header_lengths *rhl;
325
326   rhl = &m_stat->rhl;
327   tot_len = vb_len;
328   snmp_asn1_enc_s32t_cnt(m_stat->error_index, &rhl->erridxlen);
329   snmp_asn1_enc_length_cnt(rhl->erridxlen, &rhl->erridxlenlen);
330   tot_len += 1 + rhl->erridxlenlen + rhl->erridxlen;
331
332   snmp_asn1_enc_s32t_cnt(m_stat->error_status, &rhl->errstatlen);
333   snmp_asn1_enc_length_cnt(rhl->errstatlen, &rhl->errstatlenlen);
334   tot_len += 1 + rhl->errstatlenlen + rhl->errstatlen;
335
336   snmp_asn1_enc_s32t_cnt(m_stat->rid, &rhl->ridlen);
337   snmp_asn1_enc_length_cnt(rhl->ridlen, &rhl->ridlenlen);
338   tot_len += 1 + rhl->ridlenlen + rhl->ridlen;
339
340   rhl->pdulen = tot_len;
341   snmp_asn1_enc_length_cnt(rhl->pdulen, &rhl->pdulenlen);
342   tot_len += 1 + rhl->pdulenlen;
343
344   rhl->comlen = m_stat->com_strlen;
345   snmp_asn1_enc_length_cnt(rhl->comlen, &rhl->comlenlen);
346   tot_len += 1 + rhl->comlenlen + rhl->comlen;
347
348   snmp_asn1_enc_s32t_cnt(snmp_version, &rhl->verlen);
349   snmp_asn1_enc_length_cnt(rhl->verlen, &rhl->verlenlen);
350   tot_len += 1 + rhl->verlen + rhl->verlenlen;
351
352   rhl->seqlen = tot_len;
353   snmp_asn1_enc_length_cnt(rhl->seqlen, &rhl->seqlenlen);
354   tot_len += 1 + rhl->seqlenlen;
355
356   return tot_len;
357 }
358
359 /**
360  * Sums trap header field lengths from tail to head and
361  * returns trap_header_lengths for second encoding pass.
362  *
363  * @param vb_len varbind-list length
364  * @param thl points to returned header lengths
365  * @return the required lenght for encoding the trap header
366  */
367 static u16_t
368 snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len)
369 {
370   u16_t tot_len;
371   struct snmp_trap_header_lengths *thl;
372
373   thl = &m_trap->thl;
374   tot_len = vb_len;
375
376   snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen);
377   snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen);
378   tot_len += 1 + thl->tslen + thl->tslenlen;
379
380   snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen);
381   snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen);
382   tot_len += 1 + thl->strplen + thl->strplenlen;
383
384   snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen);
385   snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen);
386   tot_len += 1 + thl->gtrplen + thl->gtrplenlen;
387
388   thl->aaddrlen = 4;
389   snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen);
390   tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen;
391
392   snmp_asn1_enc_oid_cnt(m_trap->enterprise->len, &m_trap->enterprise->id[0], &thl->eidlen);
393   snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen);
394   tot_len += 1 + thl->eidlen + thl->eidlenlen;
395
396   thl->pdulen = tot_len;
397   snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen);
398   tot_len += 1 + thl->pdulenlen;
399
400   thl->comlen = sizeof(snmp_publiccommunity) - 1;
401   snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen);
402   tot_len += 1 + thl->comlenlen + thl->comlen;
403
404   snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen);
405   snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen);
406   tot_len += 1 + thl->verlen + thl->verlenlen;
407
408   thl->seqlen = tot_len;
409   snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen);
410   tot_len += 1 + thl->seqlenlen;
411
412   return tot_len;
413 }
414
415 /**
416  * Sums varbind lengths from tail to head and
417  * annotates lengths in varbind for second encoding pass.
418  *
419  * @param root points to the root of the variable binding list
420  * @return the required lenght for encoding the variable bindings
421  */
422 static u16_t
423 snmp_varbind_list_sum(struct snmp_varbind_root *root)
424 {
425   struct snmp_varbind *vb;
426   u32_t *uint_ptr;
427   s32_t *sint_ptr;
428   u16_t tot_len;
429
430   tot_len = 0;
431   vb = root->tail;
432   while ( vb != NULL )
433   {
434     /* encoded value lenght depends on type */
435     switch (vb->value_type)
436     {
437       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
438         sint_ptr = vb->value;
439         snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen);
440         break;
441       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
442       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
443       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
444         uint_ptr = vb->value;
445         snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen);
446         break;
447       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
448       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
449       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
450       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
451         vb->vlen = vb->value_len;
452         break;
453       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
454         sint_ptr = vb->value;
455         snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen);
456         break;
457       default:
458         /* unsupported type */
459         vb->vlen = 0;
460         break;
461     };
462     /* encoding length of value length field */
463     snmp_asn1_enc_length_cnt(vb->vlen, &vb->vlenlen);
464     snmp_asn1_enc_oid_cnt(vb->ident_len, vb->ident, &vb->olen);
465     snmp_asn1_enc_length_cnt(vb->olen, &vb->olenlen);
466
467     vb->seqlen = 1 + vb->vlenlen + vb->vlen;
468     vb->seqlen += 1 + vb->olenlen + vb->olen;
469     snmp_asn1_enc_length_cnt(vb->seqlen, &vb->seqlenlen);
470
471     /* varbind seq */
472     tot_len += 1 + vb->seqlenlen + vb->seqlen;
473
474     vb = vb->prev;
475   }
476
477   /* varbind-list seq */
478   root->seqlen = tot_len;
479   snmp_asn1_enc_length_cnt(root->seqlen, &root->seqlenlen);
480   tot_len += 1 + root->seqlenlen;
481
482   return tot_len;
483 }
484
485 /**
486  * Encodes response header from head to tail.
487  */
488 static u16_t
489 snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p)
490 {
491   u16_t ofs;
492
493   ofs = 0;
494   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
495   ofs += 1;
496   snmp_asn1_enc_length(p, ofs, m_stat->rhl.seqlen);
497   ofs += m_stat->rhl.seqlenlen;
498
499   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
500   ofs += 1;
501   snmp_asn1_enc_length(p, ofs, m_stat->rhl.verlen);
502   ofs += m_stat->rhl.verlenlen;
503   snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_version);
504   ofs += m_stat->rhl.verlen;
505
506   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));
507   ofs += 1;
508   snmp_asn1_enc_length(p, ofs, m_stat->rhl.comlen);
509   ofs += m_stat->rhl.comlenlen;
510   snmp_asn1_enc_raw(p, ofs, m_stat->rhl.comlen, m_stat->community);
511   ofs += m_stat->rhl.comlen;
512
513   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP));
514   ofs += 1;
515   snmp_asn1_enc_length(p, ofs, m_stat->rhl.pdulen);
516   ofs += m_stat->rhl.pdulenlen;
517
518   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
519   ofs += 1;
520   snmp_asn1_enc_length(p, ofs, m_stat->rhl.ridlen);
521   ofs += m_stat->rhl.ridlenlen;
522   snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.ridlen, m_stat->rid);
523   ofs += m_stat->rhl.ridlen;
524
525   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
526   ofs += 1;
527   snmp_asn1_enc_length(p, ofs, m_stat->rhl.errstatlen);
528   ofs += m_stat->rhl.errstatlenlen;
529   snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.errstatlen, m_stat->error_status);
530   ofs += m_stat->rhl.errstatlen;
531
532   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
533   ofs += 1;
534   snmp_asn1_enc_length(p, ofs, m_stat->rhl.erridxlen);
535   ofs += m_stat->rhl.erridxlenlen;
536   snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.erridxlen, m_stat->error_index);
537   ofs += m_stat->rhl.erridxlen;
538
539   return ofs;
540 }
541
542 /**
543  * Encodes trap header from head to tail.
544  */
545 static u16_t
546 snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p)
547 {
548   u16_t ofs;
549
550   ofs = 0;
551   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
552   ofs += 1;
553   snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen);
554   ofs += m_trap->thl.seqlenlen;
555
556   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
557   ofs += 1;
558   snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen);
559   ofs += m_trap->thl.verlenlen;
560   snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version);
561   ofs += m_trap->thl.verlen;
562
563   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));
564   ofs += 1;
565   snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen);
566   ofs += m_trap->thl.comlenlen;
567   snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (u8_t *)&snmp_publiccommunity[0]);
568   ofs += m_trap->thl.comlen;
569
570   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP));
571   ofs += 1;
572   snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen);
573   ofs += m_trap->thl.pdulenlen;
574
575   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));
576   ofs += 1;
577   snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen);
578   ofs += m_trap->thl.eidlenlen;
579   snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]);
580   ofs += m_trap->thl.eidlen;
581
582   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR));
583   ofs += 1;
584   snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen);
585   ofs += m_trap->thl.aaddrlenlen;
586   snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]);
587   ofs += m_trap->thl.aaddrlen;
588
589   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
590   ofs += 1;
591   snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen);
592   ofs += m_trap->thl.gtrplenlen;
593   snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap);
594   ofs += m_trap->thl.gtrplen;
595
596   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
597   ofs += 1;
598   snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen);
599   ofs += m_trap->thl.strplenlen;
600   snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap);
601   ofs += m_trap->thl.strplen;
602
603   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS));
604   ofs += 1;
605   snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen);
606   ofs += m_trap->thl.tslenlen;
607   snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts);
608   ofs += m_trap->thl.tslen;
609
610   return ofs;
611 }
612
613 /**
614  * Encodes varbind list from head to tail.
615  */
616 static u16_t
617 snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs)
618 {
619   struct snmp_varbind *vb;
620   s32_t *sint_ptr;
621   u32_t *uint_ptr;
622   u8_t *raw_ptr;
623
624   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
625   ofs += 1;
626   snmp_asn1_enc_length(p, ofs, root->seqlen);
627   ofs += root->seqlenlen;
628
629   vb = root->head;
630   while ( vb != NULL )
631   {
632     snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
633     ofs += 1;
634     snmp_asn1_enc_length(p, ofs, vb->seqlen);
635     ofs += vb->seqlenlen;
636
637     snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));
638     ofs += 1;
639     snmp_asn1_enc_length(p, ofs, vb->olen);
640     ofs += vb->olenlen;
641     snmp_asn1_enc_oid(p, ofs, vb->ident_len, &vb->ident[0]);
642     ofs += vb->olen;
643
644     snmp_asn1_enc_type(p, ofs, vb->value_type);
645     ofs += 1;
646     snmp_asn1_enc_length(p, ofs, vb->vlen);
647     ofs += vb->vlenlen;
648
649     switch (vb->value_type)
650     {
651       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
652         sint_ptr = vb->value;
653         snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr);
654         break;
655       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
656       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
657       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
658         uint_ptr = vb->value;
659         snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr);
660         break;
661       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
662       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
663       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
664         raw_ptr = vb->value;
665         snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr);
666         break;
667       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
668         break;
669       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
670         sint_ptr = vb->value;
671         snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr);
672         break;
673       default:
674         /* unsupported type */
675         break;
676     };
677     ofs += vb->vlen;
678     vb = vb->next;
679   }
680   return ofs;
681 }
682
683 #endif /* LWIP_SNMP */