snmp_agent_message.c
Go to the documentation of this file.
1 /**
2  * @file snmp_message.c
3  * @brief SNMP message formatting and parsing
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2019 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 1.9.6
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL SNMP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "snmp/snmp_agent.h"
39 #include "core/crypto.h"
40 #include "encoding/asn1.h"
41 #include "debug.h"
42 
43 //Check TCP/IP stack configuration
44 #if (SNMP_AGENT_SUPPORT == ENABLED)
45 
46 
47 /**
48  * @brief Initialize a SNMP message
49  * @param[in] message Pointer to the SNMP message
50  **/
51 
53 {
54  //Current position in the message
55  message->pos = NULL;
56  //Length of the message
57  message->length = 0;
58 
59  //SNMP version identifier
60  message->version = SNMP_VERSION_1;
61 
62 #if (SNMP_V1_SUPPORT == ENABLED || SNMP_V2C_SUPPORT == ENABLED)
63  //Initialize community name
64  message->community = NULL;
65  message->communityLen = 0;
66 #endif
67 
68 #if (SNMP_V3_SUPPORT == ENABLED)
69  //Initialize msgGlobalData fields
70  message->msgId = 0;
71  message->msgMaxSize = 0;
72  message->msgFlags = 0;
73  message->msgSecurityModel = 0;
74 
75  //Initialize msgSecurityParameters fields
76  message->msgAuthEngineId = NULL;
77  message->msgAuthEngineIdLen = 0;
78  message->msgAuthEngineBoots = 0;
79  message->msgAuthEngineTime = 0;
80  message->msgUserName = NULL;
81  message->msgUserNameLen = 0;
82  message->msgAuthParameters = NULL;
83  message->msgAuthParametersLen = 0;
84  message->msgPrivParameters = NULL;
85  message->msgPrivParametersLen = 0;
86 
87  //Initialize scopedPDU fields
88  message->contextEngineId = NULL;
89  message->contextEngineIdLen = 0;
90  message->contextName = NULL;
91  message->contextNameLen = 0;
92 #endif
93 
94  //Initialize PDU fields
95  message->pduType = SNMP_PDU_GET_REQUEST;
96  message->requestId = 0;
97  message->errorStatus = SNMP_ERROR_NONE;
98  message->errorIndex = 0;
99 
100 #if (SNMP_V1_SUPPORT == ENABLED)
101  message->enterpriseOid = NULL;
102  message->enterpriseOidLen = 0;
103  message->agentAddr = IPV4_UNSPECIFIED_ADDR;
104  message->genericTrapType = 0;
105  message->specificTrapCode = 0;
106  message->timestamp = 0;
107 #endif
108 
109 #if (SNMP_V2C_SUPPORT == ENABLED || SNMP_V3_SUPPORT == ENABLED)
110  message->nonRepeaters = 0;
111  message->maxRepetitions = 0;
112 #endif
113 
114  //Initialize the list of variable bindings
115  message->varBindList = NULL;
116  message->varBindListLen = 0;
117  message->varBindListMaxLen = 0;
118  message->oidLen = 0;
119 }
120 
121 
122 /**
123  * @brief Initialize a GetResponse-PDU
124  * @param[in] context Pointer to the SNMP agent context
125  * @return Error code
126  **/
127 
129 {
130  error_t error;
131 
132  //SNMP version identifier
133  context->response.version = context->request.version;
134 
135 #if (SNMP_V1_SUPPORT == ENABLED || SNMP_V2C_SUPPORT == ENABLED)
136  //Community name
137  context->response.community = context->request.community;
138  context->response.communityLen = context->request.communityLen;
139 #endif
140 
141 #if (SNMP_V3_SUPPORT == ENABLED)
142  //Message identifier
143  context->response.msgId = context->request.msgId;
144  //Maximum message size supported by the sender
145  context->response.msgMaxSize = SNMP_MAX_MSG_SIZE;
146 
147  //Bit fields which control processing of the message
148  context->response.msgFlags = context->request.msgFlags &
150 
151  //Security model used by the sender
152  context->response.msgSecurityModel = context->request.msgSecurityModel;
153 
154  //Authoritative engine identifier
155  context->response.msgAuthEngineId = context->contextEngine;
156  context->response.msgAuthEngineIdLen = context->contextEngineLen;
157 
158  //Number of times the SNMP engine has rebooted
159  context->response.msgAuthEngineBoots = context->engineBoots;
160  //Number of seconds since last reboot
161  context->response.msgAuthEngineTime = context->engineTime;
162 
163  //User name
164  context->response.msgUserName = context->request.msgUserName;
165  context->response.msgUserNameLen = context->request.msgUserNameLen;
166 
167  //Authentication parameters
168  context->response.msgAuthParameters = NULL;
169  context->response.msgAuthParametersLen = context->request.msgAuthParametersLen;
170 
171  //Privacy parameters
172  context->response.msgPrivParameters = context->privParameters;
173  context->response.msgPrivParametersLen = context->request.msgPrivParametersLen;
174 
175  //Context engine identifier
176  context->response.contextEngineId = context->contextEngine;
177  context->response.contextEngineIdLen = context->contextEngineLen;
178 
179  //Context name
180  context->response.contextName = context->request.contextName;
181  context->response.contextNameLen = context->request.contextNameLen;
182 #endif
183 
184  //PDU type
185  context->response.pduType = SNMP_PDU_GET_RESPONSE;
186  //Request identifier
187  context->response.requestId = context->request.requestId;
188 
189  //Make room for the message header at the beginning of the buffer
190  error = snmpComputeMessageOverhead(&context->response);
191  //Return status code
192  return error;
193 }
194 
195 
196 /**
197  * @brief Compute SNMP message overhead
198  * @param[in] message Pointer to the SNMP message
199  **/
200 
202 {
203  size_t n;
204 
205 #if (SNMP_V1_SUPPORT == ENABLED)
206  //SNMPv1 version?
207  if(message->version == SNMP_VERSION_1)
208  {
209  //SNMPv1 message header overhead
211  //Take into consideration variable-length fields
212  n += message->communityLen + message->enterpriseOidLen;
213  }
214  else
215 #endif
216 #if (SNMP_V2C_SUPPORT == ENABLED)
217  //SNMPv2c version?
218  if(message->version == SNMP_VERSION_2C)
219  {
220  //SNMPv2c message header overhead
222  //Take into consideration variable-length fields
223  n += message->communityLen;
224  }
225  else
226 #endif
227 #if (SNMP_V3_SUPPORT == ENABLED)
228  //SNMPv3 version?
229  if(message->version == SNMP_VERSION_3)
230  {
231  //SNMPv3 message header overhead
233 
234  //Take into consideration variable-length fields
235  n += message->msgAuthEngineIdLen + message->msgUserNameLen +
236  message->msgAuthParametersLen + message->msgPrivParametersLen +
237  message->contextEngineIdLen + message->contextNameLen;
238  }
239  else
240 #endif
241  //Invalid SNMP version?
242  {
243  //Report an error
244  return ERROR_INVALID_VERSION;
245  }
246 
247  //Sanity check
249  return ERROR_FAILURE;
250 
251  //Make room for the message header at the beginning of the buffer
252  message->varBindList = message->buffer + n;
253  //Maximum length of the variable binding list
254  message->varBindListMaxLen = (SNMP_MAX_MSG_SIZE - SNMP_MSG_ENCRYPTION_OVERHEAD) - n;
255 
256  //Successful processing
257  return NO_ERROR;
258 }
259 
260 
261 /**
262  * @brief Parse SNMP message header
263  * @param[in,out] message Pointer to the incoming SNMP message
264  * @return Error code
265  **/
266 
268 {
269  error_t error;
270  size_t length;
271  const uint8_t *p;
272  Asn1Tag tag;
273 
274  //Point to the first byte of the SNMP message
275  p = message->buffer;
276  //Retrieve the length of the SNMP message
277  length = message->bufferLen;
278 
279  //The SNMP message is encapsulated within a sequence
280  error = asn1ReadSequence(p, length, &tag);
281  //Failed to decode ASN.1 tag?
282  if(error)
283  return error;
284 
285  //Point to the first field of the sequence
286  p = tag.value;
287  length = tag.length;
288 
289  //Read version identifier
290  error = asn1ReadInt32(p, length, &tag, &message->version);
291  //Failed to decode ASN.1 tag?
292  if(error)
293  return error;
294 
295  //Make sure the SNMP version identifier is valid
296  if(message->version != SNMP_VERSION_1 &&
297  message->version != SNMP_VERSION_2C &&
298  message->version != SNMP_VERSION_3)
299  {
300  //The SNMP version is not acceptable
301  return ERROR_INVALID_VERSION;
302  }
303 
304  //Advance data pointer
305  message->pos = (uint8_t *) p + tag.totalLength;
306  //Remaining bytes to process
307  message->length = length - tag.totalLength;
308 
309  //Successful processing
310  return NO_ERROR;
311 }
312 
313 
314 /**
315  * @brief Format SNMP message header
316  * @param[in,out] message Pointer to the outgoing SNMP message
317  * @return Error code
318  **/
319 
321 {
322  error_t error;
323  size_t n;
324  Asn1Tag tag;
325 
326  //SNMPv1 or SNMPv2c version?
327  if(message->version == SNMP_VERSION_1 ||
328  message->version == SNMP_VERSION_2C)
329  {
330  //Write the community name
331  error = snmpWriteCommunity(message);
332  //Any error to report?
333  if(error)
334  return error;
335  }
336  //SNMPv3 version?
337  else if(message->version == SNMP_VERSION_3)
338  {
339  //Write msgSecurityParameters field
341  //Any error to report?
342  if(error)
343  return error;
344 
345  //Write msgGlobalData field
346  error = snmpWriteGlobalData(message);
347  //Any error to report?
348  if(error)
349  return error;
350  }
351  //Invalid version?
352  else
353  {
354  //Report an error
355  return ERROR_INVALID_VERSION;
356  }
357 
358  //Write version identifier
359  error = asn1WriteInt32(message->version, TRUE, message->pos, &n);
360  //Any error to report?
361  if(error)
362  return error;
363 
364  //Move backward
365  message->pos -= n;
366  //Update the length of the message
367  message->length += n;
368 
369  //The SNMP message is encapsulated within a sequence
370  tag.constructed = TRUE;
373  tag.length = message->length;
374  tag.value = NULL;
375 
376  //Write the corresponding ASN.1 tag
377  error = asn1WriteTag(&tag, TRUE, message->pos, &n);
378  //Any error to report?
379  if(error)
380  return error;
381 
382  //Move backward
383  message->pos -= n;
384  //Total length of the SNMP message
385  message->length += n;
386 
387  //Successful processing
388  return NO_ERROR;
389 }
390 
391 
392 /**
393  * @brief Parse community name
394  * @param[in,out] message Pointer to the incoming SNMP message
395  * @return Error code
396  **/
397 
399 {
400 #if (SNMP_V1_SUPPORT == ENABLED || SNMP_V2C_SUPPORT == ENABLED)
401  error_t error;
402  Asn1Tag tag;
403 
404  //Read community name
405  error = asn1ReadTag(message->pos, message->length, &tag);
406  //Failed to decode ASN.1 tag?
407  if(error)
408  return error;
409 
410  //Enforce encoding, class and type
412  //The tag does not match the criteria?
413  if(error)
414  return error;
415 
416  //Save community name
417  message->community = (char_t *) tag.value;
418  message->communityLen = tag.length;
419 
420  //Advance data pointer
421  message->pos += tag.totalLength;
422  //Remaining bytes to process
423  message->length -= tag.totalLength;
424 
425  //No error to report
426  return NO_ERROR;
427 #else
428  //Not implemented
429  return ERROR_NOT_IMPLEMENTED;
430 #endif
431 }
432 
433 
434 /**
435  * @brief Format community name
436  * @param[in,out] message Pointer to the outgoing SNMP message
437  * @return Error code
438  **/
439 
441 {
442 #if (SNMP_V1_SUPPORT == ENABLED || SNMP_V2C_SUPPORT == ENABLED)
443  error_t error;
444  size_t n;
445  Asn1Tag tag;
446 
447  //The community name is an octet string
448  tag.constructed = FALSE;
451  tag.length = message->communityLen;
452  tag.value = (uint8_t *) message->community;
453 
454  //Write the corresponding ASN.1 tag
455  error = asn1WriteTag(&tag, TRUE, message->pos, &n);
456  //Any error to report?
457  if(error)
458  return error;
459 
460  //Point to the first byte of the community name
461  message->pos -= n;
462  //Total length of the message
463  message->length += n;
464 
465  //Successful processing
466  return NO_ERROR;
467 #else
468  //Not implemented
469  return ERROR_NOT_IMPLEMENTED;
470 #endif
471 }
472 
473 
474 /**
475  * @brief Parse msgGlobalData field
476  * @param[in,out] message Pointer to the incoming SNMP message
477  * @return Error code
478  **/
479 
481 {
482 #if (SNMP_V3_SUPPORT == ENABLED)
483  error_t error;
484  size_t length;
485  const uint8_t *p;
486  Asn1Tag tag;
487 
488  //Read the msgGlobalData field
489  error = asn1ReadSequence(message->pos, message->length, &tag);
490  //Failed to decode ASN.1 tag?
491  if(error)
492  return error;
493 
494  //Advance pointer over the msgGlobalData field
495  message->pos += tag.totalLength;
496  //Remaining bytes to process
497  message->length -= tag.totalLength;
498 
499  //Point to the first field of the sequence
500  p = tag.value;
501  length = tag.length;
502 
503  //The msgID is used between two SNMP entities to coordinate request
504  //messages and responses
505  error = asn1ReadInt32(p, length, &tag, &message->msgId);
506  //Failed to decode ASN.1 tag?
507  if(error)
508  return error;
509 
510  //Make sure the value is in the range 0..2147483647
511  if(message->msgId < 0)
512  return ERROR_WRONG_ENCODING;
513 
514  //Point to the next field
515  p += tag.totalLength;
516  length -= tag.totalLength;
517 
518  //The msgMaxSize field of the message conveys the maximum message size
519  //supported by the sender of the message
520  error = asn1ReadInt32(p, length, &tag, &message->msgMaxSize);
521  //Failed to decode ASN.1 tag?
522  if(error)
523  return error;
524 
525  //Make sure the value is in the range 484..2147483647
526  if(message->msgMaxSize < 484)
527  return ERROR_WRONG_ENCODING;
528 
529  //Point to the next field
530  p += tag.totalLength;
531  length -= tag.totalLength;
532 
533  //The msgFlags field of the message contains several bit fields which
534  //control processing of the message
535  error = asn1ReadTag(p, length, &tag);
536  //Failed to decode ASN.1 tag?
537  if(error)
538  return error;
539 
540  //Enforce encoding, class and type
542  //The tag does not match the criteria?
543  if(error)
544  return error;
545 
546  //The msgFlags field consists of a single byte
547  if(tag.length != sizeof(uint8_t))
548  return ERROR_WRONG_ENCODING;
549 
550  //Save the bit field
551  message->msgFlags = tag.value[0];
552 
553  //If the authFlag is not set and privFlag is set, then the snmpInvalidMsgs
554  //counter is incremented and the message is silently discarded
555  if(!(message->msgFlags & SNMP_MSG_FLAG_AUTH) &&
556  (message->msgFlags & SNMP_MSG_FLAG_PRIV))
557  {
558  //Total number of packets received by the SNMP engine which were dropped
559  //because there were invalid or inconsistent components in the message
560  SNMP_MPD_MIB_INC_COUNTER32(snmpInvalidMsgs, 1);
561 
562  //The message is discarded without further processing
563  return ERROR_FAILURE;
564  }
565 
566  //Point to the next field
567  p += tag.totalLength;
568  length -= tag.totalLength;
569 
570  //The msgSecurityModel field identifies which security model was used
571  //by the sender to generate the message
572  error = asn1ReadInt32(p, length, &tag, &message->msgSecurityModel);
573  //Failed to decode ASN.1 tag?
574  if(error)
575  return error;
576 
577  //Make sure the value is in the range 1..2147483647
578  if(message->msgSecurityModel < 1)
579  return ERROR_WRONG_ENCODING;
580 
581  //Successful processing
582  return NO_ERROR;
583 #else
584  //Not implemented
585  return ERROR_NOT_IMPLEMENTED;
586 #endif
587 }
588 
589 
590 /**
591  * @brief Format msgGlobalData field
592  * @param[in,out] message Pointer to the outgoing SNMP message
593  * @return Error code
594  **/
595 
597 {
598 #if (SNMP_V3_SUPPORT == ENABLED)
599  error_t error;
600  size_t n;
601  size_t length;
602  uint8_t *p;
603  Asn1Tag tag;
604 
605  //The msgGlobalData field is encoded in reverse order
606  p = message->pos;
607  //Length of the msgGlobalData field
608  length = 0;
609 
610  //Write msgSecurityModel field
611  error = asn1WriteInt32(message->msgSecurityModel, TRUE, p, &n);
612  //Any error to report?
613  if(error)
614  return error;
615 
616  //Move backward
617  p -= n;
618  //Update the length of the msgGlobalData field
619  length += n;
620 
621  //The msgFlags field consists of a single byte
622  tag.constructed = FALSE;
625  tag.length = sizeof(uint8_t);
626  tag.value = &message->msgFlags;
627 
628  //Write the corresponding ASN.1 tag
629  error = asn1WriteTag(&tag, TRUE, p, &n);
630  //Any error to report?
631  if(error)
632  return error;
633 
634  //Move backward
635  p -= n;
636  //Update the length of the msgGlobalData field
637  length += n;
638 
639  //Write msgMaxSize field
640  error = asn1WriteInt32(message->msgMaxSize, TRUE, p, &n);
641  //Any error to report?
642  if(error)
643  return error;
644 
645  //Move backward
646  p -= n;
647  //Update the length of the msgGlobalData field
648  length += n;
649 
650  //Write msgID field
651  error = asn1WriteInt32(message->msgId, TRUE, p, &n);
652  //Any error to report?
653  if(error)
654  return error;
655 
656  //Move backward
657  p -= n;
658  //Update the length of the msgGlobalData field
659  length += n;
660 
661  //The parameters are encapsulated within a sequence
662  tag.constructed = TRUE;
665  tag.length = length;
666  tag.value = NULL;
667 
668  //Write the corresponding ASN.1 tag
669  error = asn1WriteTag(&tag, TRUE, p, &n);
670  //Any error to report?
671  if(error)
672  return error;
673 
674  //Point to the first byte of the msgGlobalData field
675  message->pos = p - n;
676  //Total length of the message
677  message->length += length + n;
678 
679  //Successful processing
680  return NO_ERROR;
681 #else
682  //Not implemented
683  return ERROR_NOT_IMPLEMENTED;
684 #endif
685 }
686 
687 
688 /**
689  * @brief Parse msgSecurityParameters field
690  * @param[in,out] message Pointer to the incoming SNMP message
691  * @return Error code
692  **/
693 
695 {
696 #if (SNMP_V3_SUPPORT == ENABLED)
697  error_t error;
698  size_t length;
699  const uint8_t *p;
700  Asn1Tag tag;
701 
702  //Read the msgSecurityParameters field
703  error = asn1ReadTag(message->pos, message->length, &tag);
704  //Failed to decode ASN.1 tag?
705  if(error)
706  return error;
707 
708  //Enforce encoding, class and type
710  //The tag does not match the criteria?
711  if(error)
712  return error;
713 
714  //Advance pointer over the msgSecurityParameters field
715  message->pos += tag.totalLength;
716  //Remaining bytes to process
717  message->length -= tag.totalLength;
718 
719  //Point to the very first field of the sequence
720  p = tag.value;
721  length = tag.length;
722 
723  //User-based security model?
724  if(message->msgSecurityModel == SNMP_SECURITY_MODEL_USM)
725  {
726  //The USM security parameters are encapsulated within a sequence
727  error = asn1ReadSequence(p, length, &tag);
728  //Failed to decode ASN.1 tag?
729  if(error)
730  return error;
731 
732  //Point to the first field of the sequence
733  p = tag.value;
734  length = tag.length;
735 
736  //Read the msgAuthoritativeEngineID field
737  error = asn1ReadTag(p, length, &tag);
738  //Failed to decode ASN.1 tag?
739  if(error)
740  return error;
741 
742  //Enforce encoding, class and type
744  //The tag does not match the criteria?
745  if(error)
746  return error;
747 
748  //Save authoritative engine identifier
749  message->msgAuthEngineId = tag.value;
750  message->msgAuthEngineIdLen = tag.length;
751 
752  //Point to the next field
753  p += tag.totalLength;
754  length -= tag.totalLength;
755 
756  //Read the msgAuthoritativeEngineBoots field
757  error = asn1ReadInt32(p, length, &tag,
758  &message->msgAuthEngineBoots);
759  //Failed to decode ASN.1 tag?
760  if(error)
761  return error;
762 
763  //Point to the next field
764  p += tag.totalLength;
765  length -= tag.totalLength;
766 
767  //Read the msgAuthoritativeEngineTime field
768  error = asn1ReadInt32(p, length, &tag,
769  &message->msgAuthEngineTime);
770  //Failed to decode ASN.1 tag?
771  if(error)
772  return error;
773 
774  //Point to the next field
775  p += tag.totalLength;
776  length -= tag.totalLength;
777 
778  //Read the msgUserName field
779  error = asn1ReadTag(p, length, &tag);
780  //Failed to decode ASN.1 tag?
781  if(error)
782  return error;
783 
784  //Enforce encoding, class and type
786  //The tag does not match the criteria?
787  if(error)
788  return error;
789 
790  //Check the length of the user name
791  if(tag.length > 32)
792  return ERROR_WRONG_ENCODING;
793 
794  //Save user name
795  message->msgUserName = (char_t *) tag.value;
796  message->msgUserNameLen = tag.length;
797 
798  //Point to the next field
799  p += tag.totalLength;
800  length -= tag.totalLength;
801 
802  //Read the msgAuthenticationParameters field
803  error = asn1ReadTag(p, length, &tag);
804  //Failed to decode ASN.1 tag?
805  if(error)
806  return error;
807 
808  //Enforce encoding, class and type
810  //The tag does not match the criteria?
811  if(error)
812  return error;
813 
814  //Save authentication parameters
815  message->msgAuthParameters = (uint8_t *) tag.value;
816  message->msgAuthParametersLen = tag.length;
817 
818  //Point to the next field
819  p += tag.totalLength;
820  length -= tag.totalLength;
821 
822  //Read the msgPrivacyParameters field
823  error = asn1ReadTag(p, length, &tag);
824  //Failed to decode ASN.1 tag?
825  if(error)
826  return error;
827 
828  //Enforce encoding, class and type
830  //The tag does not match the criteria?
831  if(error)
832  return error;
833 
834  //Save privacy parameters
835  message->msgPrivParameters = tag.value;
836  message->msgPrivParametersLen = tag.length;
837  }
838  else
839  {
840  //Total number of packets received by the SNMP engine which were dropped
841  //because they referenced a securityModel that was not known to or
842  //supported by the SNMP engine
843  SNMP_MPD_MIB_INC_COUNTER32(snmpUnknownSecurityModels, 1);
844 
845  //The message is discarded without further processing
846  return ERROR_FAILURE;
847  }
848 
849  //Successful processing
850  return NO_ERROR;
851 #else
852  //Not implemented
853  return ERROR_NOT_IMPLEMENTED;
854 #endif
855 }
856 
857 
858 /**
859  * @brief Format msgSecurityParameters field
860  * @param[in,out] message Pointer to the outgoing SNMP message
861  * @return Error code
862  **/
863 
865 {
866 #if (SNMP_V3_SUPPORT == ENABLED)
867  error_t error;
868  size_t n;
869  size_t length;
870  uint8_t *p;
871  Asn1Tag tag;
872 
873  //The msgSecurityParameters field is encoded in reverse order
874  p = message->pos;
875  //Length of the msgSecurityParameters field
876  length = 0;
877 
878  //User-based security model?
879  if(message->msgSecurityModel == SNMP_SECURITY_MODEL_USM)
880  {
881  //Encode the msgPrivacyParameters field as an octet string
882  tag.constructed = FALSE;
885  tag.length = message->msgPrivParametersLen;
886  tag.value = message->msgPrivParameters;
887 
888  //Write the corresponding ASN.1 tag
889  error = asn1WriteTag(&tag, TRUE, p, &n);
890  //Any error to report?
891  if(error)
892  return error;
893 
894  //Move backward
895  p -= n;
896  //Update the length of the msgSecurityParameters field
897  length += n;
898 
899  //Authentication required?
900  if(message->msgAuthParametersLen > 0)
901  {
902  //Make room for the message digest
903  p -= message->msgAuthParametersLen;
904  //Update the length of the msgSecurityParameters field
905  length += message->msgAuthParametersLen;
906 
907  //Clear the message digest
908  memset(p, 0, message->msgAuthParametersLen);
909  }
910 
911  //Save the location of the msgAuthenticationParameters field
912  message->msgAuthParameters = p;
913 
914  //Encoded the msgAuthenticationParameters field as an octet string
915  tag.constructed = FALSE;
918  tag.length = message->msgAuthParametersLen;
919  tag.value = NULL;
920 
921  //Write the corresponding ASN.1 tag
922  error = asn1WriteTag(&tag, TRUE, p, &n);
923  //Any error to report?
924  if(error)
925  return error;
926 
927  //Move backward
928  p -= n;
929  //Update the length of the msgSecurityParameters field
930  length += n;
931 
932  //Encode the msgUserName field as an octet string
933  tag.constructed = FALSE;
936  tag.length = message->msgUserNameLen;
937  tag.value = (uint8_t *) message->msgUserName;
938 
939  //Write the corresponding ASN.1 tag
940  error = asn1WriteTag(&tag, TRUE, p, &n);
941  //Any error to report?
942  if(error)
943  return error;
944 
945  //Move backward
946  p -= n;
947  //Update the length of the msgSecurityParameters field
948  length += n;
949 
950  //Write the msgAuthoritativeEngineTime field
951  error = asn1WriteInt32(message->msgAuthEngineTime, TRUE, p, &n);
952  //Any error to report?
953  if(error)
954  return error;
955 
956  //Move backward
957  p -= n;
958  //Update the length of the msgSecurityParameters field
959  length += n;
960 
961  //Write the msgAuthoritativeEngineBoots field
962  error = asn1WriteInt32(message->msgAuthEngineBoots, TRUE, p, &n);
963  //Any error to report?
964  if(error)
965  return error;
966 
967  //Move backward
968  p -= n;
969  //Update the length of the msgSecurityParameters field
970  length += n;
971 
972  //The msgAuthoritativeEngineID field is an octet string
973  tag.constructed = FALSE;
976  tag.length = message->msgAuthEngineIdLen;
977  tag.value = message->msgAuthEngineId;
978 
979  //Write the corresponding ASN.1 tag
980  error = asn1WriteTag(&tag, TRUE, p, &n);
981  //Any error to report?
982  if(error)
983  return error;
984 
985  //Move backward
986  p -= n;
987  //Update the length of the msgSecurityParameters field
988  length += n;
989 
990  //The USM security parameters are encapsulated within a sequence
991  tag.constructed = TRUE;
994  tag.length = length;
995  tag.value = NULL;
996 
997  //Write the corresponding ASN.1 tag
998  error = asn1WriteTag(&tag, TRUE, p, &n);
999  //Any error to report?
1000  if(error)
1001  return error;
1002 
1003  //Move backward
1004  p -= n;
1005  //Update the length of the msgSecurityParameters field
1006  length += n;
1007  }
1008  else
1009  {
1010  //The security model is not supported
1011  return ERROR_FAILURE;
1012  }
1013 
1014  //The security parameters are encapsulated within an octet string
1015  tag.constructed = FALSE;
1018  tag.length = length;
1019  tag.value = NULL;
1020 
1021  //Write the corresponding ASN.1 tag
1022  error = asn1WriteTag(&tag, TRUE, p, &n);
1023  //Any error to report?
1024  if(error)
1025  return error;
1026 
1027  //Point to the first byte of the msgSecurityParameters field
1028  message->pos = p - n;
1029  //Total length of the message
1030  message->length += length + n;
1031 
1032  //Successful processing
1033  return NO_ERROR;
1034 #else
1035  //Not implemented
1036  return ERROR_NOT_IMPLEMENTED;
1037 #endif
1038 }
1039 
1040 
1041 /**
1042  * @brief Parse scopedPDU field
1043  * @param[in,out] message Pointer to the incoming SNMP message
1044  * @return Error code
1045  **/
1046 
1048 {
1049 #if (SNMP_V3_SUPPORT == ENABLED)
1050  error_t error;
1051  size_t length;
1052  const uint8_t *p;
1053  Asn1Tag tag;
1054 
1055  //Read the scopedPDU field
1056  error = asn1ReadSequence(message->pos, message->length, &tag);
1057  //Failed to decode ASN.1 tag?
1058  if(error)
1059  return error;
1060 
1061  //Point to the first field of the sequence
1062  p = tag.value;
1063  length = tag.length;
1064 
1065  //Read contextEngineID field
1066  error = asn1ReadTag(p, length, &tag);
1067  //Failed to decode ASN.1 tag?
1068  if(error)
1069  return error;
1070 
1071  //Enforce encoding, class and type
1073  //The tag does not match the criteria?
1074  if(error)
1075  return error;
1076 
1077  //Save context engine identifier
1078  message->contextEngineId = tag.value;
1079  message->contextEngineIdLen = tag.length;
1080 
1081  //Point to the next field
1082  p += tag.totalLength;
1083  length -= tag.totalLength;
1084 
1085  //Read contextName field
1086  error = asn1ReadTag(p, length, &tag);
1087  //Failed to decode ASN.1 tag?
1088  if(error)
1089  return error;
1090 
1091  //Enforce encoding, class and type
1093  //The tag does not match the criteria?
1094  if(error)
1095  return error;
1096 
1097  //Save context name
1098  message->contextName = (char_t *) tag.value;
1099  message->contextNameLen = tag.length;
1100 
1101  //Point to the first byte of the PDU
1102  message->pos = (uint8_t *) p + tag.totalLength;
1103  //Length of the PDU
1104  message->length = length - tag.totalLength;
1105 
1106  //Return status code
1107  return error;
1108 #else
1109  //Not implemented
1110  return ERROR_NOT_IMPLEMENTED;
1111 #endif
1112 }
1113 
1114 
1115 /**
1116  * @brief Format scopedPDU
1117  * @param[in,out] message Pointer to the outgoing SNMP message
1118  * @return Error code
1119  **/
1120 
1122 {
1123 #if (SNMP_V3_SUPPORT == ENABLED)
1124  error_t error;
1125  size_t n;
1126  size_t length;
1127  uint8_t *p;
1128  Asn1Tag tag;
1129 
1130  //Point to the first byte of the PDU
1131  p = message->pos;
1132  //Retrieve the length of the PDU
1133  length = message->length;
1134 
1135  //The contextName is an octet string
1136  tag.constructed = FALSE;
1139  tag.length = message->contextNameLen;
1140  tag.value = (uint8_t *) message->contextName;
1141 
1142  //Write the corresponding ASN.1 tag
1143  error = asn1WriteTag(&tag, TRUE, p, &n);
1144  //Any error to report?
1145  if(error)
1146  return error;
1147 
1148  //Move backward
1149  p -= n;
1150  //Update the length of the scopedPduData
1151  length += n;
1152 
1153  //The contextEngineID is an octet string
1154  tag.constructed = FALSE;
1157  tag.length = message->contextEngineIdLen;
1158  tag.value = message->contextEngineId;
1159 
1160  //Write the corresponding ASN.1 tag
1161  error = asn1WriteTag(&tag, TRUE, p, &n);
1162  //Any error to report?
1163  if(error)
1164  return error;
1165 
1166  //Move backward
1167  p -= n;
1168  //Update the length of the scopedPduData
1169  length += n;
1170 
1171  //The scopedPduData is encapsulated within a sequence
1172  tag.constructed = TRUE;
1175  tag.length = length;
1176  tag.value = NULL;
1177 
1178  //Write the corresponding ASN.1 tag
1179  error = asn1WriteTag(&tag, TRUE, p, &n);
1180  //Any error to report?
1181  if(error)
1182  return error;
1183 
1184  //Point to the first byte of the scopedPDU
1185  message->pos = p - n;
1186  //Length of the scopedPDU
1187  message->length = length + n;
1188 
1189  //Successful processing
1190  return NO_ERROR;
1191 #else
1192  //Not implemented
1193  return ERROR_NOT_IMPLEMENTED;
1194 #endif
1195 }
1196 
1197 
1198 /**
1199  * @brief Parse PDU header
1200  * @param[in,out] message Pointer to the incoming SNMP message
1201  * @return Error code
1202  **/
1203 
1205 {
1206  error_t error;
1207  size_t length;
1208  const uint8_t *p;
1209  Asn1Tag tag;
1210 
1211  //The PDU is encapsulated within a sequence
1212  error = asn1ReadTag(message->pos, message->length, &tag);
1213  //Failed to decode ASN.1 tag?
1214  if(error)
1215  return error;
1216 
1217  //Check encoding
1218  if(tag.constructed != TRUE)
1219  return ERROR_WRONG_ENCODING;
1220  //Enforce class
1222  return ERROR_INVALID_CLASS;
1223 
1224  //Save PDU type
1225  message->pduType = (SnmpPduType) tag.objType;
1226 
1227  //Point to the first field
1228  p = tag.value;
1229  //Remaining bytes to process
1230  length = tag.length;
1231 
1232  //Read request-id field
1233  error = asn1ReadInt32(p, length, &tag, &message->requestId);
1234  //Failed to decode ASN.1 tag?
1235  if(error)
1236  return error;
1237 
1238  //Point to the next field
1239  p += tag.totalLength;
1240  length -= tag.totalLength;
1241 
1242 #if (SNMP_V2C_SUPPORT == ENABLED || SNMP_V3_SUPPORT == ENABLED)
1243  //GetBulkRequest-PDU?
1244  if(message->pduType == SNMP_PDU_GET_BULK_REQUEST)
1245  {
1246  //Read non-repeaters field
1247  error = asn1ReadInt32(p, length, &tag, &message->nonRepeaters);
1248  //Failed to decode ASN.1 tag?
1249  if(error)
1250  return error;
1251 
1252  //If the value in the non-repeaters field is less than zero, then the
1253  //value of the field is set to zero
1254  if(message->nonRepeaters < 0)
1255  message->nonRepeaters = 0;
1256 
1257  //Point to the next field
1258  p += tag.totalLength;
1259  length -= tag.totalLength;
1260 
1261  //Read max-repetitions field
1262  error = asn1ReadInt32(p, length, &tag, &message->maxRepetitions);
1263  //Failed to decode ASN.1 tag?
1264  if(error)
1265  return error;
1266 
1267  //If the value in the max-repetitions field is less than zero, then the
1268  //value of the field is set to zero
1269  if(message->maxRepetitions < 0)
1270  message->maxRepetitions = 0;
1271  }
1272  else
1273 #endif
1274  {
1275  //Read error-status field
1276  error = asn1ReadInt32(p, length, &tag, &message->errorStatus);
1277  //Failed to decode ASN.1 tag?
1278  if(error)
1279  return error;
1280 
1281  //Point to the next field
1282  p += tag.totalLength;
1283  length -= tag.totalLength;
1284 
1285  //Read error-index field
1286  error = asn1ReadInt32(p, length, &tag, &message->errorIndex);
1287  //Failed to decode ASN.1 tag?
1288  if(error)
1289  return error;
1290  }
1291 
1292  //Point to the next field
1293  p += tag.totalLength;
1294  length -= tag.totalLength;
1295 
1296  //The variable bindings are encapsulated within a sequence
1297  error = asn1ReadSequence(p, length, &tag);
1298  //Failed to decode ASN.1 tag?
1299  if(error)
1300  return error;
1301 
1302  //Save the location of the variable binding list
1303  message->varBindList = (uint8_t *) tag.value;
1304  message->varBindListLen = tag.length;
1305 
1306  //Successful processing
1307  return NO_ERROR;
1308 }
1309 
1310 
1311 /**
1312  * @brief Format PDU header
1313  * @param[in,out] message Pointer to the outgoing SNMP message
1314  * @return Error code
1315  **/
1316 
1318 {
1319  error_t error;
1320  size_t n;
1321  size_t length;
1322  uint8_t *p;
1323  Asn1Tag tag;
1324 
1325  //The PDU header will be encoded in reverse order...
1326  p = message->varBindList;
1327  //Length of the PDU
1328  length = message->varBindListLen;
1329 
1330  //The variable bindings are encapsulated within a sequence
1331  tag.constructed = TRUE;
1334  tag.length = length;
1335  tag.value = NULL;
1336 
1337  //Write the corresponding ASN.1 tag
1338  error = asn1WriteTag(&tag, TRUE, p, &n);
1339  //Any error to report?
1340  if(error)
1341  return error;
1342 
1343  //Move backward
1344  p -= n;
1345  //Update the length of the PDU
1346  length += n;
1347 
1348  //GetRequest-PDU, GetResponse-PDU, InformRequest-PDU, SNMPv2-Trap-PDU
1349  //or Report-PDU?
1350  if(message->pduType == SNMP_PDU_GET_REQUEST ||
1351  message->pduType == SNMP_PDU_GET_RESPONSE ||
1352  message->pduType == SNMP_PDU_INFORM_REQUEST ||
1353  message->pduType == SNMP_PDU_TRAP_V2 ||
1354  message->pduType == SNMP_PDU_REPORT)
1355  {
1356  //Write error index
1357  error = asn1WriteInt32(message->errorIndex, TRUE, p, &n);
1358  //Any error to report?
1359  if(error)
1360  return error;
1361 
1362  //Move backward
1363  p -= n;
1364  //Update the length of the PDU
1365  length += n;
1366 
1367  //Write error status
1368  error = asn1WriteInt32(message->errorStatus, TRUE, p, &n);
1369  //Any error to report?
1370  if(error)
1371  return error;
1372 
1373  //Move backward
1374  p -= n;
1375  //Update the length of the PDU
1376  length += n;
1377 
1378  //Write request identifier
1379  error = asn1WriteInt32(message->requestId, TRUE, p, &n);
1380  //Any error to report?
1381  if(error)
1382  return error;
1383 
1384  //Move backward
1385  p -= n;
1386  //Update the length of the PDU
1387  length += n;
1388  }
1389 #if (SNMP_V1_SUPPORT == ENABLED)
1390  //Trap-PDU?
1391  else if(message->pduType == SNMP_PDU_TRAP)
1392  {
1393  //Encode the object value using ASN.1 rules
1394  error = snmpEncodeUnsignedInt32(message->timestamp, message->buffer, &n);
1395  //Any error to report?
1396  if(error)
1397  return error;
1398 
1399  //The time stamp is encoded in ASN.1 format
1400  tag.constructed = FALSE;
1403  tag.length = n;
1404  tag.value = message->buffer;
1405 
1406  //Write the corresponding ASN.1 tag
1407  error = asn1WriteTag(&tag, TRUE, p, &n);
1408  //Any error to report?
1409  if(error)
1410  return error;
1411 
1412  //Move backward
1413  p -= n;
1414  //Update the length of the PDU
1415  length += n;
1416 
1417  //Write specific trap code
1418  error = asn1WriteInt32(message->specificTrapCode, TRUE, p, &n);
1419  //Any error to report?
1420  if(error)
1421  return error;
1422 
1423  //Move backward
1424  p -= n;
1425  //Update the length of the PDU
1426  length += n;
1427 
1428  //Write generic trap type
1429  error = asn1WriteInt32(message->genericTrapType, TRUE, p, &n);
1430  //Any error to report?
1431  if(error)
1432  return error;
1433 
1434  //Move backward
1435  p -= n;
1436  //Update the length of the PDU
1437  length += n;
1438 
1439  //The agent address is encoded in ASN.1 format
1440  tag.constructed = FALSE;
1443  tag.length = sizeof(Ipv4Addr);
1444  tag.value = (uint8_t *) &message->agentAddr;
1445 
1446  //Write the corresponding ASN.1 tag
1447  error = asn1WriteTag(&tag, TRUE, p, &n);
1448  //Any error to report?
1449  if(error)
1450  return error;
1451 
1452  //Move backward
1453  p -= n;
1454  //Update the length of the PDU
1455  length += n;
1456 
1457  //The enterprise OID is encoded in ASN.1 format
1458  tag.constructed = FALSE;
1461  tag.length = message->enterpriseOidLen;
1462  tag.value = message->enterpriseOid;
1463 
1464  //Write the corresponding ASN.1 tag
1465  error = asn1WriteTag(&tag, TRUE, p, &n);
1466  //Any error to report?
1467  if(error)
1468  return error;
1469 
1470  //Move backward
1471  p -= n;
1472  //Update the length of the PDU
1473  length += n;
1474  }
1475 #endif
1476  //Unknown PDU type?
1477  else
1478  {
1479  //Report an error
1480  return ERROR_FAILURE;
1481  }
1482 
1483  //The PDU is encapsulated within a sequence
1484  tag.constructed = TRUE;
1486  tag.objType = message->pduType;
1487  tag.length = length;
1488  tag.value = NULL;
1489 
1490  //Write the corresponding ASN.1 tag
1491  error = asn1WriteTag(&tag, TRUE, p, &n);
1492  //Any error to report?
1493  if(error)
1494  return error;
1495 
1496  //Point to the first byte of the PDU
1497  message->pos = p - n;
1498  //Total length of the PDU
1499  message->length = length + n;
1500 
1501  //Successful processing
1502  return NO_ERROR;
1503 }
1504 
1505 
1506 /**
1507  * @brief Encode a 32-bit signed integer
1508  * @param[in] value Integer value
1509  * @param[out] dest Buffer where to encode the integer
1510  * @param[out] length Total number of bytes that have been written
1511  * @return Error code
1512  **/
1513 
1514 error_t snmpEncodeInt32(int32_t value, uint8_t *dest, size_t *length)
1515 {
1516  size_t i;
1517  size_t j;
1518  uint8_t *src;
1519 
1520  //Check parameters
1521  if(dest == NULL || length == NULL)
1522  return ERROR_INVALID_PARAMETER;
1523 
1524  //The integer is encoded MSB first
1525  value = (int32_t) htobe32(value);
1526  //Cast the integer to byte array
1527  src = (uint8_t *) &value;
1528 
1529  //An integer value is always encoded in the smallest possible number of octets
1530  for(i = 0; i < 3; i++)
1531  {
1532  //The upper 9 bits shall not have the same value (all 0 or all 1)
1533  if((src[i] != 0x00 || (src[i + 1] & 0x80) != 0x00) &&
1534  (src[i] != 0xFF || (src[i + 1] & 0x80) != 0x80))
1535  {
1536  break;
1537  }
1538  }
1539 
1540  //Point to the beginning of the output buffer
1541  j = 0;
1542 
1543  //Copy integer value
1544  while(i < 4)
1545  {
1546  dest[j++] = src[i++];
1547  }
1548 
1549  //Total number of bytes that have been written
1550  *length = j;
1551 
1552  //Successful processing
1553  return NO_ERROR;
1554 }
1555 
1556 
1557 /**
1558  * @brief Encode a 32-bit unsigned integer
1559  * @param[in] value Integer value
1560  * @param[out] dest Buffer where to encode the integer
1561  * @param[out] length Total number of bytes that have been written
1562  * @return Error code
1563  **/
1564 
1565 error_t snmpEncodeUnsignedInt32(uint32_t value, uint8_t *dest, size_t *length)
1566 {
1567  size_t i;
1568  size_t j;
1569  uint8_t *src;
1570 
1571  //Check parameters
1572  if(dest == NULL || length == NULL)
1573  return ERROR_INVALID_PARAMETER;
1574 
1575  //The integer is encoded MSB first
1576  value = htobe32(value);
1577  //Cast the integer to byte array
1578  src = (uint8_t *) &value;
1579 
1580  //An integer value is always encoded in the smallest possible number of octets
1581  for(i = 0; i < 3; i++)
1582  {
1583  //Check the upper 8 bits
1584  if(src[i] != 0x00)
1585  break;
1586  }
1587 
1588  //Point to the beginning of the output buffer
1589  j = 0;
1590 
1591  //Check the most significant bit
1592  if(src[i] & 0x80)
1593  dest[j++] = 0;
1594 
1595  //Copy integer value
1596  while(i < 4)
1597  {
1598  dest[j++] = src[i++];
1599  }
1600 
1601  //Total number of bytes that have been written
1602  *length = j;
1603 
1604  //Successful processing
1605  return NO_ERROR;
1606 }
1607 
1608 
1609 /**
1610  * @brief Encode a 64-bit unsigned integer
1611  * @param[in] value Integer value
1612  * @param[out] dest Buffer where to encode the integer
1613  * @param[out] length Total number of bytes that have been written
1614  * @return Error code
1615  **/
1616 
1617 error_t snmpEncodeUnsignedInt64(uint64_t value, uint8_t *dest, size_t *length)
1618 {
1619  size_t i;
1620  size_t j;
1621  uint8_t *src;
1622 
1623  //Check parameters
1624  if(dest == NULL || length == NULL)
1625  return ERROR_INVALID_PARAMETER;
1626 
1627  //The integer is encoded MSB first
1628  value = htobe64(value);
1629  //Cast the integer to byte array
1630  src = (uint8_t *) &value;
1631 
1632  //An integer value is always encoded in the smallest possible number of octets
1633  for(i = 0; i < 7; i++)
1634  {
1635  //Check the upper 8 bits
1636  if(src[i] != 0x00)
1637  break;
1638  }
1639 
1640  //Point to the beginning of the output buffer
1641  j = 0;
1642 
1643  //Check the most significant bit
1644  if(src[i] & 0x80)
1645  {
1646  dest[j++] = 0;
1647  }
1648 
1649  //Copy integer value
1650  while(i < 8)
1651  {
1652  dest[j++] = src[i++];
1653  }
1654 
1655  //Total number of bytes that have been written
1656  *length = j;
1657 
1658  //Successful processing
1659  return NO_ERROR;
1660 }
1661 
1662 
1663 /**
1664  * @brief Decode a 32-bit signed integer
1665  * @param[in] src Buffer that contains the encoded value
1666  * @param[in] length Number of bytes to be processed
1667  * @param[out] value Resulting integer value
1668  * @return Error code
1669  **/
1670 
1671 error_t snmpDecodeInt32(const uint8_t *src, size_t length, int32_t *value)
1672 {
1673  size_t i;
1674 
1675  //Check parameters
1676  if(src == NULL || value == NULL)
1677  return ERROR_INVALID_PARAMETER;
1678  if(length < 1)
1679  return ERROR_INVALID_PARAMETER;
1680 
1681  //The contents octets shall be a two's complement binary
1682  //number equal to the integer value
1683  *value = (src[0] & 0x80) ? -1 : 0;
1684 
1685  //Process contents octets
1686  for(i = 0; i < length; i++)
1687  {
1688  //Rotate left operation
1689  *value <<= 8;
1690  //Reconstruct integer value
1691  *value |= src[i];
1692  }
1693 
1694  //Successful processing
1695  return NO_ERROR;
1696 }
1697 
1698 
1699 /**
1700  * @brief Decode a 32-bit unsigned integer
1701  * @param[in] src Buffer that contains the encoded value
1702  * @param[in] length Number of bytes to be processed
1703  * @param[out] value Resulting integer value
1704  * @return Error code
1705  **/
1706 
1707 error_t snmpDecodeUnsignedInt32(const uint8_t *src, size_t length, uint32_t *value)
1708 {
1709  size_t i;
1710 
1711  //Check parameters
1712  if(src == NULL || value == NULL)
1713  return ERROR_INVALID_PARAMETER;
1714  if(length < 1)
1715  return ERROR_INVALID_PARAMETER;
1716 
1717  //Only accept non-negative numbers
1718  if(src[0] & 0x80)
1719  return ERROR_FAILURE;
1720 
1721  //Initialize integer value
1722  *value = 0;
1723 
1724  //Process contents octets
1725  for(i = 0; i < length; i++)
1726  {
1727  //Rotate left operation
1728  *value <<= 8;
1729  //Reconstruct integer value
1730  *value |= src[i];
1731  }
1732 
1733  //Successful processing
1734  return NO_ERROR;
1735 }
1736 
1737 
1738 /**
1739  * @brief Decode a 64-bit unsigned integer
1740  * @param[in] src Buffer that contains the encoded value
1741  * @param[in] length Number of bytes to be processed
1742  * @param[out] value Resulting integer value
1743  * @return Error code
1744  **/
1745 
1746 error_t snmpDecodeUnsignedInt64(const uint8_t *src, size_t length, uint64_t *value)
1747 {
1748  size_t i;
1749 
1750  //Check parameters
1751  if(src == NULL || value == NULL)
1752  return ERROR_INVALID_PARAMETER;
1753  if(length < 1)
1754  return ERROR_INVALID_PARAMETER;
1755 
1756  //Only accept non-negative numbers
1757  if(src[0] & 0x80)
1758  return ERROR_FAILURE;
1759 
1760  //Initialize integer value
1761  *value = 0;
1762 
1763  //Process contents octets
1764  for(i = 0; i < length; i++)
1765  {
1766  //Rotate left operation
1767  *value <<= 8;
1768  //Reconstruct integer value
1769  *value |= src[i];
1770  }
1771 
1772  //Successful processing
1773  return NO_ERROR;
1774 }
1775 
1776 #endif
@ MIB_TYPE_IP_ADDRESS
Definition: mib_common.h:60
uint8_t length
Definition: dtls_misc.h:149
@ SNMP_PDU_TRAP
Definition: snmp_common.h:154
@ SNMP_PDU_INFORM_REQUEST
Definition: snmp_common.h:156
@ SNMP_PDU_GET_REQUEST
Definition: snmp_common.h:150
error_t snmpEncodeUnsignedInt32(uint32_t value, uint8_t *dest, size_t *length)
Encode a 32-bit unsigned integer.
@ SNMP_PDU_TRAP_V2
Definition: snmp_common.h:157
error_t snmpWriteGlobalData(SnmpMessage *message)
Format msgGlobalData field.
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
error_t snmpParseGlobalData(SnmpMessage *message)
Parse msgGlobalData field.
uint8_t p
Definition: ndp.h:298
@ SNMP_PDU_GET_RESPONSE
Definition: snmp_common.h:152
#define TRUE
Definition: os_port.h:50
error_t snmpParsePduHeader(SnmpMessage *message)
Parse PDU header.
error_t snmpWriteScopedPdu(SnmpMessage *message)
Format scopedPDU.
#define SNMP_V3_MSG_HEADER_OVERHEAD
@ SNMP_SECURITY_MODEL_USM
User-based security model.
error_t snmpWriteCommunity(SnmpMessage *message)
Format community name.
error_t asn1ReadTag(const uint8_t *data, size_t length, Asn1Tag *tag)
Read an ASN.1 tag from the input stream.
Definition: asn1.c:52
@ SNMP_VERSION_2C
Definition: snmp_common.h:139
@ ERROR_INVALID_VERSION
Definition: error.h:116
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:239
SNMP agent (Simple Network Management Protocol)
#define SNMP_V2C_MSG_HEADER_OVERHEAD
@ SNMP_MSG_FLAG_PRIV
size_t totalLength
Definition: asn1.h:104
size_t length
Definition: asn1.h:102
#define FALSE
Definition: os_port.h:46
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t snmpInitResponse(SnmpAgentContext *context)
Initialize a GetResponse-PDU.
#define SNMP_MSG_ENCRYPTION_OVERHEAD
error_t
Error codes.
Definition: error.h:42
error_t snmpParseScopedPdu(SnmpMessage *message)
Parse scopedPDU field.
#define ASN1_CLASS_UNIVERSAL
Definition: asn1.h:48
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
ASN.1 tag.
Definition: asn1.h:97
error_t asn1ReadInt32(const uint8_t *data, size_t length, Asn1Tag *tag, int32_t *value)
Read a 32-bit integer from the input stream.
Definition: asn1.c:285
@ SNMP_PDU_GET_BULK_REQUEST
Definition: snmp_common.h:155
General definitions for cryptographic algorithms.
SnmpPduType
SNMP PDU types.
Definition: snmp_common.h:148
@ SNMP_ERROR_NONE
Definition: snmp_common.h:184
error_t asn1WriteTag(Asn1Tag *tag, bool_t reverse, uint8_t *data, size_t *written)
Write an ASN.1 tag.
Definition: asn1.c:377
#define SNMP_V1_MSG_HEADER_OVERHEAD
#define htobe64(value)
Definition: cpu_endian.h:423
@ SNMP_MSG_FLAG_AUTH
uint_t objClass
Definition: asn1.h:100
@ SNMP_VERSION_3
Definition: snmp_common.h:140
#define htobe32(value)
Definition: cpu_endian.h:422
@ ASN1_TYPE_OCTET_STRING
Definition: asn1.h:68
SNMP MPD MIB module.
char char_t
Definition: compiler_port.h:43
@ MIB_TYPE_TIME_TICKS
Definition: mib_common.h:64
error_t snmpWriteSecurityParameters(SnmpMessage *message)
Format msgSecurityParameters field.
error_t snmpParseSecurityParameters(SnmpMessage *message)
Parse msgSecurityParameters field.
@ SNMP_PDU_REPORT
Definition: snmp_common.h:158
#define SNMP_MAX_MSG_SIZE
Definition: snmp_common.h:60
error_t snmpEncodeInt32(int32_t value, uint8_t *dest, size_t *length)
Encode a 32-bit signed integer.
uint8_t n
error_t snmpParseMessageHeader(SnmpMessage *message)
Parse SNMP message header.
error_t snmpDecodeInt32(const uint8_t *src, size_t length, int32_t *value)
Decode a 32-bit signed integer.
error_t snmpWritePduHeader(SnmpMessage *message)
Format PDU header.
#define ASN1_CLASS_CONTEXT_SPECIFIC
Definition: asn1.h:50
uint8_t message[]
Definition: chap.h:152
error_t snmpDecodeUnsignedInt64(const uint8_t *src, size_t length, uint64_t *value)
Decode a 64-bit unsigned integer.
bool_t constructed
Definition: asn1.h:99
SNMP message.
@ SNMP_VERSION_1
Definition: snmp_common.h:138
@ ASN1_TYPE_OBJECT_IDENTIFIER
Definition: asn1.h:70
@ ASN1_TYPE_SEQUENCE
Definition: asn1.h:76
#define SnmpAgentContext
Definition: snmp_agent.h:36
@ ERROR_WRONG_ENCODING
Definition: error.h:120
error_t snmpEncodeUnsignedInt64(uint64_t value, uint8_t *dest, size_t *length)
Encode a 64-bit unsigned integer.
error_t snmpComputeMessageOverhead(SnmpMessage *message)
Compute SNMP message overhead.
#define SNMP_MPD_MIB_INC_COUNTER32(name, value)
@ ERROR_INVALID_CLASS
Definition: error.h:115
uint8_t value[]
Definition: dtls_misc.h:150
TCP/IP stack core.
error_t asn1ReadSequence(const uint8_t *data, size_t length, Asn1Tag *tag)
Read an ASN.1 sequence from the input stream.
Definition: asn1.c:163
error_t asn1WriteInt32(int32_t value, bool_t reverse, uint8_t *data, size_t *written)
Write a 32-bit integer to the output stream.
Definition: asn1.c:516
error_t snmpParseCommunity(SnmpMessage *message)
Parse community name.
#define ASN1_CLASS_APPLICATION
Definition: asn1.h:49
const uint8_t * value
Definition: asn1.h:103
error_t snmpDecodeUnsignedInt32(const uint8_t *src, size_t length, uint32_t *value)
Decode a 32-bit unsigned integer.
error_t asn1CheckTag(const Asn1Tag *tag, bool_t constructed, uint_t objClass, uint_t objType)
Enforce the type of a specified tag.
Definition: asn1.c:637
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
uint_t objType
Definition: asn1.h:101
ASN.1 (Abstract Syntax Notation One)
void snmpInitMessage(SnmpMessage *message)
Initialize a SNMP message.
error_t snmpWriteMessageHeader(SnmpMessage *message)
Format SNMP message header.
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:104