In order to get trap support back into relayd libagentx needs to get notify support. Here's my interpretation on the matter. Relayd itself still needs a proper NOTIFICATION-TYPE definition before that can be implemented, but that shouldn't stop this diff.
I already have an OK rob@, but additional feedback welcome. Since this has an additional manpage and library bump: any good/bad timeframe for committing this? martijn@ Index: Makefile =================================================================== RCS file: /cvs/src/lib/libagentx/Makefile,v retrieving revision 1.4 diff -u -p -r1.4 Makefile --- Makefile 26 Oct 2020 15:57:03 -0000 1.4 +++ Makefile 4 Jan 2021 17:34:01 -0000 @@ -4,7 +4,7 @@ LIB= agentx SRCS= ax.c agentx.c agentx_log.c HDRS= agentx.h -MAN= agentx.3 +MAN= agentx.3 agentx_notify.3 CFLAGS+= -Wall CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes Index: Symbols.list =================================================================== RCS file: /cvs/src/lib/libagentx/Symbols.list,v retrieving revision 1.3 diff -u -p -r1.3 Symbols.list --- Symbols.list 27 Oct 2020 18:24:01 -0000 1.3 +++ Symbols.list 4 Jan 2021 17:34:01 -0000 @@ -29,6 +29,23 @@ agentx_index_oid_dynamic agentx_index_noid_dynamic agentx_index_ipaddress_dynamic agentx_index_free +agentx_notify +agentx_notify_counter32 +agentx_notify_counter64 +agentx_notify_gauge32 +agentx_notify_index +agentx_notify_integer +agentx_notify_ipaddress +agentx_notify_nstring +agentx_notify_null +agentx_notify_object +agentx_notify_oid +agentx_notify_opaque +agentx_notify_printf +agentx_notify_send +agentx_notify_string +agentx_notify_timeticks +agentx_notify_unsigned32 agentx_object agentx_object_free agentx_varbind_integer Index: agentx.3 =================================================================== RCS file: /cvs/src/lib/libagentx/agentx.3,v retrieving revision 1.5 diff -u -p -r1.5 agentx.3 --- agentx.3 3 Dec 2020 22:47:21 -0000 1.5 +++ agentx.3 4 Jan 2021 17:34:01 -0000 @@ -621,6 +621,7 @@ in timeticks. .El .Sh SEE ALSO .Xr snmp 1 , +.Xr agentx_notify 3 , .Xr snmpd 8 .Sh STANDARDS .Rs Index: agentx.c =================================================================== RCS file: /cvs/src/lib/libagentx/agentx.c,v retrieving revision 1.8 diff -u -p -r1.8 agentx.c --- agentx.c 27 Oct 2020 18:24:01 -0000 1.8 +++ agentx.c 4 Jan 2021 17:34:01 -0000 @@ -87,6 +87,18 @@ struct agentx_object { TAILQ_ENTRY(agentx_object) axo_axr_objects; }; +struct agentx_notify { + struct agentx_context *axn_axc; + struct ax_varbind *axn_vb; + struct ax_oid axn_trapoid; + uint32_t axn_uptime; + int axn_sent; + size_t axn_nvb; + size_t axn_vbsize; + int axn_fail; + TAILQ_ENTRY(agentx_notify) axn_axc_notifications; +}; + struct agentx_varbind { struct agentx_get *axv_axg; struct agentx_object *axv_axo; @@ -160,6 +172,9 @@ static void agentx_object_free_finalize( static void agentx_object_reset(struct agentx_object *); static int agentx_object_cmp(struct agentx_object *, struct agentx_object *); +static int agentx_notify_add(struct agentx_notify *, const uint32_t [], size_t); +static int agentx_notify_finalize(struct ax_pdu *, void *); +static void agentx_notify_free(struct agentx_notify *); static void agentx_get_start(struct agentx_context *, struct ax_pdu *); static void agentx_get_finalize(struct agentx_get *); @@ -596,6 +611,7 @@ agentx_context(struct agentx_session *ax axc->axc_dstate = AX_DSTATE_OPEN; TAILQ_INIT(&(axc->axc_agentcaps)); TAILQ_INIT(&(axc->axc_regions)); + TAILQ_INIT(&(axc->axc_notifications)); TAILQ_INSERT_HEAD(&(axs->axs_contexts), axc, axc_axs_contexts); @@ -690,6 +706,7 @@ agentx_context_free(struct agentx_contex { struct agentx_agentcaps *axa, *tsaa; struct agentx_region *axr, *tsar; + struct agentx_notify *axn, *taxn; if (axc == NULL) return; @@ -700,6 +717,14 @@ agentx_context_free(struct agentx_contex #endif axc->axc_dstate = AX_DSTATE_CLOSE; + TAILQ_FOREACH_SAFE(axn, &(axc->axc_notifications), + axn_axc_notifications, taxn) { + axn->axn_axc = NULL; + TAILQ_REMOVE(&(axc->axc_notifications), axn, + axn_axc_notifications); + if (axn->axn_sent) + agentx_notify_free(axn); + } TAILQ_FOREACH_SAFE(axa, &(axc->axc_agentcaps), axa_axc_agentcaps, tsaa) { if (axa->axa_dstate != AX_DSTATE_CLOSE) @@ -720,6 +745,9 @@ agentx_context_free_finalize(struct agen if (axc->axc_dstate != AX_DSTATE_CLOSE) agentx_log_axc_fatalx(axc, "%s: unexpected context free", __func__); + if (!TAILQ_EMPTY(&(axc->axc_notifications))) + agentx_log_axc_fatalx(axc, "%s: notifications not empty", + __func__); #endif if (!TAILQ_EMPTY(&(axc->axc_regions)) || !TAILQ_EMPTY(&(axc->axc_agentcaps))) @@ -734,11 +762,20 @@ agentx_context_reset(struct agentx_conte { struct agentx_agentcaps *axa, *tsaa; struct agentx_region *axr, *tsar; + struct agentx_notify *axn, *taxn; axc->axc_cstate = AX_CSTATE_CLOSE; axc->axc_sysuptimespec.tv_sec = 0; axc->axc_sysuptimespec.tv_nsec = 0; + TAILQ_FOREACH_SAFE(axn, &(axc->axc_notifications), + axn_axc_notifications, taxn) { + axn->axn_axc = NULL; + TAILQ_REMOVE(&(axc->axc_notifications), axn, + axn_axc_notifications); + if (axn->axn_sent) + agentx_notify_free(axn); + } TAILQ_FOREACH_SAFE(axa, &(axc->axc_agentcaps), axa_axc_agentcaps, tsaa) agentx_agentcaps_reset(axa); TAILQ_FOREACH_SAFE(axr, &(axc->axc_regions), axr_axc_regions, tsar) @@ -2473,6 +2510,379 @@ agentx_object_implied(struct agentx_obje __func__); #endif return 0; +} + +struct agentx_notify * +agentx_notify(struct agentx_context *axc, const uint32_t oid[], size_t oidlen) +{ + struct agentx_notify *axn; + size_t i; + + if (axc->axc_dstate == AX_DSTATE_CLOSE) + agentx_log_axc_fatalx(axc, "%s: use after free", __func__); + + if ((axn = calloc(1, sizeof(*axn))) == NULL) + return NULL; + axn->axn_axc = axc; + TAILQ_INSERT_TAIL(&(axc->axc_notifications), axn, + axn_axc_notifications); + + for (i = 0; i < oidlen; i++) + axn->axn_trapoid.aoi_id[i] = oid[i]; + axn->axn_trapoid.aoi_idlen = oidlen; + if ((axn->axn_uptime = agentx_context_uptime(axc)) == 0) { + agentx_notify_free(axn); + errno = ENOTCONN; + return NULL; + } + + agentx_notify_timeticks(axn, AGENTX_OID(AGENTX_SYSUPTIME, 0), + axn->axn_uptime); + agentx_notify_oid(axn, AGENTX_OID(AGENTX_SNMPTRAPOID, 0), oid, oidlen); + + if (axn->axn_fail) { + agentx_notify_free(axn); + return NULL; + } + return axn; +} + +void +agentx_notify_integer(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen, int32_t value) +{ + if (agentx_notify_add(axn, oid, oidlen) == -1) + return; + axn->axn_vb[axn->axn_nvb].avb_type = AX_DATA_TYPE_INTEGER; + axn->axn_vb[axn->axn_nvb++].avb_data.avb_int32 = value; +} + +void +agentx_notify_string(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen, const char *value) +{ + agentx_notify_nstring(axn, oid, oidlen, value, strlen(value)); +} + +void +agentx_notify_nstring(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen, const char *value, size_t slen) +{ + if (agentx_notify_add(axn, oid, oidlen) == -1) + return; + + if ((axn->axn_vb[axn->axn_nvb].avb_data.avb_ostring.aos_string = + malloc(slen)) == NULL) { + agentx_log_axc_warnx(axn->axn_axc, "Failed to bind string to " + "notify"); + axn->axn_fail = 1; + return; + } + + axn->axn_vb[axn->axn_nvb].avb_type = AX_DATA_TYPE_OCTETSTRING; + memcpy(axn->axn_vb[axn->axn_nvb].avb_data.avb_ostring.aos_string, value, + slen); + axn->axn_vb[axn->axn_nvb++].avb_data.avb_ostring.aos_slen = slen; +} + +void +agentx_notify_printf(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen, const char *fmt, ...) +{ + va_list ap; + int r; + + if (agentx_notify_add(axn, oid, oidlen) == -1) + return; + + va_start(ap, fmt); + r = vasprintf((char **) + &(axn->axn_vb[axn->axn_nvb].avb_data.avb_ostring.aos_string), + fmt, ap); + va_end(ap); + + if (r == -1) { + agentx_log_axc_warn(axn->axn_axc, "Failed to bind string to " + "notify"); + axn->axn_vb[axn->axn_nvb].avb_data.avb_ostring.aos_string = + NULL; + axn->axn_fail = 1; + return; + } + + axn->axn_vb[axn->axn_nvb].avb_type = AX_DATA_TYPE_OCTETSTRING; + axn->axn_vb[axn->axn_nvb++].avb_data.avb_ostring.aos_slen = r; +} + +void +agentx_notify_null(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen) +{ + if (agentx_notify_add(axn, oid, oidlen) == -1) + return; + + axn->axn_vb[axn->axn_nvb++].avb_type = AX_DATA_TYPE_NULL; +} + +void +agentx_notify_oid(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen, const uint32_t value[], size_t vlen) +{ + size_t i; + + if (agentx_notify_add(axn, oid, oidlen) == -1) + return; + + axn->axn_vb[axn->axn_nvb].avb_type = AX_DATA_TYPE_OID; + for (i = 0; i < vlen; i++) + axn->axn_vb[axn->axn_nvb].avb_data.avb_oid.aoi_id[i] = value[i]; + axn->axn_vb[axn->axn_nvb++].avb_data.avb_oid.aoi_idlen = vlen; +} + +void +agentx_notify_object(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen, struct agentx_object *axo) +{ + agentx_notify_oid(axn, oid, oidlen, axo->axo_oid.aoi_id, + axo->axo_oid.aoi_idlen); +} + +void +agentx_notify_index(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen, struct agentx_index *axi) +{ + agentx_notify_oid(axn, oid, oidlen, axi->axi_vb.avb_oid.aoi_id, + axi->axi_vb.avb_oid.aoi_idlen); +} + +void +agentx_notify_ipaddress(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen, const struct in_addr *value) +{ + if (agentx_notify_add(axn, oid, oidlen) == -1) + return; + + if ((axn->axn_vb[axn->axn_nvb].avb_data.avb_ostring.aos_string = + malloc(4)) == NULL) { + agentx_log_axc_warn(axn->axn_axc, "Couldn't bind ipaddress to" + "notify"); + axn->axn_fail = 1; + return; + } + axn->axn_vb[axn->axn_nvb].avb_type = AX_DATA_TYPE_IPADDRESS; + memcpy(axn->axn_vb[axn->axn_nvb].avb_data.avb_ostring.aos_string, + value, 4); + axn->axn_vb[axn->axn_nvb++].avb_data.avb_ostring.aos_slen = 4; +} + +void +agentx_notify_counter32(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen, uint32_t value) +{ + if (agentx_notify_add(axn, oid, oidlen) == -1) + return; + + axn->axn_vb[axn->axn_nvb].avb_type = AX_DATA_TYPE_COUNTER32; + axn->axn_vb[axn->axn_nvb++].avb_data.avb_uint32 = value; +} + +void +agentx_notify_gauge32(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen, uint32_t value) +{ + if (agentx_notify_add(axn, oid, oidlen) == -1) + return; + + axn->axn_vb[axn->axn_nvb].avb_type = AX_DATA_TYPE_GAUGE32; + axn->axn_vb[axn->axn_nvb++].avb_data.avb_uint32 = value; +} + +void +agentx_notify_unsigned32(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen, uint32_t value) +{ + agentx_notify_gauge32(axn, oid, oidlen, value); +} + +void +agentx_notify_timeticks(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen, uint32_t value) +{ + if (agentx_notify_add(axn, oid, oidlen) == -1) + return; + + axn->axn_vb[axn->axn_nvb].avb_type = AX_DATA_TYPE_TIMETICKS; + axn->axn_vb[axn->axn_nvb++].avb_data.avb_uint32 = value; +} + +void +agentx_notify_opaque(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen, const char *value, size_t slen) +{ + if (agentx_notify_add(axn, oid, oidlen) == -1) + return; + + if ((axn->axn_vb[axn->axn_nvb].avb_data.avb_ostring.aos_string = + malloc(slen)) == NULL) { + agentx_log_axc_warn(axn->axn_axc, "Failed to bind opaque to " + "notify"); + axn->axn_fail = 1; + return; + } + axn->axn_vb[axn->axn_nvb].avb_type = AX_DATA_TYPE_OPAQUE; + memcpy(axn->axn_vb[axn->axn_nvb].avb_data.avb_ostring.aos_string, value, + slen); + axn->axn_vb[axn->axn_nvb++].avb_data.avb_ostring.aos_slen = slen; +} + +void +agentx_notify_counter64(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen, uint64_t value) +{ + if (agentx_notify_add(axn, oid, oidlen) == -1) + return; + + axn->axn_vb[axn->axn_nvb].avb_type = AX_DATA_TYPE_COUNTER64; + axn->axn_vb[axn->axn_nvb++].avb_data.avb_uint64 = value; +} + +void +agentx_notify_send(struct agentx_notify *axn) +{ + struct agentx_context *axc = axn->axn_axc; + struct agentx_session *axs; + struct agentx *ax; + uint32_t packetid; + char *logmsg = NULL; + size_t i; + int fail = 0; + + if (axn->axn_fail || axc == NULL) { + agentx_log_axc_warn(axc, "Failed to send notify: %s: %s", + ax_oid2string(&(axn->axn_trapoid)), + axn->axn_fail ? "Prior error" : "Connection reset"); + agentx_notify_free(axn); + return; + } + axs = axc->axc_axs; + ax = axs->axs_ax; + + if ((packetid = ax_notify(ax->ax_ax, axs->axs_id, + AGENTX_CONTEXT_CTX(axc), axn->axn_vb, axn->axn_nvb)) == 0) { + agentx_log_axc_warn(axc, "Couldn't generate %s: %s", + ax_oid2string(&(axn->axn_trapoid)), + ax_pdutype2string(AX_PDU_TYPE_NOTIFY)); + agentx_notify_free(axn); + return; + } + + for (i = 2; i < axn->axn_nvb; i++) { + if (i == 2) + fail |= agentx_strcat(&logmsg, " {"); + else + fail |= agentx_strcat(&logmsg, ",{"); + fail |= agentx_strcat(&logmsg, + ax_varbind2string(&(axn->axn_vb[i]))); + fail |= agentx_strcat(&logmsg, "}"); + if (fail) + break; + } + if (fail) + agentx_log_axc_warn(axc, "Failed to generate notify log"); + else { + agentx_log_axc_debug(axc, "Notify %s(%u):%s", + ax_oid2string(&(axn->axn_trapoid)), axn->axn_uptime, + logmsg); + } + free(logmsg); + agentx_log_axc_info(axc, "Notify %s(%u): sent", + ax_oid2string(&(axn->axn_trapoid)), axn->axn_uptime); + axn->axn_sent = 1; + if (agentx_request(ax, packetid, agentx_notify_finalize, axn) == -1) + agentx_notify_free(axn); +} + +static int +agentx_notify_add(struct agentx_notify *axn, const uint32_t oid[], + size_t oidlen) +{ + struct ax_varbind *vb; + size_t i; + + if (oidlen < 1) { +#ifdef AX_DEBUG + agentx_log_axc_fatalx(axn->axn_axc, "%s: oidlen == 0", + __func__); +#else + agentx_log_axc_warnx(axn->axn_axc, "%s: oidlen == 0", __func__); + axn->axn_fail = 1; + return -1; +#endif + } + if (oidlen > AGENTX_OID_MAX_LEN) { +#ifdef AX_DEBUG + agentx_log_axc_fatalx(axn->axn_axc, "%s: oidlen > %d", __func__, + AGENTX_OID_MAX_LEN); +#else + agentx_log_axc_warnx(axn->axn_axc, "%s: oidlen > %d", __func__, + AGENTX_OID_MAX_LEN); + axn->axn_fail = 1; + return -1; +#endif + } + + if (axn->axn_fail) + return -1; + + if (axn->axn_nvb == axn->axn_vbsize) { + if ((vb = recallocarray(axn->axn_vb, axn->axn_vbsize, + axn->axn_vbsize + 5, sizeof (*vb))) == NULL) { + agentx_log_axc_warnx(axn->axn_axc, "Failed to add " + "varbind to notify"); + axn->axn_fail = 1; + return -1; + } + axn->axn_vb = vb; + axn->axn_vbsize += 5; + } + + for (i = 0; i < oidlen; i++) + axn->axn_vb[axn->axn_nvb].avb_oid.aoi_id[i] = oid[i]; + axn->axn_vb[axn->axn_nvb].avb_oid.aoi_idlen = oidlen; + + return 0; +} + +static int +agentx_notify_finalize(struct ax_pdu *pdu, void *cookie) +{ + struct agentx_notify *axn = cookie; + struct agentx_context *axc = axn->axn_axc; + + if (pdu->ap_payload.ap_response.ap_error != AX_PDU_ERROR_NOERROR) + agentx_log_axc_warnx(axc, "Failed to send notify %s(%u): %s", + ax_oid2string(&(axn->axn_trapoid)), axn->axn_uptime, + ax_error2string(pdu->ap_payload.ap_response.ap_error)); + else + agentx_log_axc_info(axc, "notify sent %s(%u)", + ax_oid2string(&(axn->axn_trapoid)), axn->axn_uptime); + + agentx_notify_free(axn); + return 0; +} + +static void +agentx_notify_free(struct agentx_notify *axn) +{ + size_t i; + + for (i = 0; i < axn->axn_nvb; i++) + ax_varbind_free(&(axn->axn_vb[i])); + free(axn->axn_vb); + if (axn->axn_axc != NULL) + TAILQ_REMOVE(&(axn->axn_axc->axc_notifications), axn, + axn_axc_notifications); + free(axn); } static void Index: agentx.h =================================================================== RCS file: /cvs/src/lib/libagentx/agentx.h,v retrieving revision 1.5 diff -u -p -r1.5 agentx.h --- agentx.h 27 Oct 2020 18:24:01 -0000 1.5 +++ agentx.h 4 Jan 2021 17:34:01 -0000 @@ -27,6 +27,7 @@ struct agentx_agentcaps; struct agentx_region; struct agentx_index; struct agentx_object; +struct agentx_notify; struct agentx_varbind; enum agentx_request_type { @@ -40,6 +41,8 @@ enum agentx_request_type { #define AGENTX_OID_INDEX_MAX_LEN 10 #define AGENTX_MIB2 1, 3, 6, 1, 2, 1 #define AGENTX_ENTERPRISES 1, 3, 6, 1, 4, 1 +#define AGENTX_SYSUPTIME AGENTX_MIB2, 1, 3 +#define AGENTX_SNMPTRAPOID 1, 3, 6, 1, 6, 3, 1, 1, 4, 1 #define AGENTX_OID(...) (uint32_t []) { __VA_ARGS__ }, \ (sizeof((uint32_t []) { __VA_ARGS__ }) / sizeof(uint32_t)) @@ -147,3 +150,36 @@ void agentx_varbind_set_index_object(str struct agentx_index *, struct agentx_object *); void agentx_varbind_set_index_ipaddress(struct agentx_varbind *, struct agentx_index *, const struct in_addr *); + +struct agentx_notify *agentx_notify(struct agentx_context *, const uint32_t[], + size_t); +void agentx_notify_integer(struct agentx_notify *, const uint32_t[], size_t, + int32_t); +void agentx_notify_string(struct agentx_notify *, const uint32_t[], size_t, + const char *); +void agentx_notify_nstring(struct agentx_notify *, const uint32_t[], size_t, + const char *, size_t); +void agentx_notify_printf(struct agentx_notify *, const uint32_t[], size_t, + const char *, ...) __attribute__((__format__ (printf, 4, 5))); +void agentx_notify_null(struct agentx_notify *, const uint32_t[], size_t); +void agentx_notify_oid(struct agentx_notify *, const uint32_t[], size_t, + const uint32_t[], size_t); +void agentx_notify_object(struct agentx_notify *, const uint32_t[], size_t, + struct agentx_object *); +void agentx_notify_index(struct agentx_notify *, const uint32_t[], size_t, + struct agentx_index *); +void agentx_notify_ipaddress(struct agentx_notify *, const uint32_t[], size_t, + const struct in_addr *); +void agentx_notify_counter32(struct agentx_notify *, const uint32_t[], size_t, + uint32_t); +void agentx_notify_gauge32(struct agentx_notify *, const uint32_t[], size_t, + uint32_t); +void agentx_notify_unsigned32(struct agentx_notify *, const uint32_t[], size_t, + uint32_t); +void agentx_notify_timeticks(struct agentx_notify *, const uint32_t[], size_t, + uint32_t); +void agentx_notify_opaque(struct agentx_notify *, const uint32_t[], size_t, + const char *, size_t); +void agentx_notify_counter64(struct agentx_notify *, const uint32_t[], size_t, + uint64_t); +void agentx_notify_send(struct agentx_notify *); Index: agentx_internal.h =================================================================== RCS file: /cvs/src/lib/libagentx/agentx_internal.h,v retrieving revision 1.2 diff -u -p -r1.2 agentx_internal.h --- agentx_internal.h 26 Oct 2020 16:02:16 -0000 1.2 +++ agentx_internal.h 4 Jan 2021 17:34:01 -0000 @@ -67,6 +67,7 @@ struct agentx_context { enum agentx_dstate axc_dstate; TAILQ_HEAD(, agentx_agentcaps) axc_agentcaps; TAILQ_HEAD(, agentx_region) axc_regions; + TAILQ_HEAD(, agentx_notify) axc_notifications; RB_HEAD(axc_objects, agentx_object) axc_objects; TAILQ_ENTRY(agentx_context) axc_axs_contexts; }; Index: agentx_notify.3 =================================================================== RCS file: agentx_notify.3 diff -N agentx_notify.3 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ agentx_notify.3 4 Jan 2021 17:34:01 -0000 @@ -0,0 +1,177 @@ +.\" $OpenBSD: agentx.3,v 1.5 2020/12/03 22:47:21 jmc Exp $ +.\" +.\" Copyright (c) 2020 Martijn van Duren <mart...@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: December 3 2020 $ +.Dt AGENTX_NOTIFY 3 +.Os +.Sh NAME +.Nm agentx_notify +.Nm agentx_notify_integer +.Nm agentx_notify_string +.Nm agentx_notify_nstring +.Nm agentx_notify_printf +.Nm agentx_notify_null +.Nm agentx_notify_oid +.Nm agentx_notify_object +.Nm agentx_notify_index +.Nm agentx_notify_ipaddress +.Nm agentx_notify_counter32 +.Nm agentx_notify_gauge32 +.Nm agentx_notify_unsigned32 +.Nm agentx_notify_timeticks +.Nm agentx_notify_opaque +.Nm agentx_notify_counter64 +.Nm agentx_notify_send +.Sh SYNOPSIS +.In agentx.h +.Ft struct agentx_notify * +.Fo agentx_notify +.Fa "struct agentx_context *axc" "const uint32_t trapoid[]" "size_t oidlen" +.Fc +.Ft void +.Fo agentx_notify_integer +.Fa "struct agentx_notify *axn" "const uint32_t oid[]" "size_t oidlen" +.Fa "int32_t value" +.Fc +.Ft void +.Fo agentx_notify_string +.Fa "struct agentx_notify *axn" "const uint32_t oid[]" "size_t oidlen" +.Fa "const char *string" +.Fc +.Ft void +.Fo agentx_notify_nstring +.Fa "struct agentx_notify *axn" "const uint32_t oid[]" "size_t oidlen" +.Fa "const char *string" "size_t slen" +.Fc +.Ft void +.Fo agentx_notify_printf +.Fa "struct agentx_notify *axn" "const uint32_t oid[]" "size_t oidlen" +.Fa "const char *fmt" ... +.Fc +.Ft void +.Fo agentx_notify_null +.Fa "struct agentx_notify *axn" "const uint32_t oid[]" "size_t oidlen" +.Fc +.Ft void +.Fo agentx_notify_oid +.Fa "struct agentx_notify *axn" "const uint32_t oid[]" "size_t oidlen" +.Fa "const uint32_t oidvalue[]" "size_t oidvlen" +.Fc +.Ft void +.Fo agentx_notify_object +.Fa "struct agentx_notify *axn" "const uint32_t oid[]" "size_t oidlen" +.Fa "struct agentx_object *axo" +.Fc +.Ft void +.Fo agentx_notify_index +.Fa "struct agentx_notify *axn" "const uint32_t oid[]" "size_t oidlen" +.Fa "struct agentx_index *axi" +.Fc +.Ft void +.Fo agentx_notify_ipaddress +.Fa "struct agentx_notify *axn" "const uint32_t oid[]" "size_t oidlen" +.Fa "const struct in_addr *addr" +.Fc +.Ft void +.Fo agentx_notify_counter32 +.Fa "struct agentx_notify *axn" "const uint32_t oid[]" "size_t oidlen" +.Fa "uint32_t value" +.Fc +.Ft void +.Fo agentx_notify_gauge32 +.Fa "struct agentx_notify *axn" "const uint32_t oid[]" "size_t oidlen" +.Fa "uint32_t value" +.Fc +.Ft void +.Fo agentx_notify_unsigned32 +.Fa "struct agentx_notify *axn" "const uint32_t oid[]" "size_t oidlen" +.Fa "uint32_t value" +.Fc +.Ft void +.Fo agentx_notify_timeticks +.Fa "struct agentx_notify *axn" "const uint32_t oid[]" "size_t oidlen" +.Fa "uint32_t value" +.Fc +.Ft void +.Fo agentx_notify_opaque +.Fa "struct agentx_notify *axn" "const uint32_t oid[]" "size_t oidlen" +.Fa "const char *string" "size_t slen" +.Fc +.Ft void +.Fo agentx_notify_counter64 +.Fa "struct agentx_notify *axn" "const uint32_t oid[]" "size_t oidlen" +.Fa "uint64_t value" +.Fc +.Ft void +.Fn agentx_notify_send "struct agentx_notify *axn" +.Sh DESCRIPTION +The +.Nm agentx_notify +interface allows to send notify messages or +.Dq SNMP trap +messages to the agentx master. +To send a message a notify context needs to be set up on an context initiated +with +.Xr agentx_context 3 . +The +.Fa trapoid +and +.Fa oidlen +combination identifies the trap to be sent. +The sysuptime parameter is set internally. +.Pp +Additional objects can be added to the notify by calling agentx_notify_<type>. +These functions must be called in the order specified by the MIB and work +similar to the agentx_varbind_<type> functions. +.Pp +Once the notify is complete it can be send out by +.Fn agentx_notify_send . +This function also frees all allocated memory related to this notify. +.Sh RETURN VALUES +Upon succesful completion, +.Fn agentx_notify +returns a +.Vt "struct agentx_notify" +pointer. +Otherwise, +.Dv NULL +is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er ENOTCONN +The +.Vt "struct agentx" +pointer to which +.Fa axc +belongs is not connected. +.El +.Pp +.Fn agentx_notify +may also fail and set +.Va errno +for any of the errors specified for the routine +.Xr malloc 3 . +.Sh SEE ALSO +.Xr agentx 3 +.Sh HISTORY +The +.Nm agentx_notify +API first appeared in +.Ox 6.9 . +.Sh AUTHORS +.An Martijn van Duren Aq Mt mart...@openbsd.org Index: ax.c =================================================================== RCS file: /cvs/src/lib/libagentx/ax.c,v retrieving revision 1.7 diff -u -p -r1.7 ax.c --- ax.c 2 Jan 2021 01:06:31 -0000 1.7 +++ ax.c 4 Jan 2021 17:34:01 -0000 @@ -551,6 +551,19 @@ ax_unregister(struct ax *ax, uint32_t se return ax_pdu_queue(ax); } +uint32_t +ax_notify(struct ax *ax, uint32_t sessionid, struct ax_ostring *context, + struct ax_varbind *vblist, size_t nvb) +{ + if (ax_pdu_header(ax, AX_PDU_TYPE_NOTIFY, 0, sessionid, 0, 0, + context) == -1) + return 0; + + if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1) + return 0; + return ax_pdu_queue(ax); +} + int ax_response(struct ax *ax, uint32_t sessionid, uint32_t transactionid, uint32_t packetid, struct ax_ostring *context, uint32_t sysuptime, Index: ax.h =================================================================== RCS file: /cvs/src/lib/libagentx/ax.h,v retrieving revision 1.4 diff -u -p -r1.4 ax.h --- ax.h 2 Jan 2021 01:06:31 -0000 1.4 +++ ax.h 4 Jan 2021 17:34:01 -0000 @@ -219,6 +219,8 @@ uint32_t ax_register(struct ax *, uint8_ uint32_t); uint32_t ax_unregister(struct ax *, uint32_t, struct ax_ostring *, uint8_t, uint8_t, struct ax_oid *, uint32_t); +uint32_t ax_notify(struct ax *, uint32_t, struct ax_ostring *, + struct ax_varbind *, size_t); int ax_response(struct ax *, uint32_t, uint32_t, uint32_t, struct ax_ostring *, uint32_t, uint16_t, uint16_t, struct ax_varbind *, size_t); Index: shlib_version =================================================================== RCS file: /cvs/src/lib/libagentx/shlib_version,v retrieving revision 1.2 diff -u -p -r1.2 shlib_version --- shlib_version 26 Oct 2020 15:45:56 -0000 1.2 +++ shlib_version 4 Jan 2021 17:34:01 -0000 @@ -1,2 +1,2 @@ major=1 -minor=0 +minor=1