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