SNMP agent attached to SPI slave

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers msg_out.c Source File

msg_out.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002 *                     Copyright SEEC Ltd
00003 * File:             msg_out.c
00004 * Reference:        A3600-HDR-msg_out
00005 * Content:          Builds SNMP output messages
00006 * Version:          0.3
00007 * System:           mbed gnu compiler
00008 * Target Hardware:  mbed LPC1768                                  
00009 * Amendment Record:    
00010 * Author:      L. Smith for all versions unless otherwise specified 
00011 * Initial release
00012 * 0.1         26/04/12: L. Smith
00013   Derived from msg_out.c by Christiaan Simons <christiaan.simons@axon.tv>
00014   Allow variable length snmp_publiccommunity up to 20 characters 
00015 * 0.2         08/06/12: L. Smith
00016   Define snmp_linkdown_trap() & snmp_linkup_trap()
00017 * 0.3         19/06/12: L. Smith
00018   Define snmp_SPIdown_trap() & snmp_SPIup_trap() and f3kIOchange_trap()
00019 *******************************************************************************/
00020 /**
00021  * @file
00022  * SNMP output message processing (RFC1157).
00023  *
00024  * Output responses and traps are build in two passes:
00025  *
00026  * Pass 0: iterate over the output message backwards to determine encoding lengths
00027  * Pass 1: the actual forward encoding of internal form into ASN1
00028  *
00029  * The single-pass encoding method described by Comer & Stevens
00030  * requires extra buffer space and copying for reversal of the packet.
00031  * The buffer requirement can be prohibitively large for big payloads
00032  * (>= 484) therefore we use the two encoding passes.
00033  */
00034 
00035 /*
00036  * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
00037  * All rights reserved.
00038  *
00039  * Redistribution and use in source and binary forms, with or without modification,
00040  * are permitted provided that the following conditions are met:
00041  *
00042  * 1. Redistributions of source code must retain the above copyright notice,
00043  *    this list of conditions and the following disclaimer.
00044  * 2. Redistributions in binary form must reproduce the above copyright notice,
00045  *    this list of conditions and the following disclaimer in the documentation
00046  *    and/or other materials provided with the distribution.
00047  * 3. The name of the author may not be used to endorse or promote products
00048  *    derived from this software without specific prior written permission.
00049  *
00050  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00051  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00052  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00053  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00054  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00055  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00056  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00057  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00058  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00059  * OF SUCH DAMAGE.
00060  *
00061  * Author: Christiaan Simons <christiaan.simons@axon.tv>
00062  */
00063 
00064 #include "lwip/opt.h"
00065 
00066 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
00067 
00068 #include "lwip/udp.h"
00069 #include "lwip/netif.h"
00070 #include "lwip/snmp.h"
00071 #include "lwip/snmp_asn1.h"
00072 #include "lwip/snmp_msg.h"
00073 #include "private_mib.h"
00074 
00075 struct snmp_trap_dst
00076 {
00077   /* destination IP address in network order */
00078   ip_addr_t dip;
00079   /* set to 0 when disabled, >0 when enabled */
00080   u8_t enable;
00081 };
00082 struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS];
00083 
00084 /** TRAP message structure */
00085 struct snmp_msg_trap trap_msg;
00086 
00087 static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len);
00088 static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len);
00089 static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root);
00090 
00091 static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p);
00092 static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p);
00093 static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs);
00094 
00095 /**
00096  * Sets enable switch for this trap destination.
00097  * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
00098  * @param enable switch if 0 destination is disabled >0 enabled.
00099  */
00100 void
00101 snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)
00102 {
00103   if (dst_idx < SNMP_TRAP_DESTINATIONS)
00104   {
00105 printf("Trap %d enabled", dst_idx);
00106     trap_dst[dst_idx].enable = enable;
00107   }
00108 }
00109 
00110 /**
00111  * Sets IPv4 address for this trap destination.
00112  * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
00113  * @param dst IPv4 address in host order.
00114  */
00115 void
00116 snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst)
00117 {
00118   if (dst_idx < SNMP_TRAP_DESTINATIONS)
00119   {
00120     ip_addr_set(&trap_dst[dst_idx].dip, dst);
00121   }
00122 }
00123 
00124 /**
00125  * Sends a 'getresponse' message to the request originator.
00126  *
00127  * @param m_stat points to the current message request state source
00128  * @return ERR_OK when success, ERR_MEM if we're out of memory
00129  *
00130  * @note the caller is responsible for filling in outvb in the m_stat
00131  * and provide error-status and index (except for tooBig errors) ...
00132  */
00133 err_t
00134 snmp_send_response(struct snmp_msg_pstat *m_stat)
00135 {
00136   struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0};
00137   struct pbuf *p;
00138   u16_t tot_len;
00139   err_t err;
00140 
00141   /* pass 0, calculate length fields */
00142   tot_len = snmp_varbind_list_sum(&m_stat->outvb);
00143   tot_len = snmp_resp_header_sum(m_stat, tot_len);
00144 
00145   /* try allocating pbuf(s) for complete response */
00146   p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
00147   if (p == NULL)
00148   {
00149     LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n"));
00150 
00151     /* can't construct reply, return error-status tooBig */
00152     m_stat->error_status = SNMP_ES_TOOBIG;
00153     m_stat->error_index = 0;
00154     /* pass 0, recalculate lengths, for empty varbind-list */
00155     tot_len = snmp_varbind_list_sum(&emptyvb);
00156     tot_len = snmp_resp_header_sum(m_stat, tot_len);
00157     /* retry allocation once for header and empty varbind-list */
00158     p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
00159   }
00160   if (p != NULL)
00161   {
00162     /* first pbuf alloc try or retry alloc success */
00163     u16_t ofs;
00164 
00165     LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n"));
00166 
00167     /* pass 1, size error, encode packet ino the pbuf(s) */
00168     ofs = snmp_resp_header_enc(m_stat, p);
00169     if (m_stat->error_status == SNMP_ES_TOOBIG)
00170     {
00171       snmp_varbind_list_enc(&emptyvb, p, ofs);
00172     }
00173     else
00174     {
00175       snmp_varbind_list_enc(&m_stat->outvb, p, ofs);
00176     }
00177 
00178     switch (m_stat->error_status)
00179     {
00180       case SNMP_ES_TOOBIG:
00181         snmp_inc_snmpouttoobigs();
00182         break;
00183       case SNMP_ES_NOSUCHNAME:
00184         snmp_inc_snmpoutnosuchnames();
00185         break;
00186       case SNMP_ES_BADVALUE:
00187         snmp_inc_snmpoutbadvalues();
00188         break;
00189       case SNMP_ES_GENERROR:
00190         snmp_inc_snmpoutgenerrs();
00191         break;
00192     }
00193     snmp_inc_snmpoutgetresponses();
00194     snmp_inc_snmpoutpkts();
00195 
00196     /** @todo do we need separate rx and tx pcbs for threaded case? */
00197     /** connect to the originating source */
00198     udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp);
00199     err = udp_send(m_stat->pcb, p);
00200     if (err == ERR_MEM)
00201     {
00202       /** @todo release some memory, retry and return tooBig? tooMuchHassle? */
00203       err = ERR_MEM;
00204     }
00205     else
00206     {
00207       err = ERR_OK;
00208     }
00209     /** disassociate remote address and port with this pcb */
00210     udp_disconnect(m_stat->pcb);
00211 
00212     pbuf_free(p);
00213     LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n"));
00214     return err;
00215   }
00216   else
00217   {
00218     /* first pbuf alloc try or retry alloc failed
00219        very low on memory, couldn't return tooBig */
00220     return ERR_MEM;
00221   }
00222 }
00223 
00224 
00225 /**
00226  * Sends an generic or enterprise specific trap message.
00227  *
00228  * @param generic_trap is the trap code
00229  * @param eoid points to enterprise object identifier
00230  * @param specific_trap used for enterprise traps when generic_trap == 6
00231  * @return ERR_OK when success, ERR_MEM if we're out of memory
00232  *
00233  * @note the caller is responsible for filling in outvb in the trap_msg
00234  * @note the use of the enterpise identifier field
00235  * is per RFC1215.
00236  * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps
00237  * and .iso.org.dod.internet.private.enterprises.yourenterprise
00238  * (sysObjectID) for specific traps.
00239  */
00240 err_t
00241 snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)
00242 {
00243   struct snmp_trap_dst *td;
00244   struct netif *dst_if;
00245   ip_addr_t dst_ip;
00246   struct pbuf *p;
00247   u16_t i,tot_len;
00248 
00249   for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++)
00250   {
00251 printf("\r\nsnmp_send_trap: generic trap %d\r\n", generic_trap );
00252     if ((td->enable != 0) && !ip_addr_isany(&td->dip))
00253     {
00254       /* network order trap destination */
00255       ip_addr_copy(trap_msg.dip, td->dip);
00256 printf("trap_msg.dip %d.%d.%d.%d\r\n", ip4_addr1(&trap_msg.dip), ip4_addr2(&trap_msg.dip), ip4_addr3(&trap_msg.dip), ip4_addr4(&trap_msg.dip));
00257       /* lookup current source address for this dst */
00258       dst_if = ip_route(&td->dip);
00259       ip_addr_copy(dst_ip, dst_if->ip_addr);
00260       /* @todo: what about IPv6? */
00261       trap_msg.sip_raw[0] = ip4_addr1(&dst_ip);
00262       trap_msg.sip_raw[1] = ip4_addr2(&dst_ip);
00263       trap_msg.sip_raw[2] = ip4_addr3(&dst_ip);
00264       trap_msg.sip_raw[3] = ip4_addr4(&dst_ip);
00265 printf("snmp_send_trap: source ip %d.%d.%d.%d\r\n", trap_msg.sip_raw[0], trap_msg.sip_raw[1], trap_msg.sip_raw[2], trap_msg.sip_raw[3]);
00266       trap_msg.gen_trap = generic_trap;
00267       trap_msg.spc_trap = specific_trap;
00268       if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC)
00269       {
00270         /* enterprise-Specific trap */
00271         trap_msg.enterprise = eoid;
00272       }
00273       else
00274       {
00275         /* generic (MIB-II) trap */
00276         snmp_get_snmpgrpid_ptr(&trap_msg.enterprise);
00277       }
00278       snmp_get_sysuptime(&trap_msg.ts);
00279 
00280       /* pass 0, calculate length fields */
00281       tot_len = snmp_varbind_list_sum(&trap_msg.outvb);
00282       tot_len = snmp_trap_header_sum(&trap_msg, tot_len);
00283 
00284       /* allocate pbuf(s) */
00285       p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
00286       if (p != NULL)
00287       {
00288         u16_t ofs;
00289 
00290         /* pass 1, encode packet ino the pbuf(s) */
00291         ofs = snmp_trap_header_enc(&trap_msg, p);
00292         snmp_varbind_list_enc(&trap_msg.outvb, p, ofs);
00293 printf("\r\nsnmp_send_trap: ofs %d tot_len % d\r\n", ofs, tot_len);
00294 
00295         snmp_inc_snmpouttraps();
00296         snmp_inc_snmpoutpkts();
00297 
00298 //    udp_connect(trap_msg.pcb, (ip_addr_t *)&trap_msg.sip_raw[0], SNMP_TRAP_PORT); // added here
00299     /** LS: udp_connect to destination not required */ 
00300         udp_sendto(trap_msg.pcb, p, &trap_msg.dip, SNMP_TRAP_PORT); 
00301 //    udp_disconnect(trap_msg.pcb);  
00302 
00303         pbuf_free(p);
00304       }
00305       else
00306       {
00307         return ERR_MEM;
00308       }
00309     }
00310   }
00311   return ERR_OK;
00312 }
00313 
00314 void
00315 snmp_coldstart_trap(void)
00316 {
00317   trap_msg.outvb.head = NULL;
00318   trap_msg.outvb.tail = NULL;
00319   trap_msg.outvb.count = 0;
00320   snmp_send_trap(SNMP_GENTRAP_COLDSTART, NULL, 0);
00321 }
00322 
00323 /****************************************************************************/ 
00324 /*              snmp_linkdown_trap: v0.2
00325 * Description:  sends linkdown trap message with no OID for source
00326 * Globals used: trap_msg
00327 * Parameters:   NONE
00328 * Returns:      NONE
00329 */
00330 /****************************************************************************/ 
00331 void
00332 snmp_linkdown_trap(void)
00333 {
00334   trap_msg.outvb.head = NULL;
00335   trap_msg.outvb.tail = NULL;
00336   trap_msg.outvb.count = 0;
00337   snmp_send_trap(SNMP_GENTRAP_LINK_DOWN, NULL, 0);
00338 }
00339 
00340 /****************************************************************************/ 
00341 /*              snmp_linkup_trap: v0.2
00342 * Description:  sends linkup trap message with no OID for source
00343 * Globals used: trap_msg
00344 * Parameters:   NONE
00345 * Returns:      NONE
00346 */
00347 /****************************************************************************/ 
00348 void
00349 snmp_linkup_trap(void)
00350 {
00351   trap_msg.outvb.head = NULL;
00352   trap_msg.outvb.tail = NULL;
00353   trap_msg.outvb.count = 0;
00354   snmp_send_trap(SNMP_GENTRAP_LINK_UP, NULL, 0);
00355 }
00356 
00357 void
00358 snmp_authfail_trap(void)
00359 {
00360   u8_t enable;
00361   snmp_get_snmpenableauthentraps(&enable);
00362   if (enable == 1)
00363   {
00364     trap_msg.outvb.head = NULL;
00365     trap_msg.outvb.tail = NULL;
00366     trap_msg.outvb.count = 0;
00367     snmp_send_trap(SNMP_GENTRAP_AUTHFAIL, NULL, 0);
00368   }
00369 }
00370 
00371 
00372 /****************************************************************************/ 
00373 /*              f3kIOchange_trap: v0.3
00374 * Description:  sends SPIdown trap message
00375 * Globals used: trap_msg
00376 * Parameters:   NONE
00377 * Returns:      NONE
00378 */
00379 /****************************************************************************/ 
00380 void f3kIOchange_trap( void )
00381 {
00382   trap_msg.outvb.head = NULL;
00383   trap_msg.outvb.tail = NULL;
00384   trap_msg.outvb.count = 0;
00385   snmp_send_trap(SNMP_GENTRAP_ENTERPRISESPC, &snmptrap_id, SNMP_SPCTRAP_IO_CHANGE);
00386 }
00387 
00388 /****************************************************************************/ 
00389 /*              snmp_SPIdown_trap: v0.3
00390 * Description:  sends SPIdown trap message
00391 * Globals used: trap_msg
00392 * Parameters:   NONE
00393 * Returns:      NONE
00394 */
00395 /****************************************************************************/ 
00396 void snmp_SPIdown_trap( void )
00397 {
00398   trap_msg.outvb.head = NULL;
00399   trap_msg.outvb.tail = NULL;
00400   trap_msg.outvb.count = 0;
00401   snmp_send_trap(SNMP_GENTRAP_ENTERPRISESPC, &snmptrap_id, SNMP_SPCTRAP_SPI_DOWN);
00402 }
00403 
00404 /****************************************************************************/ 
00405 /*              snmp_SPIup_trap: v0.3
00406 * Description:  sends SPI up trap message
00407 * Globals used: trap_msg
00408 * Parameters:   NONE
00409 * Returns:      NONE
00410 */
00411 /****************************************************************************/ 
00412 void snmp_SPIup_trap( void )
00413 {
00414   trap_msg.outvb.head = NULL;
00415   trap_msg.outvb.tail = NULL;
00416   trap_msg.outvb.count = 0;
00417   snmp_send_trap(SNMP_GENTRAP_ENTERPRISESPC, &snmptrap_id, SNMP_SPCTRAP_SPI_UP);
00418 }
00419 
00420 
00421 /**
00422  * Sums response header field lengths from tail to head and
00423  * returns resp_header_lengths for second encoding pass.
00424  *
00425  * @param vb_len varbind-list length
00426  * @param rhl points to returned header lengths
00427  * @return the required lenght for encoding the response header
00428  */
00429 static u16_t
00430 snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len)
00431 {
00432   u16_t tot_len;
00433   struct snmp_resp_header_lengths *rhl;
00434 
00435   rhl = &m_stat->rhl;
00436   tot_len = vb_len;
00437   snmp_asn1_enc_s32t_cnt(m_stat->error_index, &rhl->erridxlen);
00438   snmp_asn1_enc_length_cnt(rhl->erridxlen, &rhl->erridxlenlen);
00439   tot_len += 1 + rhl->erridxlenlen + rhl->erridxlen;
00440 
00441   snmp_asn1_enc_s32t_cnt(m_stat->error_status, &rhl->errstatlen);
00442   snmp_asn1_enc_length_cnt(rhl->errstatlen, &rhl->errstatlenlen);
00443   tot_len += 1 + rhl->errstatlenlen + rhl->errstatlen;
00444 
00445   snmp_asn1_enc_s32t_cnt(m_stat->rid, &rhl->ridlen);
00446   snmp_asn1_enc_length_cnt(rhl->ridlen, &rhl->ridlenlen);
00447   tot_len += 1 + rhl->ridlenlen + rhl->ridlen;
00448 
00449   rhl->pdulen = tot_len;
00450   snmp_asn1_enc_length_cnt(rhl->pdulen, &rhl->pdulenlen);
00451   tot_len += 1 + rhl->pdulenlen;
00452 
00453 //printf("\r\n community length %d\r\n", m_stat->com_strlen); // debug
00454 
00455   rhl->comlen = m_stat->com_strlen;
00456   snmp_asn1_enc_length_cnt(rhl->comlen, &rhl->comlenlen);
00457   tot_len += 1 + rhl->comlenlen + rhl->comlen;
00458 
00459   snmp_asn1_enc_s32t_cnt(snmp_version, &rhl->verlen);
00460   snmp_asn1_enc_length_cnt(rhl->verlen, &rhl->verlenlen);
00461   tot_len += 1 + rhl->verlen + rhl->verlenlen;
00462 
00463   rhl->seqlen = tot_len;
00464   snmp_asn1_enc_length_cnt(rhl->seqlen, &rhl->seqlenlen);
00465   tot_len += 1 + rhl->seqlenlen;
00466 
00467   return tot_len;
00468 }
00469 
00470 /**
00471  * Sums trap header field lengths from tail to head and
00472  * returns trap_header_lengths for second encoding pass.
00473  *
00474  * @param vb_len varbind-list length
00475  * @param thl points to returned header lengths
00476  * @return the required lenght for encoding the trap header
00477  */
00478 static u16_t
00479 snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len)
00480 {
00481   u16_t tot_len;
00482   struct snmp_trap_header_lengths *thl;
00483 
00484   thl = &m_trap->thl;
00485   tot_len = vb_len;
00486 
00487   snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen);
00488   snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen);
00489   tot_len += 1 + thl->tslen + thl->tslenlen;
00490 
00491   snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen);
00492   snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen);
00493   tot_len += 1 + thl->strplen + thl->strplenlen;
00494 
00495   snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen);
00496   snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen);
00497   tot_len += 1 + thl->gtrplen + thl->gtrplenlen;
00498 
00499   thl->aaddrlen = 4;
00500   snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen);
00501   tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen;
00502 
00503   snmp_asn1_enc_oid_cnt(m_trap->enterprise->len, &m_trap->enterprise->id[0], &thl->eidlen);
00504   snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen);
00505   tot_len += 1 + thl->eidlen + thl->eidlenlen;
00506 
00507   thl->pdulen = tot_len;
00508   snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen);
00509   tot_len += 1 + thl->pdulenlen;
00510 
00511 // v0.1:  thl->comlen = sizeof(snmp_publiccommunity) - 1;
00512   thl->comlen = strlen(snmp_publiccommunity);   // v0.1: user-defined community of variable length
00513   snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen);
00514   tot_len += 1 + thl->comlenlen + thl->comlen;
00515 
00516   snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen);
00517   snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen);
00518   tot_len += 1 + thl->verlen + thl->verlenlen;
00519 
00520   thl->seqlen = tot_len;
00521   snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen);
00522   tot_len += 1 + thl->seqlenlen;
00523 
00524   return tot_len;
00525 }
00526 
00527 /**
00528  * Sums varbind lengths from tail to head and
00529  * annotates lengths in varbind for second encoding pass.
00530  *
00531  * @param root points to the root of the variable binding list
00532  * @return the required lenght for encoding the variable bindings
00533  */
00534 static u16_t
00535 snmp_varbind_list_sum(struct snmp_varbind_root *root)
00536 {
00537   struct snmp_varbind *vb;
00538   u32_t *uint_ptr;
00539   s32_t *sint_ptr;
00540   u16_t tot_len;
00541 
00542   tot_len = 0;
00543   vb = root->tail;
00544   while ( vb != NULL )
00545   {
00546     /* encoded value length depends on type */
00547     switch (vb->value_type)
00548     {
00549       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
00550         sint_ptr = (s32_t*)vb->value;
00551         snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen);
00552         break;
00553       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
00554       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
00555       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
00556         uint_ptr = (u32_t*)vb->value;
00557         snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen);
00558         break;
00559       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
00560       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
00561       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
00562       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
00563         vb->vlen = vb->value_len;
00564         break;
00565       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
00566         sint_ptr = (s32_t*)vb->value;
00567         snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen);
00568         break;
00569       default:
00570         /* unsupported type */
00571         vb->vlen = 0;
00572         break;
00573     };
00574     /* encoding length of value length field */
00575     snmp_asn1_enc_length_cnt(vb->vlen, &vb->vlenlen);
00576     snmp_asn1_enc_oid_cnt(vb->ident_len, vb->ident, &vb->olen);
00577     snmp_asn1_enc_length_cnt(vb->olen, &vb->olenlen);
00578 
00579     vb->seqlen = 1 + vb->vlenlen + vb->vlen;
00580     vb->seqlen += 1 + vb->olenlen + vb->olen;
00581     snmp_asn1_enc_length_cnt(vb->seqlen, &vb->seqlenlen);
00582 
00583     /* varbind seq */
00584     tot_len += 1 + vb->seqlenlen + vb->seqlen;
00585 
00586     vb = vb->prev;
00587   }
00588 
00589   /* varbind-list seq */
00590   root->seqlen = tot_len;
00591   snmp_asn1_enc_length_cnt(root->seqlen, &root->seqlenlen);
00592   tot_len += 1 + root->seqlenlen;
00593 
00594   return tot_len;
00595 }
00596 
00597 /**
00598  * Encodes response header from head to tail.
00599  */
00600 static u16_t
00601 snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p)
00602 {
00603   u16_t ofs;
00604 
00605   ofs = 0;
00606   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
00607   ofs += 1;
00608   snmp_asn1_enc_length(p, ofs, m_stat->rhl.seqlen);
00609   ofs += m_stat->rhl.seqlenlen;
00610 
00611   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
00612   ofs += 1;
00613   snmp_asn1_enc_length(p, ofs, m_stat->rhl.verlen);
00614   ofs += m_stat->rhl.verlenlen;
00615   snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_version);
00616   ofs += m_stat->rhl.verlen;
00617 
00618   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));
00619   ofs += 1;
00620   snmp_asn1_enc_length(p, ofs, m_stat->rhl.comlen);
00621   ofs += m_stat->rhl.comlenlen;
00622   snmp_asn1_enc_raw(p, ofs, m_stat->rhl.comlen, m_stat->community);
00623   ofs += m_stat->rhl.comlen;
00624 
00625   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP));
00626   ofs += 1;
00627   snmp_asn1_enc_length(p, ofs, m_stat->rhl.pdulen);
00628   ofs += m_stat->rhl.pdulenlen;
00629 
00630   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
00631   ofs += 1;
00632   snmp_asn1_enc_length(p, ofs, m_stat->rhl.ridlen);
00633   ofs += m_stat->rhl.ridlenlen;
00634   snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.ridlen, m_stat->rid);
00635   ofs += m_stat->rhl.ridlen;
00636 
00637   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
00638   ofs += 1;
00639   snmp_asn1_enc_length(p, ofs, m_stat->rhl.errstatlen);
00640   ofs += m_stat->rhl.errstatlenlen;
00641   snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.errstatlen, m_stat->error_status);
00642   ofs += m_stat->rhl.errstatlen;
00643 
00644   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
00645   ofs += 1;
00646   snmp_asn1_enc_length(p, ofs, m_stat->rhl.erridxlen);
00647   ofs += m_stat->rhl.erridxlenlen;
00648   snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.erridxlen, m_stat->error_index);
00649   ofs += m_stat->rhl.erridxlen;
00650 
00651   return ofs;
00652 }
00653 
00654 /**
00655  * Encodes trap header from head to tail.
00656  */
00657 static u16_t
00658 snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p)
00659 {
00660   u16_t ofs = 0;
00661 
00662 /* DEBUG variable added */
00663 u16_t dbug_ofs = ofs;
00664 u8_t *raw_ptr;
00665 
00666   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
00667   ofs += 1;
00668   snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen);
00669   ofs += m_trap->thl.seqlenlen;
00670 
00671   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
00672   ofs += 1;
00673   snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen);
00674   ofs += m_trap->thl.verlenlen;
00675   snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version);
00676   ofs += m_trap->thl.verlen;
00677 
00678   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));
00679   ofs += 1;
00680   snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen);
00681   ofs += m_trap->thl.comlenlen;
00682   snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (u8_t *)&snmp_publiccommunity[0]);
00683   ofs += m_trap->thl.comlen;
00684 
00685   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP));
00686   ofs += 1;
00687   snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen);
00688   ofs += m_trap->thl.pdulenlen;
00689 
00690   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));
00691   ofs += 1;
00692   snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen);
00693   ofs += m_trap->thl.eidlenlen;
00694   snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]);
00695   ofs += m_trap->thl.eidlen;
00696 
00697   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR));
00698   ofs += 1;
00699   snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen);
00700   ofs += m_trap->thl.aaddrlenlen;
00701   snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]);
00702   ofs += m_trap->thl.aaddrlen;
00703 
00704   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
00705   ofs += 1;
00706   snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen);
00707   ofs += m_trap->thl.gtrplenlen;
00708   snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap);
00709   ofs += m_trap->thl.gtrplen;
00710 
00711   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
00712   ofs += 1;
00713   snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen);
00714   ofs += m_trap->thl.strplenlen;
00715   snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap);
00716   ofs += m_trap->thl.strplen;
00717 
00718   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS));
00719   ofs += 1;
00720   snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen);
00721   ofs += m_trap->thl.tslenlen;
00722   snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts);
00723   ofs += m_trap->thl.tslen;
00724 
00725 /* DEBUG code */
00726 printf("\r\nsnmp_trap_header_enc: ");
00727   raw_ptr = (u8_t*)p->payload;
00728   raw_ptr += dbug_ofs;
00729   while ( dbug_ofs < ofs )
00730   {
00731 printf("%d.", *raw_ptr);
00732     raw_ptr++;
00733     dbug_ofs++;
00734   }
00735 printf("\r\nsnmp_trap_header_enc: ofs %d\r\n", ofs);
00736   return ofs;
00737 }
00738 
00739 /**
00740  * Encodes varbind list from head to tail.
00741  */
00742 static u16_t
00743 snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs)
00744 {
00745   struct snmp_varbind *vb;
00746   s32_t *sint_ptr;
00747   u32_t *uint_ptr;
00748   u8_t *raw_ptr;
00749   
00750 /* DEBUG variable added */
00751 u16_t dbug_ofs = ofs;
00752 
00753   snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
00754   ofs += 1;
00755   snmp_asn1_enc_length(p, ofs, root->seqlen);
00756   ofs += root->seqlenlen;
00757 
00758   vb = root->head;
00759   while ( vb != NULL )
00760   {
00761 printf("\r\nsnmp_varbind_list_enc: start offset %d\r\n", ofs);
00762     snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
00763     ofs += 1;
00764     snmp_asn1_enc_length(p, ofs, vb->seqlen);
00765     ofs += vb->seqlenlen;
00766 
00767     snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));
00768     ofs += 1;
00769     snmp_asn1_enc_length(p, ofs, vb->olen);
00770     ofs += vb->olenlen;
00771     snmp_asn1_enc_oid(p, ofs, vb->ident_len, &vb->ident[0]);
00772     ofs += vb->olen;
00773 
00774     snmp_asn1_enc_type(p, ofs, vb->value_type);
00775     ofs += 1;
00776     snmp_asn1_enc_length(p, ofs, vb->vlen);
00777     ofs += vb->vlenlen;
00778 
00779     switch (vb->value_type)
00780     {
00781       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
00782         sint_ptr = (s32_t*)vb->value;
00783         snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr);
00784         break;
00785       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
00786       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
00787       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
00788         uint_ptr = (u32_t*)vb->value;
00789         snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr);
00790         break;
00791       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
00792       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
00793       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
00794         raw_ptr = (u8_t*)vb->value;
00795         snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr);
00796         break;
00797       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
00798         break;
00799       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
00800         sint_ptr = (s32_t*)vb->value;
00801         snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr);
00802         break;
00803       default:
00804         /* unsupported type */
00805         break;
00806     };
00807     ofs += vb->vlen;
00808     vb = vb->next;
00809   }
00810 /* DEBUG code */
00811 printf("\r\nsnmp_varbind_list_enc: ");
00812   raw_ptr = (u8_t*)p->payload;
00813   raw_ptr += dbug_ofs;
00814   while ( dbug_ofs < ofs )
00815   {
00816 printf("%d.", *raw_ptr);
00817     raw_ptr++;
00818     dbug_ofs++;
00819   }
00820 printf("\r\nsnmp_varbind_list_enc: end ofs %d\r\n", ofs);
00821   return ofs;
00822 }
00823 
00824 #endif /* LWIP_SNMP */