Index | Thread | Search

From:
Martijn van Duren <openbsd+tech@list.imperialat.at>
Subject:
snmpd: Add support for AGENTX-MIB
To:
tech@openbsd.org
Date:
Thu, 16 Jul 2026 12:15:16 +0200

Download raw body.

Thread
  • Martijn van Duren:

    snmpd: Add support for AGENTX-MIB

Hello tech@,

Right now it's only possible to know which AgentX connections are
currently established by parsing the daemon log and hoping the lines
haven't rotated out.

Diff below implements AGENTX-MIB, and gives a present overview of active
AgentX connections and registrations.

AGENTX-MIB is defined in RFC 2742, and is omitted from this diff for
brevity. It can be found inside the net-snmp package under
/usr/local/share/snmp/mibs/AGENTX-MIB.txt. Funny enough, net-snmp
doesn't seem to export this information.

OK?

martijn@

diff refs/heads/master refs/heads/snmpd/mib_agentx
commit - 7659da292c89adc3f3c89cc4a96023e23c0ff431
commit + 692d8646c12a477940c047be66dce2de5fda3c8e
blob - d10832282ef99d838e2ddb8096c7633205f3f551
blob + 870d9662f4a6a28b6e922d618358816f8b04208a
--- share/snmp/Makefile
+++ share/snmp/Makefile
@@ -7,9 +7,9 @@ FILES+= OPENBSD-CARP-MIB.txt OPENBSD-PF-MIB.txt
 FILES+= OPENBSD-RELAYD-MIB.txt
 
 # IANA/IETF
-FILES+=	BRIDGE-MIB.txt HOST-RESOURCES-MIB.txt IANA-RTPROTO-MIB.txt
-FILES+=	IANA-STORAGE-MEDIA-TYPE-MIB.txt IANAifType-MIB.txt IF-MIB.txt
-FILES+=	INET-ADDRESS-MIB.txt IP-FORWARD-MIB.txt IP-MIB.txt
+FILES+=	AGENTX-MIB.txt BRIDGE-MIB.txt HOST-RESOURCES-MIB.txt
+FILES+=	IANA-RTPROTO-MIB.txt IANA-STORAGE-MEDIA-TYPE-MIB.txt IANAifType-MIB.txt
+FILES+=	IF-MIB.txt INET-ADDRESS-MIB.txt IP-FORWARD-MIB.txt IP-MIB.txt
 FILES+=	SNMP-FRAMEWORK-MIB.txt SNMP-USER-BASED-SM-MIB.txt SNMP-USM-AES-MIB.txt
 FILES+=	SNMP-USM-HMAC-SHA2-MIB.txt SNMPv2-CONF.txt SNMPv2-MIB.txt SNMPv2-SMI.txt
 FILES+=	SNMPv2-TC.txt SNMPv2-TM.txt TRANSPORT-ADDRESS-MIB.txt UUID-TC-MIB.txt
blob - 7280c96fcde968f557670fed2043d6f856bc6bea
blob + 739daed2e26fa53eae196bc08c1d4c9cb269ae8f
--- usr.sbin/snmpd/application.c
+++ usr.sbin/snmpd/application.c
@@ -247,6 +247,12 @@ appl_context(const char *name, int create)
 	return ctx;
 }
 
+const char *
+appl_context_name(struct appl_context *ctx)
+{
+	return ctx->ac_name;
+}
+
 /* Name from RFC 2741 section 6.2.14 */
 enum appl_error
 appl_addagentcaps(const char *ctxname, struct ber_oid *oid, const char *descr,
blob - 03f09b54c38dfa9bb13cd1b612515806e6f30d5f
blob + 0e5bc85ecfada8cd37bc82c173b1cd0309c5ab9d
--- usr.sbin/snmpd/application.h
+++ usr.sbin/snmpd/application.h
@@ -123,6 +123,7 @@ void appl(void);
 void appl_init(void);
 void appl_shutdown(void);
 struct appl_context *appl_context(const char *, int);
+const char *appl_context_name(struct appl_context *);
 uint32_t appl_sysuptime(const char *);
 enum appl_error appl_addagentcaps(const char *, struct ber_oid *, const char *,
     struct appl_backend *);
@@ -149,6 +150,13 @@ void	 appl_agentx(void);
 void	 appl_agentx_init(void);
 void	 appl_agentx_shutdown(void);
 void	 appl_agentx_backend(int);
+struct ber_element *appl_agentx_mib_generic(struct ber_oid *);
+struct ber_element *appl_agentx_mib_conntable(struct ber_oid *);
+struct ber_element *appl_agentx_mib_conntable_next(int8_t, struct ber_oid *);
+struct ber_element *appl_agentx_mib_sessiontable(struct ber_oid *);
+struct ber_element *appl_agentx_mib_sessiontable_next(int8_t, struct ber_oid *);
+struct ber_element *appl_agentx_mib_registrationtable(struct ber_oid *);
+struct ber_element *appl_agentx_mib_registrationtable_next(int8_t, struct ber_oid *);
 
 /* application_blocklist.c */
 void	 appl_blocklist_init(void);
blob - 967f479f6fc98fb2892e6b860692bb8e83cbecbd
blob + 868510ebf9b785e31d2b3a81447cc94b2167d309
--- usr.sbin/snmpd/application_agentx.c
+++ usr.sbin/snmpd/application_agentx.c
@@ -43,6 +43,7 @@
 
 struct appl_agentx_connection {
 	uint32_t conn_id;
+	uint32_t conn_opentime;
 	/*
 	 * A backend has several overruling properties:
 	 * - If it exits, snmpd crashes
@@ -60,6 +61,7 @@ struct appl_agentx_connection {
 
 struct appl_agentx_session {
 	uint32_t sess_id;
+	uint32_t sess_opentime;
 	struct appl_agentx_connection *sess_conn;
 	/*
 	 * RFC 2741 section 7.1.1:
@@ -69,14 +71,31 @@ struct appl_agentx_session {
 	 */
 	enum ax_byte_order sess_byteorder;
 	uint8_t sess_timeout;
-	struct ax_oid sess_oid;
+	struct ber_oid sess_oid;
 	struct ax_ostring sess_descr;
 	struct appl_backend sess_backend;
 
-	RB_ENTRY(appl_agentx_session) sess_entry;
+	TAILQ_HEAD(, appl_agentx_registration) sess_registrations;
+	RB_ENTRY(appl_agentx_session) sess_global_entry;
+	RB_ENTRY(appl_agentx_session) sess_table_entry;
 	TAILQ_ENTRY(appl_agentx_session) sess_conn_entry;
 };
 
+struct appl_agentx_registration {
+	uint32_t reg_id;
+	struct appl_agentx_session *reg_session;
+	struct appl_context *reg_context;
+	struct ber_oid reg_start;
+	uint32_t reg_range_subid;
+	uint32_t reg_upper_bound;
+	uint32_t reg_priority;
+	uint8_t reg_timeout;
+	int reg_instance;
+	RB_ENTRY(appl_agentx_registration) reg_global_entry;
+	RB_ENTRY(appl_agentx_registration) reg_table_entry;
+	TAILQ_ENTRY(appl_agentx_registration) reg_sess_entry;
+};
+
 void appl_agentx_listen(struct agentx_master *);
 void appl_agentx_accept(int, short, void *);
 void appl_agentx_free(struct appl_agentx_connection *, enum appl_close_reason);
@@ -101,8 +120,14 @@ struct ax_ostring *appl_agentx_string2ostring(const ch
     struct ax_ostring *);
 int appl_agentx_cmp(struct appl_agentx_connection *,
     struct appl_agentx_connection *);
-int appl_agentx_session_cmp(struct appl_agentx_session *,
+int appl_agentx_session_global_cmp(struct appl_agentx_session *,
     struct appl_agentx_session *);
+int appl_agentx_session_table_cmp(struct appl_agentx_session *,
+    struct appl_agentx_session *);
+int appl_agentx_registration_global_cmp(struct appl_agentx_registration *,
+    struct appl_agentx_registration *);
+int appl_agentx_registration_table_cmp(struct appl_agentx_registration *,
+    struct appl_agentx_registration *);
 
 struct appl_backend_functions appl_agentx_functions = {
 	.ab_close = appl_agentx_forceclose,
@@ -113,13 +138,30 @@ struct appl_backend_functions appl_agentx_functions = 
 
 RB_HEAD(appl_agentx_conns, appl_agentx_connection) appl_agentx_conns =
     RB_INITIALIZER(&appl_agentx_conns);
-RB_HEAD(appl_agentx_sessions, appl_agentx_session) appl_agentx_sessions =
-    RB_INITIALIZER(&appl_agentx_sessions);
+RB_HEAD(appl_agentx_sessions_global, appl_agentx_session)
+    appl_agentx_sessions_global = RB_INITIALIZER(&appl_agentx_sessions_global);
+RB_HEAD(appl_agentx_sessions_table, appl_agentx_session)
+    appl_agentx_sessions_table = RB_INITIALIZER(&appl_agentx_sessions_table);
+RB_HEAD(appl_agentx_registrations_global, appl_agentx_registration)
+    appl_agentx_registrations_global =
+    RB_INITIALIZER(&appl_agentx_registrations_global);
+RB_HEAD(appl_agentx_registrations_table, appl_agentx_registration)
+    appl_agentx_registrations_table =
+    RB_INITIALIZER(&appl_agentx_registrations_table);
+static uint32_t appl_agentx_conn_last_change;
+static uint32_t appl_agentx_sess_last_change;
+static uint32_t appl_agentx_reg_last_change;
 
 RB_PROTOTYPE_STATIC(appl_agentx_conns, appl_agentx_connection, conn_entry,
     appl_agentx_cmp);
-RB_PROTOTYPE_STATIC(appl_agentx_sessions, appl_agentx_session, sess_entry,
-    appl_agentx_session_cmp);
+RB_PROTOTYPE_STATIC(appl_agentx_sessions_global, appl_agentx_session,
+    sess_global_entry, appl_agentx_session_global_cmp);
+RB_PROTOTYPE_STATIC(appl_agentx_sessions_table, appl_agentx_session,
+    sess_table_entry, appl_agentx_session_table_cmp);
+RB_PROTOTYPE_STATIC(appl_agentx_registrations_global, appl_agentx_registration,
+    reg_global_entry, appl_agentx_registration_global_cmp);
+RB_PROTOTYPE_STATIC(appl_agentx_registrations_table, appl_agentx_registration,
+    reg_table_entry, appl_agentx_registration_table_cmp);
 
 void
 appl_agentx(void)
@@ -215,6 +257,8 @@ appl_agentx_accept(int masterfd, short event, void *co
 		conn->conn_id = arc4random();
 	} while (RB_INSERT(appl_agentx_conns,
 	    &appl_agentx_conns, conn) != NULL);
+	conn->conn_opentime = appl_sysuptime(NULL);
+	appl_agentx_conn_last_change = conn->conn_opentime;
 
 	event_set(&(conn->conn_rev), fd, EV_READ | EV_PERSIST,
 	    appl_agentx_recv, conn);
@@ -245,6 +289,8 @@ appl_agentx_backend(int fd)
 		conn->conn_id = arc4random();
 	} while (RB_INSERT(appl_agentx_conns,
 	    &appl_agentx_conns, conn) != NULL);
+	conn->conn_opentime = appl_sysuptime(NULL);
+	appl_agentx_conn_last_change = conn->conn_opentime;
 
 	event_set(&(conn->conn_rev), fd, EV_READ | EV_PERSIST,
 	    appl_agentx_recv, conn);
@@ -270,6 +316,7 @@ appl_agentx_free(struct appl_agentx_connection *conn,
 	event_del(&(conn->conn_wev));
 
 	RB_REMOVE(appl_agentx_conns, &appl_agentx_conns, conn);
+	appl_agentx_conn_last_change = appl_sysuptime(NULL);
 	if (conn->conn_ax != NULL)
 		(void)ax_send(conn->conn_ax);
 	ax_free(conn->conn_ax);
@@ -475,7 +522,6 @@ void
 appl_agentx_open(struct appl_agentx_connection *conn, struct ax_pdu *pdu)
 {
 	struct appl_agentx_session *session;
-	struct ber_oid oid;
 	char oidbuf[1024];
 	enum appl_error error = APPL_ERROR_NOERROR;
 
@@ -526,7 +572,8 @@ appl_agentx_open(struct appl_agentx_connection *conn, 
 	}
 
 	session->sess_timeout = pdu->ap_payload.ap_open.ap_timeout;
-	session->sess_oid = pdu->ap_payload.ap_open.ap_oid;
+	appl_agentx_oid2ber_oid(&pdu->ap_payload.ap_open.ap_oid,
+	    &session->sess_oid);
 	session->sess_descr.aos_slen = pdu->ap_payload.ap_open.ap_descr.aos_slen;
 	if (pdu->ap_payload.ap_open.ap_descr.aos_string != NULL) {
 		session->sess_descr.aos_string =
@@ -542,8 +589,12 @@ appl_agentx_open(struct appl_agentx_connection *conn, 
 	/* RFC 2742 agentxSessionIndex: chances of reuse, slim to none */
 	do {
 		session->sess_id = arc4random();
-	} while (RB_INSERT(appl_agentx_sessions,
-	    &appl_agentx_sessions, session) != NULL);
+	} while (RB_INSERT(appl_agentx_sessions_global,
+	    &appl_agentx_sessions_global, session) != NULL);
+	RB_INSERT(appl_agentx_sessions_table, &appl_agentx_sessions_table,
+	    session);
+	session->sess_opentime = appl_sysuptime(NULL);
+	appl_agentx_sess_last_change = session->sess_opentime;
 
 	if (asprintf(&(session->sess_backend.ab_name),
 	    "AgentX(%"PRIu32"/%"PRIu32")",
@@ -557,11 +608,12 @@ appl_agentx_open(struct appl_agentx_connection *conn, 
 	session->sess_backend.ab_retries = 0;
 	session->sess_backend.ab_fn = &appl_agentx_functions;
 	session->sess_backend.ab_range = 1;
+	TAILQ_INIT(&session->sess_registrations);
 	RB_INIT(&(session->sess_backend.ab_requests));
 	TAILQ_INSERT_TAIL(&(conn->conn_sessions), session, sess_conn_entry);
 
-	appl_agentx_oid2ber_oid(&(session->sess_oid), &oid);
-	mib_oid2string(&oid, oidbuf, sizeof(oidbuf), snmpd_env->sc_oidfmt);
+	mib_oid2string(&session->sess_oid, oidbuf, sizeof(oidbuf),
+	    snmpd_env->sc_oidfmt);
 	log_info("%s: %s %s: Open", session->sess_backend.ab_name, oidbuf,
 	    session->sess_descr.aos_string);
 
@@ -633,11 +685,26 @@ void
 appl_agentx_session_free(struct appl_agentx_session *session)
 {
 	struct appl_agentx_connection *conn = session->sess_conn;
+	struct appl_agentx_registration *reg;
 
 	appl_close(&(session->sess_backend));
 
-	RB_REMOVE(appl_agentx_sessions, &appl_agentx_sessions, session);
+	while ((reg = TAILQ_FIRST(&session->sess_registrations)) != NULL) {
+		TAILQ_REMOVE(&session->sess_registrations, reg, reg_sess_entry);
+		RB_REMOVE(appl_agentx_registrations_global,
+		    &appl_agentx_registrations_global, reg);
+		RB_REMOVE(appl_agentx_registrations_table,
+		    &appl_agentx_registrations_table, reg);
+		free(reg);
+	}
+
+	RB_REMOVE(appl_agentx_sessions_global, &appl_agentx_sessions_global,
+	    session);
+	RB_REMOVE(appl_agentx_sessions_table, &appl_agentx_sessions_table,
+	    session);
 	TAILQ_REMOVE(&(conn->conn_sessions), session, sess_conn_entry);
+	appl_agentx_sess_last_change = appl_agentx_reg_last_change =
+	    appl_sysuptime(NULL);
 
 	free(session->sess_backend.ab_name);
 	free(session->sess_descr.aos_string);
@@ -647,8 +714,8 @@ appl_agentx_session_free(struct appl_agentx_session *s
 void
 appl_agentx_register(struct appl_agentx_session *session, struct ax_pdu *pdu)
 {
+	struct appl_agentx_registration *reg;
 	uint32_t timeout;
-	struct ber_oid oid;
 	enum appl_error error;
 	int subtree = 0;
 
@@ -661,21 +728,48 @@ appl_agentx_register(struct appl_agentx_session *sessi
 		pdu->ap_payload.ap_register.ap_priority = 1;
 		subtree = 1;
 	}
-	if (appl_agentx_oid2ber_oid(
-	    &(pdu->ap_payload.ap_register.ap_subtree), &oid) == NULL) {
+
+	if ((reg = malloc(sizeof(*reg))) == NULL) {
+		log_warn("%s: Failed to register",
+		    session->sess_backend.ab_name);
+		error = APPL_ERROR_PROCESSINGERROR;
+		goto fail;
+	}
+	reg->reg_session = session;
+	reg->reg_context = appl_context(pdu->ap_context.aos_string, 0);
+	if (appl_agentx_oid2ber_oid(&pdu->ap_payload.ap_register.ap_subtree,
+	    &reg->reg_start) == NULL) {
 		log_warnx("%s: Failed to register: oid too small",
 		    session->sess_backend.ab_name);
 		error = APPL_ERROR_PROCESSINGERROR;
 		goto fail;
 	}
+	reg->reg_range_subid = pdu->ap_payload.ap_register.ap_range_subid;
+	reg->reg_upper_bound = pdu->ap_payload.ap_register.ap_upper_bound;
+	reg->reg_priority = pdu->ap_payload.ap_register.ap_priority;
+	reg->reg_timeout = pdu->ap_payload.ap_register.ap_timeout;
+	reg->reg_instance =
+	    pdu->ap_header.aph_flags & AX_PDU_FLAG_INSTANCE_REGISTRATION ?
+	    1 : 0;
 
 	error = appl_register(pdu->ap_context.aos_string, timeout,
-	    pdu->ap_payload.ap_register.ap_priority, &oid, 
-	    pdu->ap_header.aph_flags & AX_PDU_FLAG_INSTANCE_REGISTRATION,
-	    subtree, pdu->ap_payload.ap_register.ap_range_subid,
-	    pdu->ap_payload.ap_register.ap_upper_bound,
+	    reg->reg_priority, &reg->reg_start, reg->reg_instance,
+	    subtree, reg->reg_range_subid, reg->reg_upper_bound,
 	    &(session->sess_backend));
 
+	if (error == APPL_ERROR_NOERROR) {
+		do {
+			reg->reg_id = arc4random();
+		} while (RB_INSERT(appl_agentx_registrations_global,
+		    &appl_agentx_registrations_global, reg) != NULL);
+		RB_INSERT(appl_agentx_registrations_table,
+		    &appl_agentx_registrations_table, reg);
+		TAILQ_INSERT_TAIL(&session->sess_registrations, reg,
+		    reg_sess_entry);
+		appl_agentx_reg_last_change = appl_sysuptime(NULL);
+	} else
+		free(reg);
+
  fail:
 	ax_response(session->sess_conn->conn_ax, session->sess_id,
 	    pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,
@@ -686,6 +780,8 @@ appl_agentx_register(struct appl_agentx_session *sessi
 void
 appl_agentx_unregister(struct appl_agentx_session *session, struct ax_pdu *pdu)
 {
+	struct appl_context *ctx;
+	struct appl_agentx_registration *reg;
 	struct ber_oid oid;
 	enum appl_error error;
 
@@ -697,11 +793,40 @@ appl_agentx_unregister(struct appl_agentx_session *ses
 		goto fail;
 	}
 
-	error = appl_unregister(pdu->ap_context.aos_string, 
-	    pdu->ap_payload.ap_unregister.ap_priority, &oid, 
-	    pdu->ap_payload.ap_unregister.ap_range_subid,
-	    pdu->ap_payload.ap_unregister.ap_upper_bound,
+	/* This is stricter than appl_unregister(), but needed for RFC2742 */
+	ctx = appl_context(pdu->ap_context.aos_string, 0);
+	TAILQ_FOREACH(reg, &session->sess_registrations, reg_sess_entry) {
+		if (reg->reg_context != ctx ||
+		    ober_oid_cmp(&reg->reg_start, &oid) != 0)
+			continue;
+		if (reg->reg_range_subid !=
+		    pdu->ap_payload.ap_unregister.ap_range_subid)
+			continue;
+		if (reg->reg_upper_bound !=
+		    pdu->ap_payload.ap_unregister.ap_upper_bound)
+			continue;
+		if (reg->reg_priority !=
+		    pdu->ap_payload.ap_unregister.ap_priority)
+			continue;
+		break;
+	}
+	if (reg == NULL) {
+		error = APPL_ERROR_UNKNOWNREGISTRATION;
+		goto fail;
+	}
+
+	error = appl_unregister(pdu->ap_context.aos_string, reg->reg_priority,
+	    &oid, reg->reg_range_subid, reg->reg_upper_bound,
 	    &(session->sess_backend));
+	if (error == APPL_ERROR_NOERROR) {
+		TAILQ_REMOVE(&session->sess_registrations, reg, reg_sess_entry);
+		RB_REMOVE(appl_agentx_registrations_global,
+		    &appl_agentx_registrations_global, reg);
+		RB_REMOVE(appl_agentx_registrations_table,
+		    &appl_agentx_registrations_table, reg);
+		free(reg);
+		appl_agentx_reg_last_change = appl_sysuptime(NULL);
+	}
 
  fail:
 	ax_response(session->sess_conn->conn_ax, session->sess_id,
@@ -1050,13 +1175,358 @@ appl_agentx_cmp(struct appl_agentx_connection *conn1,
 }
 
 int
-appl_agentx_session_cmp(struct appl_agentx_session *sess1,
+appl_agentx_session_global_cmp(struct appl_agentx_session *sess1,
     struct appl_agentx_session *sess2)
 {
 	return sess1->sess_id < sess2->sess_id ? -1 : sess1->sess_id > sess2->sess_id;
 }
 
+int
+appl_agentx_session_table_cmp(struct appl_agentx_session *sess1,
+    struct appl_agentx_session *sess2)
+{
+	if (sess1->sess_conn->conn_id != sess2->sess_conn->conn_id)
+		return sess1->sess_conn->conn_id < sess2->sess_conn->conn_id ?
+		    -1 : 1;
+	return sess1->sess_id < sess2->sess_id ? -1 : sess1->sess_id > sess2->sess_id;
+}
+
+int
+appl_agentx_registration_global_cmp(struct appl_agentx_registration *r1,
+    struct appl_agentx_registration *r2)
+{
+	return r1->reg_id < r2->reg_id ? -1 : r1->reg_id > r2->reg_id;
+}
+
+int
+appl_agentx_registration_table_cmp(struct appl_agentx_registration *r1,
+    struct appl_agentx_registration *r2)
+{
+	struct appl_agentx_session *s1 = r1->reg_session, *s2 = r2->reg_session;
+	struct appl_agentx_connection *c1 = s1->sess_conn, *c2 = s2->sess_conn;
+
+	if (c1->conn_id != c2->conn_id)
+		return c1->conn_id < c2->conn_id ? -1 : 1;
+	if (s1->sess_id != s2->sess_id)
+		return s1->sess_id < s2->sess_id ? -1 : 1;
+	return r1->reg_id < r2->reg_id ? -1 : r1->reg_id > r2->reg_id;
+}
+
+struct ber_element *
+appl_agentx_mib_generic(struct ber_oid *oid)
+{
+	struct ber_element *value = NULL;
+
+	if (ober_oid_cmp(&OID(MIB_agentxDefaultTimeout, 0), oid) == 0)
+		return ober_add_integer(NULL, AGENTX_DEFAULTTIMEOUT);
+	else if (ober_oid_cmp(&OID(MIB_agentxMasterAgentxVer, 0), oid) == 0)
+		return ober_add_integer(NULL, 1);
+	else if (ober_oid_cmp(&OID(MIB_agentxConnTableLastChange, 0), oid) == 0) {
+		value = ober_add_integer(NULL, appl_agentx_conn_last_change);
+		ober_set_header(value, BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
+	} else if (ober_oid_cmp(&OID(MIB_agentxSessionTableLastChange, 0), oid) == 0) {
+		value = ober_add_integer(NULL, appl_agentx_sess_last_change);
+		ober_set_header(value, BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
+	} else if (ober_oid_cmp(&OID(MIB_agentxRegistrationTableLastChange, 0), oid) == 0) {
+		value = ober_add_integer(NULL, appl_agentx_reg_last_change);
+		ober_set_header(value, BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
+	} else
+		return NULL;
+
+	return value;
+}
+
+struct ber_element *
+appl_agentx_mib_conntable(struct ber_oid *oid)
+{
+	struct appl_agentx_connection *conn, search;
+	struct ber_element *value = NULL;
+
+	if (oid->bo_n != OID(MIB_agentxConnOpenTime, 0).bo_n)
+		return appl_exception(APPL_EXC_NOSUCHINSTANCE);
+	search.conn_id = oid->bo_id[OID(MIB_agentxConnOpenTime).bo_n];
+	conn = RB_FIND(appl_agentx_conns, &appl_agentx_conns, &search);
+	if (conn == NULL)
+		return appl_exception(APPL_EXC_NOSUCHINSTANCE);
+
+	if (ober_oid_cmp(&OID(MIB_agentxConnOpenTime), oid) == -2) {
+		value = ober_add_integer(NULL, conn->conn_opentime);
+		ober_set_header(value, BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
+	} else if (ober_oid_cmp(&OID(MIB_agentxConnTransportDomain), oid) == -2)
+		return ober_add_oid(NULL, &OID(MIB_transportDomainLocal));
+	else if (ober_oid_cmp(&OID(MIB_agentxConnTransportAddress), oid) == -2)
+		return ober_add_string(NULL, "");
+	else
+		return NULL;
+
+	return value;
+}
+
+struct ber_element *
+appl_agentx_mib_conntable_next(int8_t include, struct ber_oid *oid)
+{
+	struct appl_agentx_connection *conn, search;
+	struct ber_element *value = NULL;
+
+	if (oid->bo_n < OID(MIB_agentxConnOpenTime, 0).bo_n) {
+		search.conn_id = 0;
+		include = 1;
+	} else if (oid->bo_n == OID(MIB_agentxConnOpenTime, 0).bo_n) {
+		search.conn_id =
+		    oid->bo_id[OID(MIB_agentxConnOpenTime).bo_n];
+	} else {
+		search.conn_id =
+		    oid->bo_id[OID(MIB_agentxConnOpenTime).bo_n];
+		include = 0;
+	}
+	conn = RB_NFIND(appl_agentx_conns, &appl_agentx_conns, &search);
+	if (conn != NULL && !include && search.conn_id == conn->conn_id)
+		conn = RB_NEXT(appl_agentx_conns, &appl_agentx_conns, conn);
+	if (conn == NULL)
+		return appl_exception(APPL_EXC_ENDOFMIBVIEW);
+
+	oid->bo_n = OID(MIB_agentxConnOpenTime).bo_n;
+	oid->bo_id[oid->bo_n++] = conn->conn_id;
+	if (ober_oid_cmp(&OID(MIB_agentxConnOpenTime), oid) == -2) {
+		value = ober_add_integer(NULL, conn->conn_opentime);
+		ober_set_header(value, BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
+	} else if (ober_oid_cmp(&OID(MIB_agentxConnTransportDomain), oid) == -2)
+		return ober_add_oid(NULL, &OID(MIB_transportDomainLocal));
+	else if (ober_oid_cmp(&OID(MIB_agentxConnTransportAddress), oid) == -2)
+		return ober_add_string(NULL, "");
+	else
+		return NULL;
+
+	return value;
+}
+
+struct ber_element *
+appl_agentx_mib_sessiontable(struct ber_oid *oid)
+{
+	struct appl_agentx_connection conn;
+	struct appl_agentx_session *session, search;
+	struct ber_element *value = NULL;
+
+	if (oid->bo_n != OID(MIB_agentxSessionObjectID, 0, 0).bo_n)
+		return appl_exception(APPL_EXC_NOSUCHINSTANCE);
+	conn.conn_id = oid->bo_id[OID(MIB_agentxSessionObjectID).bo_n];
+	search.sess_id = oid->bo_id[OID(MIB_agentxSessionObjectID, 0).bo_n];
+	search.sess_conn = &conn;
+	session = RB_FIND(appl_agentx_sessions_table,
+	    &appl_agentx_sessions_table, &search);
+	if (session == NULL)
+		return appl_exception(APPL_EXC_NOSUCHINSTANCE);
+
+	if (ober_oid_cmp(&OID(MIB_agentxSessionObjectID), oid) == -2)
+		return ober_add_oid(NULL, &session->sess_oid);
+	else if (ober_oid_cmp(&OID(MIB_agentxSessionDescr), oid) == -2)
+		return ober_add_nstring(NULL, session->sess_descr.aos_string,
+		    session->sess_descr.aos_slen);
+	else if (ober_oid_cmp(&OID(MIB_agentxSessionAdminStatus), oid) == -2)
+		return ober_add_integer(NULL, 1);
+	else if (ober_oid_cmp(&OID(MIB_agentxSessionOpenTime), oid) == -2) {
+		value = ober_add_integer(NULL, session->sess_opentime);
+		ober_set_header(value, BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
+	} else if (ober_oid_cmp(&OID(MIB_agentxSessionAgentXVer), oid) == -2)
+		return ober_add_integer(NULL, 1);
+	else if (ober_oid_cmp(&OID(MIB_agentxSessionTimeout), oid) == -2)
+		return ober_add_integer(NULL, session->sess_timeout);
+	else
+		return NULL;
+
+	return value;
+}
+
+struct ber_element *
+appl_agentx_mib_sessiontable_next(int8_t include, struct ber_oid *oid)
+{
+	struct appl_agentx_connection conn;
+	struct appl_agentx_session *session, search;
+	struct ber_element *value = NULL;
+
+	if (oid->bo_n < OID(MIB_agentxSessionObjectID, 0).bo_n) {
+		conn.conn_id = 0;
+		search.sess_id = 0;
+		include = 1;
+	} else if (oid->bo_n == OID(MIB_agentxSessionObjectID, 0).bo_n) {
+		conn.conn_id = oid->bo_id[OID(MIB_agentxSessionObjectID).bo_n];
+		search.sess_id = 0;
+		include = 1;
+	} else if (oid->bo_n == OID(MIB_agentxSessionObjectID, 0, 0).bo_n) {
+		conn.conn_id = oid->bo_id[OID(MIB_agentxSessionObjectID).bo_n];
+		search.sess_id =
+		    oid->bo_id[OID(MIB_agentxSessionObjectID, 0).bo_n];
+	} else {
+		conn.conn_id = oid->bo_id[OID(MIB_agentxSessionObjectID).bo_n];
+		search.sess_id =
+		    oid->bo_id[OID(MIB_agentxSessionObjectID, 0).bo_n];
+		include = 0;
+	}
+	search.sess_conn = &conn;
+	session = RB_NFIND(appl_agentx_sessions_table,
+	    &appl_agentx_sessions_table, &search);
+	if (session != NULL && !include &&
+	    appl_agentx_session_table_cmp(&search, session) == 0)
+		session = RB_NEXT(appl_agentx_sessions_table,
+		    &appl_agentx_sessions_table, session);
+	if (session == NULL)
+		return appl_exception(APPL_EXC_ENDOFMIBVIEW);
+
+	oid->bo_n = OID(MIB_agentxSessionObjectID).bo_n;
+	oid->bo_id[oid->bo_n++] = session->sess_conn->conn_id;
+	oid->bo_id[oid->bo_n++] = session->sess_id;
+	if (ober_oid_cmp(&OID(MIB_agentxSessionObjectID), oid) == -2)
+		return ober_add_oid(NULL, &session->sess_oid);
+	else if (ober_oid_cmp(&OID(MIB_agentxSessionDescr), oid) == -2)
+		return ober_add_nstring(NULL, session->sess_descr.aos_string,
+		    session->sess_descr.aos_slen);
+	else if (ober_oid_cmp(&OID(MIB_agentxSessionAdminStatus), oid) == -2)
+		return ober_add_integer(NULL, 1);
+	else if (ober_oid_cmp(&OID(MIB_agentxSessionOpenTime), oid) == -2) {
+		value = ober_add_integer(NULL, session->sess_opentime);
+		ober_set_header(value, BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
+	} else if (ober_oid_cmp(&OID(MIB_agentxSessionAgentXVer), oid) == -2)
+		return ober_add_integer(NULL, 1);
+	else if (ober_oid_cmp(&OID(MIB_agentxSessionTimeout), oid) == -2)
+		return ober_add_integer(NULL, session->sess_timeout);
+	else
+		return NULL;
+
+	return value;
+}
+
+struct ber_element *
+appl_agentx_mib_registrationtable(struct ber_oid *oid)
+{
+	struct appl_agentx_connection conn;
+	struct appl_agentx_session session;
+	struct appl_agentx_registration *reg, search;
+	struct ber_element *value = NULL;
+
+	if (oid->bo_n != OID(MIB_agentxRegContext, 0, 0, 0).bo_n)
+		return appl_exception(APPL_EXC_NOSUCHINSTANCE);
+	conn.conn_id = oid->bo_id[OID(MIB_agentxRegContext).bo_n];
+	session.sess_id = oid->bo_id[OID(MIB_agentxRegContext, 0).bo_n];
+	search.reg_id = oid->bo_id[OID(MIB_agentxRegContext, 0, 0).bo_n];
+	search.reg_session = &session;
+	session.sess_conn = &conn;
+
+	reg = RB_FIND(appl_agentx_registrations_table,
+	    &appl_agentx_registrations_table, &search);
+	if (reg == NULL)
+		return appl_exception(APPL_EXC_NOSUCHINSTANCE);
+
+	if (ober_oid_cmp(&OID(MIB_agentxRegContext), oid) == -2)
+		return ober_add_string(
+		    NULL, appl_context_name(reg->reg_context));
+	else if (ober_oid_cmp(&OID(MIB_agentxRegStart), oid) == -2)
+		return ober_add_oid(NULL, &reg->reg_start);
+	else if (ober_oid_cmp(&OID(MIB_agentxRegRangeSubId), oid) == -2) {
+		value = ober_add_integer(NULL, reg->reg_range_subid);
+		ober_set_header(
+		    value, BER_CLASS_APPLICATION, SNMP_T_UNSIGNED32);
+	} else if (ober_oid_cmp(&OID(MIB_agentxRegUpperBound), oid) == -2) {
+		value = ober_add_integer(NULL, reg->reg_upper_bound);
+		ober_set_header(
+		    value, BER_CLASS_APPLICATION, SNMP_T_UNSIGNED32);
+	} else if (ober_oid_cmp(&OID(MIB_agentxRegPriority), oid) == -2) {
+		value = ober_add_integer(NULL, reg->reg_priority);
+		ober_set_header(
+		    value, BER_CLASS_APPLICATION, SNMP_T_UNSIGNED32);
+	} else if (ober_oid_cmp(&OID(MIB_agentxRegTimeout), oid) == -2)
+		return ober_add_integer(NULL, reg->reg_timeout);
+	else if (ober_oid_cmp(&OID(MIB_agentxRegInstance), oid) == -2)
+		return ober_add_integer(NULL, reg->reg_instance ? 1 : 2);
+	else
+		return NULL;
+
+	return value;
+}
+
+struct ber_element *
+appl_agentx_mib_registrationtable_next(int8_t include, struct ber_oid *oid)
+{
+	struct appl_agentx_connection conn;
+	struct appl_agentx_session session;
+	struct appl_agentx_registration *reg, search;
+	struct ber_element *value = NULL;
+
+	if (oid->bo_n < OID(MIB_agentxRegContext, 0).bo_n) {
+		conn.conn_id = 0;
+		session.sess_id = 0;
+		search.reg_id = 0;
+		include = 1;
+	} else if (oid->bo_n == OID(MIB_agentxRegContext, 0).bo_n) {
+		conn.conn_id = oid->bo_id[OID(MIB_agentxRegContext).bo_n];
+		session.sess_id = 0;
+		search.reg_id = 0;
+		include = 1;
+	} else if (oid->bo_n == OID(MIB_agentxRegContext, 0, 0).bo_n) {
+		conn.conn_id = oid->bo_id[OID(MIB_agentxRegContext).bo_n];
+		session.sess_id = oid->bo_id[OID(MIB_agentxRegContext, 0).bo_n];
+		search.reg_id = 0;
+		include = 1;
+	} else if (oid->bo_n == OID(MIB_agentxRegContext, 0, 0, 0).bo_n) {
+		conn.conn_id = oid->bo_id[OID(MIB_agentxRegContext).bo_n];
+		session.sess_id = oid->bo_id[OID(MIB_agentxRegContext, 0).bo_n];
+		search.reg_id =
+		    oid->bo_id[OID(MIB_agentxRegContext, 0, 0).bo_n];
+	} else {
+		conn.conn_id = oid->bo_id[OID(MIB_agentxRegContext).bo_n];
+		session.sess_id = oid->bo_id[OID(MIB_agentxRegContext, 0).bo_n];
+		search.reg_id =
+		    oid->bo_id[OID(MIB_agentxRegContext, 0, 0).bo_n];
+		include = 0;
+	}
+	session.sess_conn = &conn;
+	search.reg_session = &session;
+	reg = RB_NFIND(appl_agentx_registrations_table,
+	    &appl_agentx_registrations_table, &search);
+	if (reg != NULL && !include &&
+	    appl_agentx_registration_table_cmp(&search, reg) == 0)
+		reg = RB_NEXT(appl_agentx_registrations_table,
+		    &appl_agentx_registrations_table, reg);
+	if (reg == NULL)
+		return appl_exception(APPL_EXC_ENDOFMIBVIEW);
+	oid->bo_n = OID(MIB_agentxRegContext).bo_n;
+	oid->bo_id[oid->bo_n++] = reg->reg_session->sess_conn->conn_id;
+	oid->bo_id[oid->bo_n++] = reg->reg_session->sess_id;
+	oid->bo_id[oid->bo_n++] = reg->reg_id;
+
+	if (ober_oid_cmp(&OID(MIB_agentxRegContext), oid) == -2)
+		return ober_add_string(
+		    NULL, appl_context_name(reg->reg_context));
+	else if (ober_oid_cmp(&OID(MIB_agentxRegStart), oid) == -2)
+		return ober_add_oid(NULL, &reg->reg_start);
+	else if (ober_oid_cmp(&OID(MIB_agentxRegRangeSubId), oid) == -2) {
+		value = ober_add_integer(NULL, reg->reg_range_subid);
+		ober_set_header(
+		    value, BER_CLASS_APPLICATION, SNMP_T_UNSIGNED32);
+	} else if (ober_oid_cmp(&OID(MIB_agentxRegUpperBound), oid) == -2) {
+		value = ober_add_integer(NULL, reg->reg_upper_bound);
+		ober_set_header(
+		    value, BER_CLASS_APPLICATION, SNMP_T_UNSIGNED32);
+	} else if (ober_oid_cmp(&OID(MIB_agentxRegPriority), oid) == -2) {
+		value = ober_add_integer(NULL, reg->reg_priority);
+		ober_set_header(
+		    value, BER_CLASS_APPLICATION, SNMP_T_UNSIGNED32);
+	} else if (ober_oid_cmp(&OID(MIB_agentxRegTimeout), oid) == -2)
+		return ober_add_integer(NULL, reg->reg_timeout);
+	else if (ober_oid_cmp(&OID(MIB_agentxRegInstance), oid) == -2)
+		return ober_add_integer(NULL, reg->reg_instance ? 1 : 2);
+	else
+		return NULL;
+
+	return value;
+}
+
 RB_GENERATE_STATIC(appl_agentx_conns, appl_agentx_connection, conn_entry,
     appl_agentx_cmp);
-RB_GENERATE_STATIC(appl_agentx_sessions, appl_agentx_session, sess_entry,
-    appl_agentx_session_cmp);
+RB_GENERATE_STATIC(appl_agentx_sessions_global, appl_agentx_session,
+    sess_global_entry, appl_agentx_session_global_cmp);
+RB_GENERATE_STATIC(appl_agentx_sessions_table, appl_agentx_session,
+    sess_table_entry, appl_agentx_session_table_cmp);
+RB_GENERATE_STATIC(appl_agentx_registrations_global, appl_agentx_registration,
+    reg_global_entry, appl_agentx_registration_global_cmp);
+RB_GENERATE_STATIC(appl_agentx_registrations_table, appl_agentx_registration,
+    reg_table_entry, appl_agentx_registration_table_cmp);
blob - ac3fcb01ced659fa6557cf3fc5b5bc7ae522e029
blob + 877dd40379e225fab5b144f0211bf7451e5381ad
--- usr.sbin/snmpd/application_internal.c
+++ usr.sbin/snmpd/application_internal.c
@@ -200,6 +200,57 @@ appl_internal_init(void)
 	appl_internal_object(&OID(MIB_usmStatsDecryptionErrors),
 	    appl_internal_usmstats, NULL);
 
+	appl_internal_region(&OID(MIB_agentx));
+	appl_internal_object(&OID(MIB_agentxDefaultTimeout),
+	    appl_agentx_mib_generic, NULL);
+	appl_internal_object(&OID(MIB_agentxMasterAgentxVer),
+	    appl_agentx_mib_generic, NULL);
+	appl_internal_object(&OID(MIB_agentxConnTableLastChange),
+	    appl_agentx_mib_generic, NULL);
+	appl_internal_object(&OID(MIB_agentxConnOpenTime),
+	    appl_agentx_mib_conntable, appl_agentx_mib_conntable_next);
+	appl_internal_object(&OID(MIB_agentxConnTransportDomain),
+	    appl_agentx_mib_conntable, appl_agentx_mib_conntable_next);
+	appl_internal_object(&OID(MIB_agentxConnTransportAddress),
+	    appl_agentx_mib_conntable, appl_agentx_mib_conntable_next);
+	appl_internal_object(&OID(MIB_agentxSessionTableLastChange),
+	    appl_agentx_mib_generic, NULL);
+	appl_internal_object(&OID(MIB_agentxSessionObjectID),
+	    appl_agentx_mib_sessiontable, appl_agentx_mib_sessiontable_next);
+	appl_internal_object(&OID(MIB_agentxSessionDescr),
+	    appl_agentx_mib_sessiontable, appl_agentx_mib_sessiontable_next);
+	appl_internal_object(&OID(MIB_agentxSessionAdminStatus),
+	    appl_agentx_mib_sessiontable, appl_agentx_mib_sessiontable_next);
+	appl_internal_object(&OID(MIB_agentxSessionOpenTime),
+	    appl_agentx_mib_sessiontable, appl_agentx_mib_sessiontable_next);
+	appl_internal_object(&OID(MIB_agentxSessionAgentXVer),
+	    appl_agentx_mib_sessiontable, appl_agentx_mib_sessiontable_next);
+	appl_internal_object(&OID(MIB_agentxSessionTimeout),
+	    appl_agentx_mib_sessiontable, appl_agentx_mib_sessiontable_next);
+	appl_internal_object(&OID(MIB_agentxRegistrationTableLastChange),
+	    appl_agentx_mib_generic, NULL);
+	appl_internal_object(&OID(MIB_agentxRegContext),
+	    appl_agentx_mib_registrationtable,
+	    appl_agentx_mib_registrationtable_next);
+	appl_internal_object(&OID(MIB_agentxRegStart),
+	    appl_agentx_mib_registrationtable,
+	    appl_agentx_mib_registrationtable_next);
+	appl_internal_object(&OID(MIB_agentxRegRangeSubId),
+	    appl_agentx_mib_registrationtable,
+	    appl_agentx_mib_registrationtable_next);
+	appl_internal_object(&OID(MIB_agentxRegUpperBound),
+	    appl_agentx_mib_registrationtable,
+	    appl_agentx_mib_registrationtable_next);
+	appl_internal_object(&OID(MIB_agentxRegPriority),
+	    appl_agentx_mib_registrationtable,
+	    appl_agentx_mib_registrationtable_next);
+	appl_internal_object(&OID(MIB_agentxRegTimeout),
+	    appl_agentx_mib_registrationtable,
+	    appl_agentx_mib_registrationtable_next);
+	appl_internal_object(&OID(MIB_agentxRegInstance),
+	    appl_agentx_mib_registrationtable,
+	    appl_agentx_mib_registrationtable_next);
+
 	while ((obj = RB_MIN(appl_internal_objects,
 	    &appl_internal_objects_conf)) != NULL) {
 		RB_REMOVE(appl_internal_objects,
blob - fc2a428828de5e9ca1761e25223fc7eeee165e2f
blob + 9e2f2a6b2e838b105d140520c01ce51305cff0e7
--- usr.sbin/snmpd/mib.h
+++ usr.sbin/snmpd/mib.h
@@ -425,6 +425,49 @@ const char	*mib_string2oid(const char *, struct ber_oi
 #define MIB_dot1dTp			MIB_dot1dBridge, 4
 #define MIB_dot1dStatic			MIB_dot1dBridge, 5
 
+/* AGENTX-MIB */
+#define MIB_agentx			MIB_mib_2, 74
+#define MIB_agentxObjects		MIB_agentx, 1
+#define MIB_agentxGeneral		MIB_agentxObjects, 1
+#define MIB_agentxConnection		MIB_agentxObjects, 2
+#define MIB_agentxSession		MIB_agentxObjects, 3
+#define MIB_agentxRegistration		MIB_agentxObjects, 4
+#define MIB_agentxDefaultTimeout	MIB_agentxGeneral, 1
+#define MIB_agentxMasterAgentxVer	MIB_agentxGeneral, 2
+#define MIB_agentxConnTableLastChange	MIB_agentxConnection, 1
+#define MIB_agentxConnectionTable	MIB_agentxConnection, 2
+#define MIB_agentxConnectionEntry	MIB_agentxConnectionTable, 1
+#define MIB_agentxConnIndex		MIB_agentxConnectionEntry, 1
+#define MIB_agentxConnOpenTime		MIB_agentxConnectionEntry, 2
+#define MIB_agentxConnTransportDomain	MIB_agentxConnectionEntry, 3
+#define MIB_agentxConnTransportAddress	MIB_agentxConnectionEntry, 4
+#define MIB_agentxSessionTableLastChange MIB_agentxSession, 1
+#define MIB_agentxSessionTable		MIB_agentxSession, 2
+#define MIB_agentxSessionEntry		MIB_agentxSessionTable, 1
+#define MIB_agentxSessionIndex		MIB_agentxSessionEntry, 1
+#define MIB_agentxSessionObjectID	MIB_agentxSessionEntry, 2
+#define MIB_agentxSessionDescr		MIB_agentxSessionEntry, 3
+#define MIB_agentxSessionAdminStatus	MIB_agentxSessionEntry, 4
+#define MIB_agentxSessionOpenTime	MIB_agentxSessionEntry, 5
+#define MIB_agentxSessionAgentXVer	MIB_agentxSessionEntry, 6
+#define MIB_agentxSessionTimeout	MIB_agentxSessionEntry, 7
+#define MIB_agentxRegistrationTableLastChange MIB_agentxRegistration, 1
+#define MIB_agentxRegistrationTable	MIB_agentxRegistration, 2
+#define MIB_agentxRegistrationEntry	MIB_agentxRegistrationTable, 1
+#define MIB_agentxRegIndex		MIB_agentxRegistrationEntry, 1
+#define MIB_agentxRegContext		MIB_agentxRegistrationEntry, 2
+#define MIB_agentxRegStart		MIB_agentxRegistrationEntry, 3
+#define MIB_agentxRegRangeSubId		MIB_agentxRegistrationEntry, 4
+#define MIB_agentxRegUpperBound		MIB_agentxRegistrationEntry, 5
+#define MIB_agentxRegPriority		MIB_agentxRegistrationEntry, 6
+#define MIB_agentxRegTimeout		MIB_agentxRegistrationEntry, 7
+#define MIB_agentxRegInstance		MIB_agentxRegistrationEntry, 8
+
+/* TRANSPORT-ADDRESS-MIB */
+#define MIB_transportAddress		MIB_mib_2, 100
+#define MIB_transportDomains		MIB_transportAddress, 1
+#define MIB_transportDomainLocal	MIB_transportDomains, 13
+
 /*
  * PRIVATE ENTERPRISE NUMBERS from
  * https://www.iana.org/assignments/enterprise-numbers