snmp_agent_inform.c
Go to the documentation of this file.
1 /**
2  * @file snmp_agent_inform.c
3  * @brief SNMP inform notifications
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"
37 #include "snmp/snmp_agent_misc.h"
38 #include "snmp/snmp_agent_inform.h"
39 #include "mibs/mib2_module.h"
40 #include "debug.h"
41 
42 //Check TCP/IP stack configuration
43 #if (SNMP_AGENT_SUPPORT == ENABLED && SNMP_AGENT_INFORM_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Format SNMP InformRequest message
48  * @param[in] context Pointer to the SNMP agent context
49  * @param[in] version SNMP version identifier
50  * @param[in] userName User name or community name
51  * @param[in] genericTrapType Generic trap type
52  * @param[in] specificTrapCode Specific code
53  * @param[in] objectList List of object names
54  * @param[in] objectListSize Number of entries in the list
55  * @return Error code
56  **/
57 
59  SnmpVersion version, const char_t *userName, uint_t genericTrapType,
60  uint_t specificTrapCode, const SnmpTrapObject *objectList,
61  uint_t objectListSize)
62 {
63  error_t error;
64 
65 #if (SNMP_V2C_SUPPORT == ENABLED)
66  //SNMPv2c version?
68  {
69  //Format InformRequest-PDU
70  error = snmpFormatInformRequestPdu(context, version, userName,
71  genericTrapType, specificTrapCode, objectList, objectListSize);
72  //Any error to report?
73  if(error)
74  return error;
75 
76  //Format SMNP message header
77  error = snmpWriteMessageHeader(&context->response);
78  //Any error to report?
79  if(error)
80  return error;
81  }
82  else
83 #endif
84 #if (SNMP_V3_SUPPORT == ENABLED)
85  //SNMPv3 version?
86  if(version == SNMP_VERSION_3)
87  {
88  SnmpUserEntry *user;
89 
90  //Information about the user name is extracted from the local
91  //configuration datastore
92  user = snmpFindUserEntry(context, userName, strlen(userName));
93 
94  //Invalid user name?
95  if(user == NULL || user->status != MIB_ROW_STATUS_ACTIVE)
97 
98  //Save the security profile associated with the current user
99  context->user = *user;
100 
101  //Localize the authentication key with the engine ID of the
102  //remote SNMP device
103  if(context->user.authProtocol != SNMP_AUTH_PROTOCOL_NONE)
104  {
105  //Key localization algorithm
106  error = snmpLocalizeKey(context->user.authProtocol,
107  context->informContextEngine, context->informContextEngineLen,
108  &context->user.rawAuthKey, &context->user.localizedAuthKey);
109  //Any error to report?
110  if(error)
111  return error;
112  }
113 
114  //Localize the privacy key with the engine ID of the remote
115  //SNMP device
116  if(context->user.privProtocol != SNMP_AUTH_PROTOCOL_NONE)
117  {
118  //Key localization algorithm
119  error = snmpLocalizeKey(context->user.authProtocol,
120  context->informContextEngine, context->informContextEngineLen,
121  &context->user.rawPrivKey, &context->user.localizedPrivKey);
122  //Any error to report?
123  if(error)
124  return error;
125  }
126 
127  //Format InformRequest-PDU
128  error = snmpFormatInformRequestPdu(context, version, userName,
129  genericTrapType, specificTrapCode, objectList, objectListSize);
130  //Any error to report?
131  if(error)
132  return error;
133 
134  //Format scopedPDU
135  error = snmpWriteScopedPdu(&context->response);
136  //Any error to report?
137  if(error)
138  return error;
139 
140  //Check whether the privFlag is set
141  if(context->response.msgFlags & SNMP_MSG_FLAG_PRIV)
142  {
143  //Encrypt data
144  error = snmpEncryptData(&context->user, &context->response,
145  &context->salt);
146  //Any error to report?
147  if(error)
148  return error;
149  }
150 
151  //Format SMNP message header
152  error = snmpWriteMessageHeader(&context->response);
153  //Any error to report?
154  if(error)
155  return error;
156 
157  //Check whether the authFlag is set
158  if(context->response.msgFlags & SNMP_MSG_FLAG_AUTH)
159  {
160  //Authenticate outgoing SNMP message
161  error = snmpAuthOutgoingMessage(&context->user, &context->response);
162  //Any error to report?
163  if(error)
164  return error;
165  }
166  }
167  else
168 #endif
169  //Invalid SNMP version?
170  {
171  //Debug message
172  TRACE_WARNING(" Invalid SNMP version!\r\n");
173  //Report an error
174  return ERROR_INVALID_VERSION;
175  }
176 
177  //Successful processing
178  return NO_ERROR;
179 }
180 
181 
182 /**
183  * @brief Format InformRequest-PDU
184  * @param[in] context Pointer to the SNMP agent context
185  * @param[in] version SNMP version identifier
186  * @param[in] userName User name or community name
187  * @param[in] genericTrapType Generic trap type
188  * @param[in] specificTrapCode Specific code
189  * @param[in] objectList List of object names
190  * @param[in] objectListSize Number of entries in the list
191  * @return Error code
192  **/
193 
195  SnmpVersion version, const char_t *userName, uint_t genericTrapType,
196  uint_t specificTrapCode, const SnmpTrapObject *objectList,
197  uint_t objectListSize)
198 {
199  error_t error;
201 
202  //Point to the SNMP message
203  message = &context->response;
204  //Initialize SNMP message
206 
207  //SNMP version identifier
208  message->version = version;
209 
210 #if (SNMP_V2C_SUPPORT == ENABLED)
211  //SNMPv2c version?
212  if(version == SNMP_VERSION_2C)
213  {
214  //Community name
215  message->community = userName;
216  message->communityLen = strlen(userName);
217  }
218  else
219 #endif
220 #if (SNMP_V3_SUPPORT == ENABLED)
221  //SNMPv3 version?
222  if(version == SNMP_VERSION_3)
223  {
224  //Increment message identifier
225  message->msgId = context->msgId++;
226  //Wrap around if necessary
227  if(context->msgId < 0)
228  context->msgId = 0;
229 
230  //Save the value of the msgId field
231  context->informMsgId = message->msgId;
232 
233  //Maximum message size supported by the sender
234  message->msgMaxSize = SNMP_MAX_MSG_SIZE;
235 
236  //Bit fields which control processing of the message
237  if(context->user.authProtocol != SNMP_AUTH_PROTOCOL_NONE)
238  message->msgFlags |= SNMP_MSG_FLAG_AUTH;
239  if(context->user.privProtocol != SNMP_PRIV_PROTOCOL_NONE)
240  message->msgFlags |= SNMP_MSG_FLAG_PRIV;
241 
242  //The reportable flag must always be set for acknowledged
243  //notification-type PDUs (refer to RFC 3412, section 6.4)
244  message->msgFlags |= SNMP_MSG_FLAG_REPORTABLE;
245 
246  //Security model used by the sender
247  message->msgSecurityModel = SNMP_SECURITY_MODEL_USM;
248 
249  //Authoritative engine identifier
250  message->msgAuthEngineId = context->informContextEngine;
251  message->msgAuthEngineIdLen = context->informContextEngineLen;
252  //Number of times the SNMP engine has rebooted
253  message->msgAuthEngineBoots = context->informEngineBoots;
254  //Number of seconds since last reboot
255  message->msgAuthEngineTime = context->informEngineTime;
256  //User name
257  message->msgUserName = userName;
258  message->msgUserNameLen = strlen(userName);
259  //Authentication parameters
260  message->msgAuthParameters = NULL;
261  //Length of the authentication parameters
262  message->msgAuthParametersLen = snmpGetMacLength(context->user.authProtocol);
263  //Privacy parameters
264  message->msgPrivParameters = context->privParameters;
265 
266  //Length of the privacy parameters
267  if(context->user.privProtocol == SNMP_PRIV_PROTOCOL_DES)
268  message->msgPrivParametersLen = 8;
269  else if(context->user.privProtocol == SNMP_PRIV_PROTOCOL_AES)
270  message->msgPrivParametersLen = 8;
271  else
272  message->msgPrivParametersLen = 0;
273 
274  //Context engine identifier
275  message->contextEngineId = context->contextEngine;
276  message->contextEngineIdLen = context->contextEngineLen;
277  //Context name
278  message->contextName = context->contextName;
279  message->contextNameLen = strlen(context->contextName);
280  }
281  else
282 #endif
283  //Invalid SNMP version?
284  {
285  //Report an error
286  return ERROR_INVALID_VERSION;
287  }
288 
289  //Prepare to send an InformRequest-PDU
290  message->pduType = SNMP_PDU_INFORM_REQUEST;
291 
292  //Increment request identifier
293  message->requestId = context->requestId++;
294  //Wrap around if necessary
295  if(context->requestId < 0)
296  context->requestId = 0;
297 
298  //Save the value of the request-id field
299  context->informRequestId = message->requestId;
300 
301  //Make room for the message header at the beginning of the buffer
302  error = snmpComputeMessageOverhead(&context->response);
303  //Any error to report?
304  if(error)
305  return error;
306 
307  //Format the list of variable bindings
308  error = snmpWriteTrapVarBindingList(context, genericTrapType,
309  specificTrapCode, objectList, objectListSize);
310  //Any error to report?
311  if(error)
312  return error;
313 
314  //Format PDU header
315  error = snmpWritePduHeader(&context->response);
316  //Return status code
317  return error;
318 }
319 
320 
321 /**
322  * @brief Format SNMP GetRequest message
323  * @param[in] context Pointer to the SNMP agent context
324  * @param[in] version SNMP version identifier
325  * @return Error code
326  **/
327 
330 {
331  error_t error;
332 
333  //Clear the security profile
334  memset(&context->user, 0, sizeof(SnmpUserEntry));
335 
336  //Format GetRequest-PDU
337  error = snmpFormatGetRequestPdu(context, version);
338  //Any error to report?
339  if(error)
340  return error;
341 
342  //Format scopedPDU
343  error = snmpWriteScopedPdu(&context->response);
344  //Any error to report?
345  if(error)
346  return error;
347 
348  //Format SMNP message header
349  error = snmpWriteMessageHeader(&context->response);
350  //Any error to report?
351  if(error)
352  return error;
353 
354  //Successful processing
355  return NO_ERROR;
356 }
357 
358 
359 /**
360  * @brief Format GetRequest-PDU (engine ID discovery procedure)
361  * @param[in] context Pointer to the SNMP agent context
362  * @param[in] version SNMP version identifier
363  * @return Error code
364  **/
365 
367 {
368  error_t error;
370 
371  //Point to the SNMP message
372  message = &context->response;
373  //Initialize SNMP message
375 
376  //SNMP version identifier
377  message->version = version;
378 
379 #if (SNMP_V3_SUPPORT == ENABLED)
380  //SNMPv3 version?
381  if(version == SNMP_VERSION_3)
382  {
383  //Increment message identifier
384  message->msgId = context->msgId++;
385  //Wrap around if necessary
386  if(context->msgId < 0)
387  context->msgId = 0;
388 
389  //Save the value of the msgId field
390  context->informMsgId = message->msgId;
391 
392  //Maximum message size supported by the sender
393  message->msgMaxSize = SNMP_MAX_MSG_SIZE;
394 
395  //The reportable flag must always be set for request-type PDUs (refer
396  //to RFC 3412, section 6.4)
397  message->msgFlags |= SNMP_MSG_FLAG_REPORTABLE;
398 
399  //Security model used by the sender
400  message->msgSecurityModel = SNMP_SECURITY_MODEL_USM;
401  }
402 #endif
403 
404  //Prepare to send an GetRequest-PDU
405  message->pduType = SNMP_PDU_GET_REQUEST;
406 
407  //Increment request identifier
408  message->requestId = context->requestId++;
409  //Wrap around if necessary
410  if(context->requestId < 0)
411  context->requestId = 0;
412 
413  //Save the value of the request-id field
414  context->informRequestId = message->requestId;
415 
416  //Make room for the message header at the beginning of the buffer
417  error = snmpComputeMessageOverhead(&context->response);
418  //Any error to report?
419  if(error)
420  return error;
421 
422  //Format PDU header
423  error = snmpWritePduHeader(&context->response);
424  //Return status code
425  return error;
426 }
427 
428 
429 /**
430  * @brief Process GetResponse-PDU
431  * @param[in] context Pointer to the SNMP agent context
432  * @return Error code
433  **/
434 
436 {
438 
439  //Debug message
440  TRACE_INFO("Parsing GetResponse-PDU...\r\n");
441 
442  //Point to the incoming SNMP message
443  message = &context->request;
444 
445  //Total number of SNMP Get-Response PDUs which have been accepted and
446  //processed by the SNMP protocol entity
447  MIB2_INC_COUNTER32(snmpGroup.snmpInGetResponses, 1);
448 
449  //Check the error-status field
450  if(message->errorStatus == SNMP_ERROR_NONE)
451  {
452  //Compare the request-id against the expected identifier
453  if(message->requestId == context->informRequestId)
454  {
455  //The inform request has been acknowledged
456  osSetEvent(&context->informEvent);
457  }
458  }
459 
460  //Successful processing
461  return NO_ERROR;
462 }
463 
464 
465 /**
466  * @brief Process Report-PDU
467  * @param[in] context Pointer to the SNMP agent context
468  * @return Error code
469  **/
470 
472 {
473 #if (SNMP_V3_SUPPORT == ENABLED)
475 
476  //Debug message
477  TRACE_INFO("Parsing Report-PDU...\r\n");
478 
479  //Point to the incoming SNMP message
480  message = &context->request;
481 
482  //Sanity check
483  if(message->msgAuthEngineIdLen <= SNMP_MAX_CONTEXT_ENGINE_SIZE)
484  {
485  //Save the authoritative engine identifier
486  memcpy(context->informContextEngine, message->msgAuthEngineId,
487  message->msgAuthEngineIdLen);
488 
489  //Save the length of the engine identifier
490  context->informContextEngineLen = message->msgAuthEngineIdLen;
491 
492  //Save the msgAuthoritativeEngineBoots field
493  context->informEngineBoots = message->msgAuthEngineBoots;
494  //Save the msgAuthoritativeEngineTime field
495  context->informEngineTime = message->msgAuthEngineTime;
496 
497  //Check current state
498  if(context->informState == SNMP_AGENT_STATE_WAITING_REPORT)
499  {
500  //Valid context engine identifier?
501  if(context->informContextEngineLen > 0)
502  {
503  //The discovery process is complete
504  osSetEvent(&context->informEvent);
505  }
506  }
507  }
508 
509  //Successful processing
510  return NO_ERROR;
511 #else
512  //SNMPv3 is not supported
513  return ERROR_NOT_IMPLEMENTED;
514 #endif
515 }
516 
517 #endif
error_t snmpEncryptData(const SnmpUserEntry *user, SnmpMessage *message, uint64_t *salt)
Data encryption.
MIB-II module.
error_t snmpProcessReportPdu(SnmpAgentContext *context)
Process Report-PDU.
@ SNMP_PDU_INFORM_REQUEST
Definition: snmp_common.h:156
@ ERROR_UNKNOWN_USER_NAME
Definition: error.h:256
@ SNMP_PDU_GET_REQUEST
Definition: snmp_common.h:150
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
error_t snmpWriteScopedPdu(SnmpMessage *message)
Format scopedPDU.
uint16_t version
Definition: dtls_misc.h:172
Object descriptor for trap notifications.
@ SNMP_AGENT_STATE_WAITING_REPORT
error_t snmpFormatInformRequestPdu(SnmpAgentContext *context, SnmpVersion version, const char_t *userName, uint_t genericTrapType, uint_t specificTrapCode, const SnmpTrapObject *objectList, uint_t objectListSize)
Format InformRequest-PDU.
@ SNMP_SECURITY_MODEL_USM
User-based security model.
User table entry.
@ SNMP_VERSION_2C
Definition: snmp_common.h:139
@ ERROR_INVALID_VERSION
Definition: error.h:116
SNMP agent (Simple Network Management Protocol)
SnmpVersion
SNMP version identifiers.
Definition: snmp_common.h:136
@ SNMP_MSG_FLAG_PRIV
SNMP inform notifications.
@ SNMP_PRIV_PROTOCOL_NONE
No privacy.
error_t
Error codes.
Definition: error.h:42
error_t snmpFormatInformRequestMessage(SnmpAgentContext *context, SnmpVersion version, const char_t *userName, uint_t genericTrapType, uint_t specificTrapCode, const SnmpTrapObject *objectList, uint_t objectListSize)
Format SNMP InformRequest message.
SnmpUserEntry * snmpFindUserEntry(SnmpAgentContext *context, const char_t *name, size_t length)
Search the user table for a given user name.
@ SNMP_MSG_FLAG_REPORTABLE
@ SNMP_ERROR_NONE
Definition: snmp_common.h:184
Helper functions for SNMP agent.
@ SNMP_MSG_FLAG_AUTH
#define TRACE_INFO(...)
Definition: debug.h:94
MibRowStatus status
Status of the user.
@ SNMP_VERSION_3
Definition: snmp_common.h:140
size_t snmpGetMacLength(SnmpAuthProtocol authProtocol)
Get the length of the truncated MAC for a given authentication protocol.
#define TRACE_WARNING(...)
Definition: debug.h:84
char char_t
Definition: compiler_port.h:43
@ MIB_ROW_STATUS_ACTIVE
Definition: mib_common.h:103
#define SNMP_MAX_MSG_SIZE
Definition: snmp_common.h:60
error_t snmpWritePduHeader(SnmpMessage *message)
Format PDU header.
#define MIB2_INC_COUNTER32(name, value)
Definition: mib2_module.h:156
error_t snmpLocalizeKey(SnmpAuthProtocol authProtocol, const uint8_t *engineId, size_t engineIdLen, SnmpKey *key, SnmpKey *localizedKey)
Key localization algorithm.
uint8_t message[]
Definition: chap.h:152
SNMP message.
error_t snmpProcessGetResponsePdu(SnmpAgentContext *context)
Process GetResponse-PDU.
#define SNMP_MAX_CONTEXT_ENGINE_SIZE
Definition: snmp_common.h:67
#define SnmpAgentContext
Definition: snmp_agent.h:36
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
error_t snmpComputeMessageOverhead(SnmpMessage *message)
Compute SNMP message overhead.
error_t snmpAuthOutgoingMessage(const SnmpUserEntry *user, SnmpMessage *message)
Authenticate outgoing SNMP message.
@ SNMP_PRIV_PROTOCOL_AES
AES-128-CFB.
error_t snmpFormatGetRequestPdu(SnmpAgentContext *context, SnmpVersion version)
Format GetRequest-PDU (engine ID discovery procedure)
unsigned int uint_t
Definition: compiler_port.h:45
TCP/IP stack core.
@ SNMP_AUTH_PROTOCOL_NONE
No authentication.
@ SNMP_PRIV_PROTOCOL_DES
DES-CBC.
error_t snmpWriteTrapVarBindingList(SnmpAgentContext *context, uint_t genericTrapType, uint_t specificTrapCode, const SnmpTrapObject *objectList, uint_t objectListSize)
Format the variable binding list for Trap-PDU or SNMPv2-Trap-PDU.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
error_t snmpFormatGetRequestMessage(SnmpAgentContext *context, SnmpVersion version)
Format SNMP GetRequest message.
void snmpInitMessage(SnmpMessage *message)
Initialize a SNMP message.
error_t snmpWriteMessageHeader(SnmpMessage *message)
Format SNMP message header.