xref: /openbsd-src/usr.sbin/snmpd/application_agentx.c (revision f0bcdb5c6239ddfcf095a4b7b5b5205416faadb1)
1*f0bcdb5cSmartijn /*	$OpenBSD: application_agentx.c,v 1.16 2024/02/06 12:44:27 martijn Exp $ */
24100cc5fSmartijn /*
34100cc5fSmartijn  * Copyright (c) 2022 Martijn van Duren <martijn@openbsd.org>
44100cc5fSmartijn  *
54100cc5fSmartijn  * Permission to use, copy, modify, and distribute this software for any
64100cc5fSmartijn  * purpose with or without fee is hereby granted, provided that the above
74100cc5fSmartijn  * copyright notice and this permission notice appear in all copies.
84100cc5fSmartijn  *
94100cc5fSmartijn  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
104100cc5fSmartijn  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
114100cc5fSmartijn  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
124100cc5fSmartijn  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
134100cc5fSmartijn  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
144100cc5fSmartijn  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
154100cc5fSmartijn  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
164100cc5fSmartijn  */
174100cc5fSmartijn 
184100cc5fSmartijn #include <sys/queue.h>
194100cc5fSmartijn #include <sys/socket.h>
204100cc5fSmartijn #include <sys/stat.h>
21a9292d2aSmartijn #include <sys/tree.h>
224100cc5fSmartijn #include <sys/un.h>
234100cc5fSmartijn 
24a9292d2aSmartijn #include <ber.h>
254100cc5fSmartijn #include <errno.h>
264100cc5fSmartijn #include <event.h>
274100cc5fSmartijn #include <inttypes.h>
28a9292d2aSmartijn #include <stdint.h>
294100cc5fSmartijn #include <stdio.h>
30a9292d2aSmartijn #include <stdlib.h>
314100cc5fSmartijn #include <string.h>
324100cc5fSmartijn #include <unistd.h>
334100cc5fSmartijn 
344100cc5fSmartijn #include "application.h"
354100cc5fSmartijn #include "ax.h"
364100cc5fSmartijn #include "log.h"
37*f0bcdb5cSmartijn #include "mib.h"
384100cc5fSmartijn #include "smi.h"
394100cc5fSmartijn #include "snmp.h"
404100cc5fSmartijn #include "snmpd.h"
414100cc5fSmartijn 
424100cc5fSmartijn #define AGENTX_DEFAULTTIMEOUT 5
434100cc5fSmartijn 
444100cc5fSmartijn struct appl_agentx_connection {
454100cc5fSmartijn 	uint32_t conn_id;
461985d3ebSmartijn 	/*
471985d3ebSmartijn 	 * A backend has several overruling properties:
481985d3ebSmartijn 	 * - If it exits, snmpd crashes
491985d3ebSmartijn 	 * - All registrations are priority 1
501985d3ebSmartijn 	 * - All registrations own the subtree.
511985d3ebSmartijn 	 */
521985d3ebSmartijn 	int conn_backend;
534100cc5fSmartijn 	struct ax *conn_ax;
544100cc5fSmartijn 	struct event conn_rev;
554100cc5fSmartijn 	struct event conn_wev;
564100cc5fSmartijn 
574100cc5fSmartijn 	TAILQ_HEAD(, appl_agentx_session) conn_sessions;
584100cc5fSmartijn 	RB_ENTRY(appl_agentx_connection) conn_entry;
594100cc5fSmartijn };
604100cc5fSmartijn 
614100cc5fSmartijn struct appl_agentx_session {
624100cc5fSmartijn 	uint32_t sess_id;
634100cc5fSmartijn 	struct appl_agentx_connection *sess_conn;
644100cc5fSmartijn 	/*
654100cc5fSmartijn 	 * RFC 2741 section 7.1.1:
664100cc5fSmartijn 	 * All subsequent AgentX protocol operations initiated by the master
674100cc5fSmartijn 	 * agent for this session must use this byte ordering and set this bit
684100cc5fSmartijn 	 * accordingly.
694100cc5fSmartijn 	 */
704100cc5fSmartijn 	enum ax_byte_order sess_byteorder;
714100cc5fSmartijn 	uint8_t sess_timeout;
724100cc5fSmartijn 	struct ax_oid sess_oid;
734100cc5fSmartijn 	struct ax_ostring sess_descr;
744100cc5fSmartijn 	struct appl_backend sess_backend;
754100cc5fSmartijn 
764100cc5fSmartijn 	RB_ENTRY(appl_agentx_session) sess_entry;
774100cc5fSmartijn 	TAILQ_ENTRY(appl_agentx_session) sess_conn_entry;
784100cc5fSmartijn };
794100cc5fSmartijn 
804100cc5fSmartijn void appl_agentx_listen(struct agentx_master *);
814100cc5fSmartijn void appl_agentx_accept(int, short, void *);
82273d3fb0Smartijn void appl_agentx_free(struct appl_agentx_connection *, enum appl_close_reason);
834100cc5fSmartijn void appl_agentx_recv(int, short, void *);
844100cc5fSmartijn void appl_agentx_open(struct appl_agentx_connection *, struct ax_pdu *);
854100cc5fSmartijn void appl_agentx_close(struct appl_agentx_session *, struct ax_pdu *);
864100cc5fSmartijn void appl_agentx_forceclose(struct appl_backend *, enum appl_close_reason);
874100cc5fSmartijn void appl_agentx_session_free(struct appl_agentx_session *);
884100cc5fSmartijn void appl_agentx_register(struct appl_agentx_session *, struct ax_pdu *);
894100cc5fSmartijn void appl_agentx_unregister(struct appl_agentx_session *, struct ax_pdu *);
904100cc5fSmartijn void appl_agentx_get(struct appl_backend *, int32_t, int32_t, const char *,
914100cc5fSmartijn     struct appl_varbind *);
924100cc5fSmartijn void appl_agentx_getnext(struct appl_backend *, int32_t, int32_t, const char *,
934100cc5fSmartijn     struct appl_varbind *);
949bbbacf6Smartijn void appl_agentx_addagentcaps(struct appl_agentx_session *, struct ax_pdu *);
959bbbacf6Smartijn void appl_agentx_removeagentcaps(struct appl_agentx_session *, struct ax_pdu *);
964100cc5fSmartijn void appl_agentx_response(struct appl_agentx_session *, struct ax_pdu *);
974100cc5fSmartijn void appl_agentx_send(int, short, void *);
984100cc5fSmartijn struct ber_oid *appl_agentx_oid2ber_oid(struct ax_oid *, struct ber_oid *);
994100cc5fSmartijn struct ber_element *appl_agentx_value2ber_element(struct ax_varbind *);
1004100cc5fSmartijn struct ax_ostring *appl_agentx_string2ostring(const char *,
1014100cc5fSmartijn     struct ax_ostring *);
1024100cc5fSmartijn int appl_agentx_cmp(struct appl_agentx_connection *,
1034100cc5fSmartijn     struct appl_agentx_connection *);
1044100cc5fSmartijn int appl_agentx_session_cmp(struct appl_agentx_session *,
1054100cc5fSmartijn     struct appl_agentx_session *);
1064100cc5fSmartijn 
1074100cc5fSmartijn struct appl_backend_functions appl_agentx_functions = {
1084100cc5fSmartijn 	.ab_close = appl_agentx_forceclose,
1094100cc5fSmartijn 	.ab_get = appl_agentx_get,
1104100cc5fSmartijn 	.ab_getnext = appl_agentx_getnext,
1114100cc5fSmartijn 	.ab_getbulk = NULL, /* not properly supported in application.c and libagentx */
1124100cc5fSmartijn };
1134100cc5fSmartijn 
1144100cc5fSmartijn RB_HEAD(appl_agentx_conns, appl_agentx_connection) appl_agentx_conns =
1154100cc5fSmartijn     RB_INITIALIZER(&appl_agentx_conns);
1164100cc5fSmartijn RB_HEAD(appl_agentx_sessions, appl_agentx_session) appl_agentx_sessions =
1174100cc5fSmartijn     RB_INITIALIZER(&appl_agentx_sessions);
1184100cc5fSmartijn 
1194100cc5fSmartijn RB_PROTOTYPE_STATIC(appl_agentx_conns, appl_agentx_connection, conn_entry,
1204100cc5fSmartijn     appl_agentx_cmp);
1214100cc5fSmartijn RB_PROTOTYPE_STATIC(appl_agentx_sessions, appl_agentx_session, sess_entry,
1224100cc5fSmartijn     appl_agentx_session_cmp);
1234100cc5fSmartijn 
1244100cc5fSmartijn void
appl_agentx(void)1254100cc5fSmartijn appl_agentx(void)
1264100cc5fSmartijn {
1274100cc5fSmartijn 	struct agentx_master *master;
1284100cc5fSmartijn 
1294100cc5fSmartijn 	TAILQ_FOREACH(master, &(snmpd_env->sc_agentx_masters), axm_entry)
1304100cc5fSmartijn 		appl_agentx_listen(master);
1314100cc5fSmartijn }
1324100cc5fSmartijn 
1334100cc5fSmartijn void
appl_agentx_init(void)1344100cc5fSmartijn appl_agentx_init(void)
1354100cc5fSmartijn {
1364100cc5fSmartijn 	struct agentx_master *master;
1374100cc5fSmartijn 
1384100cc5fSmartijn 	TAILQ_FOREACH(master, &(snmpd_env->sc_agentx_masters), axm_entry) {
1394100cc5fSmartijn 		if (master->axm_fd == -1)
1404100cc5fSmartijn 			continue;
1414100cc5fSmartijn 		event_set(&(master->axm_ev), master->axm_fd,
1424100cc5fSmartijn 		    EV_READ | EV_PERSIST, appl_agentx_accept, master);
1434100cc5fSmartijn 		event_add(&(master->axm_ev), NULL);
1444100cc5fSmartijn 		log_info("AgentX: listening on %s", master->axm_sun.sun_path);
1454100cc5fSmartijn 	}
1464100cc5fSmartijn }
1474100cc5fSmartijn void
appl_agentx_listen(struct agentx_master * master)1484100cc5fSmartijn appl_agentx_listen(struct agentx_master *master)
1494100cc5fSmartijn {
1504100cc5fSmartijn 	mode_t mask;
1514100cc5fSmartijn 
1524100cc5fSmartijn 	unlink(master->axm_sun.sun_path);
1534100cc5fSmartijn 
1544100cc5fSmartijn 	mask = umask(0777);
1554100cc5fSmartijn 	if ((master->axm_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 ||
1564100cc5fSmartijn 	    bind(master->axm_fd, (struct sockaddr *)&(master->axm_sun),
1574100cc5fSmartijn 	    sizeof(master->axm_sun)) == -1 ||
1584100cc5fSmartijn 	    listen(master->axm_fd, 5)) {
15969acb4a3Smartijn 		log_warn("AgentX: listen %s", master->axm_sun.sun_path);
1604100cc5fSmartijn 		umask(mask);
1614100cc5fSmartijn 		return;
1624100cc5fSmartijn 	}
1634100cc5fSmartijn 	umask(mask);
1644100cc5fSmartijn 	if (chown(master->axm_sun.sun_path, master->axm_owner,
1654100cc5fSmartijn 	    master->axm_group) == -1) {
1664100cc5fSmartijn 		log_warn("AgentX: chown %s", master->axm_sun.sun_path);
1674100cc5fSmartijn 		goto fail;
1684100cc5fSmartijn 	}
1694100cc5fSmartijn 	if (chmod(master->axm_sun.sun_path, master->axm_mode) == -1) {
1704100cc5fSmartijn 		log_warn("AgentX: chmod %s", master->axm_sun.sun_path);
1714100cc5fSmartijn 		goto fail;
1724100cc5fSmartijn 	}
1734100cc5fSmartijn 	return;
1744100cc5fSmartijn  fail:
1754100cc5fSmartijn 	close(master->axm_fd);
1764100cc5fSmartijn 	master->axm_fd = -1;
1774100cc5fSmartijn }
1784100cc5fSmartijn 
1794100cc5fSmartijn void
appl_agentx_shutdown(void)1804100cc5fSmartijn appl_agentx_shutdown(void)
1814100cc5fSmartijn {
1824100cc5fSmartijn 	struct appl_agentx_connection *conn, *tconn;
1834100cc5fSmartijn 
1844100cc5fSmartijn 	RB_FOREACH_SAFE(conn, appl_agentx_conns, &appl_agentx_conns, tconn)
185273d3fb0Smartijn 		appl_agentx_free(conn, APPL_CLOSE_REASONSHUTDOWN);
1864100cc5fSmartijn }
1874100cc5fSmartijn 
1884100cc5fSmartijn void
appl_agentx_accept(int masterfd,short event,void * cookie)1894100cc5fSmartijn appl_agentx_accept(int masterfd, short event, void *cookie)
1904100cc5fSmartijn {
1914100cc5fSmartijn 	int fd;
1924100cc5fSmartijn 	struct agentx_master *master = cookie;
1934100cc5fSmartijn 	struct sockaddr_un sun;
1944100cc5fSmartijn 	socklen_t sunlen = sizeof(sun);
1954100cc5fSmartijn 	struct appl_agentx_connection *conn = NULL;
1964100cc5fSmartijn 
1974100cc5fSmartijn 	if ((fd = accept(masterfd, (struct sockaddr *)&sun, &sunlen)) == -1) {
1984100cc5fSmartijn 		log_warn("AgentX: accept %s", master->axm_sun.sun_path);
1994100cc5fSmartijn 		return;
2004100cc5fSmartijn 	}
2014100cc5fSmartijn 
2024100cc5fSmartijn 	if ((conn = malloc(sizeof(*conn))) == NULL) {
2034100cc5fSmartijn 		log_warn(NULL);
2044100cc5fSmartijn 		goto fail;
2054100cc5fSmartijn 	}
2064100cc5fSmartijn 
2071985d3ebSmartijn 	conn->conn_backend = 0;
2084100cc5fSmartijn 	TAILQ_INIT(&(conn->conn_sessions));
2094100cc5fSmartijn 	if ((conn->conn_ax = ax_new(fd)) == NULL) {
2104100cc5fSmartijn 		log_warn(NULL);
2114100cc5fSmartijn 		goto fail;
2124100cc5fSmartijn 	}
2134100cc5fSmartijn 
2144100cc5fSmartijn 	do {
2154100cc5fSmartijn 		conn->conn_id = arc4random();
2164100cc5fSmartijn 	} while (RB_INSERT(appl_agentx_conns,
2174100cc5fSmartijn 	    &appl_agentx_conns, conn) != NULL);
2184100cc5fSmartijn 
2194100cc5fSmartijn 	event_set(&(conn->conn_rev), fd, EV_READ | EV_PERSIST,
2204100cc5fSmartijn 	    appl_agentx_recv, conn);
2214100cc5fSmartijn 	event_add(&(conn->conn_rev), NULL);
2224100cc5fSmartijn 	event_set(&(conn->conn_wev), fd, EV_WRITE, appl_agentx_send, conn);
22369acb4a3Smartijn 	log_info("AgentX(%"PRIu32"): new connection", conn->conn_id);
2244100cc5fSmartijn 
2254100cc5fSmartijn 	return;
2264100cc5fSmartijn  fail:
2274100cc5fSmartijn 	close(fd);
2284100cc5fSmartijn 	free(conn);
2294100cc5fSmartijn }
2304100cc5fSmartijn 
2314100cc5fSmartijn void
appl_agentx_backend(int fd)2321985d3ebSmartijn appl_agentx_backend(int fd)
2331985d3ebSmartijn {
2341985d3ebSmartijn 	struct appl_agentx_connection *conn;
2351985d3ebSmartijn 
2361985d3ebSmartijn 	if ((conn = malloc(sizeof(*conn))) == NULL)
2371985d3ebSmartijn 		fatal(NULL);
2381985d3ebSmartijn 
2391985d3ebSmartijn 	conn->conn_backend = 1;
2401985d3ebSmartijn 	TAILQ_INIT(&(conn->conn_sessions));
2411985d3ebSmartijn 	if ((conn->conn_ax = ax_new(fd)) == NULL)
2421985d3ebSmartijn 		fatal("ax_new");
2431985d3ebSmartijn 
2441985d3ebSmartijn 	do {
2451985d3ebSmartijn 		conn->conn_id = arc4random();
2461985d3ebSmartijn 	} while (RB_INSERT(appl_agentx_conns,
2471985d3ebSmartijn 	    &appl_agentx_conns, conn) != NULL);
2481985d3ebSmartijn 
2491985d3ebSmartijn 	event_set(&(conn->conn_rev), fd, EV_READ | EV_PERSIST,
2501985d3ebSmartijn 	    appl_agentx_recv, conn);
2511985d3ebSmartijn 	event_add(&(conn->conn_rev), NULL);
2521985d3ebSmartijn 	event_set(&(conn->conn_wev), fd, EV_WRITE, appl_agentx_send, conn);
2531985d3ebSmartijn }
2541985d3ebSmartijn 
2551985d3ebSmartijn void
appl_agentx_free(struct appl_agentx_connection * conn,enum appl_close_reason reason)256273d3fb0Smartijn appl_agentx_free(struct appl_agentx_connection *conn,
257273d3fb0Smartijn     enum appl_close_reason reason)
2584100cc5fSmartijn {
2594100cc5fSmartijn 	struct appl_agentx_session *session;
2604100cc5fSmartijn 
2614100cc5fSmartijn 	while ((session = TAILQ_FIRST(&(conn->conn_sessions))) != NULL) {
2624100cc5fSmartijn 		if (conn->conn_ax == NULL)
2634100cc5fSmartijn 			appl_agentx_session_free(session);
2644100cc5fSmartijn 		else
2654100cc5fSmartijn 			appl_agentx_forceclose(&(session->sess_backend),
266273d3fb0Smartijn 			    reason);
2674100cc5fSmartijn 	}
2684100cc5fSmartijn 
269eb6ea173Smartijn 	event_del(&(conn->conn_rev));
270eb6ea173Smartijn 	event_del(&(conn->conn_wev));
271eb6ea173Smartijn 
2724100cc5fSmartijn 	RB_REMOVE(appl_agentx_conns, &appl_agentx_conns, conn);
273eb6ea173Smartijn 	if (conn->conn_ax != NULL)
274eb6ea173Smartijn 		(void)ax_send(conn->conn_ax);
2754100cc5fSmartijn 	ax_free(conn->conn_ax);
2761985d3ebSmartijn 	if (conn->conn_backend)
2771985d3ebSmartijn 		fatalx("AgentX(%"PRIu32"): disappeared unexpected",
2781985d3ebSmartijn 		    conn->conn_id);
2794100cc5fSmartijn 	free(conn);
2804100cc5fSmartijn }
2814100cc5fSmartijn 
2824100cc5fSmartijn void
appl_agentx_recv(int fd,short event,void * cookie)2834100cc5fSmartijn appl_agentx_recv(int fd, short event, void *cookie)
2844100cc5fSmartijn {
2854100cc5fSmartijn 	struct appl_agentx_connection *conn = cookie;
28669014b58Smartijn 	struct appl_agentx_session *session = NULL;
2874100cc5fSmartijn 	struct ax_pdu *pdu;
28869014b58Smartijn 	enum appl_error error;
28969014b58Smartijn 	char name[100];
2904100cc5fSmartijn 
29169014b58Smartijn 	snprintf(name, sizeof(name), "AgentX(%"PRIu32")", conn->conn_id);
2924100cc5fSmartijn 	if ((pdu = ax_recv(conn->conn_ax)) == NULL) {
2934100cc5fSmartijn 		if (errno == EAGAIN)
2944100cc5fSmartijn 			return;
29569014b58Smartijn 		log_warn("%s", name);
2964100cc5fSmartijn 		/*
2974100cc5fSmartijn 		 * Either the connection is dead, or we had garbage on the line.
2984100cc5fSmartijn 		 * Both make sure we can't continue on this stream.
2994100cc5fSmartijn 		 */
3004100cc5fSmartijn 		if (errno == ECONNRESET) {
3014100cc5fSmartijn 			ax_free(conn->conn_ax);
3024100cc5fSmartijn 			conn->conn_ax = NULL;
3034100cc5fSmartijn 		}
304273d3fb0Smartijn 		appl_agentx_free(conn, errno == EPROTO ?
305273d3fb0Smartijn 		    APPL_CLOSE_REASONPROTOCOLERROR : APPL_CLOSE_REASONOTHER);
3064100cc5fSmartijn 		return;
3074100cc5fSmartijn 	}
3084100cc5fSmartijn 
3094100cc5fSmartijn 	conn->conn_ax->ax_byteorder = pdu->ap_header.aph_flags &
3104100cc5fSmartijn 	    AX_PDU_FLAG_NETWORK_BYTE_ORDER ?
3114100cc5fSmartijn 	    AX_BYTE_ORDER_BE : AX_BYTE_ORDER_LE;
3124100cc5fSmartijn 	if (pdu->ap_header.aph_type != AX_PDU_TYPE_OPEN) {
3134100cc5fSmartijn 		/* Make sure we only look for connection-local sessions */
3144100cc5fSmartijn 		TAILQ_FOREACH(session, &(conn->conn_sessions),
3154100cc5fSmartijn 		    sess_conn_entry) {
3164100cc5fSmartijn 			if (session->sess_id == pdu->ap_header.aph_sessionid)
3174100cc5fSmartijn 				break;
3184100cc5fSmartijn 		}
3194100cc5fSmartijn 		if (session == NULL) {
32069014b58Smartijn 			log_warnx("%s: Session %"PRIu32" not found for request",
32169014b58Smartijn 			    name, pdu->ap_header.aph_sessionid);
32269014b58Smartijn 			error = APPL_ERROR_NOTOPEN;
3234100cc5fSmartijn 			goto fail;
3244100cc5fSmartijn 		}
32569014b58Smartijn 		strlcpy(name, session->sess_backend.ab_name, sizeof(name));
3264100cc5fSmartijn 		/*
3274100cc5fSmartijn 		 * RFC2741 section 7.1.1 bullet 4 is unclear on what byte order
3284100cc5fSmartijn 		 * the response should be. My best guess is that it makes more
3294100cc5fSmartijn 		 * sense that replies are in the same byte-order as what was
3304100cc5fSmartijn 		 * requested.
3314100cc5fSmartijn 		 * In practice we always have the same byte order as when we
3324100cc5fSmartijn 		 * opened the session, so it's likely a non-issue, however, we
3334100cc5fSmartijn 		 * can change to session byte order here.
3344100cc5fSmartijn 		 */
3354100cc5fSmartijn 	}
3364100cc5fSmartijn 
33769014b58Smartijn 	if (pdu->ap_header.aph_flags & AX_PDU_FLAG_INSTANCE_REGISTRATION) {
33869014b58Smartijn 		if (pdu->ap_header.aph_type != AX_PDU_TYPE_REGISTER) {
33969014b58Smartijn 			log_warnx("%s: %s: Invalid INSTANCE_REGISTRATION flag",
34069014b58Smartijn 			    name, ax_pdutype2string(pdu->ap_header.aph_flags));
34169014b58Smartijn 			error = APPL_ERROR_PARSEERROR;
34269014b58Smartijn 			goto fail;
34369014b58Smartijn 		}
34469014b58Smartijn 	}
34569014b58Smartijn 	if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NEW_INDEX) {
34669014b58Smartijn 		if (pdu->ap_header.aph_type != AX_PDU_TYPE_INDEXALLOCATE &&
34769014b58Smartijn 		    pdu->ap_header.aph_type != AX_PDU_TYPE_INDEXDEALLOCATE) {
34869014b58Smartijn 			log_warnx("%s: %s: Invalid NEW_INDEX flag", name,
34969014b58Smartijn 			    ax_pdutype2string(pdu->ap_header.aph_flags));
35069014b58Smartijn 			error = APPL_ERROR_PARSEERROR;
35169014b58Smartijn 			goto fail;
35269014b58Smartijn 		}
35369014b58Smartijn 	}
35469014b58Smartijn 	if (pdu->ap_header.aph_flags & AX_PDU_FLAG_ANY_INDEX) {
35569014b58Smartijn 		if (pdu->ap_header.aph_type != AX_PDU_TYPE_INDEXALLOCATE &&
35669014b58Smartijn 		    pdu->ap_header.aph_type != AX_PDU_TYPE_INDEXDEALLOCATE) {
35769014b58Smartijn 			log_warnx("%s: %s: Invalid ANY_INDEX flag", name,
35869014b58Smartijn 			    ax_pdutype2string(pdu->ap_header.aph_flags));
35969014b58Smartijn 			error = APPL_ERROR_PARSEERROR;
36069014b58Smartijn 			goto fail;
36169014b58Smartijn 		}
36269014b58Smartijn 	}
36369014b58Smartijn 	if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NON_DEFAULT_CONTEXT) {
36469014b58Smartijn 		if (pdu->ap_header.aph_type != AX_PDU_TYPE_REGISTER &&
36569014b58Smartijn 		    pdu->ap_header.aph_type != AX_PDU_TYPE_UNREGISTER &&
36669014b58Smartijn 		    pdu->ap_header.aph_type != AX_PDU_TYPE_ADDAGENTCAPS &&
36769014b58Smartijn 		    pdu->ap_header.aph_type != AX_PDU_TYPE_REMOVEAGENTCAPS &&
36869014b58Smartijn 		    pdu->ap_header.aph_type != AX_PDU_TYPE_GET &&
36969014b58Smartijn 		    pdu->ap_header.aph_type != AX_PDU_TYPE_GETNEXT &&
37069014b58Smartijn 		    pdu->ap_header.aph_type != AX_PDU_TYPE_GETBULK &&
37169014b58Smartijn 		    pdu->ap_header.aph_type != AX_PDU_TYPE_INDEXALLOCATE &&
37269014b58Smartijn 		    pdu->ap_header.aph_type != AX_PDU_TYPE_INDEXDEALLOCATE &&
37369014b58Smartijn 		    pdu->ap_header.aph_type != AX_PDU_TYPE_NOTIFY &&
37469014b58Smartijn 		    pdu->ap_header.aph_type != AX_PDU_TYPE_TESTSET &&
37569014b58Smartijn 		    pdu->ap_header.aph_type != AX_PDU_TYPE_PING) {
37669014b58Smartijn 			log_warnx("%s: %s: Invalid NON_DEFAULT_CONTEXT flag",
37769014b58Smartijn 			    name, ax_pdutype2string(pdu->ap_header.aph_flags));
37869014b58Smartijn 			error = APPL_ERROR_PARSEERROR;
37969014b58Smartijn 			goto fail;
38069014b58Smartijn 		}
381253352b6Smartijn 		if (appl_context(pdu->ap_context.aos_string, 0) == NULL) {
382253352b6Smartijn 			log_warnx("%s: %s: Unsupported context",
383253352b6Smartijn 			    name, ax_pdutype2string(pdu->ap_header.aph_flags));
384253352b6Smartijn 			error = APPL_ERROR_UNSUPPORTEDCONTEXT;
385253352b6Smartijn 			goto fail;
386253352b6Smartijn 		}
38769014b58Smartijn 	}
3884100cc5fSmartijn 	switch (pdu->ap_header.aph_type) {
3894100cc5fSmartijn 	case AX_PDU_TYPE_OPEN:
3904100cc5fSmartijn 		appl_agentx_open(conn, pdu);
3914100cc5fSmartijn 		break;
3924100cc5fSmartijn 	case AX_PDU_TYPE_CLOSE:
3934100cc5fSmartijn 		appl_agentx_close(session, pdu);
3944100cc5fSmartijn 		break;
3954100cc5fSmartijn 	case AX_PDU_TYPE_REGISTER:
3964100cc5fSmartijn 		appl_agentx_register(session, pdu);
3974100cc5fSmartijn 		break;
3984100cc5fSmartijn 	case AX_PDU_TYPE_UNREGISTER:
3994100cc5fSmartijn 		appl_agentx_unregister(session, pdu);
4004100cc5fSmartijn 		break;
4014100cc5fSmartijn 	case AX_PDU_TYPE_GET:
4024100cc5fSmartijn 	case AX_PDU_TYPE_GETNEXT:
4034100cc5fSmartijn 	case AX_PDU_TYPE_GETBULK:
4044100cc5fSmartijn 	case AX_PDU_TYPE_TESTSET:
4054100cc5fSmartijn 	case AX_PDU_TYPE_COMMITSET:
4064100cc5fSmartijn 	case AX_PDU_TYPE_UNDOSET:
4074100cc5fSmartijn 	case AX_PDU_TYPE_CLEANUPSET:
40869014b58Smartijn 		log_warnx("%s: %s: Not an adminsitrative message", name,
40969014b58Smartijn 		    ax_pdutype2string(pdu->ap_header.aph_type));
41069014b58Smartijn 		error = APPL_ERROR_PARSEERROR;
4114100cc5fSmartijn 		goto fail;
4124100cc5fSmartijn 	case AX_PDU_TYPE_NOTIFY:
41369014b58Smartijn 		log_warnx("%s: %s: not supported", name,
4144100cc5fSmartijn 		    ax_pdutype2string(pdu->ap_header.aph_type));
4154100cc5fSmartijn 		/*
4164100cc5fSmartijn 		 * RFC 2741 section 7.1.10:
4174100cc5fSmartijn 		 * Note that the master agent's successful response indicates
4184100cc5fSmartijn 		 * the agentx-Notify-PDU was received and validated.  It does
4194100cc5fSmartijn 		 * not indicate that any particular notifications were actually
4204100cc5fSmartijn 		 * generated or received by notification targets
4214100cc5fSmartijn 		 */
4224100cc5fSmartijn 		/* XXX Not yet - FALLTHROUGH */
4234100cc5fSmartijn 	case AX_PDU_TYPE_PING:
4244100cc5fSmartijn 		ax_response(conn->conn_ax, pdu->ap_header.aph_sessionid,
4254100cc5fSmartijn 		    pdu->ap_header.aph_transactionid,
4266f5d9364Smartijn 		    pdu->ap_header.aph_packetid, smi_getticks(),
4276f5d9364Smartijn 		    APPL_ERROR_NOERROR, 0, NULL, 0);
428eb6ea173Smartijn 		event_add(&(conn->conn_wev), NULL);
4294100cc5fSmartijn 		break;
4304100cc5fSmartijn 	case AX_PDU_TYPE_INDEXALLOCATE:
4314100cc5fSmartijn 	case AX_PDU_TYPE_INDEXDEALLOCATE:
43269014b58Smartijn 		log_warnx("%s: %s: not supported", name,
4334100cc5fSmartijn 		    ax_pdutype2string(pdu->ap_header.aph_type));
4344100cc5fSmartijn 		ax_response(conn->conn_ax, pdu->ap_header.aph_sessionid,
4354100cc5fSmartijn 		    pdu->ap_header.aph_transactionid,
4366f5d9364Smartijn 		    pdu->ap_header.aph_packetid, smi_getticks(),
4376f5d9364Smartijn 		    APPL_ERROR_PROCESSINGERROR, 1,
4384100cc5fSmartijn 		    pdu->ap_payload.ap_vbl.ap_varbind,
4394100cc5fSmartijn 		    pdu->ap_payload.ap_vbl.ap_nvarbind);
440eb6ea173Smartijn 		event_add(&(conn->conn_wev), NULL);
4414100cc5fSmartijn 		break;
4424100cc5fSmartijn 	case AX_PDU_TYPE_ADDAGENTCAPS:
4439bbbacf6Smartijn 		appl_agentx_addagentcaps(session, pdu);
4449bbbacf6Smartijn 		break;
4454100cc5fSmartijn 	case AX_PDU_TYPE_REMOVEAGENTCAPS:
4469bbbacf6Smartijn 		appl_agentx_removeagentcaps(session, pdu);
4479bbbacf6Smartijn 		break;
4484100cc5fSmartijn 	case AX_PDU_TYPE_RESPONSE:
4494100cc5fSmartijn 		appl_agentx_response(session, pdu);
4504100cc5fSmartijn 		break;
4514100cc5fSmartijn 	}
4524100cc5fSmartijn 
4534100cc5fSmartijn 	ax_pdu_free(pdu);
45469014b58Smartijn 	return;
45569014b58Smartijn  fail:
45669014b58Smartijn 	ax_response(conn->conn_ax, pdu->ap_header.aph_sessionid,
45769014b58Smartijn 	    pdu->ap_header.aph_transactionid,
45869014b58Smartijn 	    pdu->ap_header.aph_packetid, smi_getticks(),
45969014b58Smartijn 	    error, 0, NULL, 0);
460eb6ea173Smartijn 	event_add(&(conn->conn_wev), NULL);
46169014b58Smartijn 	ax_pdu_free(pdu);
46269014b58Smartijn 
46369014b58Smartijn 	if (session == NULL || error != APPL_ERROR_PARSEERROR)
46469014b58Smartijn 		return;
46569014b58Smartijn 
46669014b58Smartijn 	appl_agentx_forceclose(&(session->sess_backend),
46769014b58Smartijn 	    APPL_CLOSE_REASONPARSEERROR);
46869014b58Smartijn 	if (TAILQ_EMPTY(&(conn->conn_sessions)))
469273d3fb0Smartijn 		appl_agentx_free(conn, APPL_CLOSE_REASONOTHER);
4704100cc5fSmartijn }
4714100cc5fSmartijn 
4724100cc5fSmartijn void
appl_agentx_open(struct appl_agentx_connection * conn,struct ax_pdu * pdu)4734100cc5fSmartijn appl_agentx_open(struct appl_agentx_connection *conn, struct ax_pdu *pdu)
4744100cc5fSmartijn {
4754100cc5fSmartijn 	struct appl_agentx_session *session;
4764100cc5fSmartijn 	struct ber_oid oid;
4774100cc5fSmartijn 	char oidbuf[1024];
478d2fe463cSmartijn 	enum appl_error error = APPL_ERROR_NOERROR;
4794100cc5fSmartijn 
4804100cc5fSmartijn 	if ((session = malloc(sizeof(*session))) == NULL) {
4814100cc5fSmartijn 		log_warn(NULL);
482d2fe463cSmartijn 		error = APPL_ERROR_OPENFAILED;
4834100cc5fSmartijn 		goto fail;
4844100cc5fSmartijn 	}
4854100cc5fSmartijn 	session->sess_descr.aos_string = NULL;
4864100cc5fSmartijn 
4874100cc5fSmartijn 	session->sess_conn = conn;
4884100cc5fSmartijn 	if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER)
4894100cc5fSmartijn 		session->sess_byteorder = AX_BYTE_ORDER_BE;
4904100cc5fSmartijn 	else
4914100cc5fSmartijn 		session->sess_byteorder = AX_BYTE_ORDER_LE;
4924100cc5fSmartijn 
4934100cc5fSmartijn 	/* RFC 2742 agentxSessionObjectID */
4944100cc5fSmartijn 	if (pdu->ap_payload.ap_open.ap_oid.aoi_idlen == 0) {
4954100cc5fSmartijn 		pdu->ap_payload.ap_open.ap_oid.aoi_id[0] = 0;
4964100cc5fSmartijn 		pdu->ap_payload.ap_open.ap_oid.aoi_id[1] = 0;
4974100cc5fSmartijn 		pdu->ap_payload.ap_open.ap_oid.aoi_idlen = 2;
4984100cc5fSmartijn 	} else if (pdu->ap_payload.ap_open.ap_oid.aoi_idlen == 1) {
4994100cc5fSmartijn 		log_warnx("AgentX(%"PRIu32"): Invalid oid: Open Failed",
5004100cc5fSmartijn 		    conn->conn_id);
501d2fe463cSmartijn 		error = APPL_ERROR_PARSEERROR;
5024100cc5fSmartijn 		goto fail;
5034100cc5fSmartijn 	}
5044100cc5fSmartijn 	/* RFC 2742 agentxSessionDescr */
5054100cc5fSmartijn 	if (pdu->ap_payload.ap_open.ap_descr.aos_slen > 255) {
5064100cc5fSmartijn 		log_warnx("AgentX(%"PRIu32"): Invalid descr (too long): Open "
5074100cc5fSmartijn 		    "Failed", conn->conn_id);
508d2fe463cSmartijn 		error = APPL_ERROR_PARSEERROR;
5094100cc5fSmartijn 		goto fail;
5104100cc5fSmartijn 	}
5114100cc5fSmartijn 	/*
5124100cc5fSmartijn 	 * ax_ostring is always NUL-terminated, but doesn't scan for internal
5134100cc5fSmartijn 	 * NUL-bytes. However, mbstowcs stops at NUL, which might be in the
5144100cc5fSmartijn 	 * middle of the string.
5154100cc5fSmartijn 	 */
5164100cc5fSmartijn 	if (strlen(pdu->ap_payload.ap_open.ap_descr.aos_string) !=
5174100cc5fSmartijn 	    pdu->ap_payload.ap_open.ap_descr.aos_slen ||
5184100cc5fSmartijn 	    mbstowcs(NULL,
5194100cc5fSmartijn 	    pdu->ap_payload.ap_open.ap_descr.aos_string, 0) == (size_t)-1) {
5204100cc5fSmartijn 		log_warnx("AgentX(%"PRIu32"): Invalid descr (not UTF-8): "
5214100cc5fSmartijn 		    "Open Failed", conn->conn_id);
522d2fe463cSmartijn 		error = APPL_ERROR_PARSEERROR;
5234100cc5fSmartijn 		goto fail;
5244100cc5fSmartijn 	}
5254100cc5fSmartijn 
5264100cc5fSmartijn 	session->sess_timeout = pdu->ap_payload.ap_open.ap_timeout;
5274100cc5fSmartijn 	session->sess_oid = pdu->ap_payload.ap_open.ap_oid;
5284100cc5fSmartijn 	session->sess_descr.aos_slen = pdu->ap_payload.ap_open.ap_descr.aos_slen;
5294100cc5fSmartijn 	if (pdu->ap_payload.ap_open.ap_descr.aos_string != NULL) {
5304100cc5fSmartijn 		session->sess_descr.aos_string =
5314100cc5fSmartijn 		    strdup(pdu->ap_payload.ap_open.ap_descr.aos_string);
5324100cc5fSmartijn 		if (session->sess_descr.aos_string == NULL) {
5334100cc5fSmartijn 			log_warn("AgentX(%"PRIu32"): strdup: Open Failed",
5344100cc5fSmartijn 			    conn->conn_id);
535d2fe463cSmartijn 			error = APPL_ERROR_OPENFAILED;
5364100cc5fSmartijn 			goto fail;
5374100cc5fSmartijn 		}
5384100cc5fSmartijn 	}
5394100cc5fSmartijn 
5404100cc5fSmartijn 	/* RFC 2742 agentxSessionIndex: chances of reuse, slim to none */
5414100cc5fSmartijn 	do {
5424100cc5fSmartijn 		session->sess_id = arc4random();
5434100cc5fSmartijn 	} while (RB_INSERT(appl_agentx_sessions,
5444100cc5fSmartijn 	    &appl_agentx_sessions, session) != NULL);
5454100cc5fSmartijn 
5464100cc5fSmartijn 	if (asprintf(&(session->sess_backend.ab_name),
5474100cc5fSmartijn 	    "AgentX(%"PRIu32"/%"PRIu32")",
5484100cc5fSmartijn 	    conn->conn_id, session->sess_id) == -1) {
54969acb4a3Smartijn 		log_warn("AgentX(%"PRIu32"): asprintf: Open Failed",
5504100cc5fSmartijn 		    conn->conn_id);
551d2fe463cSmartijn 		error = APPL_ERROR_OPENFAILED;
5524100cc5fSmartijn 		goto fail;
5534100cc5fSmartijn 	}
5544100cc5fSmartijn 	session->sess_backend.ab_cookie = session;
5554100cc5fSmartijn 	session->sess_backend.ab_retries = 0;
5564100cc5fSmartijn 	session->sess_backend.ab_fn = &appl_agentx_functions;
557752950f9Smartijn 	session->sess_backend.ab_range = 1;
5584100cc5fSmartijn 	RB_INIT(&(session->sess_backend.ab_requests));
5594100cc5fSmartijn 	TAILQ_INSERT_TAIL(&(conn->conn_sessions), session, sess_conn_entry);
5604100cc5fSmartijn 
5614100cc5fSmartijn 	appl_agentx_oid2ber_oid(&(session->sess_oid), &oid);
562*f0bcdb5cSmartijn 	mib_oid2string(&oid, oidbuf, sizeof(oidbuf), snmpd_env->sc_oidfmt);
5634100cc5fSmartijn 	log_info("%s: %s %s: Open", session->sess_backend.ab_name, oidbuf,
5644100cc5fSmartijn 	    session->sess_descr.aos_string);
5654100cc5fSmartijn 
5666f5d9364Smartijn 	ax_response(conn->conn_ax, session->sess_id,
5676f5d9364Smartijn 	    pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,
5686f5d9364Smartijn 	    smi_getticks(), APPL_ERROR_NOERROR, 0, NULL, 0);
569eb6ea173Smartijn 	event_add(&(conn->conn_wev), NULL);
5704100cc5fSmartijn 
5714100cc5fSmartijn 	return;
5724100cc5fSmartijn  fail:
5734100cc5fSmartijn 	ax_response(conn->conn_ax, 0, pdu->ap_header.aph_transactionid,
574d2fe463cSmartijn 	    pdu->ap_header.aph_packetid, 0, error, 0, NULL, 0);
575eb6ea173Smartijn 	event_add(&(conn->conn_wev), NULL);
5764100cc5fSmartijn 	if (session != NULL)
5774100cc5fSmartijn 		free(session->sess_descr.aos_string);
5784100cc5fSmartijn 	free(session);
5794100cc5fSmartijn }
5804100cc5fSmartijn 
5814100cc5fSmartijn void
appl_agentx_close(struct appl_agentx_session * session,struct ax_pdu * pdu)5824100cc5fSmartijn appl_agentx_close(struct appl_agentx_session *session, struct ax_pdu *pdu)
5834100cc5fSmartijn {
5844100cc5fSmartijn 	struct appl_agentx_connection *conn = session->sess_conn;
5854100cc5fSmartijn 	char name[100];
58689417623Smartijn 	enum appl_error error = APPL_ERROR_NOERROR;
5874100cc5fSmartijn 
5884100cc5fSmartijn 	strlcpy(name, session->sess_backend.ab_name, sizeof(name));
58989417623Smartijn 	if (pdu->ap_payload.ap_close.ap_reason == AX_CLOSE_BYMANAGER) {
59089417623Smartijn 		log_warnx("%s: Invalid close reason", name);
59189417623Smartijn 		error = APPL_ERROR_PARSEERROR;
59289417623Smartijn 	} else {
5934100cc5fSmartijn 		appl_agentx_session_free(session);
5944100cc5fSmartijn 		log_info("%s: Closed by subagent (%s)", name,
5954100cc5fSmartijn 		    ax_closereason2string(pdu->ap_payload.ap_close.ap_reason));
59689417623Smartijn 	}
5974100cc5fSmartijn 
5984100cc5fSmartijn 	ax_response(conn->conn_ax, pdu->ap_header.aph_sessionid,
5994100cc5fSmartijn 	    pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,
60089417623Smartijn 	    smi_getticks(), error, 0, NULL, 0);
601eb6ea173Smartijn 	event_add(&(conn->conn_wev), NULL);
60289417623Smartijn 	if (error == APPL_ERROR_NOERROR)
60389417623Smartijn 		return;
60489417623Smartijn 
60589417623Smartijn 	appl_agentx_forceclose(&(session->sess_backend),
60689417623Smartijn 	    APPL_CLOSE_REASONPARSEERROR);
60789417623Smartijn 	if (TAILQ_EMPTY(&(conn->conn_sessions)))
60889417623Smartijn 		appl_agentx_free(conn, APPL_CLOSE_REASONOTHER);
6094100cc5fSmartijn }
6104100cc5fSmartijn 
6114100cc5fSmartijn void
appl_agentx_forceclose(struct appl_backend * backend,enum appl_close_reason reason)6124100cc5fSmartijn appl_agentx_forceclose(struct appl_backend *backend,
6134100cc5fSmartijn     enum appl_close_reason reason)
6144100cc5fSmartijn {
6154100cc5fSmartijn 	struct appl_agentx_session *session = backend->ab_cookie;
6164100cc5fSmartijn 	char name[100];
6174100cc5fSmartijn 
6184100cc5fSmartijn 	session->sess_conn->conn_ax->ax_byteorder = session->sess_byteorder;
6194100cc5fSmartijn 	ax_close(session->sess_conn->conn_ax, session->sess_id,
6204100cc5fSmartijn 	    (enum ax_close_reason) reason);
621eb6ea173Smartijn 	event_add(&(session->sess_conn->conn_wev), NULL);
6224100cc5fSmartijn 
6234100cc5fSmartijn 	strlcpy(name, session->sess_backend.ab_name, sizeof(name));
6244100cc5fSmartijn 	appl_agentx_session_free(session);
6254100cc5fSmartijn 	log_info("%s: Closed by snmpd (%s)", name,
6264100cc5fSmartijn 	    ax_closereason2string((enum ax_close_reason)reason));
6274100cc5fSmartijn }
6284100cc5fSmartijn 
6294100cc5fSmartijn void
appl_agentx_session_free(struct appl_agentx_session * session)6304100cc5fSmartijn appl_agentx_session_free(struct appl_agentx_session *session)
6314100cc5fSmartijn {
6324100cc5fSmartijn 	struct appl_agentx_connection *conn = session->sess_conn;
6334100cc5fSmartijn 
6344100cc5fSmartijn 	appl_close(&(session->sess_backend));
6354100cc5fSmartijn 
6364100cc5fSmartijn 	RB_REMOVE(appl_agentx_sessions, &appl_agentx_sessions, session);
6374100cc5fSmartijn 	TAILQ_REMOVE(&(conn->conn_sessions), session, sess_conn_entry);
6384100cc5fSmartijn 
6394100cc5fSmartijn 	free(session->sess_backend.ab_name);
6404100cc5fSmartijn 	free(session->sess_descr.aos_string);
6414100cc5fSmartijn 	free(session);
6424100cc5fSmartijn }
6434100cc5fSmartijn 
6444100cc5fSmartijn void
appl_agentx_register(struct appl_agentx_session * session,struct ax_pdu * pdu)6454100cc5fSmartijn appl_agentx_register(struct appl_agentx_session *session, struct ax_pdu *pdu)
6464100cc5fSmartijn {
6474100cc5fSmartijn 	uint32_t timeout;
6484100cc5fSmartijn 	struct ber_oid oid;
6494100cc5fSmartijn 	enum appl_error error;
6501985d3ebSmartijn 	int subtree = 0;
6514100cc5fSmartijn 
6524100cc5fSmartijn 	timeout = pdu->ap_payload.ap_register.ap_timeout;
6534100cc5fSmartijn 	timeout = timeout != 0 ? timeout : session->sess_timeout != 0 ?
6544100cc5fSmartijn 	    session->sess_timeout : AGENTX_DEFAULTTIMEOUT;
6554100cc5fSmartijn 	timeout *= 100;
6564100cc5fSmartijn 
6571985d3ebSmartijn 	if (session->sess_conn->conn_backend) {
6581985d3ebSmartijn 		pdu->ap_payload.ap_register.ap_priority = 1;
6591985d3ebSmartijn 		subtree = 1;
6601985d3ebSmartijn 	}
6614100cc5fSmartijn 	if (appl_agentx_oid2ber_oid(
6624100cc5fSmartijn 	    &(pdu->ap_payload.ap_register.ap_subtree), &oid) == NULL) {
6634100cc5fSmartijn 		log_warnx("%s: Failed to register: oid too small",
6644100cc5fSmartijn 		    session->sess_backend.ab_name);
6654100cc5fSmartijn 		error = APPL_ERROR_PROCESSINGERROR;
6664100cc5fSmartijn 		goto fail;
6674100cc5fSmartijn 	}
6684100cc5fSmartijn 
6694100cc5fSmartijn 	error = appl_register(pdu->ap_context.aos_string, timeout,
6704100cc5fSmartijn 	    pdu->ap_payload.ap_register.ap_priority, &oid,
6711985d3ebSmartijn 	    pdu->ap_header.aph_flags & AX_PDU_FLAG_INSTANCE_REGISTRATION,
6721985d3ebSmartijn 	    subtree, pdu->ap_payload.ap_register.ap_range_subid,
6734100cc5fSmartijn 	    pdu->ap_payload.ap_register.ap_upper_bound,
6744100cc5fSmartijn 	    &(session->sess_backend));
6754100cc5fSmartijn 
6764100cc5fSmartijn  fail:
6774100cc5fSmartijn 	ax_response(session->sess_conn->conn_ax, session->sess_id,
6784100cc5fSmartijn 	    pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,
6796f5d9364Smartijn 	    smi_getticks(), error, 0, NULL, 0);
680eb6ea173Smartijn 	event_add(&(session->sess_conn->conn_wev), NULL);
6814100cc5fSmartijn }
6824100cc5fSmartijn 
6834100cc5fSmartijn void
appl_agentx_unregister(struct appl_agentx_session * session,struct ax_pdu * pdu)6844100cc5fSmartijn appl_agentx_unregister(struct appl_agentx_session *session, struct ax_pdu *pdu)
6854100cc5fSmartijn {
6864100cc5fSmartijn 	struct ber_oid oid;
6874100cc5fSmartijn 	enum appl_error error;
6884100cc5fSmartijn 
6894100cc5fSmartijn 	if (appl_agentx_oid2ber_oid(
6904100cc5fSmartijn 	    &(pdu->ap_payload.ap_unregister.ap_subtree), &oid) == NULL) {
6914100cc5fSmartijn 		log_warnx("%s: Failed to unregister: oid too small",
6924100cc5fSmartijn 		    session->sess_backend.ab_name);
6934100cc5fSmartijn 		error = APPL_ERROR_PROCESSINGERROR;
6944100cc5fSmartijn 		goto fail;
6954100cc5fSmartijn 	}
6964100cc5fSmartijn 
6974100cc5fSmartijn 	error = appl_unregister(pdu->ap_context.aos_string,
6984100cc5fSmartijn 	    pdu->ap_payload.ap_unregister.ap_priority, &oid,
6994100cc5fSmartijn 	    pdu->ap_payload.ap_unregister.ap_range_subid,
7004100cc5fSmartijn 	    pdu->ap_payload.ap_unregister.ap_upper_bound,
7014100cc5fSmartijn 	    &(session->sess_backend));
7024100cc5fSmartijn 
7034100cc5fSmartijn  fail:
7044100cc5fSmartijn 	ax_response(session->sess_conn->conn_ax, session->sess_id,
7054100cc5fSmartijn 	    pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,
7066f5d9364Smartijn 	    smi_getticks(), error, 0, NULL, 0);
707eb6ea173Smartijn 	event_add(&(session->sess_conn->conn_wev), NULL);
7084100cc5fSmartijn }
7094100cc5fSmartijn 
7104100cc5fSmartijn #define AX_PDU_FLAG_INDEX (AX_PDU_FLAG_NEW_INDEX | AX_PDU_FLAG_ANY_INDEX)
7114100cc5fSmartijn 
7124100cc5fSmartijn void
appl_agentx_get(struct appl_backend * backend,int32_t transactionid,int32_t requestid,const char * ctx,struct appl_varbind * vblist)7134100cc5fSmartijn appl_agentx_get(struct appl_backend *backend, int32_t transactionid,
7144100cc5fSmartijn     int32_t requestid, const char *ctx, struct appl_varbind *vblist)
7154100cc5fSmartijn {
7164100cc5fSmartijn 	struct appl_agentx_session *session = backend->ab_cookie;
7174100cc5fSmartijn 	struct ax_ostring *context, string;
7184100cc5fSmartijn 	struct appl_varbind *vb;
7194100cc5fSmartijn 	struct ax_searchrange *srl;
7204100cc5fSmartijn 	size_t i, j, nsr;
7214100cc5fSmartijn 
722fe6f1a99Smartijn 	if (session->sess_conn->conn_ax == NULL)
723fe6f1a99Smartijn 		return;
724fe6f1a99Smartijn 
7254100cc5fSmartijn 	for (nsr = 0, vb = vblist; vb != NULL; vb = vb->av_next)
7264100cc5fSmartijn 		nsr++;
7274100cc5fSmartijn 
7284100cc5fSmartijn 	if ((srl = calloc(nsr, sizeof(*srl))) == NULL) {
7294100cc5fSmartijn 		log_warn(NULL);
7304100cc5fSmartijn 		appl_response(backend, requestid, APPL_ERROR_GENERR, 1, vblist);
7314100cc5fSmartijn 		return;
7324100cc5fSmartijn 	}
7334100cc5fSmartijn 
7344100cc5fSmartijn 	for (i = 0, vb = vblist; i < nsr; i++, vb = vb->av_next) {
7354100cc5fSmartijn 		srl[i].asr_start.aoi_include = vb->av_include;
7364100cc5fSmartijn 		srl[i].asr_start.aoi_idlen = vb->av_oid.bo_n;
7374100cc5fSmartijn 		for (j = 0; j < vb->av_oid.bo_n; j++)
7384100cc5fSmartijn 			srl[i].asr_start.aoi_id[j] = vb->av_oid.bo_id[j];
7394100cc5fSmartijn 		srl[i].asr_stop.aoi_include = 0;
7404100cc5fSmartijn 		srl[i].asr_stop.aoi_idlen = 0;
7414100cc5fSmartijn 	}
7424100cc5fSmartijn 	if ((context = appl_agentx_string2ostring(ctx, &string)) == NULL) {
7434100cc5fSmartijn 		if (errno != 0) {
7444100cc5fSmartijn 			log_warn("Failed to convert context");
7454100cc5fSmartijn 			appl_response(backend, requestid,
7464100cc5fSmartijn 			    APPL_ERROR_GENERR, 1, vblist);
7474100cc5fSmartijn 			free(srl);
7484100cc5fSmartijn 			return;
7494100cc5fSmartijn 		}
7504100cc5fSmartijn 	}
7514100cc5fSmartijn 
7524100cc5fSmartijn 	session->sess_conn->conn_ax->ax_byteorder = session->sess_byteorder;
7534100cc5fSmartijn 	if (ax_get(session->sess_conn->conn_ax, session->sess_id, transactionid,
7544100cc5fSmartijn 	    requestid, context, srl, nsr) == -1)
7554100cc5fSmartijn 		appl_response(backend, requestid, APPL_ERROR_GENERR, 1, vblist);
7564100cc5fSmartijn 	else
757eb6ea173Smartijn 		event_add(&(session->sess_conn->conn_wev), NULL);
7584100cc5fSmartijn 	free(srl);
7594100cc5fSmartijn 	if (context != NULL)
7604100cc5fSmartijn 		free(context->aos_string);
7614100cc5fSmartijn }
7624100cc5fSmartijn 
7634100cc5fSmartijn void
appl_agentx_getnext(struct appl_backend * backend,int32_t transactionid,int32_t requestid,const char * ctx,struct appl_varbind * vblist)7644100cc5fSmartijn appl_agentx_getnext(struct appl_backend *backend, int32_t transactionid,
7654100cc5fSmartijn     int32_t requestid, const char *ctx, struct appl_varbind *vblist)
7664100cc5fSmartijn {
7674100cc5fSmartijn 	struct appl_agentx_session *session = backend->ab_cookie;
7684100cc5fSmartijn 	struct ax_ostring *context, string;
7694100cc5fSmartijn 	struct appl_varbind *vb;
7704100cc5fSmartijn 	struct ax_searchrange *srl;
7714100cc5fSmartijn 	size_t i, j, nsr;
7724100cc5fSmartijn 
773fe6f1a99Smartijn 	if (session->sess_conn->conn_ax == NULL)
774fe6f1a99Smartijn 		return;
775fe6f1a99Smartijn 
7764100cc5fSmartijn 	for (nsr = 0, vb = vblist; vb != NULL; vb = vb->av_next)
7774100cc5fSmartijn 		nsr++;
7784100cc5fSmartijn 
7794100cc5fSmartijn 	if ((srl = calloc(nsr, sizeof(*srl))) == NULL) {
7804100cc5fSmartijn 		log_warn(NULL);
7814100cc5fSmartijn 		appl_response(backend, requestid, APPL_ERROR_GENERR, 1, vblist);
7824100cc5fSmartijn 		return;
7834100cc5fSmartijn 	}
7844100cc5fSmartijn 
7854100cc5fSmartijn 	for (i = 0, vb = vblist; i < nsr; i++, vb = vb->av_next) {
7864100cc5fSmartijn 		srl[i].asr_start.aoi_include = vb->av_include;
7874100cc5fSmartijn 		srl[i].asr_start.aoi_idlen = vb->av_oid.bo_n;
7884100cc5fSmartijn 		for (j = 0; j < vb->av_oid.bo_n; j++)
7894100cc5fSmartijn 			srl[i].asr_start.aoi_id[j] = vb->av_oid.bo_id[j];
7904100cc5fSmartijn 		srl[i].asr_stop.aoi_include = 0;
7914100cc5fSmartijn 		srl[i].asr_stop.aoi_idlen = vb->av_oid_end.bo_n;
7920601d079Smartijn 		for (j = 0; j < vb->av_oid_end.bo_n; j++)
7934100cc5fSmartijn 			srl[i].asr_stop.aoi_id[j] = vb->av_oid_end.bo_id[j];
7944100cc5fSmartijn 	}
7954100cc5fSmartijn 	if ((context = appl_agentx_string2ostring(ctx, &string)) == NULL) {
7964100cc5fSmartijn 		if (errno != 0) {
7974100cc5fSmartijn 			log_warn("Failed to convert context");
7984100cc5fSmartijn 			appl_response(backend, requestid,
7994100cc5fSmartijn 			    APPL_ERROR_GENERR, 1, vblist);
8004100cc5fSmartijn 			free(srl);
8014100cc5fSmartijn 			return;
8024100cc5fSmartijn 		}
8034100cc5fSmartijn 	}
8044100cc5fSmartijn 
8054100cc5fSmartijn 	session->sess_conn->conn_ax->ax_byteorder = session->sess_byteorder;
8064100cc5fSmartijn 	if (ax_getnext(session->sess_conn->conn_ax, session->sess_id, transactionid,
8074100cc5fSmartijn 	    requestid, context, srl, nsr) == -1)
8084100cc5fSmartijn 		appl_response(backend, requestid, APPL_ERROR_GENERR, 1, vblist);
8094100cc5fSmartijn 	else
810eb6ea173Smartijn 		event_add(&(session->sess_conn->conn_wev), NULL);
8114100cc5fSmartijn 	free(srl);
8124100cc5fSmartijn 	if (context != NULL)
8134100cc5fSmartijn 		free(context->aos_string);
8144100cc5fSmartijn }
8154100cc5fSmartijn 
8164100cc5fSmartijn void
appl_agentx_addagentcaps(struct appl_agentx_session * session,struct ax_pdu * pdu)8179bbbacf6Smartijn appl_agentx_addagentcaps(struct appl_agentx_session *session,
8189bbbacf6Smartijn     struct ax_pdu *pdu)
8199bbbacf6Smartijn {
8209bbbacf6Smartijn 	struct ber_oid oid;
8219bbbacf6Smartijn 	enum appl_error error;
8229bbbacf6Smartijn 
8239bbbacf6Smartijn 	if (appl_agentx_oid2ber_oid(&(pdu->ap_payload.ap_addagentcaps.ap_oid),
8249bbbacf6Smartijn 	    &oid) == NULL) {
8259bbbacf6Smartijn 		log_warnx("%s: Failed to add agent capabilities: oid too small",
8269bbbacf6Smartijn 		    session->sess_backend.ab_name);
8279bbbacf6Smartijn 		error = APPL_ERROR_PARSEERROR;
8289bbbacf6Smartijn 		goto fail;
8299bbbacf6Smartijn 	}
8309bbbacf6Smartijn 
8319bbbacf6Smartijn 	error = appl_addagentcaps(pdu->ap_context.aos_string, &oid,
8329bbbacf6Smartijn 	    pdu->ap_payload.ap_addagentcaps.ap_descr.aos_string,
8339bbbacf6Smartijn 	    &(session->sess_backend));
8349bbbacf6Smartijn 
8359bbbacf6Smartijn  fail:
8369bbbacf6Smartijn 	ax_response(session->sess_conn->conn_ax, session->sess_id,
8379bbbacf6Smartijn 	    pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,
8389bbbacf6Smartijn 	    smi_getticks(), error, 0, NULL, 0);
8399bbbacf6Smartijn 	event_add(&(session->sess_conn->conn_wev), NULL);
8409bbbacf6Smartijn }
8419bbbacf6Smartijn 
8429bbbacf6Smartijn void
appl_agentx_removeagentcaps(struct appl_agentx_session * session,struct ax_pdu * pdu)8439bbbacf6Smartijn appl_agentx_removeagentcaps(struct appl_agentx_session *session,
8449bbbacf6Smartijn     struct ax_pdu *pdu)
8459bbbacf6Smartijn {
8469bbbacf6Smartijn 	struct ber_oid oid;
8479bbbacf6Smartijn 	enum appl_error error;
8489bbbacf6Smartijn 
8499bbbacf6Smartijn 	if (appl_agentx_oid2ber_oid(&(pdu->ap_payload.ap_addagentcaps.ap_oid),
8509bbbacf6Smartijn 	    &oid) == NULL) {
8519bbbacf6Smartijn 		log_warnx("%s: Failed to remove agent capabilities: "
8529bbbacf6Smartijn 		    "oid too small", session->sess_backend.ab_name);
8539bbbacf6Smartijn 		error = APPL_ERROR_PARSEERROR;
8549bbbacf6Smartijn 		goto fail;
8559bbbacf6Smartijn 	}
8569bbbacf6Smartijn 
8579bbbacf6Smartijn 	error = appl_removeagentcaps(pdu->ap_context.aos_string, &oid,
8589bbbacf6Smartijn 	    &(session->sess_backend));
8599bbbacf6Smartijn 
8609bbbacf6Smartijn  fail:
8619bbbacf6Smartijn 	ax_response(session->sess_conn->conn_ax, session->sess_id,
8629bbbacf6Smartijn 	    pdu->ap_header.aph_transactionid, pdu->ap_header.aph_packetid,
8639bbbacf6Smartijn 	    smi_getticks(), error, 0, NULL, 0);
8649bbbacf6Smartijn 	event_add(&(session->sess_conn->conn_wev), NULL);
8659bbbacf6Smartijn }
8669bbbacf6Smartijn 
8679bbbacf6Smartijn void
appl_agentx_response(struct appl_agentx_session * session,struct ax_pdu * pdu)8684100cc5fSmartijn appl_agentx_response(struct appl_agentx_session *session, struct ax_pdu *pdu)
8694100cc5fSmartijn {
8704100cc5fSmartijn 	struct appl_varbind *response = NULL;
8714100cc5fSmartijn 	struct ax_varbind *vb;
8724100cc5fSmartijn 	enum appl_error error;
8734100cc5fSmartijn 	uint16_t index;
8744100cc5fSmartijn 	size_t i, nvarbind;
8754100cc5fSmartijn 
8764100cc5fSmartijn 	nvarbind = pdu->ap_payload.ap_response.ap_nvarbind;
8774100cc5fSmartijn 	if ((response = calloc(nvarbind, sizeof(*response))) == NULL) {
8784100cc5fSmartijn 		log_warn(NULL);
8794100cc5fSmartijn 		appl_response(&(session->sess_backend),
8804100cc5fSmartijn 		    pdu->ap_header.aph_packetid,
8814100cc5fSmartijn 		    APPL_ERROR_GENERR, 1, NULL);
8824100cc5fSmartijn 		return;
8834100cc5fSmartijn 	}
8844100cc5fSmartijn 
8854100cc5fSmartijn 	error = (enum appl_error)pdu->ap_payload.ap_response.ap_error;
8864100cc5fSmartijn 	index = pdu->ap_payload.ap_response.ap_index;
8874100cc5fSmartijn 	for (i = 0; i < nvarbind; i++) {
8884100cc5fSmartijn 		response[i].av_next = i + 1 == nvarbind ?
8894100cc5fSmartijn 		    NULL : &(response[i + 1]);
8904100cc5fSmartijn 		vb = &(pdu->ap_payload.ap_response.ap_varbindlist[i]);
8914100cc5fSmartijn 
8924100cc5fSmartijn 		if (appl_agentx_oid2ber_oid(&(vb->avb_oid),
8934100cc5fSmartijn 		    &(response[i].av_oid)) == NULL) {
8944100cc5fSmartijn 			log_warnx("%s: invalid oid",
8954100cc5fSmartijn 			    session->sess_backend.ab_name);
8964100cc5fSmartijn 			if (error != APPL_ERROR_NOERROR) {
8974100cc5fSmartijn 				error = APPL_ERROR_GENERR;
8984100cc5fSmartijn 				index = i + 1;
8994100cc5fSmartijn 			}
9004100cc5fSmartijn 			continue;
9014100cc5fSmartijn 		}
9024100cc5fSmartijn 		response[i].av_value = appl_agentx_value2ber_element(vb);
9034100cc5fSmartijn 		if (response[i].av_value == NULL) {
9044100cc5fSmartijn 			log_warn("%s: Failed to parse response value",
9054100cc5fSmartijn 			    session->sess_backend.ab_name);
9064100cc5fSmartijn 			if (error != APPL_ERROR_NOERROR) {
9074100cc5fSmartijn 				error = APPL_ERROR_GENERR;
9084100cc5fSmartijn 				index = i + 1;
9094100cc5fSmartijn 			}
9104100cc5fSmartijn 		}
9114100cc5fSmartijn 	}
9124100cc5fSmartijn 	appl_response(&(session->sess_backend), pdu->ap_header.aph_packetid,
9134100cc5fSmartijn 	    error, index, response);
9144100cc5fSmartijn 	free(response);
9154100cc5fSmartijn }
9164100cc5fSmartijn 
9174100cc5fSmartijn void
appl_agentx_send(int fd,short event,void * cookie)9184100cc5fSmartijn appl_agentx_send(int fd, short event, void *cookie)
9194100cc5fSmartijn {
9204100cc5fSmartijn 	struct appl_agentx_connection *conn = cookie;
9214100cc5fSmartijn 
9224100cc5fSmartijn 	switch (ax_send(conn->conn_ax)) {
9234100cc5fSmartijn 	case -1:
9244100cc5fSmartijn 		if (errno == EAGAIN)
9254100cc5fSmartijn 			break;
9264100cc5fSmartijn 		log_warn("AgentX(%"PRIu32")", conn->conn_id);
9274100cc5fSmartijn 		ax_free(conn->conn_ax);
9284100cc5fSmartijn 		conn->conn_ax = NULL;
929273d3fb0Smartijn 		appl_agentx_free(conn, APPL_CLOSE_REASONOTHER);
9304100cc5fSmartijn 		return;
9314100cc5fSmartijn 	case 0:
9324100cc5fSmartijn 		return;
9334100cc5fSmartijn 	default:
9344100cc5fSmartijn 		break;
9354100cc5fSmartijn 	}
9364100cc5fSmartijn 	event_add(&(conn->conn_wev), NULL);
9374100cc5fSmartijn }
9384100cc5fSmartijn 
9394100cc5fSmartijn struct ber_oid *
appl_agentx_oid2ber_oid(struct ax_oid * aoid,struct ber_oid * boid)9404100cc5fSmartijn appl_agentx_oid2ber_oid(struct ax_oid *aoid, struct ber_oid *boid)
9414100cc5fSmartijn {
9424100cc5fSmartijn 	size_t i;
9434100cc5fSmartijn 
9444100cc5fSmartijn 	if (aoid->aoi_idlen < BER_MIN_OID_LEN ||
9454100cc5fSmartijn 	    aoid->aoi_idlen > BER_MAX_OID_LEN) {
9464100cc5fSmartijn 		errno = EINVAL;
9474100cc5fSmartijn 		return NULL;
9484100cc5fSmartijn 	}
9494100cc5fSmartijn 
9504100cc5fSmartijn 
9514100cc5fSmartijn 	boid->bo_n = aoid->aoi_idlen;
9524100cc5fSmartijn 	for (i = 0; i < boid->bo_n; i++)
9534100cc5fSmartijn 		boid->bo_id[i] = aoid->aoi_id[i];
9544100cc5fSmartijn 	return boid;
9554100cc5fSmartijn }
9564100cc5fSmartijn 
9574100cc5fSmartijn struct ber_element *
appl_agentx_value2ber_element(struct ax_varbind * vb)9584100cc5fSmartijn appl_agentx_value2ber_element(struct ax_varbind *vb)
9594100cc5fSmartijn {
9604100cc5fSmartijn 	struct ber_oid oid;
9614100cc5fSmartijn 	struct ber_element *elm;
9624100cc5fSmartijn 
9634100cc5fSmartijn 	switch (vb->avb_type) {
9644100cc5fSmartijn 	case AX_DATA_TYPE_INTEGER:
9654100cc5fSmartijn 		return ober_add_integer(NULL, vb->avb_data.avb_int32);
9664100cc5fSmartijn 	case AX_DATA_TYPE_OCTETSTRING:
9674100cc5fSmartijn 		return ober_add_nstring(NULL,
9684100cc5fSmartijn 		    vb->avb_data.avb_ostring.aos_string,
9694100cc5fSmartijn 		    vb->avb_data.avb_ostring.aos_slen);
9704100cc5fSmartijn 	case AX_DATA_TYPE_NULL:
9714100cc5fSmartijn 		return ober_add_null(NULL);
9724100cc5fSmartijn 	case AX_DATA_TYPE_OID:
9734100cc5fSmartijn 		if (appl_agentx_oid2ber_oid(
9744100cc5fSmartijn 		    &(vb->avb_data.avb_oid), &oid) == NULL)
9754100cc5fSmartijn 			return NULL;
9764100cc5fSmartijn 		return ober_add_oid(NULL, &oid);
9774100cc5fSmartijn 	case AX_DATA_TYPE_IPADDRESS:
9784100cc5fSmartijn 		if ((elm = ober_add_nstring(NULL,
9794100cc5fSmartijn 		    vb->avb_data.avb_ostring.aos_string,
9804100cc5fSmartijn 		    vb->avb_data.avb_ostring.aos_slen)) == NULL)
9814100cc5fSmartijn 			return NULL;
9824100cc5fSmartijn 		ober_set_header(elm, BER_CLASS_APPLICATION, SNMP_T_IPADDR);
9834100cc5fSmartijn 		return elm;
9844100cc5fSmartijn 	case AX_DATA_TYPE_COUNTER32:
9854100cc5fSmartijn 		elm = ober_add_integer(NULL, vb->avb_data.avb_uint32);
9864100cc5fSmartijn 		if (elm == NULL)
9874100cc5fSmartijn 			return NULL;
9884100cc5fSmartijn 		ober_set_header(elm, BER_CLASS_APPLICATION, SNMP_T_COUNTER32);
9894100cc5fSmartijn 		return elm;
9904100cc5fSmartijn 	case AX_DATA_TYPE_GAUGE32:
9914100cc5fSmartijn 		elm = ober_add_integer(NULL, vb->avb_data.avb_uint32);
9924100cc5fSmartijn 		if (elm == NULL)
9934100cc5fSmartijn 			return NULL;
9944100cc5fSmartijn 		ober_set_header(elm, BER_CLASS_APPLICATION, SNMP_T_GAUGE32);
9954100cc5fSmartijn 		return elm;
9964100cc5fSmartijn 	case AX_DATA_TYPE_TIMETICKS:
9974100cc5fSmartijn 		elm = ober_add_integer(NULL, vb->avb_data.avb_uint32);
9984100cc5fSmartijn 		if (elm == NULL)
9994100cc5fSmartijn 			return NULL;
10004100cc5fSmartijn 		ober_set_header(elm, BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
10014100cc5fSmartijn 		return elm;
10024100cc5fSmartijn 	case AX_DATA_TYPE_OPAQUE:
10034100cc5fSmartijn 		if ((elm = ober_add_nstring(NULL,
10044100cc5fSmartijn 		    vb->avb_data.avb_ostring.aos_string,
10054100cc5fSmartijn 		    vb->avb_data.avb_ostring.aos_slen)) == NULL)
10064100cc5fSmartijn 			return NULL;
10074100cc5fSmartijn 		ober_set_header(elm, BER_CLASS_APPLICATION, SNMP_T_OPAQUE);
10084100cc5fSmartijn 		return elm;
10094100cc5fSmartijn 	case AX_DATA_TYPE_COUNTER64:
10104100cc5fSmartijn 		elm = ober_add_integer(NULL, vb->avb_data.avb_uint64);
10114100cc5fSmartijn 		if (elm == NULL)
10124100cc5fSmartijn 			return NULL;
10134100cc5fSmartijn 		ober_set_header(elm, BER_CLASS_APPLICATION, SNMP_T_COUNTER64);
10144100cc5fSmartijn 		return elm;
10154100cc5fSmartijn 	case AX_DATA_TYPE_NOSUCHOBJECT:
10164100cc5fSmartijn 		return appl_exception(APPL_EXC_NOSUCHOBJECT);
10174100cc5fSmartijn 	case AX_DATA_TYPE_NOSUCHINSTANCE:
10184100cc5fSmartijn 		return appl_exception(APPL_EXC_NOSUCHINSTANCE);
10194100cc5fSmartijn 	case AX_DATA_TYPE_ENDOFMIBVIEW:
10204100cc5fSmartijn 		return appl_exception(APPL_EXC_ENDOFMIBVIEW);
10214100cc5fSmartijn 	default:
10224100cc5fSmartijn 		errno = EINVAL;
10234100cc5fSmartijn 		return NULL;
10244100cc5fSmartijn 	}
10254100cc5fSmartijn }
10264100cc5fSmartijn 
10274100cc5fSmartijn struct ax_ostring *
appl_agentx_string2ostring(const char * str,struct ax_ostring * ostring)10284100cc5fSmartijn appl_agentx_string2ostring(const char *str, struct ax_ostring *ostring)
10294100cc5fSmartijn {
10304100cc5fSmartijn 	if (str == NULL) {
10314100cc5fSmartijn 		errno = 0;
10324100cc5fSmartijn 		return NULL;
10334100cc5fSmartijn 	}
10344100cc5fSmartijn 
10354100cc5fSmartijn 	ostring->aos_slen = strlen(str);
10364100cc5fSmartijn 	if ((ostring->aos_string = strdup(str)) == NULL)
10374100cc5fSmartijn 		return NULL;
10384100cc5fSmartijn 	return ostring;
10394100cc5fSmartijn }
10404100cc5fSmartijn 
10414100cc5fSmartijn int
appl_agentx_cmp(struct appl_agentx_connection * conn1,struct appl_agentx_connection * conn2)10424100cc5fSmartijn appl_agentx_cmp(struct appl_agentx_connection *conn1,
10434100cc5fSmartijn     struct appl_agentx_connection *conn2)
10444100cc5fSmartijn {
10454100cc5fSmartijn 	return conn1->conn_id < conn2->conn_id ? -1 :
10464100cc5fSmartijn 	    conn1->conn_id > conn2->conn_id;
10474100cc5fSmartijn }
10484100cc5fSmartijn 
10494100cc5fSmartijn int
appl_agentx_session_cmp(struct appl_agentx_session * sess1,struct appl_agentx_session * sess2)10504100cc5fSmartijn appl_agentx_session_cmp(struct appl_agentx_session *sess1,
10514100cc5fSmartijn     struct appl_agentx_session *sess2)
10524100cc5fSmartijn {
10534100cc5fSmartijn 	return sess1->sess_id < sess2->sess_id ? -1 : sess1->sess_id > sess2->sess_id;
10544100cc5fSmartijn }
10554100cc5fSmartijn 
10564100cc5fSmartijn RB_GENERATE_STATIC(appl_agentx_conns, appl_agentx_connection, conn_entry,
10574100cc5fSmartijn     appl_agentx_cmp);
10584100cc5fSmartijn RB_GENERATE_STATIC(appl_agentx_sessions, appl_agentx_session, sess_entry,
10594100cc5fSmartijn     appl_agentx_session_cmp);
1060