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