📄 msg_out.c
字号:
/** * @file * SNMP output message processing (RFC1157). * * Output responses and traps are build in two passes: * * Pass 0: iterate over the output message backwards to determine encoding lengths * Pass 1: the actual forward encoding of internal form into ASN1 * * The single-pass encoding method described by Comer & Stevens * requires extra buffer space and copying for reversal of the packet. * The buffer requirement can be prohibitively large for big payloads * (>= 484) therefore we use the two encoding passes. *//* * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Christiaan Simons <christiaan.simons@axon.tv> */#include "lwip/opt.h"#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */#include "lwip/udp.h"#include "lwip/netif.h"#include "lwip/snmp.h"#include "lwip/snmp_asn1.h"#include "lwip/snmp_msg.h"struct snmp_trap_dst{ /* destination IP address in network order */ struct ip_addr dip; /* set to 0 when disabled, >0 when enabled */ u8_t enable;};struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS];/** TRAP message structure */struct snmp_msg_trap trap_msg;static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len);static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len);static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root);static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p);static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p);static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs);/** * Sets enable switch for this trap destination. * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 * @param enable switch if 0 destination is disabled >0 enabled. */voidsnmp_trap_dst_enable(u8_t dst_idx, u8_t enable){ if (dst_idx < SNMP_TRAP_DESTINATIONS) { trap_dst[dst_idx].enable = enable; }}/** * Sets IPv4 address for this trap destination. * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 * @param dst IPv4 address in host order. */voidsnmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst){ if (dst_idx < SNMP_TRAP_DESTINATIONS) { trap_dst[dst_idx].dip.addr = htonl(dst->addr); }}/** * Sends a 'getresponse' message to the request originator. * * @param m_stat points to the current message request state source * @return ERR_OK when success, ERR_MEM if we're out of memory * * @note the caller is responsible for filling in outvb in the m_stat * and provide error-status and index (except for tooBig errors) ... */err_tsnmp_send_response(struct snmp_msg_pstat *m_stat){ struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0}; struct pbuf *p; u16_t tot_len; err_t err; /* pass 0, calculate length fields */ tot_len = snmp_varbind_list_sum(&m_stat->outvb); tot_len = snmp_resp_header_sum(m_stat, tot_len); /* try allocating pbuf(s) for complete response */ p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL); if (p == NULL) { LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n")); /* can't construct reply, return error-status tooBig */ m_stat->error_status = SNMP_ES_TOOBIG; m_stat->error_index = 0; /* pass 0, recalculate lengths, for empty varbind-list */ tot_len = snmp_varbind_list_sum(&emptyvb); tot_len = snmp_resp_header_sum(m_stat, tot_len); /* retry allocation once for header and empty varbind-list */ p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL); } if (p != NULL) { /* first pbuf alloc try or retry alloc success */ u16_t ofs; LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n")); /* pass 1, size error, encode packet ino the pbuf(s) */ ofs = snmp_resp_header_enc(m_stat, p); if (m_stat->error_status == SNMP_ES_TOOBIG) { snmp_varbind_list_enc(&emptyvb, p, ofs); } else { snmp_varbind_list_enc(&m_stat->outvb, p, ofs); } switch (m_stat->error_status) { case SNMP_ES_TOOBIG: snmp_inc_snmpouttoobigs(); break; case SNMP_ES_NOSUCHNAME: snmp_inc_snmpoutnosuchnames(); break; case SNMP_ES_BADVALUE: snmp_inc_snmpoutbadvalues(); break; case SNMP_ES_GENERROR: snmp_inc_snmpoutgenerrs(); break; } snmp_inc_snmpoutgetresponses(); snmp_inc_snmpoutpkts(); /** @todo do we need separate rx and tx pcbs for threaded case? */ /** connect to the originating source */ udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp); err = udp_send(m_stat->pcb, p); if (err == ERR_MEM) { /** @todo release some memory, retry and return tooBig? tooMuchHassle? */ err = ERR_MEM; } else { err = ERR_OK; } /** disassociate remote address and port with this pcb */ udp_disconnect(m_stat->pcb); pbuf_free(p); LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n")); return err; } else { /* first pbuf alloc try or retry alloc failed very low on memory, couldn't return tooBig */ return ERR_MEM; }}/** * Sends an generic or enterprise specific trap message. * * @param generic_trap is the trap code * @param eoid points to enterprise object identifier * @param specific_trap used for enterprise traps when generic_trap == 6 * @return ERR_OK when success, ERR_MEM if we're out of memory * * @note the caller is responsible for filling in outvb in the trap_msg * @note the use of the enterpise identifier field * is per RFC1215. * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps * and .iso.org.dod.internet.private.enterprises.yourenterprise * (sysObjectID) for specific traps. */err_tsnmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap){ struct snmp_trap_dst *td; struct netif *dst_if; struct ip_addr dst_ip; struct pbuf *p; u16_t i,tot_len; for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++) { if ((td->enable != 0) && (td->dip.addr != 0)) { /* network order trap destination */ trap_msg.dip.addr = td->dip.addr; /* lookup current source address for this dst */ dst_if = ip_route(&td->dip); dst_ip.addr = ntohl(dst_if->ip_addr.addr); trap_msg.sip_raw[0] = dst_ip.addr >> 24; trap_msg.sip_raw[1] = dst_ip.addr >> 16; trap_msg.sip_raw[2] = dst_ip.addr >> 8; trap_msg.sip_raw[3] = dst_ip.addr; trap_msg.gen_trap = generic_trap; trap_msg.spc_trap = specific_trap; if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC) { /* enterprise-Specific trap */ trap_msg.enterprise = eoid; } else { /* generic (MIB-II) trap */ snmp_get_snmpgrpid_ptr(&trap_msg.enterprise); } snmp_get_sysuptime(&trap_msg.ts); /* pass 0, calculate length fields */ tot_len = snmp_varbind_list_sum(&trap_msg.outvb); tot_len = snmp_trap_header_sum(&trap_msg, tot_len); /* allocate pbuf(s) */ p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL); if (p != NULL) { u16_t ofs; /* pass 1, encode packet ino the pbuf(s) */ ofs = snmp_trap_header_enc(&trap_msg, p); snmp_varbind_list_enc(&trap_msg.outvb, p, ofs); snmp_inc_snmpouttraps(); snmp_inc_snmpoutpkts(); /** connect to the TRAP destination */ udp_connect(trap_msg.pcb, &trap_msg.dip, SNMP_TRAP_PORT); udp_send(trap_msg.pcb, p); /** disassociate remote address and port with this pcb */ udp_disconnect(trap_msg.pcb); pbuf_free(p); } else { return ERR_MEM; } } } return ERR_OK;}voidsnmp_coldstart_trap(void){ trap_msg.outvb.head = NULL; trap_msg.outvb.tail = NULL; trap_msg.outvb.count = 0; snmp_send_trap(SNMP_GENTRAP_COLDSTART, NULL, 0);}voidsnmp_authfail_trap(void){ u8_t enable; snmp_get_snmpenableauthentraps(&enable); if (enable == 1) { trap_msg.outvb.head = NULL; trap_msg.outvb.tail = NULL; trap_msg.outvb.count = 0; snmp_send_trap(SNMP_GENTRAP_AUTHFAIL, NULL, 0); }}/** * Sums response header field lengths from tail to head and * returns resp_header_lengths for second encoding pass. * * @param vb_len varbind-list length * @param rhl points to returned header lengths * @return the required lenght for encoding the response header */static u16_tsnmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len){ u16_t tot_len; struct snmp_resp_header_lengths *rhl; rhl = &m_stat->rhl; tot_len = vb_len; snmp_asn1_enc_s32t_cnt(m_stat->error_index, &rhl->erridxlen); snmp_asn1_enc_length_cnt(rhl->erridxlen, &rhl->erridxlenlen); tot_len += 1 + rhl->erridxlenlen + rhl->erridxlen; snmp_asn1_enc_s32t_cnt(m_stat->error_status, &rhl->errstatlen); snmp_asn1_enc_length_cnt(rhl->errstatlen, &rhl->errstatlenlen); tot_len += 1 + rhl->errstatlenlen + rhl->errstatlen; snmp_asn1_enc_s32t_cnt(m_stat->rid, &rhl->ridlen); snmp_asn1_enc_length_cnt(rhl->ridlen, &rhl->ridlenlen); tot_len += 1 + rhl->ridlenlen + rhl->ridlen; rhl->pdulen = tot_len; snmp_asn1_enc_length_cnt(rhl->pdulen, &rhl->pdulenlen); tot_len += 1 + rhl->pdulenlen;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -