]>
Commit | Line | Data |
---|---|---|
6e6d4a8b JP |
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 */ |