xref: /openbsd-src/usr.sbin/snmpd/ax.c (revision 5556c6a83211db11082a6959ba09fd95c58f5f6b)
1*5556c6a8Smartijn /*	$OpenBSD: ax.c,v 1.6 2024/02/20 12:51:10 martijn Exp $ */
24100cc5fSmartijn /*
34100cc5fSmartijn  * Copyright (c) 2019 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 #include <sys/socket.h>
184100cc5fSmartijn 
194100cc5fSmartijn #include <arpa/inet.h>
204100cc5fSmartijn 
214100cc5fSmartijn #include <ctype.h>
224100cc5fSmartijn #include <endian.h>
234100cc5fSmartijn #include <errno.h>
244100cc5fSmartijn #include <inttypes.h>
254100cc5fSmartijn #include <stdlib.h>
264100cc5fSmartijn #include <stdint.h>
274100cc5fSmartijn #include <stdio.h>
284100cc5fSmartijn #include <string.h>
294100cc5fSmartijn #include <unistd.h>
304100cc5fSmartijn 
314100cc5fSmartijn #include "ax.h"
324100cc5fSmartijn 
334100cc5fSmartijn #define AX_PDU_HEADER 20
344100cc5fSmartijn 
354100cc5fSmartijn static int ax_pdu_need(struct ax *, size_t);
364100cc5fSmartijn static int ax_pdu_header(struct ax *,
374100cc5fSmartijn     enum ax_pdu_type, uint8_t, uint32_t, uint32_t, uint32_t,
384100cc5fSmartijn     struct ax_ostring *);
394100cc5fSmartijn static uint32_t ax_pdu_queue(struct ax *);
404100cc5fSmartijn static int ax_pdu_add_uint16(struct ax *, uint16_t);
414100cc5fSmartijn static int ax_pdu_add_uint32(struct ax *, uint32_t);
424100cc5fSmartijn static int ax_pdu_add_uint64(struct ax *, uint64_t);
434100cc5fSmartijn static int ax_pdu_add_oid(struct ax *, struct ax_oid *);
444100cc5fSmartijn static int ax_pdu_add_str(struct ax *, struct ax_ostring *);
454100cc5fSmartijn static int ax_pdu_add_varbindlist(struct ax *, struct ax_varbind *,
464100cc5fSmartijn     size_t);
474100cc5fSmartijn static int ax_pdu_add_searchrange(struct ax *, struct ax_searchrange *);
484100cc5fSmartijn static uint16_t ax_pdutoh16(struct ax_pdu_header *, uint8_t *);
494100cc5fSmartijn static uint32_t ax_pdutoh32(struct ax_pdu_header *, uint8_t *);
504100cc5fSmartijn static uint64_t ax_pdutoh64(struct ax_pdu_header *, uint8_t *);
514100cc5fSmartijn static ssize_t ax_pdutooid(struct ax_pdu_header *, struct ax_oid *,
524100cc5fSmartijn     uint8_t *, size_t);
534100cc5fSmartijn static ssize_t ax_pdutoostring(struct ax_pdu_header *,
544100cc5fSmartijn     struct ax_ostring *, uint8_t *, size_t);
554100cc5fSmartijn static ssize_t ax_pdutovarbind(struct ax_pdu_header *,
564100cc5fSmartijn     struct ax_varbind *, uint8_t *, size_t);
574100cc5fSmartijn 
584100cc5fSmartijn struct ax *
ax_new(int fd)594100cc5fSmartijn ax_new(int fd)
604100cc5fSmartijn {
614100cc5fSmartijn 	struct ax *ax;
624100cc5fSmartijn 
634100cc5fSmartijn 	if (fd == -1) {
644100cc5fSmartijn 		errno = EINVAL;
654100cc5fSmartijn 		return NULL;
664100cc5fSmartijn 	}
674100cc5fSmartijn 
684100cc5fSmartijn 	if ((ax = calloc(1, sizeof(*ax))) == NULL)
694100cc5fSmartijn 		return NULL;
704100cc5fSmartijn 	ax->ax_fd = fd;
714100cc5fSmartijn 	ax->ax_rbsize = 512;
724100cc5fSmartijn 	if ((ax->ax_rbuf = malloc(ax->ax_rbsize)) == NULL)
734100cc5fSmartijn 		goto fail;
744100cc5fSmartijn 	ax->ax_byteorder = AX_BYTE_ORDER_NATIVE;
754100cc5fSmartijn 
764100cc5fSmartijn 	return ax;
774100cc5fSmartijn 
784100cc5fSmartijn fail:
794100cc5fSmartijn 	free(ax);
804100cc5fSmartijn 	return NULL;
814100cc5fSmartijn }
824100cc5fSmartijn 
834100cc5fSmartijn void
ax_free(struct ax * ax)844100cc5fSmartijn ax_free(struct ax *ax)
854100cc5fSmartijn {
864100cc5fSmartijn 	if (ax == NULL)
874100cc5fSmartijn 		return;
884100cc5fSmartijn 	close(ax->ax_fd);
894100cc5fSmartijn 	free(ax->ax_rbuf);
904100cc5fSmartijn 	free(ax->ax_wbuf);
914100cc5fSmartijn 	free(ax);
924100cc5fSmartijn }
934100cc5fSmartijn 
944100cc5fSmartijn struct ax_pdu *
ax_recv(struct ax * ax)954100cc5fSmartijn ax_recv(struct ax *ax)
964100cc5fSmartijn {
974100cc5fSmartijn 	struct ax_pdu *pdu;
984100cc5fSmartijn 	struct ax_pdu_header header;
994100cc5fSmartijn 	struct ax_pdu_response *response;
1004100cc5fSmartijn 	struct ax_varbind *varbind;
1014100cc5fSmartijn 	struct ax_pdu_searchrangelist *srl = NULL;
1024100cc5fSmartijn 	struct ax_pdu_varbindlist *vbl;
1034100cc5fSmartijn 	struct ax_searchrange *sr;
104*5556c6a8Smartijn 	size_t rbsize, rawlen;
1054100cc5fSmartijn 	ssize_t nread;
1064100cc5fSmartijn 	uint8_t *u8;
1074100cc5fSmartijn 	uint8_t *rbuf;
1084100cc5fSmartijn 
1094100cc5fSmartijn 	/* Only read a single packet at a time to make sure libevent triggers */
1104100cc5fSmartijn 	if (ax->ax_rblen < AX_PDU_HEADER) {
1114100cc5fSmartijn 		if ((nread = read(ax->ax_fd, ax->ax_rbuf + ax->ax_rblen,
1124100cc5fSmartijn 		    AX_PDU_HEADER - ax->ax_rblen)) == 0) {
1134100cc5fSmartijn 			errno = ECONNRESET;
1144100cc5fSmartijn 			return NULL;
1154100cc5fSmartijn 		}
1164100cc5fSmartijn 		if (nread == -1)
1174100cc5fSmartijn 			return NULL;
1184100cc5fSmartijn 		ax->ax_rblen += nread;
1194100cc5fSmartijn 		if (ax->ax_rblen < AX_PDU_HEADER) {
1204100cc5fSmartijn 			errno = EAGAIN;
1214100cc5fSmartijn 			return NULL;
1224100cc5fSmartijn 		}
1234100cc5fSmartijn 	}
1244100cc5fSmartijn 	u8 = ax->ax_rbuf;
1254100cc5fSmartijn 	header.aph_version = *u8++;
1264100cc5fSmartijn 	header.aph_type = *u8++;
1274100cc5fSmartijn 	header.aph_flags = *u8++;
1284100cc5fSmartijn 	u8++;
1294100cc5fSmartijn 	header.aph_sessionid = ax_pdutoh32(&header, u8);
1304100cc5fSmartijn 	u8 += 4;
1314100cc5fSmartijn 	header.aph_transactionid = ax_pdutoh32(&header, u8);
1324100cc5fSmartijn 	u8 += 4;
1334100cc5fSmartijn 	header.aph_packetid = ax_pdutoh32(&header, u8);
1344100cc5fSmartijn 	u8 += 4;
1354100cc5fSmartijn 	header.aph_plength = ax_pdutoh32(&header, u8);
1364100cc5fSmartijn 
1374100cc5fSmartijn 	if (header.aph_version != 1) {
1384100cc5fSmartijn 		errno = EPROTO;
1394100cc5fSmartijn 		return NULL;
1404100cc5fSmartijn 	}
1414100cc5fSmartijn 	if (ax->ax_rblen < AX_PDU_HEADER + header.aph_plength) {
1424100cc5fSmartijn 		if (AX_PDU_HEADER + header.aph_plength > ax->ax_rbsize) {
1434100cc5fSmartijn 			rbsize = (((AX_PDU_HEADER + header.aph_plength)
1444100cc5fSmartijn 			    / 512) + 1) * 512;
1454100cc5fSmartijn 			if ((rbuf = recallocarray(ax->ax_rbuf, ax->ax_rbsize,
1464100cc5fSmartijn 			    rbsize, sizeof(*rbuf))) == NULL)
1474100cc5fSmartijn 				return NULL;
1484100cc5fSmartijn 			ax->ax_rbsize = rbsize;
1494100cc5fSmartijn 			ax->ax_rbuf = rbuf;
1504100cc5fSmartijn 		}
1514100cc5fSmartijn 		nread = read(ax->ax_fd, ax->ax_rbuf + ax->ax_rblen,
1524100cc5fSmartijn 		    header.aph_plength - (ax->ax_rblen - AX_PDU_HEADER));
1534100cc5fSmartijn 		if (nread == 0)
1544100cc5fSmartijn 			errno = ECONNRESET;
1554100cc5fSmartijn 		if (nread <= 0)
1564100cc5fSmartijn 			return NULL;
1574100cc5fSmartijn 		ax->ax_rblen += nread;
1584100cc5fSmartijn 		if (ax->ax_rblen < AX_PDU_HEADER + header.aph_plength) {
1594100cc5fSmartijn 			errno = EAGAIN;
1604100cc5fSmartijn 			return NULL;
1614100cc5fSmartijn 		}
1624100cc5fSmartijn 	}
1634100cc5fSmartijn 
1644100cc5fSmartijn 	if ((pdu = calloc(1, sizeof(*pdu))) == NULL)
1654100cc5fSmartijn 		return NULL;
1664100cc5fSmartijn 
1674100cc5fSmartijn 	memcpy(&(pdu->ap_header), &header, sizeof(header));
1684100cc5fSmartijn 
1694100cc5fSmartijn #if defined(AX_DEBUG) && defined(AX_DEBUG_VERBOSE)
1704100cc5fSmartijn 	{
1714100cc5fSmartijn 		char chars[4];
1724100cc5fSmartijn 		int print = 1;
1734100cc5fSmartijn 
1744100cc5fSmartijn 		fprintf(stderr, "received packet:\n");
1754100cc5fSmartijn 		for (i = 0; i < pdu->ap_header.aph_plength + AX_PDU_HEADER;
1764100cc5fSmartijn 		    i++) {
1774100cc5fSmartijn 			fprintf(stderr, "%02hhx ", ax->ax_rbuf[i]);
1784100cc5fSmartijn 			chars[i % 4] = ax->ax_rbuf[i];
1794100cc5fSmartijn 			if (!isprint(ax->ax_rbuf[i]))
1804100cc5fSmartijn 				print = 0;
1814100cc5fSmartijn 			if (i % 4 == 3) {
1824100cc5fSmartijn 				if (print)
1834100cc5fSmartijn 					fprintf(stderr, "%.4s", chars);
1844100cc5fSmartijn 				fprintf(stderr, "\n");
1854100cc5fSmartijn 				print = 1;
1864100cc5fSmartijn 			}
1874100cc5fSmartijn 		}
1884100cc5fSmartijn 	}
1894100cc5fSmartijn #endif
1904100cc5fSmartijn 
1914100cc5fSmartijn 	u8 = (ax->ax_rbuf) + AX_PDU_HEADER;
1924100cc5fSmartijn 	rawlen = pdu->ap_header.aph_plength;
1934100cc5fSmartijn 	if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NON_DEFAULT_CONTEXT) {
1944100cc5fSmartijn 		nread = ax_pdutoostring(&header, &(pdu->ap_context), u8,
1954100cc5fSmartijn 		    rawlen);
1964100cc5fSmartijn 		if (nread == -1)
1974100cc5fSmartijn 			goto fail;
1984100cc5fSmartijn 		rawlen -= nread;
1994100cc5fSmartijn 		u8 += nread;
2004100cc5fSmartijn 	}
2014100cc5fSmartijn 
2024100cc5fSmartijn 	switch (pdu->ap_header.aph_type) {
2034100cc5fSmartijn 	case AX_PDU_TYPE_OPEN:
2044100cc5fSmartijn 		if (rawlen < 12) {
2054100cc5fSmartijn 			errno = EPROTO;
2064100cc5fSmartijn 			goto fail;
2074100cc5fSmartijn 		}
2084100cc5fSmartijn 		pdu->ap_payload.ap_open.ap_timeout = *u8;
2094100cc5fSmartijn 		rawlen -= 4;
2104100cc5fSmartijn 		u8 += 4;
2114100cc5fSmartijn 		if ((nread = ax_pdutooid(&header,
2124100cc5fSmartijn 		    &(pdu->ap_payload.ap_open.ap_oid), u8, rawlen)) == -1)
2134100cc5fSmartijn 			goto fail;
2144100cc5fSmartijn 		rawlen -= nread;
2154100cc5fSmartijn 		u8 += nread;
2164100cc5fSmartijn 		if ((nread = ax_pdutoostring(&header,
2174100cc5fSmartijn 		    &(pdu->ap_payload.ap_open.ap_descr), u8, rawlen)) == -1)
2184100cc5fSmartijn 			goto fail;
2194100cc5fSmartijn 		if (rawlen - nread != 0) {
2204100cc5fSmartijn 			errno = EPROTO;
2214100cc5fSmartijn 			goto fail;
2224100cc5fSmartijn 		}
2234100cc5fSmartijn 		break;
2244100cc5fSmartijn 	case AX_PDU_TYPE_CLOSE:
2254100cc5fSmartijn 		if (rawlen != 4) {
2264100cc5fSmartijn 			errno = EPROTO;
2274100cc5fSmartijn 			goto fail;
2284100cc5fSmartijn 		}
2294100cc5fSmartijn 		if (u8[0] != AX_CLOSE_OTHER &&
2304100cc5fSmartijn 		    u8[0] != AX_CLOSEN_PARSEERROR &&
2314100cc5fSmartijn 		    u8[0] != AX_CLOSE_PROTOCOLERROR &&
2324100cc5fSmartijn 		    u8[0] != AX_CLOSE_TIMEOUTS &&
2334100cc5fSmartijn 		    u8[0] != AX_CLOSE_SHUTDOWN &&
2344100cc5fSmartijn 		    u8[0] != AX_CLOSE_BYMANAGER) {
2354100cc5fSmartijn 			errno = EPROTO;
2364100cc5fSmartijn 			goto fail;
2374100cc5fSmartijn 		}
2384100cc5fSmartijn 		pdu->ap_payload.ap_close.ap_reason = u8[0];
2394100cc5fSmartijn 		break;
2404100cc5fSmartijn 	case AX_PDU_TYPE_REGISTER:
2414100cc5fSmartijn 		if (rawlen < 8) {
2424100cc5fSmartijn 			errno = EPROTO;
2434100cc5fSmartijn 			goto fail;
2444100cc5fSmartijn 		}
2454100cc5fSmartijn 		pdu->ap_payload.ap_register.ap_timeout = *u8++;
2464100cc5fSmartijn 		pdu->ap_payload.ap_register.ap_priority = *u8++;
2474100cc5fSmartijn 		pdu->ap_payload.ap_register.ap_range_subid = *u8++;
2484100cc5fSmartijn 		u8++;
2494100cc5fSmartijn 		rawlen -= 4;
2504100cc5fSmartijn 		if ((nread = ax_pdutooid(&header,
2514100cc5fSmartijn 		    &(pdu->ap_payload.ap_register.ap_subtree),
2524100cc5fSmartijn 		    u8, rawlen)) == -1)
2534100cc5fSmartijn 			goto fail;
2544100cc5fSmartijn 		rawlen -= nread;
2554100cc5fSmartijn 		u8 += nread;
2564100cc5fSmartijn 		if (pdu->ap_payload.ap_register.ap_range_subid) {
2574100cc5fSmartijn 			if (rawlen != 4) {
2584100cc5fSmartijn 				errno = EPROTO;
2594100cc5fSmartijn 				goto fail;
2604100cc5fSmartijn 			}
2614100cc5fSmartijn 			pdu->ap_payload.ap_register.ap_upper_bound =
2624100cc5fSmartijn 			    ax_pdutoh32(&header, u8);
2634100cc5fSmartijn 			rawlen -= 4;
2644100cc5fSmartijn 		}
2654100cc5fSmartijn 		if (rawlen != 0) {
2664100cc5fSmartijn 			errno = EPROTO;
2674100cc5fSmartijn 			goto fail;
2684100cc5fSmartijn 		}
2694100cc5fSmartijn 		break;
2704100cc5fSmartijn 	case AX_PDU_TYPE_UNREGISTER:
2714100cc5fSmartijn 		if (rawlen < 8) {
2724100cc5fSmartijn 			errno = EPROTO;
2734100cc5fSmartijn 			goto fail;
2744100cc5fSmartijn 		}
2754100cc5fSmartijn 		u8++;
2764100cc5fSmartijn 		pdu->ap_payload.ap_unregister.ap_priority = *u8++;
2774100cc5fSmartijn 		pdu->ap_payload.ap_unregister.ap_range_subid = *u8++;
2784100cc5fSmartijn 		u8++;
2794100cc5fSmartijn 		rawlen -= 4;
2804100cc5fSmartijn 		if ((nread = ax_pdutooid(&header,
2814100cc5fSmartijn 		    &(pdu->ap_payload.ap_unregister.ap_subtree),
2824100cc5fSmartijn 		    u8, rawlen)) == -1)
2834100cc5fSmartijn 			goto fail;
2844100cc5fSmartijn 		rawlen -= nread;
2854100cc5fSmartijn 		u8 += nread;
2864100cc5fSmartijn 		if (pdu->ap_payload.ap_unregister.ap_range_subid) {
2874100cc5fSmartijn 			if (rawlen != 4) {
2884100cc5fSmartijn 				errno = EPROTO;
2894100cc5fSmartijn 				goto fail;
2904100cc5fSmartijn 			}
2914100cc5fSmartijn 			pdu->ap_payload.ap_unregister.ap_upper_bound =
2924100cc5fSmartijn 			    ax_pdutoh32(&header, u8);
2934100cc5fSmartijn 			rawlen -= 4;
2944100cc5fSmartijn 		}
2954100cc5fSmartijn 		if (rawlen != 0) {
2964100cc5fSmartijn 			errno = EPROTO;
2974100cc5fSmartijn 			goto fail;
2984100cc5fSmartijn 		}
2994100cc5fSmartijn 		break;
3004100cc5fSmartijn 	case AX_PDU_TYPE_GETBULK:
3014100cc5fSmartijn 		if (rawlen < 4) {
3024100cc5fSmartijn 			errno = EPROTO;
3034100cc5fSmartijn 			goto fail;
3044100cc5fSmartijn 		}
3054100cc5fSmartijn 		pdu->ap_payload.ap_getbulk.ap_nonrep =
3064100cc5fSmartijn 		    ax_pdutoh16(&header, u8);
3074100cc5fSmartijn 		u8 += 2;
3084100cc5fSmartijn 		pdu->ap_payload.ap_getbulk.ap_maxrep =
3094100cc5fSmartijn 		    ax_pdutoh16(&header, u8);
3104100cc5fSmartijn 		u8 += 2;
3114100cc5fSmartijn 		srl = &(pdu->ap_payload.ap_getbulk.ap_srl);
3124100cc5fSmartijn 		rawlen -= 4;
3134100cc5fSmartijn 		/* FALLTHROUGH */
3144100cc5fSmartijn 	case AX_PDU_TYPE_GET:
3154100cc5fSmartijn 	case AX_PDU_TYPE_GETNEXT:
3164100cc5fSmartijn 		if (pdu->ap_header.aph_type != AX_PDU_TYPE_GETBULK)
3174100cc5fSmartijn 			srl = &(pdu->ap_payload.ap_srl);
3184100cc5fSmartijn 		while (rawlen > 0 ) {
3194100cc5fSmartijn 			srl->ap_nsr++;
3204100cc5fSmartijn 			sr = reallocarray(srl->ap_sr, srl->ap_nsr, sizeof(*sr));
3214100cc5fSmartijn 			if (sr == NULL)
3224100cc5fSmartijn 				goto fail;
3234100cc5fSmartijn 			srl->ap_sr = sr;
3244100cc5fSmartijn 			sr += (srl->ap_nsr - 1);
3254100cc5fSmartijn 			if ((nread = ax_pdutooid(&header, &(sr->asr_start),
3264100cc5fSmartijn 			    u8, rawlen)) == -1)
3274100cc5fSmartijn 				goto fail;
3284100cc5fSmartijn 			rawlen -= nread;
3294100cc5fSmartijn 			u8 += nread;
3304100cc5fSmartijn 			if ((nread = ax_pdutooid(&header, &(sr->asr_stop),
3314100cc5fSmartijn 			    u8, rawlen)) == -1)
3324100cc5fSmartijn 				goto fail;
3334100cc5fSmartijn 			rawlen -= nread;
3344100cc5fSmartijn 			u8 += nread;
3354100cc5fSmartijn 		}
3364100cc5fSmartijn 		break;
3374100cc5fSmartijn 	case AX_PDU_TYPE_TESTSET:
3384100cc5fSmartijn 	case AX_PDU_TYPE_INDEXALLOCATE:
3394100cc5fSmartijn 	case AX_PDU_TYPE_INDEXDEALLOCATE:
3404100cc5fSmartijn 	case AX_PDU_TYPE_NOTIFY:
3414100cc5fSmartijn 		vbl = &(pdu->ap_payload.ap_vbl);
3424100cc5fSmartijn 		while (rawlen > 0) {
3434100cc5fSmartijn 			varbind = recallocarray(vbl->ap_varbind,
3444100cc5fSmartijn 			    vbl->ap_nvarbind, vbl->ap_nvarbind + 1,
3454100cc5fSmartijn 			    sizeof(*(vbl->ap_varbind)));
3464100cc5fSmartijn 			if (varbind == NULL)
3474100cc5fSmartijn 				goto fail;
3484100cc5fSmartijn 			vbl->ap_varbind = varbind;
3494100cc5fSmartijn 			nread = ax_pdutovarbind(&header,
3504100cc5fSmartijn 			    &(vbl->ap_varbind[vbl->ap_nvarbind]), u8, rawlen);
3514100cc5fSmartijn 			if (nread == -1)
3524100cc5fSmartijn 				goto fail;
3534100cc5fSmartijn 			vbl->ap_nvarbind++;
3544100cc5fSmartijn 			u8 += nread;
3554100cc5fSmartijn 			rawlen -= nread;
3564100cc5fSmartijn 		}
3574100cc5fSmartijn 		break;
3584100cc5fSmartijn 	case AX_PDU_TYPE_COMMITSET:
3594100cc5fSmartijn 	case AX_PDU_TYPE_UNDOSET:
3604100cc5fSmartijn 	case AX_PDU_TYPE_CLEANUPSET:
3614100cc5fSmartijn 	case AX_PDU_TYPE_PING:
3624100cc5fSmartijn 		if (rawlen != 0) {
3634100cc5fSmartijn 			errno = EPROTO;
3644100cc5fSmartijn 			goto fail;
3654100cc5fSmartijn 		}
3664100cc5fSmartijn 		break;
3674100cc5fSmartijn 	case AX_PDU_TYPE_ADDAGENTCAPS:
3684100cc5fSmartijn 		nread = ax_pdutooid(&header,
3694100cc5fSmartijn 		    &(pdu->ap_payload.ap_addagentcaps.ap_oid), u8, rawlen);
3704100cc5fSmartijn 		if (nread == -1)
3714100cc5fSmartijn 			goto fail;
3724100cc5fSmartijn 		rawlen -= nread;
3734100cc5fSmartijn 		u8 += nread;
3744100cc5fSmartijn 		nread = ax_pdutoostring(&header,
3754100cc5fSmartijn 		    &(pdu->ap_payload.ap_addagentcaps.ap_descr), u8, rawlen);
3764100cc5fSmartijn 		if (nread == -1)
3774100cc5fSmartijn 			goto fail;
3784100cc5fSmartijn 		if (rawlen - nread != 0) {
3794100cc5fSmartijn 			errno = EPROTO;
3804100cc5fSmartijn 			goto fail;
3814100cc5fSmartijn 		}
3824100cc5fSmartijn 		break;
3834100cc5fSmartijn 	case AX_PDU_TYPE_REMOVEAGENTCAPS:
3844100cc5fSmartijn 		nread = ax_pdutooid(&header,
3854100cc5fSmartijn 		    &(pdu->ap_payload.ap_removeagentcaps.ap_oid), u8, rawlen);
3864100cc5fSmartijn 		if (nread == -1)
3874100cc5fSmartijn 			goto fail;
3884100cc5fSmartijn 		if (rawlen - nread != 0) {
3894100cc5fSmartijn 			errno = EPROTO;
3904100cc5fSmartijn 			goto fail;
3914100cc5fSmartijn 		}
3924100cc5fSmartijn 		break;
3934100cc5fSmartijn 	case AX_PDU_TYPE_RESPONSE:
3944100cc5fSmartijn 		if (rawlen < 8) {
3954100cc5fSmartijn 			errno = EPROTO;
3964100cc5fSmartijn 			goto fail;
3974100cc5fSmartijn 		}
3984100cc5fSmartijn 		response = &(pdu->ap_payload.ap_response);
3994100cc5fSmartijn 		response->ap_uptime = ax_pdutoh32(&header, u8);
4004100cc5fSmartijn 		u8 += 4;
4014100cc5fSmartijn 		response->ap_error = ax_pdutoh16(&header, u8);
4024100cc5fSmartijn 		u8 += 2;
4034100cc5fSmartijn 		response->ap_index = ax_pdutoh16(&header, u8);
4044100cc5fSmartijn 		u8 += 2;
4054100cc5fSmartijn 		rawlen -= 8;
4064100cc5fSmartijn 		while (rawlen > 0) {
4074100cc5fSmartijn 			varbind = recallocarray(response->ap_varbindlist,
4084100cc5fSmartijn 			    response->ap_nvarbind, response->ap_nvarbind + 1,
4094100cc5fSmartijn 			    sizeof(*(response->ap_varbindlist)));
4104100cc5fSmartijn 			if (varbind == NULL)
4114100cc5fSmartijn 				goto fail;
4124100cc5fSmartijn 			response->ap_varbindlist = varbind;
4134100cc5fSmartijn 			nread = ax_pdutovarbind(&header,
4144100cc5fSmartijn 			    &(response->ap_varbindlist[response->ap_nvarbind]),
4154100cc5fSmartijn 			    u8, rawlen);
4164100cc5fSmartijn 			if (nread == -1)
4174100cc5fSmartijn 				goto fail;
4184100cc5fSmartijn 			response->ap_nvarbind++;
4194100cc5fSmartijn 			u8 += nread;
4204100cc5fSmartijn 			rawlen -= nread;
4214100cc5fSmartijn 		}
4224100cc5fSmartijn 		break;
4234100cc5fSmartijn 	default:
4244100cc5fSmartijn 		errno = EPROTO;
4254100cc5fSmartijn 		goto fail;
4264100cc5fSmartijn 	}
4274100cc5fSmartijn 
4284100cc5fSmartijn 	ax->ax_rblen = 0;
4294100cc5fSmartijn 
4304100cc5fSmartijn 	return pdu;
4314100cc5fSmartijn fail:
4324100cc5fSmartijn 	ax_pdu_free(pdu);
4334100cc5fSmartijn 	return NULL;
4344100cc5fSmartijn }
4354100cc5fSmartijn 
4364100cc5fSmartijn static int
ax_pdu_need(struct ax * ax,size_t need)4374100cc5fSmartijn ax_pdu_need(struct ax *ax, size_t need)
4384100cc5fSmartijn {
4394100cc5fSmartijn 	uint8_t *wbuf;
4404100cc5fSmartijn 	size_t wbsize;
4414100cc5fSmartijn 
4424100cc5fSmartijn 	if (ax->ax_wbtlen + need >= ax->ax_wbsize) {
4434100cc5fSmartijn 		wbsize = (((ax->ax_wbtlen + need) / 512) + 1) * 512;
4444100cc5fSmartijn 		wbuf = recallocarray(ax->ax_wbuf, ax->ax_wbsize, wbsize, 1);
4454100cc5fSmartijn 		if (wbuf == NULL) {
4464100cc5fSmartijn 			ax->ax_wbtlen = ax->ax_wblen;
4474100cc5fSmartijn 			return -1;
4484100cc5fSmartijn 		}
4494100cc5fSmartijn 		ax->ax_wbsize = wbsize;
4504100cc5fSmartijn 		ax->ax_wbuf = wbuf;
4514100cc5fSmartijn 	}
4524100cc5fSmartijn 
4534100cc5fSmartijn 	return 0;
4544100cc5fSmartijn }
4554100cc5fSmartijn 
4564100cc5fSmartijn ssize_t
ax_send(struct ax * ax)4574100cc5fSmartijn ax_send(struct ax *ax)
4584100cc5fSmartijn {
4594100cc5fSmartijn 	ssize_t nwrite;
4604100cc5fSmartijn 
4614100cc5fSmartijn 	if (ax->ax_wblen != ax->ax_wbtlen) {
4624100cc5fSmartijn 		errno = EALREADY;
4634100cc5fSmartijn 		return -1;
4644100cc5fSmartijn 	}
4654100cc5fSmartijn 
4664100cc5fSmartijn 	if (ax->ax_wblen == 0)
4674100cc5fSmartijn 		return 0;
4684100cc5fSmartijn 
4694100cc5fSmartijn #if defined(AX_DEBUG) && defined(AX_DEBUG_VERBOSE)
4704100cc5fSmartijn 	{
4714100cc5fSmartijn 		size_t i;
4724100cc5fSmartijn 		char chars[4];
4734100cc5fSmartijn 		int print = 1;
4744100cc5fSmartijn 
4754100cc5fSmartijn 		fprintf(stderr, "sending packet:\n");
4764100cc5fSmartijn 		for (i = 0; i < ax->ax_wblen; i++) {
4774100cc5fSmartijn 			fprintf(stderr, "%02hhx ", ax->ax_wbuf[i]);
4784100cc5fSmartijn 			chars[i % 4] = ax->ax_wbuf[i];
4794100cc5fSmartijn 			if (!isprint(ax->ax_wbuf[i]))
4804100cc5fSmartijn 				print = 0;
4814100cc5fSmartijn 			if (i % 4 == 3) {
4824100cc5fSmartijn 				if (print)
4834100cc5fSmartijn 					fprintf(stderr, "%.4s", chars);
4844100cc5fSmartijn 				fprintf(stderr, "\n");
4854100cc5fSmartijn 				print = 1;
4864100cc5fSmartijn 			}
4874100cc5fSmartijn 		}
4884100cc5fSmartijn 	}
4894100cc5fSmartijn #endif
4904100cc5fSmartijn 
4914100cc5fSmartijn 	if ((nwrite = send(ax->ax_fd, ax->ax_wbuf, ax->ax_wblen,
4924100cc5fSmartijn 	    MSG_NOSIGNAL | MSG_DONTWAIT)) == -1)
4934100cc5fSmartijn 		return -1;
4944100cc5fSmartijn 
4954100cc5fSmartijn 	memmove(ax->ax_wbuf, ax->ax_wbuf + nwrite, ax->ax_wblen - nwrite);
4964100cc5fSmartijn 	ax->ax_wblen -= nwrite;
4974100cc5fSmartijn 	ax->ax_wbtlen = ax->ax_wblen;
4984100cc5fSmartijn 
4994100cc5fSmartijn 	return ax->ax_wblen;
5004100cc5fSmartijn }
5014100cc5fSmartijn 
5024100cc5fSmartijn uint32_t
ax_open(struct ax * ax,uint8_t timeout,struct ax_oid * oid,struct ax_ostring * descr)5034100cc5fSmartijn ax_open(struct ax *ax, uint8_t timeout, struct ax_oid *oid,
5044100cc5fSmartijn     struct ax_ostring *descr)
5054100cc5fSmartijn {
5064100cc5fSmartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_OPEN, 0, 0, 0, 0,
5074100cc5fSmartijn 	    NULL) == -1)
5084100cc5fSmartijn 		return 0;
5094100cc5fSmartijn 	ax_pdu_need(ax, 4);
5104100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = timeout;
5114100cc5fSmartijn 	memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 3);
5124100cc5fSmartijn 	ax->ax_wbtlen += 3;
5134100cc5fSmartijn 	if (ax_pdu_add_oid(ax, oid) == -1)
5144100cc5fSmartijn 		return 0;
5154100cc5fSmartijn 	if (ax_pdu_add_str(ax, descr) == -1)
5164100cc5fSmartijn 		return 0;
5174100cc5fSmartijn 
5184100cc5fSmartijn 	return ax_pdu_queue(ax);
5194100cc5fSmartijn }
5204100cc5fSmartijn 
5214100cc5fSmartijn uint32_t
ax_close(struct ax * ax,uint32_t sessionid,enum ax_close_reason reason)5224100cc5fSmartijn ax_close(struct ax *ax, uint32_t sessionid,
5234100cc5fSmartijn     enum ax_close_reason reason)
5244100cc5fSmartijn {
525b26e5074Smartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_CLOSE, 0, sessionid, arc4random(), 0,
5264100cc5fSmartijn 	    NULL) == -1)
5274100cc5fSmartijn 		return 0;
5284100cc5fSmartijn 
5294100cc5fSmartijn 	if (ax_pdu_need(ax, 4) == -1)
5304100cc5fSmartijn 		return 0;
5314100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = (uint8_t)reason;
5324100cc5fSmartijn 	memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 3);
5334100cc5fSmartijn 	ax->ax_wbtlen += 3;
5344100cc5fSmartijn 
5354100cc5fSmartijn 	return ax_pdu_queue(ax);
5364100cc5fSmartijn }
5374100cc5fSmartijn 
5384100cc5fSmartijn int
ax_get(struct ax * ax,uint32_t sessionid,uint32_t transactionid,uint32_t packetid,struct ax_ostring * context,struct ax_searchrange * srl,size_t nsr)5394100cc5fSmartijn ax_get(struct ax *ax, uint32_t sessionid, uint32_t transactionid,
5404100cc5fSmartijn     uint32_t packetid, struct ax_ostring *context, struct ax_searchrange *srl,
5414100cc5fSmartijn     size_t nsr)
5424100cc5fSmartijn {
5434100cc5fSmartijn 	size_t i;
5444100cc5fSmartijn 
5454100cc5fSmartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_GET, 0, sessionid, transactionid,
5464100cc5fSmartijn 	    packetid, context) == -1)
5474100cc5fSmartijn 		return -1;
5484100cc5fSmartijn 
5494100cc5fSmartijn 	for (i = 0; i < nsr; i++) {
5504100cc5fSmartijn 		if (ax_pdu_add_searchrange(ax, &(srl[i])) == -1)
5514100cc5fSmartijn 			return 0;
5524100cc5fSmartijn 	}
5534100cc5fSmartijn 
5544100cc5fSmartijn 	return ax_pdu_queue(ax);
5554100cc5fSmartijn }
5564100cc5fSmartijn 
5574100cc5fSmartijn int
ax_getnext(struct ax * ax,uint32_t sessionid,uint32_t transactionid,uint32_t packetid,struct ax_ostring * context,struct ax_searchrange * srl,size_t nsr)5584100cc5fSmartijn ax_getnext(struct ax *ax, uint32_t sessionid, uint32_t transactionid,
5594100cc5fSmartijn     uint32_t packetid, struct ax_ostring *context, struct ax_searchrange *srl,
5604100cc5fSmartijn     size_t nsr)
5614100cc5fSmartijn {
5624100cc5fSmartijn 	size_t i;
5634100cc5fSmartijn 
5644100cc5fSmartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_GETNEXT, 0, sessionid, transactionid,
5654100cc5fSmartijn 	    packetid, context) == -1)
5664100cc5fSmartijn 		return -1;
5674100cc5fSmartijn 
5684100cc5fSmartijn 	for (i = 0; i < nsr; i++) {
5694100cc5fSmartijn 		if (ax_pdu_add_searchrange(ax, &(srl[i])) == -1)
5704100cc5fSmartijn 			return 0;
5714100cc5fSmartijn 	}
5724100cc5fSmartijn 
5734100cc5fSmartijn 	return ax_pdu_queue(ax);
5744100cc5fSmartijn }
5754100cc5fSmartijn 
5764100cc5fSmartijn uint32_t
ax_indexallocate(struct ax * ax,uint8_t flags,uint32_t sessionid,struct ax_ostring * context,struct ax_varbind * vblist,size_t nvb)5774100cc5fSmartijn ax_indexallocate(struct ax *ax, uint8_t flags, uint32_t sessionid,
5784100cc5fSmartijn     struct ax_ostring *context, struct ax_varbind *vblist, size_t nvb)
5794100cc5fSmartijn {
5804100cc5fSmartijn 	if (flags & ~(AX_PDU_FLAG_NEW_INDEX | AX_PDU_FLAG_ANY_INDEX)) {
5814100cc5fSmartijn 		errno = EINVAL;
5824100cc5fSmartijn 		return 0;
5834100cc5fSmartijn 	}
5844100cc5fSmartijn 
5854100cc5fSmartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_INDEXALLOCATE, flags,
5864100cc5fSmartijn 	    sessionid, 0, 0, context) == -1)
5874100cc5fSmartijn 		return 0;
5884100cc5fSmartijn 
5894100cc5fSmartijn 	if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1)
5904100cc5fSmartijn 		return 0;
5914100cc5fSmartijn 
5924100cc5fSmartijn 	return ax_pdu_queue(ax);
5934100cc5fSmartijn }
5944100cc5fSmartijn 
5954100cc5fSmartijn uint32_t
ax_indexdeallocate(struct ax * ax,uint32_t sessionid,struct ax_ostring * context,struct ax_varbind * vblist,size_t nvb)5964100cc5fSmartijn ax_indexdeallocate(struct ax *ax, uint32_t sessionid,
5974100cc5fSmartijn     struct ax_ostring *context, struct ax_varbind *vblist, size_t nvb)
5984100cc5fSmartijn {
5994100cc5fSmartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_INDEXDEALLOCATE, 0,
6004100cc5fSmartijn 	    sessionid, 0, 0, context) == -1)
6014100cc5fSmartijn 		return 0;
6024100cc5fSmartijn 
6034100cc5fSmartijn 	if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1)
6044100cc5fSmartijn 		return 0;
6054100cc5fSmartijn 
6064100cc5fSmartijn 	return ax_pdu_queue(ax);
6074100cc5fSmartijn }
6084100cc5fSmartijn 
6094100cc5fSmartijn uint32_t
ax_addagentcaps(struct ax * ax,uint32_t sessionid,struct ax_ostring * context,struct ax_oid * id,struct ax_ostring * descr)6104100cc5fSmartijn ax_addagentcaps(struct ax *ax, uint32_t sessionid,
6114100cc5fSmartijn     struct ax_ostring *context, struct ax_oid *id,
6124100cc5fSmartijn     struct ax_ostring *descr)
6134100cc5fSmartijn {
6144100cc5fSmartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_ADDAGENTCAPS, 0,
6154100cc5fSmartijn 	    sessionid, 0, 0, context) == -1)
6164100cc5fSmartijn 		return 0;
6174100cc5fSmartijn 	if (ax_pdu_add_oid(ax, id) == -1)
6184100cc5fSmartijn 		return 0;
6194100cc5fSmartijn 	if (ax_pdu_add_str(ax, descr) == -1)
6204100cc5fSmartijn 		return 0;
6214100cc5fSmartijn 
6224100cc5fSmartijn 	return ax_pdu_queue(ax);
6234100cc5fSmartijn }
6244100cc5fSmartijn 
6254100cc5fSmartijn uint32_t
ax_removeagentcaps(struct ax * ax,uint32_t sessionid,struct ax_ostring * context,struct ax_oid * id)6264100cc5fSmartijn ax_removeagentcaps(struct ax *ax, uint32_t sessionid,
6274100cc5fSmartijn     struct ax_ostring *context, struct ax_oid *id)
6284100cc5fSmartijn {
6294100cc5fSmartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_REMOVEAGENTCAPS, 0,
6304100cc5fSmartijn 	    sessionid, 0, 0, context) == -1)
6314100cc5fSmartijn 		return 0;
6324100cc5fSmartijn 	if (ax_pdu_add_oid(ax, id) == -1)
6334100cc5fSmartijn 		return 0;
6344100cc5fSmartijn 
6354100cc5fSmartijn 	return ax_pdu_queue(ax);
6364100cc5fSmartijn 
6374100cc5fSmartijn }
6384100cc5fSmartijn 
6394100cc5fSmartijn uint32_t
ax_register(struct ax * ax,uint8_t flags,uint32_t sessionid,struct ax_ostring * context,uint8_t timeout,uint8_t priority,uint8_t range_subid,struct ax_oid * subtree,uint32_t upperbound)6404100cc5fSmartijn ax_register(struct ax *ax, uint8_t flags, uint32_t sessionid,
6414100cc5fSmartijn     struct ax_ostring *context, uint8_t timeout, uint8_t priority,
6424100cc5fSmartijn     uint8_t range_subid, struct ax_oid *subtree, uint32_t upperbound)
6434100cc5fSmartijn {
6444100cc5fSmartijn 	if (flags & ~(AX_PDU_FLAG_INSTANCE_REGISTRATION)) {
6454100cc5fSmartijn 		errno = EINVAL;
6464100cc5fSmartijn 		return 0;
6474100cc5fSmartijn 	}
6484100cc5fSmartijn 
6494100cc5fSmartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_REGISTER, flags,
6504100cc5fSmartijn 	    sessionid, 0, 0, context) == -1)
6514100cc5fSmartijn 		return 0;
6524100cc5fSmartijn 
6534100cc5fSmartijn 	if (ax_pdu_need(ax, 4) == -1)
6544100cc5fSmartijn 		return 0;
6554100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = timeout;
6564100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = priority;
6574100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = range_subid;
6584100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = 0;
6594100cc5fSmartijn 	if (ax_pdu_add_oid(ax, subtree) == -1)
6604100cc5fSmartijn 		return 0;
6614100cc5fSmartijn 	if (range_subid != 0) {
6624100cc5fSmartijn 		if (ax_pdu_add_uint32(ax, upperbound) == -1)
6634100cc5fSmartijn 			return 0;
6644100cc5fSmartijn 	}
6654100cc5fSmartijn 
6664100cc5fSmartijn 	return ax_pdu_queue(ax);
6674100cc5fSmartijn }
6684100cc5fSmartijn 
6694100cc5fSmartijn uint32_t
ax_unregister(struct ax * ax,uint32_t sessionid,struct ax_ostring * context,uint8_t priority,uint8_t range_subid,struct ax_oid * subtree,uint32_t upperbound)6704100cc5fSmartijn ax_unregister(struct ax *ax, uint32_t sessionid,
6714100cc5fSmartijn     struct ax_ostring *context, uint8_t priority, uint8_t range_subid,
6724100cc5fSmartijn     struct ax_oid *subtree, uint32_t upperbound)
6734100cc5fSmartijn {
6744100cc5fSmartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_UNREGISTER, 0,
6754100cc5fSmartijn 	    sessionid, 0, 0, context) == -1)
6764100cc5fSmartijn 		return 0;
6774100cc5fSmartijn 
6784100cc5fSmartijn 	if (ax_pdu_need(ax, 4) == -1)
6794100cc5fSmartijn 		return 0;
6804100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = 0;
6814100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = priority;
6824100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = range_subid;
6834100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = 0;
6844100cc5fSmartijn 	if (ax_pdu_add_oid(ax, subtree) == -1)
6854100cc5fSmartijn 		return 0;
6864100cc5fSmartijn 	if (range_subid != 0) {
6874100cc5fSmartijn 		if (ax_pdu_add_uint32(ax, upperbound) == -1)
6884100cc5fSmartijn 			return 0;
6894100cc5fSmartijn 	}
6904100cc5fSmartijn 
6914100cc5fSmartijn 	return ax_pdu_queue(ax);
6924100cc5fSmartijn }
6934100cc5fSmartijn 
6944100cc5fSmartijn int
ax_response(struct ax * ax,uint32_t sessionid,uint32_t transactionid,uint32_t packetid,uint32_t sysuptime,uint16_t error,uint16_t index,struct ax_varbind * vblist,size_t nvb)6954100cc5fSmartijn ax_response(struct ax *ax, uint32_t sessionid, uint32_t transactionid,
6966f5d9364Smartijn     uint32_t packetid, uint32_t sysuptime, uint16_t error, uint16_t index,
6976f5d9364Smartijn     struct ax_varbind *vblist, size_t nvb)
6984100cc5fSmartijn {
6994100cc5fSmartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_RESPONSE, 0, sessionid,
7006f5d9364Smartijn 	    transactionid, packetid, NULL) == -1)
7014100cc5fSmartijn 		return -1;
7024100cc5fSmartijn 
7034100cc5fSmartijn 	if (ax_pdu_add_uint32(ax, sysuptime) == -1 ||
7044100cc5fSmartijn 	    ax_pdu_add_uint16(ax, error) == -1 ||
7054100cc5fSmartijn 	    ax_pdu_add_uint16(ax, index) == -1)
7064100cc5fSmartijn 		return -1;
7074100cc5fSmartijn 
7084100cc5fSmartijn 	if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1)
7094100cc5fSmartijn 		return -1;
7104100cc5fSmartijn 	if (ax_pdu_queue(ax) == 0)
7114100cc5fSmartijn 		return -1;
7124100cc5fSmartijn 	return 0;
7134100cc5fSmartijn }
7144100cc5fSmartijn 
7154100cc5fSmartijn void
ax_pdu_free(struct ax_pdu * pdu)7164100cc5fSmartijn ax_pdu_free(struct ax_pdu *pdu)
7174100cc5fSmartijn {
7184100cc5fSmartijn 	size_t i;
7194100cc5fSmartijn 	struct ax_pdu_response *response;
7204100cc5fSmartijn 	struct ax_pdu_varbindlist *vblist;
7214100cc5fSmartijn 
7224100cc5fSmartijn 	if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NON_DEFAULT_CONTEXT)
7234100cc5fSmartijn 		free(pdu->ap_context.aos_string);
7244100cc5fSmartijn 
7254100cc5fSmartijn 	switch (pdu->ap_header.aph_type) {
7264100cc5fSmartijn 	case AX_PDU_TYPE_OPEN:
7274100cc5fSmartijn 		free(pdu->ap_payload.ap_open.ap_descr.aos_string);
7284100cc5fSmartijn 		break;
7294100cc5fSmartijn 	case AX_PDU_TYPE_GET:
7304100cc5fSmartijn 	case AX_PDU_TYPE_GETNEXT:
7314100cc5fSmartijn 	case AX_PDU_TYPE_GETBULK:
7324100cc5fSmartijn 		free(pdu->ap_payload.ap_srl.ap_sr);
7334100cc5fSmartijn 		break;
7344100cc5fSmartijn 	case AX_PDU_TYPE_TESTSET:
7354100cc5fSmartijn 	case AX_PDU_TYPE_INDEXALLOCATE:
7364100cc5fSmartijn 	case AX_PDU_TYPE_INDEXDEALLOCATE:
7374100cc5fSmartijn 		vblist = &(pdu->ap_payload.ap_vbl);
7384100cc5fSmartijn 		for (i = 0; i < vblist->ap_nvarbind; i++)
7394100cc5fSmartijn 			ax_varbind_free(&(vblist->ap_varbind[i]));
7404100cc5fSmartijn 		free(vblist->ap_varbind);
7414100cc5fSmartijn 		break;
7424100cc5fSmartijn 	case AX_PDU_TYPE_RESPONSE:
7434100cc5fSmartijn 		response = &(pdu->ap_payload.ap_response);
7444100cc5fSmartijn 		for (i = 0; i < response->ap_nvarbind; i++)
7454100cc5fSmartijn 			ax_varbind_free(&(response->ap_varbindlist[i]));
7464100cc5fSmartijn 		free(response->ap_varbindlist);
7474100cc5fSmartijn 		break;
7484100cc5fSmartijn 	default:
7494100cc5fSmartijn 		break;
7504100cc5fSmartijn 	}
7514100cc5fSmartijn 	free(pdu);
7524100cc5fSmartijn }
7534100cc5fSmartijn 
7544100cc5fSmartijn void
ax_varbind_free(struct ax_varbind * varbind)7554100cc5fSmartijn ax_varbind_free(struct ax_varbind *varbind)
7564100cc5fSmartijn {
7574100cc5fSmartijn 	switch (varbind->avb_type) {
7584100cc5fSmartijn 	case AX_DATA_TYPE_OCTETSTRING:
7594100cc5fSmartijn 	case AX_DATA_TYPE_IPADDRESS:
7604100cc5fSmartijn 	case AX_DATA_TYPE_OPAQUE:
7614100cc5fSmartijn 		free(varbind->avb_data.avb_ostring.aos_string);
7624100cc5fSmartijn 		break;
7634100cc5fSmartijn 	default:
7644100cc5fSmartijn 		break;
7654100cc5fSmartijn 	}
7664100cc5fSmartijn }
7674100cc5fSmartijn 
7684100cc5fSmartijn const char *
ax_error2string(enum ax_pdu_error error)7694100cc5fSmartijn ax_error2string(enum ax_pdu_error error)
7704100cc5fSmartijn {
7714100cc5fSmartijn 	static char buffer[64];
7724100cc5fSmartijn 	switch (error) {
7734100cc5fSmartijn 	case AX_PDU_ERROR_NOERROR:
7744100cc5fSmartijn 		return "No error";
7754100cc5fSmartijn 	case AX_PDU_ERROR_GENERR:
7764100cc5fSmartijn 		return "Generic error";
7774100cc5fSmartijn 	case AX_PDU_ERROR_NOACCESS:
7784100cc5fSmartijn 		return "No access";
7794100cc5fSmartijn 	case AX_PDU_ERROR_WRONGTYPE:
7804100cc5fSmartijn 		return "Wrong type";
7814100cc5fSmartijn 	case AX_PDU_ERROR_WRONGLENGTH:
7824100cc5fSmartijn 		return "Wrong length";
7834100cc5fSmartijn 	case AX_PDU_ERROR_WRONGENCODING:
7844100cc5fSmartijn 		return "Wrong encoding";
7854100cc5fSmartijn 	case AX_PDU_ERROR_WRONGVALUE:
7864100cc5fSmartijn 		return "Wrong value";
7874100cc5fSmartijn 	case AX_PDU_ERROR_NOCREATION:
7884100cc5fSmartijn 		return "No creation";
7894100cc5fSmartijn 	case AX_PDU_ERROR_INCONSISTENTVALUE:
7904100cc5fSmartijn 		return "Inconsistent value";
7914100cc5fSmartijn 	case AX_PDU_ERROR_RESOURCEUNAVAILABLE:
7924100cc5fSmartijn 		return "Resource unavailable";
7934100cc5fSmartijn 	case AX_PDU_ERROR_COMMITFAILED:
7944100cc5fSmartijn 		return "Commit failed";
7954100cc5fSmartijn 	case AX_PDU_ERROR_UNDOFAILED:
7964100cc5fSmartijn 		return "Undo failed";
7974100cc5fSmartijn 	case AX_PDU_ERROR_NOTWRITABLE:
7984100cc5fSmartijn 		return "Not writable";
7994100cc5fSmartijn 	case AX_PDU_ERROR_INCONSISTENTNAME:
8004100cc5fSmartijn 		return "Inconsistent name";
8014100cc5fSmartijn 	case AX_PDU_ERROR_OPENFAILED:
8024100cc5fSmartijn 		return "Open Failed";
8034100cc5fSmartijn 	case AX_PDU_ERROR_NOTOPEN:
8044100cc5fSmartijn 		return "Not open";
8054100cc5fSmartijn 	case AX_PDU_ERROR_INDEXWRONGTYPE:
8064100cc5fSmartijn 		return "Index wrong type";
8074100cc5fSmartijn 	case AX_PDU_ERROR_INDEXALREADYALLOCATED:
8084100cc5fSmartijn 		return "Index already allocated";
8094100cc5fSmartijn 	case AX_PDU_ERROR_INDEXNONEAVAILABLE:
8104100cc5fSmartijn 		return "Index none available";
8114100cc5fSmartijn 	case AX_PDU_ERROR_INDEXNOTALLOCATED:
8124100cc5fSmartijn 		return "Index not allocated";
8134100cc5fSmartijn 	case AX_PDU_ERROR_UNSUPPORTEDCONETXT:
8144100cc5fSmartijn 		return "Unsupported context";
8154100cc5fSmartijn 	case AX_PDU_ERROR_DUPLICATEREGISTRATION:
8164100cc5fSmartijn 		return "Duplicate registration";
8174100cc5fSmartijn 	case AX_PDU_ERROR_UNKNOWNREGISTRATION:
8184100cc5fSmartijn 		return "Unkown registration";
8194100cc5fSmartijn 	case AX_PDU_ERROR_UNKNOWNAGENTCAPS:
8204100cc5fSmartijn 		return "Unknown agent capabilities";
8214100cc5fSmartijn 	case AX_PDU_ERROR_PARSEERROR:
8224100cc5fSmartijn 		return "Parse error";
8234100cc5fSmartijn 	case AX_PDU_ERROR_REQUESTDENIED:
8244100cc5fSmartijn 		return "Request denied";
8254100cc5fSmartijn 	case AX_PDU_ERROR_PROCESSINGERROR:
8264100cc5fSmartijn 		return "Processing error";
8274100cc5fSmartijn 	}
8284100cc5fSmartijn 	snprintf(buffer, sizeof(buffer), "Unknown error: %d", error);
8294100cc5fSmartijn 	return buffer;
8304100cc5fSmartijn }
8314100cc5fSmartijn 
8324100cc5fSmartijn const char *
ax_pdutype2string(enum ax_pdu_type type)8334100cc5fSmartijn ax_pdutype2string(enum ax_pdu_type type)
8344100cc5fSmartijn {
8354100cc5fSmartijn 	static char buffer[64];
8364100cc5fSmartijn 	switch(type) {
8374100cc5fSmartijn 	case AX_PDU_TYPE_OPEN:
8384100cc5fSmartijn 		return "agentx-Open-PDU";
8394100cc5fSmartijn 	case AX_PDU_TYPE_CLOSE:
8404100cc5fSmartijn 		return "agentx-Close-PDU";
8414100cc5fSmartijn 	case AX_PDU_TYPE_REGISTER:
8424100cc5fSmartijn 		return "agentx-Register-PDU";
8434100cc5fSmartijn 	case AX_PDU_TYPE_UNREGISTER:
8444100cc5fSmartijn 		return "agentx-Unregister-PDU";
8454100cc5fSmartijn 	case AX_PDU_TYPE_GET:
8464100cc5fSmartijn 		return "agentx-Get-PDU";
8474100cc5fSmartijn 	case AX_PDU_TYPE_GETNEXT:
8484100cc5fSmartijn 		return "agentx-GetNext-PDU";
8494100cc5fSmartijn 	case AX_PDU_TYPE_GETBULK:
8504100cc5fSmartijn 		return "agentx-GetBulk-PDU";
8514100cc5fSmartijn 	case AX_PDU_TYPE_TESTSET:
8524100cc5fSmartijn 		return "agentx-TestSet-PDU";
8534100cc5fSmartijn 	case AX_PDU_TYPE_COMMITSET:
8544100cc5fSmartijn 		return "agentx-CommitSet-PDU";
8554100cc5fSmartijn 	case AX_PDU_TYPE_UNDOSET:
8564100cc5fSmartijn 		return "agentx-UndoSet-PDU";
8574100cc5fSmartijn 	case AX_PDU_TYPE_CLEANUPSET:
8584100cc5fSmartijn 		return "agentx-CleanupSet-PDU";
8594100cc5fSmartijn 	case AX_PDU_TYPE_NOTIFY:
8604100cc5fSmartijn 		return "agentx-Notify-PDU";
8614100cc5fSmartijn 	case AX_PDU_TYPE_PING:
8624100cc5fSmartijn 		return "agentx-Ping-PDU";
8634100cc5fSmartijn 	case AX_PDU_TYPE_INDEXALLOCATE:
8644100cc5fSmartijn 		return "agentx-IndexAllocate-PDU";
8654100cc5fSmartijn 	case AX_PDU_TYPE_INDEXDEALLOCATE:
8664100cc5fSmartijn 		return "agentx-IndexDeallocate-PDU";
8674100cc5fSmartijn 	case AX_PDU_TYPE_ADDAGENTCAPS:
8684100cc5fSmartijn 		return "agentx-AddAgentCaps-PDU";
8694100cc5fSmartijn 	case AX_PDU_TYPE_REMOVEAGENTCAPS:
8704100cc5fSmartijn 		return "agentx-RemoveAgentCaps-PDU";
8714100cc5fSmartijn 	case AX_PDU_TYPE_RESPONSE:
8724100cc5fSmartijn 		return "agentx-Response-PDU";
8734100cc5fSmartijn 	}
8744100cc5fSmartijn 	snprintf(buffer, sizeof(buffer), "Unknown type: %d", type);
8754100cc5fSmartijn 	return buffer;
8764100cc5fSmartijn }
8774100cc5fSmartijn 
8784100cc5fSmartijn const char *
ax_closereason2string(enum ax_close_reason reason)8794100cc5fSmartijn ax_closereason2string(enum ax_close_reason reason)
8804100cc5fSmartijn {
8814100cc5fSmartijn 	static char buffer[64];
8824100cc5fSmartijn 
8834100cc5fSmartijn 	switch (reason) {
8844100cc5fSmartijn 	case AX_CLOSE_OTHER:
8854100cc5fSmartijn 		return "Undefined reason";
8864100cc5fSmartijn 	case AX_CLOSEN_PARSEERROR:
8874100cc5fSmartijn 		return "Too many AgentX parse errors from peer";
8884100cc5fSmartijn 	case AX_CLOSE_PROTOCOLERROR:
8894100cc5fSmartijn 		return "Too many AgentX protocol errors from peer";
8904100cc5fSmartijn 	case AX_CLOSE_TIMEOUTS:
8914100cc5fSmartijn 		return "Too many timeouts waiting for peer";
8924100cc5fSmartijn 	case AX_CLOSE_SHUTDOWN:
8934100cc5fSmartijn 		return "shutting down";
8944100cc5fSmartijn 	case AX_CLOSE_BYMANAGER:
8954100cc5fSmartijn 		return "Manager shuts down";
8964100cc5fSmartijn 	}
8974100cc5fSmartijn 	snprintf(buffer, sizeof(buffer), "Unknown reason: %d", reason);
8984100cc5fSmartijn 	return buffer;
8994100cc5fSmartijn }
9004100cc5fSmartijn 
9014100cc5fSmartijn const char *
ax_oid2string(struct ax_oid * oid)9024100cc5fSmartijn ax_oid2string(struct ax_oid *oid)
9034100cc5fSmartijn {
9044100cc5fSmartijn 	return ax_oidrange2string(oid, 0, 0);
9054100cc5fSmartijn }
9064100cc5fSmartijn 
9074100cc5fSmartijn const char *
ax_oidrange2string(struct ax_oid * oid,uint8_t range_subid,uint32_t upperbound)9084100cc5fSmartijn ax_oidrange2string(struct ax_oid *oid, uint8_t range_subid,
9094100cc5fSmartijn     uint32_t upperbound)
9104100cc5fSmartijn {
9114100cc5fSmartijn 	static char buf[1024];
9124100cc5fSmartijn 	char *p;
9134100cc5fSmartijn 	size_t i, rest;
9144100cc5fSmartijn 	int ret;
9154100cc5fSmartijn 
9164100cc5fSmartijn 	rest = sizeof(buf);
9174100cc5fSmartijn 	p = buf;
9184100cc5fSmartijn 	for (i = 0; i < oid->aoi_idlen; i++) {
9194100cc5fSmartijn 		if (range_subid != 0 && range_subid - 1 == (uint8_t)i)
9204100cc5fSmartijn 			ret = snprintf(p, rest, ".[%u-%u]", oid->aoi_id[i],
9214100cc5fSmartijn 			    upperbound);
9224100cc5fSmartijn 		else
9234100cc5fSmartijn 			ret = snprintf(p, rest, ".%u", oid->aoi_id[i]);
9244100cc5fSmartijn 		if ((size_t) ret >= rest) {
9254100cc5fSmartijn 			snprintf(buf, sizeof(buf), "Couldn't parse oid");
9264100cc5fSmartijn 			return buf;
9274100cc5fSmartijn 		}
9284100cc5fSmartijn 		p += ret;
9294100cc5fSmartijn 		rest -= (size_t) ret;
9304100cc5fSmartijn 	}
9314100cc5fSmartijn 	return buf;
9324100cc5fSmartijn }
9334100cc5fSmartijn 
9344100cc5fSmartijn const char *
ax_varbind2string(struct ax_varbind * vb)9354100cc5fSmartijn ax_varbind2string(struct ax_varbind *vb)
9364100cc5fSmartijn {
9374100cc5fSmartijn 	static char buf[1024];
9384100cc5fSmartijn 	char tmpbuf[1024];
9394100cc5fSmartijn 	size_t i, bufleft;
9404100cc5fSmartijn 	int ishex = 0;
9414100cc5fSmartijn 	char *p;
9424100cc5fSmartijn 	int ret;
9434100cc5fSmartijn 
9444100cc5fSmartijn 	switch (vb->avb_type) {
9454100cc5fSmartijn 	case AX_DATA_TYPE_INTEGER:
9464100cc5fSmartijn 		snprintf(buf, sizeof(buf), "%s: (int)%d",
9474100cc5fSmartijn 		    ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_int32);
9484100cc5fSmartijn 		break;
9494100cc5fSmartijn 	case AX_DATA_TYPE_OCTETSTRING:
9504100cc5fSmartijn 		for (i = 0;
9514100cc5fSmartijn 		    i < vb->avb_data.avb_ostring.aos_slen && !ishex; i++) {
9524100cc5fSmartijn 			if (!isprint(vb->avb_data.avb_ostring.aos_string[i]))
9534100cc5fSmartijn 				ishex = 1;
9544100cc5fSmartijn 		}
9554100cc5fSmartijn 		if (ishex) {
9564100cc5fSmartijn 			p = tmpbuf;
9574100cc5fSmartijn 			bufleft = sizeof(tmpbuf);
9584100cc5fSmartijn 			for (i = 0;
9594100cc5fSmartijn 			    i < vb->avb_data.avb_ostring.aos_slen; i++) {
9604100cc5fSmartijn 				ret = snprintf(p, bufleft, " %02hhX",
9614100cc5fSmartijn 				    vb->avb_data.avb_ostring.aos_string[i]);
9624100cc5fSmartijn 				if (ret >= (int) bufleft) {
9634100cc5fSmartijn 					p = strrchr(p, ' ');
9644100cc5fSmartijn 					strlcpy(p, "...", 4);
9654100cc5fSmartijn 					break;
9664100cc5fSmartijn 				}
9674100cc5fSmartijn 				p += 3;
9684100cc5fSmartijn 				bufleft -= 3;
9694100cc5fSmartijn 			}
9704100cc5fSmartijn 			ret = snprintf(buf, sizeof(buf), "%s: (hex-string)%s",
9714100cc5fSmartijn 			    ax_oid2string(&(vb->avb_oid)), tmpbuf);
9724100cc5fSmartijn 			if (ret >= (int) sizeof(buf)) {
9734100cc5fSmartijn 				p  = strrchr(buf, ' ');
9744100cc5fSmartijn 				strlcpy(p, "...", 4);
9754100cc5fSmartijn 			}
9764100cc5fSmartijn 		} else {
9774100cc5fSmartijn 			ret = snprintf(buf, sizeof(buf), "%s: (string)",
9784100cc5fSmartijn 			    ax_oid2string(&(vb->avb_oid)));
9794100cc5fSmartijn 			if (ret >= (int) sizeof(buf)) {
9804100cc5fSmartijn 				snprintf(buf, sizeof(buf), "<too large OID>: "
9814100cc5fSmartijn 				    "(string)<too large string>");
9824100cc5fSmartijn 				break;
9834100cc5fSmartijn 			}
9844100cc5fSmartijn 			p = buf + ret;
9854100cc5fSmartijn 			bufleft = (int) sizeof(buf) - ret;
9864100cc5fSmartijn 			if (snprintf(p, bufleft, "%.*s",
9874100cc5fSmartijn 			    vb->avb_data.avb_ostring.aos_slen,
9884100cc5fSmartijn 			    vb->avb_data.avb_ostring.aos_string) >=
9894100cc5fSmartijn 			    (int) bufleft) {
9904100cc5fSmartijn 				p = buf + sizeof(buf) - 4;
9914100cc5fSmartijn 				strlcpy(p, "...", 4);
9924100cc5fSmartijn 			}
9934100cc5fSmartijn 		}
9944100cc5fSmartijn 		break;
9954100cc5fSmartijn 	case AX_DATA_TYPE_NULL:
9964100cc5fSmartijn 		snprintf(buf, sizeof(buf), "%s: <null>",
9974100cc5fSmartijn 		    ax_oid2string(&(vb->avb_oid)));
9984100cc5fSmartijn 		break;
9994100cc5fSmartijn 	case AX_DATA_TYPE_OID:
10004100cc5fSmartijn 		strlcpy(tmpbuf,
10014100cc5fSmartijn 		    ax_oid2string(&(vb->avb_data.avb_oid)), sizeof(tmpbuf));
10024100cc5fSmartijn 		snprintf(buf, sizeof(buf), "%s: (oid)%s",
10034100cc5fSmartijn 		    ax_oid2string(&(vb->avb_oid)), tmpbuf);
10044100cc5fSmartijn 		break;
10054100cc5fSmartijn 	case AX_DATA_TYPE_IPADDRESS:
10064100cc5fSmartijn 		if (vb->avb_data.avb_ostring.aos_slen != 4) {
10074100cc5fSmartijn 			snprintf(buf, sizeof(buf), "%s: (ipaddress)<invalid>",
10084100cc5fSmartijn 			    ax_oid2string(&(vb->avb_oid)));
10094100cc5fSmartijn 			break;
10104100cc5fSmartijn 		}
10114100cc5fSmartijn 		if (inet_ntop(PF_INET, vb->avb_data.avb_ostring.aos_string,
10124100cc5fSmartijn 		    tmpbuf, sizeof(tmpbuf)) == NULL) {
10134100cc5fSmartijn 			snprintf(buf, sizeof(buf), "%s: (ipaddress)"
10144100cc5fSmartijn 			    "<unparseable>: %s",
10154100cc5fSmartijn 			    ax_oid2string(&(vb->avb_oid)),
10164100cc5fSmartijn 			    strerror(errno));
10174100cc5fSmartijn 			break;
10184100cc5fSmartijn 		}
10194100cc5fSmartijn 		snprintf(buf, sizeof(buf), "%s: (ipaddress)%s",
10204100cc5fSmartijn 		    ax_oid2string(&(vb->avb_oid)), tmpbuf);
10214100cc5fSmartijn 		break;
10224100cc5fSmartijn 	case AX_DATA_TYPE_COUNTER32:
10234100cc5fSmartijn 		snprintf(buf, sizeof(buf), "%s: (counter32)%u",
10244100cc5fSmartijn 		    ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32);
10254100cc5fSmartijn 		break;
10264100cc5fSmartijn 	case AX_DATA_TYPE_GAUGE32:
10274100cc5fSmartijn 		snprintf(buf, sizeof(buf), "%s: (gauge32)%u",
10284100cc5fSmartijn 		    ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32);
10294100cc5fSmartijn 		break;
10304100cc5fSmartijn 	case AX_DATA_TYPE_TIMETICKS:
10314100cc5fSmartijn 		snprintf(buf, sizeof(buf), "%s: (timeticks)%u",
10324100cc5fSmartijn 		    ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32);
10334100cc5fSmartijn 		break;
10344100cc5fSmartijn 	case AX_DATA_TYPE_OPAQUE:
10354100cc5fSmartijn 		p = tmpbuf;
10364100cc5fSmartijn 		bufleft = sizeof(tmpbuf);
10374100cc5fSmartijn 		for (i = 0;
10384100cc5fSmartijn 		    i < vb->avb_data.avb_ostring.aos_slen; i++) {
10394100cc5fSmartijn 			ret = snprintf(p, bufleft, " %02hhX",
10404100cc5fSmartijn 			    vb->avb_data.avb_ostring.aos_string[i]);
10414100cc5fSmartijn 			if (ret >= (int) bufleft) {
10424100cc5fSmartijn 				p = strrchr(p, ' ');
10434100cc5fSmartijn 				strlcpy(p, "...", 4);
10444100cc5fSmartijn 				break;
10454100cc5fSmartijn 			}
10464100cc5fSmartijn 			p += 3;
10474100cc5fSmartijn 			bufleft -= 3;
10484100cc5fSmartijn 		}
10494100cc5fSmartijn 		ret = snprintf(buf, sizeof(buf), "%s: (opaque)%s",
10504100cc5fSmartijn 		    ax_oid2string(&(vb->avb_oid)), tmpbuf);
10514100cc5fSmartijn 		if (ret >= (int) sizeof(buf)) {
10524100cc5fSmartijn 			p  = strrchr(buf, ' ');
10534100cc5fSmartijn 			strlcpy(p, "...", 4);
10544100cc5fSmartijn 		}
10554100cc5fSmartijn 		break;
10564100cc5fSmartijn 	case AX_DATA_TYPE_COUNTER64:
10574100cc5fSmartijn 		snprintf(buf, sizeof(buf), "%s: (counter64)%"PRIu64,
10584100cc5fSmartijn 		    ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint64);
10594100cc5fSmartijn 		break;
10604100cc5fSmartijn 	case AX_DATA_TYPE_NOSUCHOBJECT:
10614100cc5fSmartijn 		snprintf(buf, sizeof(buf), "%s: <noSuchObject>",
10624100cc5fSmartijn 		    ax_oid2string(&(vb->avb_oid)));
10634100cc5fSmartijn 		break;
10644100cc5fSmartijn 	case AX_DATA_TYPE_NOSUCHINSTANCE:
10654100cc5fSmartijn 		snprintf(buf, sizeof(buf), "%s: <noSuchInstance>",
10664100cc5fSmartijn 		    ax_oid2string(&(vb->avb_oid)));
10674100cc5fSmartijn 		break;
10684100cc5fSmartijn 	case AX_DATA_TYPE_ENDOFMIBVIEW:
10694100cc5fSmartijn 		snprintf(buf, sizeof(buf), "%s: <endOfMibView>",
10704100cc5fSmartijn 		    ax_oid2string(&(vb->avb_oid)));
10714100cc5fSmartijn 		break;
10724100cc5fSmartijn 	}
10734100cc5fSmartijn 	return buf;
10744100cc5fSmartijn }
10754100cc5fSmartijn 
10764100cc5fSmartijn int
ax_oid_cmp(struct ax_oid * o1,struct ax_oid * o2)10774100cc5fSmartijn ax_oid_cmp(struct ax_oid *o1, struct ax_oid *o2)
10784100cc5fSmartijn {
10794100cc5fSmartijn 	size_t i, min;
10804100cc5fSmartijn 
10814100cc5fSmartijn 	min = o1->aoi_idlen < o2->aoi_idlen ? o1->aoi_idlen : o2->aoi_idlen;
10824100cc5fSmartijn 	for (i = 0; i < min; i++) {
10834100cc5fSmartijn 		if (o1->aoi_id[i] < o2->aoi_id[i])
10844100cc5fSmartijn 			return -1;
10854100cc5fSmartijn 		if (o1->aoi_id[i] > o2->aoi_id[i])
10864100cc5fSmartijn 			return 1;
10874100cc5fSmartijn 	}
10884100cc5fSmartijn 	/* o1 is parent of o2 */
10894100cc5fSmartijn 	if (o1->aoi_idlen < o2->aoi_idlen)
10904100cc5fSmartijn 		return -2;
10914100cc5fSmartijn 	/* o1 is child of o2 */
10924100cc5fSmartijn 	if (o1->aoi_idlen > o2->aoi_idlen)
10934100cc5fSmartijn 		return 2;
10944100cc5fSmartijn 	return 0;
10954100cc5fSmartijn }
10964100cc5fSmartijn 
10974100cc5fSmartijn int
ax_oid_add(struct ax_oid * oid,uint32_t value)10984100cc5fSmartijn ax_oid_add(struct ax_oid *oid, uint32_t value)
10994100cc5fSmartijn {
11004100cc5fSmartijn 	if (oid->aoi_idlen == AX_OID_MAX_LEN)
11014100cc5fSmartijn 		return -1;
11024100cc5fSmartijn 	oid->aoi_id[oid->aoi_idlen++] = value;
11034100cc5fSmartijn 	return 0;
11044100cc5fSmartijn }
11054100cc5fSmartijn 
11064100cc5fSmartijn static uint32_t
ax_pdu_queue(struct ax * ax)11074100cc5fSmartijn ax_pdu_queue(struct ax *ax)
11084100cc5fSmartijn {
11094100cc5fSmartijn 	struct ax_pdu_header header;
11104100cc5fSmartijn 	uint32_t packetid, plength;
11114100cc5fSmartijn 	size_t wbtlen = ax->ax_wbtlen;
11124100cc5fSmartijn 
11134100cc5fSmartijn 	header.aph_flags = ax->ax_byteorder == AX_BYTE_ORDER_BE ?
11144100cc5fSmartijn 	    AX_PDU_FLAG_NETWORK_BYTE_ORDER : 0;
11154100cc5fSmartijn 	packetid = ax_pdutoh32(&header, &(ax->ax_wbuf[ax->ax_wblen + 12]));
11164100cc5fSmartijn 	plength = (ax->ax_wbtlen - ax->ax_wblen) - AX_PDU_HEADER;
11174100cc5fSmartijn 	ax->ax_wbtlen = ax->ax_wblen + 16;
11184100cc5fSmartijn 	(void)ax_pdu_add_uint32(ax, plength);
11194100cc5fSmartijn 
11204100cc5fSmartijn 	ax->ax_wblen = ax->ax_wbtlen = wbtlen;
11214100cc5fSmartijn 
11224100cc5fSmartijn 	return packetid;
11234100cc5fSmartijn }
11244100cc5fSmartijn 
11254100cc5fSmartijn static int
ax_pdu_header(struct ax * ax,enum ax_pdu_type type,uint8_t flags,uint32_t sessionid,uint32_t transactionid,uint32_t packetid,struct ax_ostring * context)11264100cc5fSmartijn ax_pdu_header(struct ax *ax, enum ax_pdu_type type, uint8_t flags,
11274100cc5fSmartijn     uint32_t sessionid, uint32_t transactionid, uint32_t packetid,
11284100cc5fSmartijn     struct ax_ostring *context)
11294100cc5fSmartijn {
11304100cc5fSmartijn 	if (ax->ax_wblen != ax->ax_wbtlen) {
11314100cc5fSmartijn 		errno = EALREADY;
11324100cc5fSmartijn 		return -1;
11334100cc5fSmartijn 	}
11344100cc5fSmartijn 
11354100cc5fSmartijn 	if (ax_pdu_need(ax, 4) == -1)
11364100cc5fSmartijn 		return -1;
11374100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = 1;
11384100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = (uint8_t) type;
11394100cc5fSmartijn 	if (context != NULL)
11404100cc5fSmartijn 		flags |= AX_PDU_FLAG_NON_DEFAULT_CONTEXT;
11414100cc5fSmartijn 	if (ax->ax_byteorder == AX_BYTE_ORDER_BE)
11424100cc5fSmartijn 		flags |= AX_PDU_FLAG_NETWORK_BYTE_ORDER;
11434100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = flags;
11444100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = 0;
11454100cc5fSmartijn 	if (ax_pdu_add_uint32(ax, sessionid) == -1 ||
11464100cc5fSmartijn 	    ax_pdu_add_uint32(ax, transactionid) == -1 ||
11474100cc5fSmartijn 	    ax_pdu_add_uint32(ax, packetid) == -1 ||
11484100cc5fSmartijn 	    ax_pdu_need(ax, 4) == -1)
11494100cc5fSmartijn 		return -1;
11504100cc5fSmartijn 	ax->ax_wbtlen += 4;
11514100cc5fSmartijn 	if (context != NULL) {
11524100cc5fSmartijn 		if (ax_pdu_add_str(ax, context) == -1)
11534100cc5fSmartijn 			return -1;
11544100cc5fSmartijn 	}
11554100cc5fSmartijn 
11564100cc5fSmartijn 	return 0;
11574100cc5fSmartijn }
11584100cc5fSmartijn 
11594100cc5fSmartijn static int
ax_pdu_add_uint16(struct ax * ax,uint16_t value)11604100cc5fSmartijn ax_pdu_add_uint16(struct ax *ax, uint16_t value)
11614100cc5fSmartijn {
11624100cc5fSmartijn 	if (ax_pdu_need(ax, sizeof(value)) == -1)
11634100cc5fSmartijn 		return -1;
11644100cc5fSmartijn 
11654100cc5fSmartijn 	if (ax->ax_byteorder == AX_BYTE_ORDER_BE)
11664100cc5fSmartijn 		value = htobe16(value);
11674100cc5fSmartijn 	else
11684100cc5fSmartijn 		value = htole16(value);
11694100cc5fSmartijn 	memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value));
11704100cc5fSmartijn 	ax->ax_wbtlen += sizeof(value);
11714100cc5fSmartijn 	return 0;
11724100cc5fSmartijn }
11734100cc5fSmartijn 
11744100cc5fSmartijn static int
ax_pdu_add_uint32(struct ax * ax,uint32_t value)11754100cc5fSmartijn ax_pdu_add_uint32(struct ax *ax, uint32_t value)
11764100cc5fSmartijn {
11774100cc5fSmartijn 	if (ax_pdu_need(ax, sizeof(value)) == -1)
11784100cc5fSmartijn 		return -1;
11794100cc5fSmartijn 
11804100cc5fSmartijn 	if (ax->ax_byteorder == AX_BYTE_ORDER_BE)
11814100cc5fSmartijn 		value = htobe32(value);
11824100cc5fSmartijn 	else
11834100cc5fSmartijn 		value = htole32(value);
11844100cc5fSmartijn 	memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value));
11854100cc5fSmartijn 	ax->ax_wbtlen += sizeof(value);
11864100cc5fSmartijn 	return 0;
11874100cc5fSmartijn }
11884100cc5fSmartijn 
11894100cc5fSmartijn static int
ax_pdu_add_uint64(struct ax * ax,uint64_t value)11904100cc5fSmartijn ax_pdu_add_uint64(struct ax *ax, uint64_t value)
11914100cc5fSmartijn {
11924100cc5fSmartijn 	if (ax_pdu_need(ax, sizeof(value)) == -1)
11934100cc5fSmartijn 		return -1;
11944100cc5fSmartijn 
11954100cc5fSmartijn 	if (ax->ax_byteorder == AX_BYTE_ORDER_BE)
11964100cc5fSmartijn 		value = htobe64(value);
11974100cc5fSmartijn 	else
11984100cc5fSmartijn 		value = htole64(value);
11994100cc5fSmartijn 	memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value));
12004100cc5fSmartijn 	ax->ax_wbtlen += sizeof(value);
12014100cc5fSmartijn 	return 0;
12024100cc5fSmartijn }
12034100cc5fSmartijn 
12044100cc5fSmartijn 
12054100cc5fSmartijn static int
ax_pdu_add_oid(struct ax * ax,struct ax_oid * oid)12064100cc5fSmartijn ax_pdu_add_oid(struct ax *ax, struct ax_oid *oid)
12074100cc5fSmartijn {
12084100cc5fSmartijn 	static struct ax_oid nulloid = {0};
12094100cc5fSmartijn 	uint8_t prefix = 0, n_subid, i = 0;
12104100cc5fSmartijn 
12114100cc5fSmartijn 	n_subid = oid->aoi_idlen;
12124100cc5fSmartijn 
12134100cc5fSmartijn 	if (oid == NULL)
12144100cc5fSmartijn 		oid = &nulloid;
12154100cc5fSmartijn 
12164100cc5fSmartijn 	if (oid->aoi_idlen > 4 &&
12174100cc5fSmartijn 	    oid->aoi_id[0] == 1 && oid->aoi_id[1] == 3 &&
12184100cc5fSmartijn 	    oid->aoi_id[2] == 6 && oid->aoi_id[3] == 1 &&
12194100cc5fSmartijn 	    oid->aoi_id[4] <= UINT8_MAX) {
12204100cc5fSmartijn 		prefix = oid->aoi_id[4];
12214100cc5fSmartijn 		i = 5;
12224100cc5fSmartijn 	}
12234100cc5fSmartijn 
12244100cc5fSmartijn 	if (ax_pdu_need(ax, 4) == -1)
12254100cc5fSmartijn 		return -1;
12264100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = n_subid - i;
12274100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = prefix;
12284100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = oid->aoi_include;
12294100cc5fSmartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = 0;
12304100cc5fSmartijn 
12314100cc5fSmartijn 	for (; i < n_subid; i++) {
12324100cc5fSmartijn 		if (ax_pdu_add_uint32(ax, oid->aoi_id[i]) == -1)
12334100cc5fSmartijn 			return -1;
12344100cc5fSmartijn 	}
12354100cc5fSmartijn 
12364100cc5fSmartijn 	return 0;
12374100cc5fSmartijn }
12384100cc5fSmartijn 
12394100cc5fSmartijn static int
ax_pdu_add_str(struct ax * ax,struct ax_ostring * str)12404100cc5fSmartijn ax_pdu_add_str(struct ax *ax, struct ax_ostring *str)
12414100cc5fSmartijn {
12424100cc5fSmartijn 	size_t length, zeroes;
12434100cc5fSmartijn 
12444100cc5fSmartijn 	if (ax_pdu_add_uint32(ax, str->aos_slen) == -1)
12454100cc5fSmartijn 		return -1;
12464100cc5fSmartijn 
12474100cc5fSmartijn 	if ((zeroes = (4 - (str->aos_slen % 4))) == 4)
12484100cc5fSmartijn 		zeroes = 0;
12494100cc5fSmartijn 	length = str->aos_slen + zeroes;
12504100cc5fSmartijn 	if (ax_pdu_need(ax, length) == -1)
12514100cc5fSmartijn 		return -1;
12524100cc5fSmartijn 
12534100cc5fSmartijn 	memcpy(&(ax->ax_wbuf[ax->ax_wbtlen]), str->aos_string, str->aos_slen);
12544100cc5fSmartijn 	ax->ax_wbtlen += str->aos_slen;
12554100cc5fSmartijn 	memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, zeroes);
12564100cc5fSmartijn 	ax->ax_wbtlen += zeroes;
12574100cc5fSmartijn 	return 0;
12584100cc5fSmartijn }
12594100cc5fSmartijn 
12604100cc5fSmartijn static int
ax_pdu_add_varbindlist(struct ax * ax,struct ax_varbind * vblist,size_t nvb)12614100cc5fSmartijn ax_pdu_add_varbindlist(struct ax *ax,
12624100cc5fSmartijn     struct ax_varbind *vblist, size_t nvb)
12634100cc5fSmartijn {
12644100cc5fSmartijn 	size_t i;
12654100cc5fSmartijn 	uint16_t temp;
12664100cc5fSmartijn 
12674100cc5fSmartijn 	for (i = 0; i < nvb; i++) {
12684100cc5fSmartijn 		temp = (uint16_t) vblist[i].avb_type;
12694100cc5fSmartijn 		if (ax_pdu_add_uint16(ax, temp) == -1 ||
12704100cc5fSmartijn 		    ax_pdu_need(ax, 2))
12714100cc5fSmartijn 			return -1;
12724100cc5fSmartijn 		memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 2);
12734100cc5fSmartijn 		ax->ax_wbtlen += 2;
12744100cc5fSmartijn 		if (ax_pdu_add_oid(ax, &(vblist[i].avb_oid)) == -1)
12754100cc5fSmartijn 			return -1;
12764100cc5fSmartijn 		switch (vblist[i].avb_type) {
12774100cc5fSmartijn 		case AX_DATA_TYPE_INTEGER:
12784100cc5fSmartijn 			if (ax_pdu_add_uint32(ax,
12794100cc5fSmartijn 			    vblist[i].avb_data.avb_int32) == -1)
12804100cc5fSmartijn 				return -1;
12814100cc5fSmartijn 			break;
12824100cc5fSmartijn 		case AX_DATA_TYPE_COUNTER32:
12834100cc5fSmartijn 		case AX_DATA_TYPE_GAUGE32:
12844100cc5fSmartijn 		case AX_DATA_TYPE_TIMETICKS:
12854100cc5fSmartijn 			if (ax_pdu_add_uint32(ax,
12864100cc5fSmartijn 			    vblist[i].avb_data.avb_uint32) == -1)
12874100cc5fSmartijn 				return -1;
12884100cc5fSmartijn 			break;
12894100cc5fSmartijn 		case AX_DATA_TYPE_COUNTER64:
12904100cc5fSmartijn 			if (ax_pdu_add_uint64(ax,
12914100cc5fSmartijn 			    vblist[i].avb_data.avb_uint64) == -1)
12924100cc5fSmartijn 				return -1;
12934100cc5fSmartijn 			break;
12944100cc5fSmartijn 		case AX_DATA_TYPE_OCTETSTRING:
12954100cc5fSmartijn 		case AX_DATA_TYPE_IPADDRESS:
12964100cc5fSmartijn 		case AX_DATA_TYPE_OPAQUE:
12974100cc5fSmartijn 			if (ax_pdu_add_str(ax,
12984100cc5fSmartijn 			    &(vblist[i].avb_data.avb_ostring)) == -1)
12994100cc5fSmartijn 				return -1;
13004100cc5fSmartijn 			break;
13014100cc5fSmartijn 		case AX_DATA_TYPE_OID:
13024100cc5fSmartijn 			if (ax_pdu_add_oid(ax,
13034100cc5fSmartijn 			    &(vblist[i].avb_data.avb_oid)) == -1)
13044100cc5fSmartijn 				return -1;
13054100cc5fSmartijn 			break;
13064100cc5fSmartijn 		case AX_DATA_TYPE_NULL:
13074100cc5fSmartijn 		case AX_DATA_TYPE_NOSUCHOBJECT:
13084100cc5fSmartijn 		case AX_DATA_TYPE_NOSUCHINSTANCE:
13094100cc5fSmartijn 		case AX_DATA_TYPE_ENDOFMIBVIEW:
13104100cc5fSmartijn 			break;
13114100cc5fSmartijn 		default:
13124100cc5fSmartijn 			errno = EINVAL;
13134100cc5fSmartijn 			return -1;
13144100cc5fSmartijn 		}
13154100cc5fSmartijn 	}
13164100cc5fSmartijn 	return 0;
13174100cc5fSmartijn }
13184100cc5fSmartijn 
13194100cc5fSmartijn static int
ax_pdu_add_searchrange(struct ax * ax,struct ax_searchrange * sr)13204100cc5fSmartijn ax_pdu_add_searchrange(struct ax *ax, struct ax_searchrange *sr)
13214100cc5fSmartijn {
13224100cc5fSmartijn 	if (ax_pdu_add_oid(ax, &(sr->asr_start)) == -1 ||
13234100cc5fSmartijn 	    ax_pdu_add_oid(ax, &(sr->asr_stop)) == -1)
13244100cc5fSmartijn 		return -1;
13254100cc5fSmartijn 	return 0;
13264100cc5fSmartijn }
13274100cc5fSmartijn 
13284100cc5fSmartijn static uint16_t
ax_pdutoh16(struct ax_pdu_header * header,uint8_t * buf)13294100cc5fSmartijn ax_pdutoh16(struct ax_pdu_header *header, uint8_t *buf)
13304100cc5fSmartijn {
13314100cc5fSmartijn 	uint16_t value;
13324100cc5fSmartijn 
13334100cc5fSmartijn 	memcpy(&value, buf, sizeof(value));
13344100cc5fSmartijn 	if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER)
13354100cc5fSmartijn 		return be16toh(value);
13364100cc5fSmartijn 	return le16toh(value);
13374100cc5fSmartijn }
13384100cc5fSmartijn 
13394100cc5fSmartijn static uint32_t
ax_pdutoh32(struct ax_pdu_header * header,uint8_t * buf)13404100cc5fSmartijn ax_pdutoh32(struct ax_pdu_header *header, uint8_t *buf)
13414100cc5fSmartijn {
13424100cc5fSmartijn 	uint32_t value;
13434100cc5fSmartijn 
13444100cc5fSmartijn 	memcpy(&value, buf, sizeof(value));
13454100cc5fSmartijn 	if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER)
13464100cc5fSmartijn 		return be32toh(value);
13474100cc5fSmartijn 	return le32toh(value);
13484100cc5fSmartijn }
13494100cc5fSmartijn 
13504100cc5fSmartijn static uint64_t
ax_pdutoh64(struct ax_pdu_header * header,uint8_t * buf)13514100cc5fSmartijn ax_pdutoh64(struct ax_pdu_header *header, uint8_t *buf)
13524100cc5fSmartijn {
13534100cc5fSmartijn 	uint64_t value;
13544100cc5fSmartijn 
13554100cc5fSmartijn 	memcpy(&value, buf, sizeof(value));
13564100cc5fSmartijn 	if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER)
13574100cc5fSmartijn 		return be64toh(value);
13584100cc5fSmartijn 	return le64toh(value);
13594100cc5fSmartijn }
13604100cc5fSmartijn 
13614100cc5fSmartijn static ssize_t
ax_pdutooid(struct ax_pdu_header * header,struct ax_oid * oid,uint8_t * buf,size_t rawlen)13624100cc5fSmartijn ax_pdutooid(struct ax_pdu_header *header, struct ax_oid *oid,
13634100cc5fSmartijn     uint8_t *buf, size_t rawlen)
13644100cc5fSmartijn {
13654100cc5fSmartijn 	size_t i = 0;
13664100cc5fSmartijn 	ssize_t nread;
13674100cc5fSmartijn 
13684100cc5fSmartijn 	if (rawlen < 4)
13694100cc5fSmartijn 		goto fail;
13704100cc5fSmartijn 	rawlen -= 4;
13714100cc5fSmartijn 	nread = 4;
13724100cc5fSmartijn 	oid->aoi_idlen = *buf++;
13734100cc5fSmartijn 	if (rawlen < (oid->aoi_idlen * 4))
13744100cc5fSmartijn 		goto fail;
13754100cc5fSmartijn 	nread += oid->aoi_idlen * 4;
13764100cc5fSmartijn 	if (*buf != 0) {
13774100cc5fSmartijn 		oid->aoi_id[0] = 1;
13784100cc5fSmartijn 		oid->aoi_id[1] = 3;
13794100cc5fSmartijn 		oid->aoi_id[2] = 6;
13804100cc5fSmartijn 		oid->aoi_id[3] = 1;
13814100cc5fSmartijn 		oid->aoi_id[4] = *buf;
13824100cc5fSmartijn 		oid->aoi_idlen += 5;
13834100cc5fSmartijn 		i = 5;
13844100cc5fSmartijn 	}
13854100cc5fSmartijn 	buf++;
13864100cc5fSmartijn 	oid->aoi_include = *buf;
13875fd2bbf0Smartijn 	if (oid->aoi_idlen > AX_OID_MAX_LEN)
13885fd2bbf0Smartijn 		goto fail;
13894100cc5fSmartijn 	for (buf += 2; i < oid->aoi_idlen; i++, buf += 4)
13904100cc5fSmartijn 		oid->aoi_id[i] = ax_pdutoh32(header, buf);
13914100cc5fSmartijn 
13924100cc5fSmartijn 	return nread;
13934100cc5fSmartijn 
13944100cc5fSmartijn fail:
13954100cc5fSmartijn 	errno = EPROTO;
13964100cc5fSmartijn 	return -1;
13974100cc5fSmartijn }
13984100cc5fSmartijn 
13994100cc5fSmartijn static ssize_t
ax_pdutoostring(struct ax_pdu_header * header,struct ax_ostring * ostring,uint8_t * buf,size_t rawlen)14004100cc5fSmartijn ax_pdutoostring(struct ax_pdu_header *header,
14014100cc5fSmartijn     struct ax_ostring *ostring, uint8_t *buf, size_t rawlen)
14024100cc5fSmartijn {
14034100cc5fSmartijn 	ssize_t nread;
14044100cc5fSmartijn 
14054100cc5fSmartijn 	if (rawlen < 4)
14064100cc5fSmartijn 		goto fail;
14074100cc5fSmartijn 
14084100cc5fSmartijn 	ostring->aos_slen = ax_pdutoh32(header, buf);
14094100cc5fSmartijn 	rawlen -= 4;
14104100cc5fSmartijn 	buf += 4;
14114100cc5fSmartijn 	if (ostring->aos_slen > rawlen)
14124100cc5fSmartijn 		goto fail;
14134100cc5fSmartijn 	if ((ostring->aos_string = malloc(ostring->aos_slen + 1)) == NULL)
14144100cc5fSmartijn 		return -1;
14154100cc5fSmartijn 	memcpy(ostring->aos_string, buf, ostring->aos_slen);
14164100cc5fSmartijn 	ostring->aos_string[ostring->aos_slen] = '\0';
14174100cc5fSmartijn 
14184100cc5fSmartijn 	nread = 4 + ostring->aos_slen;
14194100cc5fSmartijn 	if (ostring->aos_slen % 4 != 0)
14204100cc5fSmartijn 		nread += 4 - (ostring->aos_slen % 4);
14214100cc5fSmartijn 
14224100cc5fSmartijn 	return nread;
14234100cc5fSmartijn 
14244100cc5fSmartijn fail:
14254100cc5fSmartijn 	errno = EPROTO;
14264100cc5fSmartijn 	return -1;
14274100cc5fSmartijn }
14284100cc5fSmartijn 
14294100cc5fSmartijn static ssize_t
ax_pdutovarbind(struct ax_pdu_header * header,struct ax_varbind * varbind,uint8_t * buf,size_t rawlen)14304100cc5fSmartijn ax_pdutovarbind(struct ax_pdu_header *header,
14314100cc5fSmartijn     struct ax_varbind *varbind, uint8_t *buf, size_t rawlen)
14324100cc5fSmartijn {
14334100cc5fSmartijn 	ssize_t nread, rread = 4;
14344100cc5fSmartijn 
14354100cc5fSmartijn 	if (rawlen == 0)
14364100cc5fSmartijn 		return 0;
14374100cc5fSmartijn 
14384100cc5fSmartijn 	if (rawlen < 8)
14394100cc5fSmartijn 		goto fail;
14404100cc5fSmartijn 	varbind->avb_type = ax_pdutoh16(header, buf);
14414100cc5fSmartijn 
14424100cc5fSmartijn 	buf += 4;
14434100cc5fSmartijn 	rawlen -= 4;
14444100cc5fSmartijn 	nread = ax_pdutooid(header, &(varbind->avb_oid), buf, rawlen);
14454100cc5fSmartijn 	if (nread == -1)
14464100cc5fSmartijn 		return -1;
14474100cc5fSmartijn 	rread += nread;
14484100cc5fSmartijn 	buf += nread;
14494100cc5fSmartijn 	rawlen -= nread;
14504100cc5fSmartijn 
14514100cc5fSmartijn 	switch(varbind->avb_type) {
14524100cc5fSmartijn 	case AX_DATA_TYPE_INTEGER:
14534100cc5fSmartijn 		if (rawlen < 4)
14544100cc5fSmartijn 			goto fail;
14554100cc5fSmartijn 		varbind->avb_data.avb_int32 = ax_pdutoh32(header, buf);
14564100cc5fSmartijn 		return rread + 4;
14574100cc5fSmartijn 	case AX_DATA_TYPE_COUNTER32:
14584100cc5fSmartijn 	case AX_DATA_TYPE_GAUGE32:
14594100cc5fSmartijn 	case AX_DATA_TYPE_TIMETICKS:
14604100cc5fSmartijn 		if (rawlen < 4)
14614100cc5fSmartijn 			goto fail;
14624100cc5fSmartijn 		varbind->avb_data.avb_uint32 = ax_pdutoh32(header, buf);
14634100cc5fSmartijn 		return rread + 4;
14644100cc5fSmartijn 	case AX_DATA_TYPE_COUNTER64:
14654100cc5fSmartijn 		if (rawlen < 8)
14664100cc5fSmartijn 			goto fail;
14674100cc5fSmartijn 		varbind->avb_data.avb_uint64 = ax_pdutoh64(header, buf);
14684100cc5fSmartijn 		return rread + 8;
14694100cc5fSmartijn 	case AX_DATA_TYPE_OCTETSTRING:
14704100cc5fSmartijn 	case AX_DATA_TYPE_IPADDRESS:
14714100cc5fSmartijn 	case AX_DATA_TYPE_OPAQUE:
14724100cc5fSmartijn 		nread = ax_pdutoostring(header,
14734100cc5fSmartijn 		    &(varbind->avb_data.avb_ostring), buf, rawlen);
14744100cc5fSmartijn 		if (nread == -1)
14754100cc5fSmartijn 			return -1;
14764100cc5fSmartijn 		return nread + rread;
14774100cc5fSmartijn 	case AX_DATA_TYPE_OID:
14784100cc5fSmartijn 		nread = ax_pdutooid(header, &(varbind->avb_data.avb_oid),
14794100cc5fSmartijn 		    buf, rawlen);
14804100cc5fSmartijn 		if (nread == -1)
14814100cc5fSmartijn 			return -1;
14824100cc5fSmartijn 		return nread + rread;
14834100cc5fSmartijn 	case AX_DATA_TYPE_NULL:
14844100cc5fSmartijn 	case AX_DATA_TYPE_NOSUCHOBJECT:
14854100cc5fSmartijn 	case AX_DATA_TYPE_NOSUCHINSTANCE:
14864100cc5fSmartijn 	case AX_DATA_TYPE_ENDOFMIBVIEW:
14874100cc5fSmartijn 		return rread;
14884100cc5fSmartijn 	}
14894100cc5fSmartijn 
14904100cc5fSmartijn fail:
14914100cc5fSmartijn 	errno = EPROTO;
14924100cc5fSmartijn 	return -1;
14934100cc5fSmartijn }
1494