snmp_agent_trap.c
Go to the documentation of this file.
1 /**
2  * @file snmp_agent_trap.c
3  * @brief SNMP trap notifications
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 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 2.6.0
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_trap.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_TRAP_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Format SNMP Trap 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  const char_t *userName, uint_t genericTrapType, uint_t specificTrapCode,
60  const SnmpTrapObject *objectList, uint_t objectListSize)
61 {
62  error_t error;
63 
64 #if (SNMP_V1_SUPPORT == ENABLED)
65  //SNMPv1 version?
66  if(version == SNMP_VERSION_1)
67  {
68  //Format Trap-PDU
69  error = snmpFormatTrapPdu(context, version, userName,
70  genericTrapType, specificTrapCode, objectList, objectListSize);
71  //Any error to report?
72  if(error)
73  return error;
74 
75  //Format SMNP message header
76  error = snmpWriteMessageHeader(&context->response);
77  //Any error to report?
78  if(error)
79  return error;
80  }
81  else
82 #endif
83 #if (SNMP_V2C_SUPPORT == ENABLED)
84  //SNMPv2c version?
86  {
87  //Format SNMPv2-Trap-PDU
88  error = snmpFormatTrapPdu(context, version, userName,
89  genericTrapType, specificTrapCode, objectList, objectListSize);
90  //Any error to report?
91  if(error)
92  return error;
93 
94  //Format SMNP message header
95  error = snmpWriteMessageHeader(&context->response);
96  //Any error to report?
97  if(error)
98  return error;
99  }
100  else
101 #endif
102 #if (SNMP_V3_SUPPORT == ENABLED)
103  //SNMPv3 version?
104  if(version == SNMP_VERSION_3)
105  {
106  SnmpUserEntry *user;
107 
108  //Information about the user name is extracted from the local
109  //configuration datastore
110  user = snmpFindUserEntry(context, userName, osStrlen(userName));
111 
112  //Invalid user name?
113  if(user == NULL || user->status != MIB_ROW_STATUS_ACTIVE)
115 
116  //Save the security profile associated with the current user
117  context->user = *user;
118 
119  //Format SNMPv2-Trap-PDU
120  error = snmpFormatTrapPdu(context, version, userName,
121  genericTrapType, specificTrapCode, objectList, objectListSize);
122  //Any error to report?
123  if(error)
124  return error;
125 
126  //Format scopedPDU
127  error = snmpWriteScopedPdu(&context->response);
128  //Any error to report?
129  if(error)
130  return error;
131 
132  //Check whether the privFlag is set
133  if((context->response.msgFlags & SNMP_MSG_FLAG_PRIV) != 0)
134  {
135  //Encrypt data
136  error = snmpEncryptData(&context->user, &context->response,
137  context->salt);
138  //Any error to report?
139  if(error)
140  return error;
141  }
142 
143  //Format SMNP message header
144  error = snmpWriteMessageHeader(&context->response);
145  //Any error to report?
146  if(error)
147  return error;
148 
149  //Check whether the authFlag is set
150  if((context->response.msgFlags & SNMP_MSG_FLAG_AUTH) != 0)
151  {
152  //Authenticate outgoing SNMP message
153  error = snmpAuthOutgoingMessage(&context->user, &context->response);
154  //Any error to report?
155  if(error)
156  return error;
157  }
158  }
159  else
160 #endif
161  //Invalid SNMP version?
162  {
163  //Debug message
164  TRACE_WARNING(" Invalid SNMP version!\r\n");
165  //Report an error
166  return ERROR_INVALID_VERSION;
167  }
168 
169  //Successful processing
170  return NO_ERROR;
171 }
172 
173 
174 /**
175  * @brief Format Trap-PDU or SNMPv2-Trap-PDU
176  * @param[in] context Pointer to the SNMP agent context
177  * @param[in] version SNMP version identifier
178  * @param[in] userName User name or community name
179  * @param[in] genericTrapType Generic trap type
180  * @param[in] specificTrapCode Specific code
181  * @param[in] objectList List of object names
182  * @param[in] objectListSize Number of entries in the list
183  * @return Error code
184  **/
185 
187  const char_t *userName, uint_t genericTrapType, uint_t specificTrapCode,
188  const SnmpTrapObject *objectList, uint_t objectListSize)
189 {
190  error_t error;
192 
193  //Point to the SNMP message
194  message = &context->response;
195  //Initialize SNMP message
197 
198  //SNMP version identifier
199  message->version = version;
200 
201 #if (SNMP_V1_SUPPORT == ENABLED)
202  //SNMPv1 version?
203  if(version == SNMP_VERSION_1)
204  {
205 #if (IPV4_SUPPORT == ENABLED)
206  NetInterface *interface;
207 
208  //Point to the underlying network interface
209  interface = context->interface;
210 #endif
211 
212  //Community name
213  message->community = userName;
214  message->communityLen = osStrlen(userName);
215 
216  //Prepare to send a Trap-PDU
217  message->pduType = SNMP_PDU_TRAP;
218  //Type of object generating trap
219  message->enterpriseOid = context->enterpriseOid;
220  message->enterpriseOidLen = context->enterpriseOidLen;
221 
222 #if (IPV4_SUPPORT == ENABLED)
223  //Address of object generating trap
224  if(interface != NULL)
225  {
226  message->agentAddr = interface->ipv4Context.addrList[0].addr;
227  }
228 #endif
229 
230  //Generic trap type
231  message->genericTrapType = genericTrapType;
232  //Specific trap code
233  message->specificTrapCode = specificTrapCode;
234  //Timestamp
235  message->timestamp = osGetSystemTime64() / 10;
236  }
237  else
238 #endif
239 #if (SNMP_V2C_SUPPORT == ENABLED)
240  //SNMPv2c version?
241  if(version == SNMP_VERSION_2C)
242  {
243  //Community name
244  message->community = userName;
245  message->communityLen = osStrlen(userName);
246 
247  //Prepare to send a SNMPv2-Trap-PDU
248  message->pduType = SNMP_PDU_TRAP_V2;
249  }
250  else
251 #endif
252 #if (SNMP_V3_SUPPORT == ENABLED)
253  //SNMPv3 version?
254  if(version == SNMP_VERSION_3)
255  {
256  //Increment message identifier
257  message->msgId = context->msgId++;
258  //Wrap around if necessary
259  if(context->msgId < 0)
260  {
261  context->msgId = 0;
262  }
263 
264  //Maximum message size supported by the sender
265  message->msgMaxSize = SNMP_MAX_MSG_SIZE;
266 
267  //Bit fields which control processing of the message
268  if(context->user.authProtocol != SNMP_AUTH_PROTOCOL_NONE)
269  message->msgFlags |= SNMP_MSG_FLAG_AUTH;
270  if(context->user.privProtocol != SNMP_PRIV_PROTOCOL_NONE)
271  message->msgFlags |= SNMP_MSG_FLAG_PRIV;
272 
273  //Security model used by the sender
274  message->msgSecurityModel = SNMP_SECURITY_MODEL_USM;
275 
276  //Authoritative engine identifier
277  message->msgAuthEngineId = context->contextEngine;
278  message->msgAuthEngineIdLen = context->contextEngineLen;
279  //Number of times the SNMP engine has rebooted
280  message->msgAuthEngineBoots = context->engineBoots;
281  //Number of seconds since last reboot
282  message->msgAuthEngineTime = context->engineTime;
283  //User name
284  message->msgUserName = userName;
285  message->msgUserNameLen = osStrlen(userName);
286  //Authentication parameters
287  message->msgAuthParameters = NULL;
288  //Length of the authentication parameters
289  message->msgAuthParametersLen = snmpGetMacLength(context->user.authProtocol);
290  //Privacy parameters
291  message->msgPrivParameters = context->privParameters;
292 
293  //Length of the privacy parameters
294  if(context->user.privProtocol == SNMP_PRIV_PROTOCOL_DES)
295  {
296  message->msgPrivParametersLen = 8;
297  }
298  else if(context->user.privProtocol == SNMP_PRIV_PROTOCOL_AES)
299  {
300  message->msgPrivParametersLen = 8;
301  }
302  else
303  {
304  message->msgPrivParametersLen = 0;
305  }
306 
307  //Context engine identifier
308  message->contextEngineId = context->contextEngine;
309  message->contextEngineIdLen = context->contextEngineLen;
310  //Context name
311  message->contextName = context->contextName;
312  message->contextNameLen = osStrlen(context->contextName);
313 
314  //Prepare to send a SNMPv2-Trap-PDU
315  message->pduType = SNMP_PDU_TRAP_V2;
316  }
317  else
318 #endif
319  //Invalid SNMP version?
320  {
321  //Report an error
322  return ERROR_INVALID_VERSION;
323  }
324 
325  //Increment request identifier
326  message->requestId = context->requestId++;
327  //Wrap around if necessary
328  if(context->requestId < 0)
329  context->requestId = 0;
330 
331  //Make room for the message header at the beginning of the buffer
332  error = snmpComputeMessageOverhead(&context->response);
333  //Any error to report?
334  if(error)
335  return error;
336 
337  //Format the list of variable bindings
338  error = snmpWriteTrapVarBindingList(context, genericTrapType,
339  specificTrapCode, objectList, objectListSize);
340  //Any error to report?
341  if(error)
342  return error;
343 
344  //Total number of SNMP Trap PDUs which have been generated by
345  //the SNMP protocol entity
346  MIB2_SNMP_INC_COUNTER32(snmpOutTraps, 1);
347 
348  //Format PDU header
349  error = snmpWritePduHeader(&context->response);
350  //Return status code
351  return error;
352 }
353 
354 #endif
error_t snmpFormatTrapPdu(SnmpAgentContext *context, SnmpVersion version, const char_t *userName, uint_t genericTrapType, uint_t specificTrapCode, const SnmpTrapObject *objectList, uint_t objectListSize)
Format Trap-PDU or SNMPv2-Trap-PDU.
MIB-II module.
@ SNMP_PDU_TRAP
Definition: snmp_common.h:154
@ ERROR_UNKNOWN_USER_NAME
Definition: error.h:263
@ SNMP_PDU_TRAP_V2
Definition: snmp_common.h:157
uint8_t message[]
Definition: chap.h:154
error_t snmpWriteScopedPdu(SnmpMessage *message)
Format scopedPDU.
Object descriptor for trap notifications.
@ SNMP_SECURITY_MODEL_USM
User-based security model.
#define osStrlen(s)
Definition: os_port.h:168
SNMP trap notifications.
uint8_t version
Definition: coap_common.h:177
User table entry.
@ SNMP_VERSION_2C
Definition: snmp_common.h:139
@ ERROR_INVALID_VERSION
Definition: error.h:118
SNMP agent (Simple Network Management Protocol)
SnmpVersion
SNMP version identifiers.
Definition: snmp_common.h:137
@ SNMP_MSG_FLAG_PRIV
@ SNMP_PRIV_PROTOCOL_NONE
No privacy.
error_t
Error codes.
Definition: error.h:43
#define MIB2_SNMP_INC_COUNTER32(name, value)
Definition: mib2_module.h:169
SnmpUserEntry * snmpFindUserEntry(SnmpAgentContext *context, const char_t *name, size_t length)
Search the user table for a given user name.
#define NetInterface
Definition: net.h:40
Helper functions for SNMP agent.
@ SNMP_MSG_FLAG_AUTH
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:93
char char_t
Definition: compiler_port.h:55
@ 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.
error_t snmpFormatTrapMessage(SnmpAgentContext *context, SnmpVersion version, const char_t *userName, uint_t genericTrapType, uint_t specificTrapCode, const SnmpTrapObject *objectList, uint_t objectListSize)
Format SNMP Trap message.
#define osGetSystemTime64()
SNMP message.
@ SNMP_VERSION_1
Definition: snmp_common.h:138
#define SnmpAgentContext
Definition: snmp_agent.h:36
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 snmpEncryptData(const SnmpUserEntry *user, SnmpMessage *message, uint8_t *salt)
Data encryption.
unsigned int uint_t
Definition: compiler_port.h:57
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.
void snmpInitMessage(SnmpMessage *message)
Initialize a SNMP message.
error_t snmpWriteMessageHeader(SnmpMessage *message)
Format SNMP message header.