ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
snmp_notify.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file snmp_notify.h
6 * @brief Notifications: the SNMPv2-Trap-PDU and the InformRequest-PDU (PROTOCORE_ENABLE_SNMP_TRAP).
7 *
8 * The notification originator side of the agent: an event is pushed to a notification receiver
9 * instead of waiting to be polled.
10 *
11 * RFC 3416 sec 4.2.6 defines the SNMPv2-Trap-PDU and sec 4.2.7 the InformRequest-PDU. Both carry
12 * the same two mandatory first variable-bindings: sysUpTime.0 and snmpTrapOID.0 (RFC 3418 sec 2),
13 * followed by whatever bindings the caller adds. The two differ in confirmation, not in shape: a
14 * trap is unacknowledged, while an InformRequest-PDU is answered by a Response-PDU that echoes its
15 * request-id, so its sender owns the retransmission.
16 *
17 * RFC 3417 sec 3.2 suggests notification receivers listen on UDP port 162.
18 *
19 * The build calls are pure: message octets in a caller buffer, no socket and no clock, so they are
20 * unit-tested with no network stack under them. The send calls add the address parse and the
21 * datagram. SNMPv3 USM notifications are the v3 layer's, reached through ::SnmpV3.
22 *
23 * @author Douglas Quigg (dstroy0)
24 * @date 2026
25 */
26
27#ifndef PROTOCORE_SNMP_NOTIFY_H
28#define PROTOCORE_SNMP_NOTIFY_H
29
30#include "protocore_config.h" // the entry point: protocore_types.h for the widths
31
32#if PROTOCORE_ENABLE_SNMP_TRAP
33
35
36#include "services/net/snmp/snmp_ber/snmp_ber.h" // BerEnc: the open encoder a PDU append writes into
37/** @brief Which SMIv2 type a caller variable-binding carries (RFC 2578 sec 7.1). */
38typedef enum PROTO_ENUM_PACKED
39{
40 SNMP_VB_INT = 0, ///< INTEGER, in ival
41 SNMP_VB_STRING = 1, ///< OCTET STRING, in bytes/blen
42 SNMP_VB_OID = 2, ///< OBJECT IDENTIFIER, in oid_val/oid_val_len
43 SNMP_VB_COUNTER32 = 3, ///< Counter32, in ival (RFC 2578 sec 7.1.6)
44 SNMP_VB_GAUGE32 = 4, ///< Gauge32, in ival (RFC 2578 sec 7.1.7)
45 SNMP_VB_TIMETICKS = 5, ///< TimeTicks, in ival (RFC 2578 sec 7.1.8)
46 SNMP_VB_IPADDR = 6, ///< IpAddress, 4 octets in bytes (RFC 2578 sec 7.1.5)
47} SnmpVbType;
48
49/** @brief One variable-binding of the VarBindList: a name and its typed value (RFC 3416 sec 3). */
50typedef struct
51{
52 const uint32_t *oid; ///< the binding's name, as subidentifiers
53 size_t oid_len; ///< how many
54 uint8_t type; ///< which ::SnmpVbType the value is
55 long ival; ///< INTEGER, Counter32, Gauge32 or TimeTicks value
56 const uint8_t *bytes; ///< OCTET STRING or IpAddress octets
57 size_t blen; ///< how many
58 const uint32_t *oid_val; ///< an OBJECT IDENTIFIER value's subidentifiers
59 size_t oid_val_len; ///< how many
60} SnmpVarbind;
61
62/** @brief RFC 3416 sec 4.2.6 and sec 4.2.7: what a notification PDU carries. */
63typedef struct
64{
65 uint8_t pdu_tag; ///< ::SNMP_TAG_SNMP_PDU_TRAPV2 or ::SNMP_TAG_SNMP_PDU_INFORM
66 uint32_t request_id; ///< the PDU's request-id, echoed by an inform's Response-PDU
67 const uint32_t *trap_oid; ///< the snmpTrapOID.0 value (RFC 3418 sec 2)
68 size_t trap_oid_len; ///< how many subidentifiers
69 uint32_t uptime_ticks; ///< the sysUpTime.0 value, TimeTicks (RFC 2578 sec 7.1.8)
70 const SnmpVarbind *vbs; ///< the caller bindings that follow the mandatory two
71 size_t vb_count; ///< how many
72} SnmpNotifyPduArgs;
73
74/** @brief RFC 3417 sec 3.2: the notification receiver a send addresses. */
75typedef struct
76{
77 const char *dst_ip; ///< its address, as text
78 uint16_t port; ///< its port, 162 by convention
79 const char *community; ///< the community the message carries (RFC 1157 sec 3.2.5)
80} SnmpNotifyDstArgs;
81
82/** @brief Where a notification is built: an open encoder, or a bare buffer. */
83typedef struct
84{
85 BerEnc *enc; ///< the open encoder a PDU append writes into
86 uint8_t *out; ///< where a complete message is built
87 size_t cap; ///< how many octets that holds
88} SnmpNotifyBufArgs;
89
90/**
91 * @brief The notification originator (RFC 3416 sec 4.2.6, sec 4.2.7).
92 *
93 * A caller sets the members a call takes, invokes it through ::SnmpNotify, and reads the outcome
94 * off the same handle.
95 *
96 * @var SnmpNotifyNs::pdu what the notification PDU carries
97 * @var SnmpNotifyNs::dst the notification receiver a send addresses
98 * @var SnmpNotifyNs::buf where the message is built
99 * @var SnmpNotifyNs::ok a send's true/false outcome: the stack took the datagram
100 * @var SnmpNotifyNs::n octets a build wrote, 0 when the buffer could not hold them
101 * @var SnmpNotifyNs::build_pdu append the notification PDU to @c buf.enc, mandatory bindings first
102 * @var SnmpNotifyNs::build_v2c build a complete SNMPv2c notification message into @c buf.out
103 * @var SnmpNotifyNs::trap_v2c build and send an SNMPv2-Trap-PDU, sysUpTime.0 from the clock
104 * @var SnmpNotifyNs::inform_v2c build and send an InformRequest-PDU under the caller's request-id
105 */
106typedef struct
107{
108 SnmpNotifyPduArgs pdu; ///< what the notification PDU carries
109 SnmpNotifyDstArgs dst; ///< where a send goes
110 SnmpNotifyBufArgs buf; ///< where the message is built
111 proto_bool ok;
112 size_t n;
113} SnmpNotifyVars;
114
115/** @brief The operands and the outcome. */
116extern SnmpNotifyVars SnmpNotifyV;
117
118/** @brief The entries. */
119typedef struct
120{
121 void (*const build_pdu)(uint8_t *work);
122 void (*const build_v2c)(uint8_t *work);
123 void (*const trap_v2c)(uint8_t *work);
124 void (*const inform_v2c)(uint8_t *work);
125} SnmpNotifyNs;
126
127// What the table binds, defined once in the .c and taking one parameter each: everything
128// else an entry needs is an operand in SnmpNotifyV or a region of the borrow at a fixed offset.
129void protocore_snmp_notify_build_pdu(uint8_t *work);
130void protocore_snmp_notify_build_v2c(uint8_t *work);
131void protocore_snmp_notify_trap_v2c(uint8_t *work);
132void protocore_snmp_notify_inform_v2c(uint8_t *work);
133
134// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
135// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
136// `SnmpNotify.build_pdu(work)` resolves to a named function and becomes a DIRECT call. An extern table
137// leaves the call indirect and the symbol live at every level, -O2 -flto included.
138static const SnmpNotifyNs SnmpNotify __attribute__((unused)) = {
139 .build_pdu = protocore_snmp_notify_build_pdu,
140 .build_v2c = protocore_snmp_notify_build_v2c,
141 .trap_v2c = protocore_snmp_notify_trap_v2c,
142 .inform_v2c = protocore_snmp_notify_inform_v2c,
143};
144
145/**
146 * @brief The PROTOCORE_SNMP_NOTIFY_BORROW bytes this module's state lives in.
147 *
148 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
149 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
150 * walks, so the state lasts the life of the program.
151 *
152 * @return the span.
153 */
154uint8_t *protocore_snmp_notify_span(void);
155
157
158#endif // PROTOCORE_ENABLE_SNMP_TRAP
159
160#endif // PROTOCORE_SNMP_NOTIFY_H
PROTO_ENUM_PACKED
Application protocol spoken on a listener port or connection slot.
The SNMP serialization: ASN.1 Basic Encoding Rules over a caller buffer.
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97