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