xref: /openbsd-src/lib/libagentx/ax.c (revision 6f5d93645a6e9b04bccbd48ae2196a66638a49ca)
1*6f5d9364Smartijn /*	$OpenBSD: ax.c,v 1.10 2023/10/24 08:54:52 martijn Exp $ */
281180db9Smartijn /*
381180db9Smartijn  * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
481180db9Smartijn  *
581180db9Smartijn  * Permission to use, copy, modify, and distribute this software for any
681180db9Smartijn  * purpose with or without fee is hereby granted, provided that the above
781180db9Smartijn  * copyright notice and this permission notice appear in all copies.
881180db9Smartijn  *
981180db9Smartijn  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1081180db9Smartijn  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1181180db9Smartijn  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1281180db9Smartijn  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1381180db9Smartijn  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1481180db9Smartijn  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1581180db9Smartijn  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1681180db9Smartijn  */
1781180db9Smartijn #include <sys/socket.h>
1881180db9Smartijn 
1981180db9Smartijn #include <arpa/inet.h>
2081180db9Smartijn 
2181180db9Smartijn #include <ctype.h>
2281180db9Smartijn #include <endian.h>
2381180db9Smartijn #include <errno.h>
2481180db9Smartijn #include <inttypes.h>
2581180db9Smartijn #include <stdlib.h>
2681180db9Smartijn #include <stdint.h>
2781180db9Smartijn #include <stdio.h>
2881180db9Smartijn #include <string.h>
2981180db9Smartijn #include <strings.h>
3081180db9Smartijn #include <unistd.h>
3181180db9Smartijn 
3281180db9Smartijn #include "ax.h"
3381180db9Smartijn 
3481180db9Smartijn #define AX_PDU_HEADER 20
3581180db9Smartijn 
3681180db9Smartijn static int ax_pdu_need(struct ax *, size_t);
3781180db9Smartijn static int ax_pdu_header(struct ax *,
3881180db9Smartijn     enum ax_pdu_type, uint8_t, uint32_t, uint32_t, uint32_t,
3981180db9Smartijn     struct ax_ostring *);
4081180db9Smartijn static uint32_t ax_packetid(struct ax *);
4181180db9Smartijn static uint32_t ax_pdu_queue(struct ax *);
4281180db9Smartijn static int ax_pdu_add_uint16(struct ax *, uint16_t);
4381180db9Smartijn static int ax_pdu_add_uint32(struct ax *, uint32_t);
4481180db9Smartijn static int ax_pdu_add_uint64(struct ax *, uint64_t);
4581180db9Smartijn static int ax_pdu_add_oid(struct ax *, struct ax_oid *, int);
4681180db9Smartijn static int ax_pdu_add_str(struct ax *, struct ax_ostring *);
4781180db9Smartijn static int ax_pdu_add_varbindlist( struct ax *, struct ax_varbind *,
4881180db9Smartijn     size_t);
4981180db9Smartijn static uint16_t ax_pdutoh16(struct ax_pdu_header *, uint8_t *);
5081180db9Smartijn static uint32_t ax_pdutoh32(struct ax_pdu_header *, uint8_t *);
5181180db9Smartijn static uint64_t ax_pdutoh64(struct ax_pdu_header *, uint8_t *);
5281180db9Smartijn static ssize_t ax_pdutooid(struct ax_pdu_header *, struct ax_oid *,
5381180db9Smartijn     uint8_t *, size_t);
5481180db9Smartijn static ssize_t ax_pdutoostring(struct ax_pdu_header *,
5581180db9Smartijn     struct ax_ostring *, uint8_t *, size_t);
5681180db9Smartijn static ssize_t ax_pdutovarbind(struct ax_pdu_header *,
5781180db9Smartijn     struct ax_varbind *, uint8_t *, size_t);
5881180db9Smartijn 
5981180db9Smartijn struct ax *
ax_new(int fd)6081180db9Smartijn ax_new(int fd)
6181180db9Smartijn {
6281180db9Smartijn 	struct ax *ax;
6381180db9Smartijn 
6481180db9Smartijn 	if (fd == -1) {
6581180db9Smartijn 		errno = EINVAL;
6681180db9Smartijn 		return NULL;
6781180db9Smartijn 	}
6881180db9Smartijn 
6981180db9Smartijn 	if ((ax = calloc(1, sizeof(*ax))) == NULL)
7081180db9Smartijn 		return NULL;
7181180db9Smartijn 	ax->ax_fd = fd;
7281180db9Smartijn 	ax->ax_rbsize = 512;
731140d57fSmartijn 	if ((ax->ax_rbuf = malloc(ax->ax_rbsize)) == NULL)
741140d57fSmartijn 		goto fail;
7581180db9Smartijn 	ax->ax_byteorder = AX_BYTE_ORDER_NATIVE;
7681180db9Smartijn 
7781180db9Smartijn 	return ax;
7881180db9Smartijn 
7981180db9Smartijn fail:
8081180db9Smartijn 	free(ax);
8181180db9Smartijn 	return NULL;
8281180db9Smartijn }
8381180db9Smartijn 
8481180db9Smartijn void
ax_free(struct ax * ax)8581180db9Smartijn ax_free(struct ax *ax)
8681180db9Smartijn {
8781180db9Smartijn 	if (ax == NULL)
8881180db9Smartijn 		return;
8981180db9Smartijn 	close(ax->ax_fd);
9081180db9Smartijn 	free(ax->ax_rbuf);
9181180db9Smartijn 	free(ax->ax_wbuf);
9281180db9Smartijn 	free(ax->ax_packetids);
9381180db9Smartijn 	free(ax);
9481180db9Smartijn }
9581180db9Smartijn 
9681180db9Smartijn struct ax_pdu *
ax_recv(struct ax * ax)9781180db9Smartijn ax_recv(struct ax *ax)
9881180db9Smartijn {
9981180db9Smartijn 	struct ax_pdu *pdu;
10081180db9Smartijn 	struct ax_pdu_header header;
10181180db9Smartijn 	struct ax_pdu_response *response;
10281180db9Smartijn 	struct ax_varbind *varbind;
10381180db9Smartijn 	struct ax_pdu_searchrangelist *srl = NULL;
10481180db9Smartijn 	struct ax_pdu_varbindlist *vbl;
10581180db9Smartijn 	struct ax_searchrange *sr;
10681180db9Smartijn 	size_t rbsize, packetidx = 0, i, rawlen;
10781180db9Smartijn 	ssize_t nread;
10881180db9Smartijn 	uint8_t *u8;
10981180db9Smartijn 	uint8_t *rbuf;
11081180db9Smartijn 	int found;
11181180db9Smartijn 
11281180db9Smartijn 	/* Only read a single packet at a time to make sure libevent triggers */
11381180db9Smartijn 	if (ax->ax_rblen < AX_PDU_HEADER) {
11481180db9Smartijn 		if ((nread = read(ax->ax_fd, ax->ax_rbuf + ax->ax_rblen,
11581180db9Smartijn 		    AX_PDU_HEADER - ax->ax_rblen)) == 0) {
11681180db9Smartijn 			errno = ECONNRESET;
11781180db9Smartijn 			return NULL;
11881180db9Smartijn 		}
11981180db9Smartijn 		if (nread == -1)
12081180db9Smartijn 			return NULL;
12181180db9Smartijn 		ax->ax_rblen += nread;
12281180db9Smartijn 		if (ax->ax_rblen < AX_PDU_HEADER) {
12381180db9Smartijn 			errno = EAGAIN;
12481180db9Smartijn 			return NULL;
12581180db9Smartijn 		}
12681180db9Smartijn 	}
12781180db9Smartijn 	u8 = ax->ax_rbuf;
12881180db9Smartijn 	header.aph_version = *u8++;
12981180db9Smartijn 	header.aph_type = *u8++;
13081180db9Smartijn 	header.aph_flags = *u8++;
13181180db9Smartijn 	u8++;
13281180db9Smartijn 	header.aph_sessionid = ax_pdutoh32(&header, u8);
13381180db9Smartijn 	u8 += 4;
13481180db9Smartijn 	header.aph_transactionid = ax_pdutoh32(&header, u8);
13581180db9Smartijn 	u8 += 4;
13681180db9Smartijn 	header.aph_packetid = ax_pdutoh32(&header, u8);
13781180db9Smartijn 	u8 += 4;
13881180db9Smartijn 	header.aph_plength = ax_pdutoh32(&header, u8);
13981180db9Smartijn 
14081180db9Smartijn 	if (header.aph_version != 1) {
14181180db9Smartijn 		errno = EPROTO;
14281180db9Smartijn 		return NULL;
14381180db9Smartijn 	}
14481180db9Smartijn 	if (ax->ax_rblen < AX_PDU_HEADER + header.aph_plength) {
14581180db9Smartijn 		if (AX_PDU_HEADER + header.aph_plength > ax->ax_rbsize) {
14681180db9Smartijn 			rbsize = (((AX_PDU_HEADER + header.aph_plength)
14781180db9Smartijn 			    / 512) + 1) * 512;
14881180db9Smartijn 			if ((rbuf = recallocarray(ax->ax_rbuf, ax->ax_rbsize,
14981180db9Smartijn 			    rbsize, sizeof(*rbuf))) == NULL)
15081180db9Smartijn 				return NULL;
15181180db9Smartijn 			ax->ax_rbsize = rbsize;
15281180db9Smartijn 			ax->ax_rbuf = rbuf;
15381180db9Smartijn 		}
15481180db9Smartijn 		nread = read(ax->ax_fd, ax->ax_rbuf + ax->ax_rblen,
15581180db9Smartijn 		    header.aph_plength - (ax->ax_rblen - AX_PDU_HEADER));
15681180db9Smartijn 		if (nread == 0)
15781180db9Smartijn 			errno = ECONNRESET;
15881180db9Smartijn 		if (nread <= 0)
15981180db9Smartijn 			return NULL;
16081180db9Smartijn 		ax->ax_rblen += nread;
16181180db9Smartijn 		if (ax->ax_rblen < AX_PDU_HEADER + header.aph_plength) {
16281180db9Smartijn 			errno = EAGAIN;
16381180db9Smartijn 			return NULL;
16481180db9Smartijn 		}
16581180db9Smartijn 	}
16681180db9Smartijn 
16781180db9Smartijn 	if ((pdu = calloc(1, sizeof(*pdu))) == NULL)
16881180db9Smartijn 		return NULL;
16981180db9Smartijn 
17081180db9Smartijn 	memcpy(&(pdu->ap_header), &header, sizeof(header));
17181180db9Smartijn 
17281180db9Smartijn #if defined(AX_DEBUG) && defined(AX_DEBUG_VERBOSE)
17381180db9Smartijn 	{
17481180db9Smartijn 		char chars[4];
17581180db9Smartijn 		int print = 1;
17681180db9Smartijn 
17781180db9Smartijn 		fprintf(stderr, "received packet:\n");
17881180db9Smartijn 		for (i = 0; i < pdu->ap_header.aph_plength + AX_PDU_HEADER;
17981180db9Smartijn 		    i++) {
18081180db9Smartijn 			fprintf(stderr, "%02hhx ", ax->ax_rbuf[i]);
18181180db9Smartijn 			chars[i % 4] = ax->ax_rbuf[i];
18281180db9Smartijn 			if (!isprint(ax->ax_rbuf[i]))
18381180db9Smartijn 				print = 0;
18481180db9Smartijn 			if (i % 4 == 3) {
18581180db9Smartijn 				if (print)
18681180db9Smartijn 					fprintf(stderr, "%.4s", chars);
18781180db9Smartijn 				fprintf(stderr, "\n");
18881180db9Smartijn 				print = 1;
18981180db9Smartijn 			}
19081180db9Smartijn 		}
19181180db9Smartijn 	}
19281180db9Smartijn #endif
19381180db9Smartijn 
19481180db9Smartijn 	u8 = (ax->ax_rbuf) + AX_PDU_HEADER;
19581180db9Smartijn 	rawlen = pdu->ap_header.aph_plength;
19681180db9Smartijn 	if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NON_DEFAULT_CONTEXT) {
19781180db9Smartijn 		nread = ax_pdutoostring(&header, &(pdu->ap_context), u8,
19881180db9Smartijn 		    rawlen);
19981180db9Smartijn 		if (nread == -1)
20081180db9Smartijn 			goto fail;
20181180db9Smartijn 		rawlen -= nread;
20281180db9Smartijn 		u8 += nread;
20381180db9Smartijn 	}
20481180db9Smartijn 
20581180db9Smartijn 	switch (pdu->ap_header.aph_type) {
20681180db9Smartijn 	case AX_PDU_TYPE_GETBULK:
20781180db9Smartijn 		if (rawlen < 4) {
20881180db9Smartijn 			errno = EPROTO;
20981180db9Smartijn 			goto fail;
21081180db9Smartijn 		}
21181180db9Smartijn 		pdu->ap_payload.ap_getbulk.ap_nonrep =
21281180db9Smartijn 		    ax_pdutoh16(&header, u8);
21381180db9Smartijn 		u8 += 2;
21481180db9Smartijn 		pdu->ap_payload.ap_getbulk.ap_maxrep =
21581180db9Smartijn 		    ax_pdutoh16(&header, u8);
21681180db9Smartijn 		u8 += 2;
21781180db9Smartijn 		srl = &(pdu->ap_payload.ap_getbulk.ap_srl);
21881180db9Smartijn 		rawlen -= 4;
21981180db9Smartijn 		/* FALLTHROUGH */
22081180db9Smartijn 	case AX_PDU_TYPE_GET:
22181180db9Smartijn 	case AX_PDU_TYPE_GETNEXT:
22281180db9Smartijn 		if (pdu->ap_header.aph_type != AX_PDU_TYPE_GETBULK)
22381180db9Smartijn 			srl = &(pdu->ap_payload.ap_srl);
22481180db9Smartijn 		while (rawlen > 0 ) {
22581180db9Smartijn 			srl->ap_nsr++;
22681180db9Smartijn 			sr = reallocarray(srl->ap_sr, srl->ap_nsr, sizeof(*sr));
22781180db9Smartijn 			if (sr == NULL)
22881180db9Smartijn 				goto fail;
22981180db9Smartijn 			srl->ap_sr = sr;
23081180db9Smartijn 			sr += (srl->ap_nsr - 1);
23181180db9Smartijn 			if ((nread = ax_pdutooid(&header, &(sr->asr_start),
23281180db9Smartijn 			    u8, rawlen)) == -1)
23381180db9Smartijn 				goto fail;
23481180db9Smartijn 			rawlen -= nread;
23581180db9Smartijn 			u8 += nread;
23681180db9Smartijn 			if ((nread = ax_pdutooid(&header, &(sr->asr_stop),
23781180db9Smartijn 			    u8, rawlen)) == -1)
23881180db9Smartijn 				goto fail;
23981180db9Smartijn 			rawlen -= nread;
24081180db9Smartijn 			u8 += nread;
24181180db9Smartijn 		}
24281180db9Smartijn 		break;
24381180db9Smartijn 	case AX_PDU_TYPE_TESTSET:
24481180db9Smartijn 		vbl = &(pdu->ap_payload.ap_vbl);
24581180db9Smartijn 		while (rawlen > 0) {
24681180db9Smartijn 			varbind = recallocarray(vbl->ap_varbind,
24781180db9Smartijn 			    vbl->ap_nvarbind, vbl->ap_nvarbind + 1,
24881180db9Smartijn 			    sizeof(*(vbl->ap_varbind)));
24981180db9Smartijn 			if (varbind == NULL)
25081180db9Smartijn 				goto fail;
25181180db9Smartijn 			vbl->ap_varbind = varbind;
25281180db9Smartijn 			nread = ax_pdutovarbind(&header,
25381180db9Smartijn 			    &(vbl->ap_varbind[vbl->ap_nvarbind]), u8, rawlen);
25481180db9Smartijn 			if (nread == -1)
25581180db9Smartijn 				goto fail;
25681180db9Smartijn 			vbl->ap_nvarbind++;
25781180db9Smartijn 			u8 += nread;
25881180db9Smartijn 			rawlen -= nread;
25981180db9Smartijn 		}
26081180db9Smartijn 		break;
26181180db9Smartijn 	case AX_PDU_TYPE_COMMITSET:
26281180db9Smartijn 	case AX_PDU_TYPE_UNDOSET:
26381180db9Smartijn 	case AX_PDU_TYPE_CLEANUPSET:
26481180db9Smartijn 		if (rawlen != 0) {
26581180db9Smartijn 			errno = EPROTO;
26681180db9Smartijn 			goto fail;
26781180db9Smartijn 		}
26881180db9Smartijn 		break;
26981180db9Smartijn 	case AX_PDU_TYPE_RESPONSE:
27081180db9Smartijn 		if (ax->ax_packetids != NULL) {
27181180db9Smartijn 			found = 0;
27281180db9Smartijn 			for (i = 0; ax->ax_packetids[i] != 0; i++) {
27381180db9Smartijn 				if (ax->ax_packetids[i] ==
27481180db9Smartijn 				    pdu->ap_header.aph_packetid) {
27581180db9Smartijn 					packetidx = i;
27681180db9Smartijn 					found = 1;
27781180db9Smartijn 				}
27881180db9Smartijn 			}
27981180db9Smartijn 			if (found) {
28081180db9Smartijn 				ax->ax_packetids[packetidx] =
28181180db9Smartijn 				    ax->ax_packetids[i - 1];
28281180db9Smartijn 				ax->ax_packetids[i - 1] = 0;
28381180db9Smartijn 			} else {
28481180db9Smartijn 				errno = EPROTO;
28581180db9Smartijn 				goto fail;
28681180db9Smartijn 			}
28781180db9Smartijn 		}
28881180db9Smartijn 		if (rawlen < 8) {
28981180db9Smartijn 			errno = EPROTO;
29081180db9Smartijn 			goto fail;
29181180db9Smartijn 		}
29281180db9Smartijn 		response = &(pdu->ap_payload.ap_response);
29381180db9Smartijn 		response->ap_uptime = ax_pdutoh32(&header, u8);
29481180db9Smartijn 		u8 += 4;
29581180db9Smartijn 		response->ap_error = ax_pdutoh16(&header, u8);
29681180db9Smartijn 		u8 += 2;
29781180db9Smartijn 		response->ap_index = ax_pdutoh16(&header, u8);
29881180db9Smartijn 		u8 += 2;
29981180db9Smartijn 		rawlen -= 8;
30081180db9Smartijn 		while (rawlen > 0) {
30181180db9Smartijn 			varbind = recallocarray(response->ap_varbindlist,
30281180db9Smartijn 			    response->ap_nvarbind, response->ap_nvarbind + 1,
30381180db9Smartijn 			    sizeof(*(response->ap_varbindlist)));
30481180db9Smartijn 			if (varbind == NULL)
30581180db9Smartijn 				goto fail;
30681180db9Smartijn 			response->ap_varbindlist = varbind;
30781180db9Smartijn 			nread = ax_pdutovarbind(&header,
30881180db9Smartijn 			    &(response->ap_varbindlist[response->ap_nvarbind]),
30981180db9Smartijn 			    u8, rawlen);
31081180db9Smartijn 			if (nread == -1)
31181180db9Smartijn 				goto fail;
31281180db9Smartijn 			response->ap_nvarbind++;
31381180db9Smartijn 			u8 += nread;
31481180db9Smartijn 			rawlen -= nread;
31581180db9Smartijn 		}
31681180db9Smartijn 		break;
31781180db9Smartijn 	default:
31881180db9Smartijn 		pdu->ap_payload.ap_raw = malloc(pdu->ap_header.aph_plength);
31981180db9Smartijn 		if (pdu->ap_payload.ap_raw == NULL)
32081180db9Smartijn 			goto fail;
32181180db9Smartijn 		memcpy(pdu->ap_payload.ap_raw, ax->ax_rbuf + AX_PDU_HEADER,
32281180db9Smartijn 		    pdu->ap_header.aph_plength);
32381180db9Smartijn 		break;
32481180db9Smartijn 	}
32581180db9Smartijn 
32681180db9Smartijn 	ax->ax_rblen = 0;
32781180db9Smartijn 
32881180db9Smartijn 	return pdu;
32981180db9Smartijn fail:
33081180db9Smartijn 	ax_pdu_free(pdu);
33181180db9Smartijn 	return NULL;
33281180db9Smartijn }
33381180db9Smartijn 
33481180db9Smartijn static int
ax_pdu_need(struct ax * ax,size_t need)33581180db9Smartijn ax_pdu_need(struct ax *ax, size_t need)
33681180db9Smartijn {
33781180db9Smartijn 	uint8_t *wbuf;
33881180db9Smartijn 	size_t wbsize;
33981180db9Smartijn 
34007d49f15Srob 	if (ax->ax_wbtlen + need >= ax->ax_wbsize) {
34107d49f15Srob 		wbsize = (((ax->ax_wbtlen + need) / 512) + 1) * 512;
34281180db9Smartijn 		wbuf = recallocarray(ax->ax_wbuf, ax->ax_wbsize, wbsize, 1);
34381180db9Smartijn 		if (wbuf == NULL) {
34481180db9Smartijn 			ax->ax_wbtlen = ax->ax_wblen;
34581180db9Smartijn 			return -1;
34681180db9Smartijn 		}
34781180db9Smartijn 		ax->ax_wbsize = wbsize;
34881180db9Smartijn 		ax->ax_wbuf = wbuf;
34981180db9Smartijn 	}
35081180db9Smartijn 
35181180db9Smartijn 	return 0;
35281180db9Smartijn }
35381180db9Smartijn 
35481180db9Smartijn ssize_t
ax_send(struct ax * ax)35581180db9Smartijn ax_send(struct ax *ax)
35681180db9Smartijn {
35781180db9Smartijn 	ssize_t nwrite;
35881180db9Smartijn 
35981180db9Smartijn 	if (ax->ax_wblen != ax->ax_wbtlen) {
36081180db9Smartijn 		errno = EALREADY;
36181180db9Smartijn 		return -1;
36281180db9Smartijn 	}
36381180db9Smartijn 
36481180db9Smartijn 	if (ax->ax_wblen == 0)
36581180db9Smartijn 		return 0;
36681180db9Smartijn 
36781180db9Smartijn #if defined(AX_DEBUG) && defined(AX_DEBUG_VERBOSE)
36881180db9Smartijn 	{
36981180db9Smartijn 		size_t i;
37081180db9Smartijn 		char chars[4];
37181180db9Smartijn 		int print = 1;
37281180db9Smartijn 
37381180db9Smartijn 		fprintf(stderr, "sending packet:\n");
37481180db9Smartijn 		for (i = 0; i < ax->ax_wblen; i++) {
37581180db9Smartijn 			fprintf(stderr, "%02hhx ", ax->ax_wbuf[i]);
37681180db9Smartijn 			chars[i % 4] = ax->ax_wbuf[i];
37781180db9Smartijn 			if (!isprint(ax->ax_wbuf[i]))
37881180db9Smartijn 				print = 0;
37981180db9Smartijn 			if (i % 4 == 3) {
38081180db9Smartijn 				if (print)
38181180db9Smartijn 					fprintf(stderr, "%.4s", chars);
38281180db9Smartijn 				fprintf(stderr, "\n");
38381180db9Smartijn 				print = 1;
38481180db9Smartijn 			}
38581180db9Smartijn 		}
38681180db9Smartijn 	}
38781180db9Smartijn #endif
38881180db9Smartijn 
38981180db9Smartijn 	if ((nwrite = send(ax->ax_fd, ax->ax_wbuf, ax->ax_wblen,
39081180db9Smartijn 	    MSG_NOSIGNAL | MSG_DONTWAIT)) == -1)
39181180db9Smartijn 		return -1;
39281180db9Smartijn 
39381180db9Smartijn 	memmove(ax->ax_wbuf, ax->ax_wbuf + nwrite, ax->ax_wblen - nwrite);
39481180db9Smartijn 	ax->ax_wblen -= nwrite;
39581180db9Smartijn 	ax->ax_wbtlen = ax->ax_wblen;
39681180db9Smartijn 
39781180db9Smartijn 	return ax->ax_wblen;
39881180db9Smartijn }
39981180db9Smartijn 
40081180db9Smartijn uint32_t
ax_open(struct ax * ax,uint8_t timeout,struct ax_oid * oid,struct ax_ostring * descr)40181180db9Smartijn ax_open(struct ax *ax, uint8_t timeout, struct ax_oid *oid,
40281180db9Smartijn     struct ax_ostring *descr)
40381180db9Smartijn {
40481180db9Smartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_OPEN, 0, 0, 0, 0,
40581180db9Smartijn 	    NULL) == -1)
40681180db9Smartijn 		return 0;
40781180db9Smartijn 	ax_pdu_need(ax, 4);
40881180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = timeout;
40981180db9Smartijn 	memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 3);
41081180db9Smartijn 	ax->ax_wbtlen += 3;
41181180db9Smartijn 	if (ax_pdu_add_oid(ax, oid, 0) == -1)
41281180db9Smartijn 		return 0;
41381180db9Smartijn 	if (ax_pdu_add_str(ax, descr) == -1)
41481180db9Smartijn 		return 0;
41581180db9Smartijn 
41681180db9Smartijn 	return ax_pdu_queue(ax);
41781180db9Smartijn }
41881180db9Smartijn 
41981180db9Smartijn uint32_t
ax_close(struct ax * ax,uint32_t sessionid,enum ax_close_reason reason)42081180db9Smartijn ax_close(struct ax *ax, uint32_t sessionid,
42181180db9Smartijn     enum ax_close_reason reason)
42281180db9Smartijn {
42381180db9Smartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_CLOSE, 0, sessionid, 0, 0,
42481180db9Smartijn 	    NULL) == -1)
42581180db9Smartijn 		return 0;
42681180db9Smartijn 
42781180db9Smartijn 	if (ax_pdu_need(ax, 4) == -1)
42881180db9Smartijn 		return 0;
42981180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = (uint8_t)reason;
43081180db9Smartijn 	memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 3);
43181180db9Smartijn 	ax->ax_wbtlen += 3;
43281180db9Smartijn 
43381180db9Smartijn 	return ax_pdu_queue(ax);
43481180db9Smartijn }
43581180db9Smartijn 
43681180db9Smartijn uint32_t
ax_indexallocate(struct ax * ax,uint8_t flags,uint32_t sessionid,struct ax_ostring * context,struct ax_varbind * vblist,size_t nvb)43781180db9Smartijn ax_indexallocate(struct ax *ax, uint8_t flags, uint32_t sessionid,
43881180db9Smartijn     struct ax_ostring *context, struct ax_varbind *vblist, size_t nvb)
43981180db9Smartijn {
44081180db9Smartijn 	if (flags & ~(AX_PDU_FLAG_NEW_INDEX | AX_PDU_FLAG_ANY_INDEX)) {
44181180db9Smartijn 		errno = EINVAL;
44281180db9Smartijn 		return 0;
44381180db9Smartijn 	}
44481180db9Smartijn 
44581180db9Smartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_INDEXALLOCATE, flags,
44681180db9Smartijn 	    sessionid, 0, 0, context) == -1)
44781180db9Smartijn 		return 0;
44881180db9Smartijn 
44981180db9Smartijn 	if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1)
45081180db9Smartijn 		return 0;
45181180db9Smartijn 
45281180db9Smartijn 	return ax_pdu_queue(ax);
45381180db9Smartijn }
45481180db9Smartijn 
45581180db9Smartijn uint32_t
ax_indexdeallocate(struct ax * ax,uint32_t sessionid,struct ax_ostring * context,struct ax_varbind * vblist,size_t nvb)45681180db9Smartijn ax_indexdeallocate(struct ax *ax, uint32_t sessionid,
45781180db9Smartijn     struct ax_ostring *context, struct ax_varbind *vblist, size_t nvb)
45881180db9Smartijn {
45981180db9Smartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_INDEXDEALLOCATE, 0,
46081180db9Smartijn 	    sessionid, 0, 0, context) == -1)
46181180db9Smartijn 		return 0;
46281180db9Smartijn 
46381180db9Smartijn 	if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1)
46481180db9Smartijn 		return 0;
46581180db9Smartijn 
46681180db9Smartijn 	return ax_pdu_queue(ax);
46781180db9Smartijn }
46881180db9Smartijn 
46981180db9Smartijn uint32_t
ax_addagentcaps(struct ax * ax,uint32_t sessionid,struct ax_ostring * context,struct ax_oid * id,struct ax_ostring * descr)47081180db9Smartijn ax_addagentcaps(struct ax *ax, uint32_t sessionid,
47181180db9Smartijn     struct ax_ostring *context, struct ax_oid *id,
47281180db9Smartijn     struct ax_ostring *descr)
47381180db9Smartijn {
47481180db9Smartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_ADDAGENTCAPS, 0,
47581180db9Smartijn 	    sessionid, 0, 0, context) == -1)
47681180db9Smartijn 		return 0;
47781180db9Smartijn 	if (ax_pdu_add_oid(ax, id, 0) == -1)
47881180db9Smartijn 		return 0;
47981180db9Smartijn 	if (ax_pdu_add_str(ax, descr) == -1)
48081180db9Smartijn 		return 0;
48181180db9Smartijn 
48281180db9Smartijn 	return ax_pdu_queue(ax);
48381180db9Smartijn }
48481180db9Smartijn 
48581180db9Smartijn uint32_t
ax_removeagentcaps(struct ax * ax,uint32_t sessionid,struct ax_ostring * context,struct ax_oid * id)48681180db9Smartijn ax_removeagentcaps(struct ax *ax, uint32_t sessionid,
48781180db9Smartijn     struct ax_ostring *context, struct ax_oid *id)
48881180db9Smartijn {
48981180db9Smartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_REMOVEAGENTCAPS, 0,
49081180db9Smartijn 	    sessionid, 0, 0, context) == -1)
49181180db9Smartijn 		return 0;
49281180db9Smartijn 	if (ax_pdu_add_oid(ax, id, 0) == -1)
49381180db9Smartijn 		return 0;
49481180db9Smartijn 
49581180db9Smartijn 	return ax_pdu_queue(ax);
49681180db9Smartijn 
49781180db9Smartijn }
49881180db9Smartijn 
49981180db9Smartijn 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)50081180db9Smartijn ax_register(struct ax *ax, uint8_t flags, uint32_t sessionid,
50181180db9Smartijn     struct ax_ostring *context, uint8_t timeout, uint8_t priority,
50281180db9Smartijn     uint8_t range_subid, struct ax_oid *subtree, uint32_t upperbound)
50381180db9Smartijn {
50481180db9Smartijn 	if (flags & ~(AX_PDU_FLAG_INSTANCE_REGISTRATION)) {
50581180db9Smartijn 		errno = EINVAL;
50681180db9Smartijn 		return 0;
50781180db9Smartijn 	}
50881180db9Smartijn 
50981180db9Smartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_REGISTER, flags,
51081180db9Smartijn 	    sessionid, 0, 0, context) == -1)
51181180db9Smartijn 		return 0;
51281180db9Smartijn 
51381180db9Smartijn 	if (ax_pdu_need(ax, 4) == -1)
51481180db9Smartijn 		return 0;
51581180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = timeout;
51681180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = priority;
51781180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = range_subid;
51881180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = 0;
51981180db9Smartijn 	if (ax_pdu_add_oid(ax, subtree, 0) == -1)
52081180db9Smartijn 		return 0;
52181180db9Smartijn 	if (range_subid != 0) {
52281180db9Smartijn 		if (ax_pdu_add_uint32(ax, upperbound) == -1)
52381180db9Smartijn 			return 0;
52481180db9Smartijn 	}
52581180db9Smartijn 
52681180db9Smartijn 	return ax_pdu_queue(ax);
52781180db9Smartijn }
52881180db9Smartijn 
52981180db9Smartijn 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)53081180db9Smartijn ax_unregister(struct ax *ax, uint32_t sessionid,
53181180db9Smartijn     struct ax_ostring *context, uint8_t priority, uint8_t range_subid,
53281180db9Smartijn     struct ax_oid *subtree, uint32_t upperbound)
53381180db9Smartijn {
53481180db9Smartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_UNREGISTER, 0,
53581180db9Smartijn 	    sessionid, 0, 0, context) == -1)
53681180db9Smartijn 		return 0;
53781180db9Smartijn 
53881180db9Smartijn 	if (ax_pdu_need(ax, 4) == -1)
53981180db9Smartijn 		return 0;
54081180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = 0;
54181180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = priority;
54281180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = range_subid;
54381180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = 0;
54481180db9Smartijn 	if (ax_pdu_add_oid(ax, subtree, 0) == -1)
54581180db9Smartijn 		return 0;
54681180db9Smartijn 	if (range_subid != 0) {
54781180db9Smartijn 		if (ax_pdu_add_uint32(ax, upperbound) == -1)
54881180db9Smartijn 			return 0;
54981180db9Smartijn 	}
55081180db9Smartijn 
55181180db9Smartijn 	return ax_pdu_queue(ax);
55281180db9Smartijn }
55381180db9Smartijn 
55481180db9Smartijn 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)55581180db9Smartijn ax_response(struct ax *ax, uint32_t sessionid, uint32_t transactionid,
556*6f5d9364Smartijn     uint32_t packetid, uint32_t sysuptime, uint16_t error, uint16_t index,
557*6f5d9364Smartijn     struct ax_varbind *vblist, size_t nvb)
55881180db9Smartijn {
55981180db9Smartijn 	if (ax_pdu_header(ax, AX_PDU_TYPE_RESPONSE, 0, sessionid,
560*6f5d9364Smartijn 	    transactionid, packetid, NULL) == -1)
56181180db9Smartijn 		return -1;
56281180db9Smartijn 
56381180db9Smartijn 	if (ax_pdu_add_uint32(ax, sysuptime) == -1 ||
56481180db9Smartijn 	    ax_pdu_add_uint16(ax, error) == -1 ||
56581180db9Smartijn 	    ax_pdu_add_uint16(ax, index) == -1)
56681180db9Smartijn 		return -1;
56781180db9Smartijn 
56881180db9Smartijn 	if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1)
56981180db9Smartijn 		return -1;
57081180db9Smartijn 	if (ax_pdu_queue(ax) == 0)
57181180db9Smartijn 		return -1;
57281180db9Smartijn 	return 0;
57381180db9Smartijn }
57481180db9Smartijn 
57581180db9Smartijn void
ax_pdu_free(struct ax_pdu * pdu)57681180db9Smartijn ax_pdu_free(struct ax_pdu *pdu)
57781180db9Smartijn {
57881180db9Smartijn 	size_t i;
57981180db9Smartijn 	struct ax_pdu_response *response;
58081180db9Smartijn 
58181180db9Smartijn 	if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NON_DEFAULT_CONTEXT)
58281180db9Smartijn 		free(pdu->ap_context.aos_string);
58381180db9Smartijn 
58481180db9Smartijn 	switch (pdu->ap_header.aph_type) {
58581180db9Smartijn 	case AX_PDU_TYPE_GET:
58681180db9Smartijn 	case AX_PDU_TYPE_GETNEXT:
58781180db9Smartijn 	case AX_PDU_TYPE_GETBULK:
58881180db9Smartijn 		free(pdu->ap_payload.ap_srl.ap_sr);
58981180db9Smartijn 		break;
59081180db9Smartijn 	case AX_PDU_TYPE_RESPONSE:
59181180db9Smartijn 		response = &(pdu->ap_payload.ap_response);
59281180db9Smartijn 		for (i = 0; i < response->ap_nvarbind; i++)
59381180db9Smartijn 			ax_varbind_free(&(response->ap_varbindlist[i]));
59481180db9Smartijn 		free(response->ap_varbindlist);
59581180db9Smartijn 		break;
59681180db9Smartijn 	default:
59781180db9Smartijn 		free(pdu->ap_payload.ap_raw);
59881180db9Smartijn 		break;
59981180db9Smartijn 	}
60081180db9Smartijn 	free(pdu);
60181180db9Smartijn }
60281180db9Smartijn 
60381180db9Smartijn void
ax_varbind_free(struct ax_varbind * varbind)60481180db9Smartijn ax_varbind_free(struct ax_varbind *varbind)
60581180db9Smartijn {
60681180db9Smartijn 	switch (varbind->avb_type) {
60781180db9Smartijn 	case AX_DATA_TYPE_OCTETSTRING:
60881180db9Smartijn 	case AX_DATA_TYPE_IPADDRESS:
60981180db9Smartijn 	case AX_DATA_TYPE_OPAQUE:
61081180db9Smartijn 		free(varbind->avb_data.avb_ostring.aos_string);
61181180db9Smartijn 		break;
61281180db9Smartijn 	default:
61381180db9Smartijn 		break;
61481180db9Smartijn 	}
61581180db9Smartijn }
61681180db9Smartijn 
61781180db9Smartijn const char *
ax_error2string(enum ax_pdu_error error)61881180db9Smartijn ax_error2string(enum ax_pdu_error error)
61981180db9Smartijn {
62081180db9Smartijn 	static char buffer[64];
62181180db9Smartijn 	switch (error) {
62281180db9Smartijn 	case AX_PDU_ERROR_NOERROR:
62381180db9Smartijn 		return "No error";
62481180db9Smartijn 	case AX_PDU_ERROR_GENERR:
62581180db9Smartijn 		return "Generic error";
62681180db9Smartijn 	case AX_PDU_ERROR_NOACCESS:
62781180db9Smartijn 		return "No access";
62881180db9Smartijn 	case AX_PDU_ERROR_WRONGTYPE:
62981180db9Smartijn 		return "Wrong type";
63081180db9Smartijn 	case AX_PDU_ERROR_WRONGLENGTH:
63181180db9Smartijn 		return "Wrong length";
63281180db9Smartijn 	case AX_PDU_ERROR_WRONGENCODING:
63381180db9Smartijn 		return "Wrong encoding";
63481180db9Smartijn 	case AX_PDU_ERROR_WRONGVALUE:
63581180db9Smartijn 		return "Wrong value";
63681180db9Smartijn 	case AX_PDU_ERROR_NOCREATION:
63781180db9Smartijn 		return "No creation";
63881180db9Smartijn 	case AX_PDU_ERROR_INCONSISTENTVALUE:
63981180db9Smartijn 		return "Inconsistent value";
64081180db9Smartijn 	case AX_PDU_ERROR_RESOURCEUNAVAILABLE:
64181180db9Smartijn 		return "Resource unavailable";
64281180db9Smartijn 	case AX_PDU_ERROR_COMMITFAILED:
64381180db9Smartijn 		return "Commit failed";
64481180db9Smartijn 	case AX_PDU_ERROR_UNDOFAILED:
64581180db9Smartijn 		return "Undo failed";
64681180db9Smartijn 	case AX_PDU_ERROR_NOTWRITABLE:
64781180db9Smartijn 		return "Not writable";
64881180db9Smartijn 	case AX_PDU_ERROR_INCONSISTENTNAME:
64981180db9Smartijn 		return "Inconsistent name";
65081180db9Smartijn 	case AX_PDU_ERROR_OPENFAILED:
65181180db9Smartijn 		return "Open Failed";
65281180db9Smartijn 	case AX_PDU_ERROR_NOTOPEN:
65381180db9Smartijn 		return "Not open";
65481180db9Smartijn 	case AX_PDU_ERROR_INDEXWRONGTYPE:
65581180db9Smartijn 		return "Index wrong type";
65681180db9Smartijn 	case AX_PDU_ERROR_INDEXALREADYALLOCATED:
65781180db9Smartijn 		return "Index already allocated";
65881180db9Smartijn 	case AX_PDU_ERROR_INDEXNONEAVAILABLE:
65981180db9Smartijn 		return "Index none available";
66081180db9Smartijn 	case AX_PDU_ERROR_INDEXNOTALLOCATED:
66181180db9Smartijn 		return "Index not allocated";
66281180db9Smartijn 	case AX_PDU_ERROR_UNSUPPORTEDCONETXT:
66381180db9Smartijn 		return "Unsupported context";
66481180db9Smartijn 	case AX_PDU_ERROR_DUPLICATEREGISTRATION:
66581180db9Smartijn 		return "Duplicate registration";
66681180db9Smartijn 	case AX_PDU_ERROR_UNKNOWNREGISTRATION:
66781180db9Smartijn 		return "Unkown registration";
66881180db9Smartijn 	case AX_PDU_ERROR_UNKNOWNAGENTCAPS:
66981180db9Smartijn 		return "Unknown agent capabilities";
67081180db9Smartijn 	case AX_PDU_ERROR_PARSEERROR:
67181180db9Smartijn 		return "Parse error";
67281180db9Smartijn 	case AX_PDU_ERROR_REQUESTDENIED:
67381180db9Smartijn 		return "Request denied";
67481180db9Smartijn 	case AX_PDU_ERROR_PROCESSINGERROR:
67581180db9Smartijn 		return "Processing error";
67681180db9Smartijn 	}
67781180db9Smartijn 	snprintf(buffer, sizeof(buffer), "Unknown error: %d", error);
67881180db9Smartijn 	return buffer;
67981180db9Smartijn }
68081180db9Smartijn 
68181180db9Smartijn const char *
ax_pdutype2string(enum ax_pdu_type type)68281180db9Smartijn ax_pdutype2string(enum ax_pdu_type type)
68381180db9Smartijn {
68481180db9Smartijn 	static char buffer[64];
68581180db9Smartijn 	switch(type) {
68681180db9Smartijn 	case AX_PDU_TYPE_OPEN:
68781180db9Smartijn 		return "agentx-Open-PDU";
68881180db9Smartijn 	case AX_PDU_TYPE_CLOSE:
68981180db9Smartijn 		return "agentx-Close-PDU";
69081180db9Smartijn 	case AX_PDU_TYPE_REGISTER:
69181180db9Smartijn 		return "agentx-Register-PDU";
69281180db9Smartijn 	case AX_PDU_TYPE_UNREGISTER:
69381180db9Smartijn 		return "agentx-Unregister-PDU";
69481180db9Smartijn 	case AX_PDU_TYPE_GET:
69581180db9Smartijn 		return "agentx-Get-PDU";
69681180db9Smartijn 	case AX_PDU_TYPE_GETNEXT:
69781180db9Smartijn 		return "agentx-GetNext-PDU";
69881180db9Smartijn 	case AX_PDU_TYPE_GETBULK:
69981180db9Smartijn 		return "agentx-GetBulk-PDU";
70081180db9Smartijn 	case AX_PDU_TYPE_TESTSET:
70181180db9Smartijn 		return "agentx-TestSet-PDU";
70281180db9Smartijn 	case AX_PDU_TYPE_COMMITSET:
70381180db9Smartijn 		return "agentx-CommitSet-PDU";
70481180db9Smartijn 	case AX_PDU_TYPE_UNDOSET:
70581180db9Smartijn 		return "agentx-UndoSet-PDU";
70681180db9Smartijn 	case AX_PDU_TYPE_CLEANUPSET:
70781180db9Smartijn 		return "agentx-CleanupSet-PDU";
70881180db9Smartijn 	case AX_PDU_TYPE_NOTIFY:
70981180db9Smartijn 		return "agentx-Notify-PDU";
71081180db9Smartijn 	case AX_PDU_TYPE_PING:
71181180db9Smartijn 		return "agentx-Ping-PDU";
71281180db9Smartijn 	case AX_PDU_TYPE_INDEXALLOCATE:
71381180db9Smartijn 		return "agentx-IndexAllocate-PDU";
71481180db9Smartijn 	case AX_PDU_TYPE_INDEXDEALLOCATE:
71581180db9Smartijn 		return "agentx-IndexDeallocate-PDU";
71681180db9Smartijn 	case AX_PDU_TYPE_ADDAGENTCAPS:
71781180db9Smartijn 		return "agentx-AddAgentCaps-PDU";
71881180db9Smartijn 	case AX_PDU_TYPE_REMOVEAGENTCAPS:
71981180db9Smartijn 		return "agentx-RemoveAgentCaps-PDU";
72081180db9Smartijn 	case AX_PDU_TYPE_RESPONSE:
72181180db9Smartijn 		return "agentx-Response-PDU";
72281180db9Smartijn 	}
72381180db9Smartijn 	snprintf(buffer, sizeof(buffer), "Unknown type: %d", type);
72481180db9Smartijn 	return buffer;
72581180db9Smartijn }
72681180db9Smartijn 
72781180db9Smartijn const char *
ax_closereason2string(enum ax_close_reason reason)72881180db9Smartijn ax_closereason2string(enum ax_close_reason reason)
72981180db9Smartijn {
73081180db9Smartijn 	static char buffer[64];
73181180db9Smartijn 
73281180db9Smartijn 	switch (reason) {
73381180db9Smartijn 	case AX_CLOSE_OTHER:
73481180db9Smartijn 		return "Undefined reason";
73581180db9Smartijn 	case AX_CLOSEN_PARSEERROR:
73681180db9Smartijn 		return "Too many AgentX parse errors from peer";
73781180db9Smartijn 	case AX_CLOSE_PROTOCOLERROR:
73881180db9Smartijn 		return "Too many AgentX protocol errors from peer";
73981180db9Smartijn 	case AX_CLOSE_TIMEOUTS:
74081180db9Smartijn 		return "Too many timeouts waiting for peer";
74181180db9Smartijn 	case AX_CLOSE_SHUTDOWN:
74281180db9Smartijn 		return "shutting down";
74381180db9Smartijn 	case AX_CLOSE_BYMANAGER:
74481180db9Smartijn 		return "Manager shuts down";
74581180db9Smartijn 	}
74681180db9Smartijn 	snprintf(buffer, sizeof(buffer), "Unknown reason: %d", reason);
74781180db9Smartijn 	return buffer;
74881180db9Smartijn }
74981180db9Smartijn 
75081180db9Smartijn const char *
ax_oid2string(struct ax_oid * oid)75181180db9Smartijn ax_oid2string(struct ax_oid *oid)
75281180db9Smartijn {
75381180db9Smartijn 	return ax_oidrange2string(oid, 0, 0);
75481180db9Smartijn }
75581180db9Smartijn 
75681180db9Smartijn const char *
ax_oidrange2string(struct ax_oid * oid,uint8_t range_subid,uint32_t upperbound)75781180db9Smartijn ax_oidrange2string(struct ax_oid *oid, uint8_t range_subid,
75881180db9Smartijn     uint32_t upperbound)
75981180db9Smartijn {
76081180db9Smartijn 	static char buf[1024];
76181180db9Smartijn 	char *p;
76281180db9Smartijn 	size_t i, rest;
76381180db9Smartijn 	int ret;
76481180db9Smartijn 
76581180db9Smartijn 	rest = sizeof(buf);
76681180db9Smartijn 	p = buf;
767c47f63a5Smartijn 	if (oid->aoi_idlen == 0)
768c47f63a5Smartijn 		(void)strlcpy(buf, "null", sizeof(buf));
76981180db9Smartijn 	for (i = 0; i < oid->aoi_idlen; i++) {
77081180db9Smartijn 		if (range_subid != 0 && range_subid - 1 == (uint8_t)i)
77181180db9Smartijn 			ret = snprintf(p, rest, ".[%u-%u]", oid->aoi_id[i],
77281180db9Smartijn 			    upperbound);
77381180db9Smartijn 		else
77481180db9Smartijn 			ret = snprintf(p, rest, ".%u", oid->aoi_id[i]);
77581180db9Smartijn 		if ((size_t) ret >= rest) {
77681180db9Smartijn 			snprintf(buf, sizeof(buf), "Couldn't parse oid");
77781180db9Smartijn 			return buf;
77881180db9Smartijn 		}
77981180db9Smartijn 		p += ret;
78081180db9Smartijn 		rest -= (size_t) ret;
78181180db9Smartijn 	}
78281180db9Smartijn 	return buf;
78381180db9Smartijn }
78481180db9Smartijn 
78581180db9Smartijn const char *
ax_varbind2string(struct ax_varbind * vb)78681180db9Smartijn ax_varbind2string(struct ax_varbind *vb)
78781180db9Smartijn {
78881180db9Smartijn 	static char buf[1024];
78981180db9Smartijn 	char tmpbuf[1024];
79081180db9Smartijn 	size_t i, bufleft;
79181180db9Smartijn 	int ishex = 0;
79281180db9Smartijn 	char *p;
79381180db9Smartijn 	int ret;
79481180db9Smartijn 
79581180db9Smartijn 	switch (vb->avb_type) {
79681180db9Smartijn 	case AX_DATA_TYPE_INTEGER:
7971b6ededeSmartijn 		snprintf(buf, sizeof(buf), "%s: (int)%d",
7981b6ededeSmartijn 		    ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_int32);
79981180db9Smartijn 		break;
80081180db9Smartijn 	case AX_DATA_TYPE_OCTETSTRING:
80181180db9Smartijn 		for (i = 0;
80281180db9Smartijn 		    i < vb->avb_data.avb_ostring.aos_slen && !ishex; i++) {
80381180db9Smartijn 			if (!isprint(vb->avb_data.avb_ostring.aos_string[i]))
80481180db9Smartijn 				ishex = 1;
80581180db9Smartijn 		}
80681180db9Smartijn 		if (ishex) {
80781180db9Smartijn 			p = tmpbuf;
80881180db9Smartijn 			bufleft = sizeof(tmpbuf);
80981180db9Smartijn 			for (i = 0;
81081180db9Smartijn 			    i < vb->avb_data.avb_ostring.aos_slen; i++) {
81181180db9Smartijn 				ret = snprintf(p, bufleft, " %02hhX",
81281180db9Smartijn 				    vb->avb_data.avb_ostring.aos_string[i]);
81381180db9Smartijn 				if (ret >= (int) bufleft) {
81481180db9Smartijn 					p = strrchr(p, ' ');
81581180db9Smartijn 					strlcpy(p, "...", 4);
81681180db9Smartijn 					break;
81781180db9Smartijn 				}
81881180db9Smartijn 				p += 3;
81981180db9Smartijn 				bufleft -= 3;
82081180db9Smartijn 			}
82181180db9Smartijn 			ret = snprintf(buf, sizeof(buf), "%s: (hex-string)%s",
82281180db9Smartijn 			    ax_oid2string(&(vb->avb_oid)), tmpbuf);
82381180db9Smartijn 			if (ret >= (int) sizeof(buf)) {
82481180db9Smartijn 				p  = strrchr(buf, ' ');
82581180db9Smartijn 				strlcpy(p, "...", 4);
82681180db9Smartijn 			}
82781180db9Smartijn 		} else {
82881180db9Smartijn 			ret = snprintf(buf, sizeof(buf), "%s: (string)",
82981180db9Smartijn 			    ax_oid2string(&(vb->avb_oid)));
83081180db9Smartijn 			if (ret >= (int) sizeof(buf)) {
83181180db9Smartijn 				snprintf(buf, sizeof(buf), "<too large OID>: "
83281180db9Smartijn 				    "(string)<too large string>");
83381180db9Smartijn 				break;
83481180db9Smartijn 			}
83581180db9Smartijn 			p = buf + ret;
83681180db9Smartijn 			bufleft = (int) sizeof(buf) - ret;
83781180db9Smartijn 			if (snprintf(p, bufleft, "%.*s",
83881180db9Smartijn 			    vb->avb_data.avb_ostring.aos_slen,
83981180db9Smartijn 			    vb->avb_data.avb_ostring.aos_string) >=
84081180db9Smartijn 			    (int) bufleft) {
84181180db9Smartijn 				p = buf + sizeof(buf) - 4;
84281180db9Smartijn 				strlcpy(p, "...", 4);
84381180db9Smartijn 			}
84481180db9Smartijn 		}
84581180db9Smartijn 		break;
84681180db9Smartijn 	case AX_DATA_TYPE_NULL:
84781180db9Smartijn 		snprintf(buf, sizeof(buf), "%s: <null>",
84881180db9Smartijn 		    ax_oid2string(&(vb->avb_oid)));
84981180db9Smartijn 		break;
85081180db9Smartijn 	case AX_DATA_TYPE_OID:
85181180db9Smartijn 		strlcpy(tmpbuf,
85281180db9Smartijn 		    ax_oid2string(&(vb->avb_data.avb_oid)), sizeof(tmpbuf));
85381180db9Smartijn 		snprintf(buf, sizeof(buf), "%s: (oid)%s",
85481180db9Smartijn 		    ax_oid2string(&(vb->avb_oid)), tmpbuf);
85581180db9Smartijn 		break;
85681180db9Smartijn 	case AX_DATA_TYPE_IPADDRESS:
85781180db9Smartijn 		if (vb->avb_data.avb_ostring.aos_slen != 4) {
85881180db9Smartijn 			snprintf(buf, sizeof(buf), "%s: (ipaddress)<invalid>",
85981180db9Smartijn 			    ax_oid2string(&(vb->avb_oid)));
86081180db9Smartijn 			break;
86181180db9Smartijn 		}
86281180db9Smartijn 		if (inet_ntop(PF_INET, vb->avb_data.avb_ostring.aos_string,
86381180db9Smartijn 		    tmpbuf, sizeof(tmpbuf)) == NULL) {
86481180db9Smartijn 			snprintf(buf, sizeof(buf), "%s: (ipaddress)"
86581180db9Smartijn 			    "<unparseable>: %s",
86681180db9Smartijn 			    ax_oid2string(&(vb->avb_oid)),
86781180db9Smartijn 			    strerror(errno));
86881180db9Smartijn 			break;
86981180db9Smartijn 		}
87081180db9Smartijn 		snprintf(buf, sizeof(buf), "%s: (ipaddress)%s",
87181180db9Smartijn 		    ax_oid2string(&(vb->avb_oid)), tmpbuf);
87281180db9Smartijn 		break;
87381180db9Smartijn 	case AX_DATA_TYPE_COUNTER32:
87481180db9Smartijn 		snprintf(buf, sizeof(buf), "%s: (counter32)%u",
87581180db9Smartijn 		    ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32);
87681180db9Smartijn 		break;
87781180db9Smartijn 	case AX_DATA_TYPE_GAUGE32:
87881180db9Smartijn 		snprintf(buf, sizeof(buf), "%s: (gauge32)%u",
87981180db9Smartijn 		    ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32);
88081180db9Smartijn 		break;
88181180db9Smartijn 	case AX_DATA_TYPE_TIMETICKS:
88281180db9Smartijn 		snprintf(buf, sizeof(buf), "%s: (timeticks)%u",
88381180db9Smartijn 		    ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32);
88481180db9Smartijn 		break;
88581180db9Smartijn 	case AX_DATA_TYPE_OPAQUE:
88681180db9Smartijn 		p = tmpbuf;
88781180db9Smartijn 		bufleft = sizeof(tmpbuf);
88881180db9Smartijn 		for (i = 0;
88981180db9Smartijn 		    i < vb->avb_data.avb_ostring.aos_slen; i++) {
89081180db9Smartijn 			ret = snprintf(p, bufleft, " %02hhX",
89181180db9Smartijn 			    vb->avb_data.avb_ostring.aos_string[i]);
89281180db9Smartijn 			if (ret >= (int) bufleft) {
89381180db9Smartijn 				p = strrchr(p, ' ');
89481180db9Smartijn 				strlcpy(p, "...", 4);
89581180db9Smartijn 				break;
89681180db9Smartijn 			}
89781180db9Smartijn 			p += 3;
89881180db9Smartijn 			bufleft -= 3;
89981180db9Smartijn 		}
90081180db9Smartijn 		ret = snprintf(buf, sizeof(buf), "%s: (opaque)%s",
90181180db9Smartijn 		    ax_oid2string(&(vb->avb_oid)), tmpbuf);
90281180db9Smartijn 		if (ret >= (int) sizeof(buf)) {
90381180db9Smartijn 			p  = strrchr(buf, ' ');
90481180db9Smartijn 			strlcpy(p, "...", 4);
90581180db9Smartijn 		}
90681180db9Smartijn 		break;
90781180db9Smartijn 	case AX_DATA_TYPE_COUNTER64:
90881180db9Smartijn 		snprintf(buf, sizeof(buf), "%s: (counter64)%"PRIu64,
90981180db9Smartijn 		    ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint64);
91081180db9Smartijn 		break;
91181180db9Smartijn 	case AX_DATA_TYPE_NOSUCHOBJECT:
91281180db9Smartijn 		snprintf(buf, sizeof(buf), "%s: <noSuchObject>",
91381180db9Smartijn 		    ax_oid2string(&(vb->avb_oid)));
91481180db9Smartijn 		break;
91581180db9Smartijn 	case AX_DATA_TYPE_NOSUCHINSTANCE:
91681180db9Smartijn 		snprintf(buf, sizeof(buf), "%s: <noSuchInstance>",
91781180db9Smartijn 		    ax_oid2string(&(vb->avb_oid)));
91881180db9Smartijn 		break;
91981180db9Smartijn 	case AX_DATA_TYPE_ENDOFMIBVIEW:
92081180db9Smartijn 		snprintf(buf, sizeof(buf), "%s: <endOfMibView>",
92181180db9Smartijn 		    ax_oid2string(&(vb->avb_oid)));
92281180db9Smartijn 		break;
92381180db9Smartijn 	}
92481180db9Smartijn 	return buf;
92581180db9Smartijn }
92681180db9Smartijn 
92781180db9Smartijn int
ax_oid_cmp(struct ax_oid * o1,struct ax_oid * o2)92881180db9Smartijn ax_oid_cmp(struct ax_oid *o1, struct ax_oid *o2)
92981180db9Smartijn {
93081180db9Smartijn 	size_t i, min;
93181180db9Smartijn 
93281180db9Smartijn 	min = o1->aoi_idlen < o2->aoi_idlen ? o1->aoi_idlen : o2->aoi_idlen;
93381180db9Smartijn 	for (i = 0; i < min; i++) {
93481180db9Smartijn 		if (o1->aoi_id[i] < o2->aoi_id[i])
93581180db9Smartijn 			return -1;
93681180db9Smartijn 		if (o1->aoi_id[i] > o2->aoi_id[i])
93781180db9Smartijn 			return 1;
93881180db9Smartijn 	}
93981180db9Smartijn 	/* o1 is parent of o2 */
94081180db9Smartijn 	if (o1->aoi_idlen < o2->aoi_idlen)
94181180db9Smartijn 		return -2;
94281180db9Smartijn 	/* o1 is child of o2 */
94381180db9Smartijn 	if (o1->aoi_idlen > o2->aoi_idlen)
94481180db9Smartijn 		return 2;
94581180db9Smartijn 	return 0;
94681180db9Smartijn }
94781180db9Smartijn 
94881180db9Smartijn int
ax_oid_add(struct ax_oid * oid,uint32_t value)94981180db9Smartijn ax_oid_add(struct ax_oid *oid, uint32_t value)
95081180db9Smartijn {
95181180db9Smartijn 	if (oid->aoi_idlen == AX_OID_MAX_LEN)
95281180db9Smartijn 		return -1;
95381180db9Smartijn 	oid->aoi_id[oid->aoi_idlen++] = value;
95481180db9Smartijn 	return 0;
95581180db9Smartijn }
95681180db9Smartijn 
95781180db9Smartijn static uint32_t
ax_pdu_queue(struct ax * ax)95881180db9Smartijn ax_pdu_queue(struct ax *ax)
95981180db9Smartijn {
96081180db9Smartijn 	struct ax_pdu_header header;
96181180db9Smartijn 	uint32_t packetid, plength;
96281180db9Smartijn 	size_t wbtlen = ax->ax_wbtlen;
96381180db9Smartijn 
96481180db9Smartijn 	header.aph_flags = ax->ax_byteorder == AX_BYTE_ORDER_BE ?
96581180db9Smartijn 	    AX_PDU_FLAG_NETWORK_BYTE_ORDER : 0;
96681180db9Smartijn 	packetid = ax_pdutoh32(&header, &(ax->ax_wbuf[ax->ax_wblen + 12]));
96781180db9Smartijn 	plength = (ax->ax_wbtlen - ax->ax_wblen) - AX_PDU_HEADER;
96881180db9Smartijn 	ax->ax_wbtlen = ax->ax_wblen + 16;
96981180db9Smartijn 	(void)ax_pdu_add_uint32(ax, plength);
97081180db9Smartijn 
97181180db9Smartijn 	ax->ax_wblen = ax->ax_wbtlen = wbtlen;
97281180db9Smartijn 
97381180db9Smartijn 	return packetid;
97481180db9Smartijn }
97581180db9Smartijn 
97681180db9Smartijn 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)97781180db9Smartijn ax_pdu_header(struct ax *ax, enum ax_pdu_type type, uint8_t flags,
97881180db9Smartijn     uint32_t sessionid, uint32_t transactionid, uint32_t packetid,
97981180db9Smartijn     struct ax_ostring *context)
98081180db9Smartijn {
98181180db9Smartijn 	if (ax->ax_wblen != ax->ax_wbtlen) {
98281180db9Smartijn 		errno = EALREADY;
98381180db9Smartijn 		return -1;
98481180db9Smartijn 	}
98581180db9Smartijn 
98681180db9Smartijn 	if (ax_pdu_need(ax, 4) == -1)
98781180db9Smartijn 		return -1;
98881180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = 1;
98981180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = (uint8_t) type;
99081180db9Smartijn 	if (context != NULL)
99181180db9Smartijn 		flags |= AX_PDU_FLAG_NON_DEFAULT_CONTEXT;
99281180db9Smartijn 	if (ax->ax_byteorder == AX_BYTE_ORDER_BE)
99381180db9Smartijn 		flags |= AX_PDU_FLAG_NETWORK_BYTE_ORDER;
99481180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = flags;
99581180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = 0;
99681180db9Smartijn 	if (packetid == 0)
99781180db9Smartijn 		packetid = ax_packetid(ax);
99881180db9Smartijn 	if (ax_pdu_add_uint32(ax, sessionid) == -1 ||
99981180db9Smartijn 	    ax_pdu_add_uint32(ax, transactionid) == -1 ||
100081180db9Smartijn 	    ax_pdu_add_uint32(ax, packetid) == -1 ||
100181180db9Smartijn 	    ax_pdu_need(ax, 4) == -1)
100281180db9Smartijn 		return -1;
100381180db9Smartijn 	ax->ax_wbtlen += 4;
100481180db9Smartijn 	if (context != NULL) {
100581180db9Smartijn 		if (ax_pdu_add_str(ax, context) == -1)
100681180db9Smartijn 			return -1;
100781180db9Smartijn 	}
100881180db9Smartijn 
100981180db9Smartijn 	return 0;
101081180db9Smartijn }
101181180db9Smartijn 
101281180db9Smartijn static uint32_t
ax_packetid(struct ax * ax)101381180db9Smartijn ax_packetid(struct ax *ax)
101481180db9Smartijn {
101581180db9Smartijn 	uint32_t packetid, *packetids;
101681180db9Smartijn 	size_t npackets = 0, i;
101781180db9Smartijn 	int found;
101881180db9Smartijn 
101981180db9Smartijn 	if (ax->ax_packetids != NULL) {
102081180db9Smartijn 		for (npackets = 0; ax->ax_packetids[npackets] != 0; npackets++)
102181180db9Smartijn 			continue;
102281180db9Smartijn 	}
102381180db9Smartijn 	if (ax->ax_packetidsize == 0 || npackets == ax->ax_packetidsize - 1) {
102481180db9Smartijn 		packetids = recallocarray(ax->ax_packetids, ax->ax_packetidsize,
102581180db9Smartijn 		    ax->ax_packetidsize + 25, sizeof(*packetids));
102681180db9Smartijn 		if (packetids == NULL)
102781180db9Smartijn 			return 0;
102881180db9Smartijn 		ax->ax_packetidsize += 25;
102981180db9Smartijn 		ax->ax_packetids = packetids;
103081180db9Smartijn 	}
103181180db9Smartijn 	do {
103281180db9Smartijn 		found = 0;
103381180db9Smartijn 		packetid = arc4random();
103481180db9Smartijn 		for (i = 0; ax->ax_packetids[i] != 0; i++) {
103581180db9Smartijn 			if (ax->ax_packetids[i] == packetid) {
103681180db9Smartijn 				found = 1;
103781180db9Smartijn 				break;
103881180db9Smartijn 			}
103981180db9Smartijn 		}
104081180db9Smartijn 	} while (packetid == 0 || found);
104181180db9Smartijn 	ax->ax_packetids[npackets] = packetid;
104281180db9Smartijn 
104381180db9Smartijn 	return packetid;
104481180db9Smartijn }
104581180db9Smartijn 
104681180db9Smartijn static int
ax_pdu_add_uint16(struct ax * ax,uint16_t value)104781180db9Smartijn ax_pdu_add_uint16(struct ax *ax, uint16_t value)
104881180db9Smartijn {
104981180db9Smartijn 	if (ax_pdu_need(ax, sizeof(value)) == -1)
105081180db9Smartijn 		return -1;
105181180db9Smartijn 
105281180db9Smartijn 	if (ax->ax_byteorder == AX_BYTE_ORDER_BE)
105381180db9Smartijn 		value = htobe16(value);
105481180db9Smartijn 	else
105581180db9Smartijn 		value = htole16(value);
105681180db9Smartijn 	memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value));
105781180db9Smartijn 	ax->ax_wbtlen += sizeof(value);
105881180db9Smartijn 	return 0;
105981180db9Smartijn }
106081180db9Smartijn 
106181180db9Smartijn static int
ax_pdu_add_uint32(struct ax * ax,uint32_t value)106281180db9Smartijn ax_pdu_add_uint32(struct ax *ax, uint32_t value)
106381180db9Smartijn {
106481180db9Smartijn 	if (ax_pdu_need(ax, sizeof(value)) == -1)
106581180db9Smartijn 		return -1;
106681180db9Smartijn 
106781180db9Smartijn 	if (ax->ax_byteorder == AX_BYTE_ORDER_BE)
106881180db9Smartijn 		value = htobe32(value);
106981180db9Smartijn 	else
107081180db9Smartijn 		value = htole32(value);
107181180db9Smartijn 	memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value));
107281180db9Smartijn 	ax->ax_wbtlen += sizeof(value);
107381180db9Smartijn 	return 0;
107481180db9Smartijn }
107581180db9Smartijn 
107681180db9Smartijn static int
ax_pdu_add_uint64(struct ax * ax,uint64_t value)107781180db9Smartijn ax_pdu_add_uint64(struct ax *ax, uint64_t value)
107881180db9Smartijn {
107981180db9Smartijn 	if (ax_pdu_need(ax, sizeof(value)) == -1)
108081180db9Smartijn 		return -1;
108181180db9Smartijn 
108281180db9Smartijn 	if (ax->ax_byteorder == AX_BYTE_ORDER_BE)
108381180db9Smartijn 		value = htobe64(value);
108481180db9Smartijn 	else
108581180db9Smartijn 		value = htole64(value);
108681180db9Smartijn 	memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value));
108781180db9Smartijn 	ax->ax_wbtlen += sizeof(value);
108881180db9Smartijn 	return 0;
108981180db9Smartijn }
109081180db9Smartijn 
109181180db9Smartijn 
109281180db9Smartijn static int
ax_pdu_add_oid(struct ax * ax,struct ax_oid * oid,int include)109381180db9Smartijn ax_pdu_add_oid(struct ax *ax, struct ax_oid *oid, int include)
109481180db9Smartijn {
109581180db9Smartijn 	static struct ax_oid nulloid = {0};
109681180db9Smartijn 	uint8_t prefix = 0, n_subid, i = 0;
109781180db9Smartijn 
109881180db9Smartijn 	n_subid = oid->aoi_idlen;
109981180db9Smartijn 
110081180db9Smartijn 	if (oid == NULL)
110181180db9Smartijn 		oid = &nulloid;
110281180db9Smartijn 
110381180db9Smartijn 	if (oid->aoi_idlen > 4 &&
110481180db9Smartijn 	    oid->aoi_id[0] == 1 && oid->aoi_id[1] == 3 &&
110581180db9Smartijn 	    oid->aoi_id[2] == 6 && oid->aoi_id[3] == 1 &&
110681180db9Smartijn 	    oid->aoi_id[4] <= UINT8_MAX) {
110781180db9Smartijn 		prefix = oid->aoi_id[4];
110881180db9Smartijn 		i = 5;
110981180db9Smartijn 	}
111081180db9Smartijn 
111181180db9Smartijn 	if (ax_pdu_need(ax, 4) == -1)
111281180db9Smartijn 		return -1;
111381180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = n_subid - i;
111481180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = prefix;
111581180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = !!include;
111681180db9Smartijn 	ax->ax_wbuf[ax->ax_wbtlen++] = 0;
111781180db9Smartijn 
111881180db9Smartijn 	for (; i < n_subid; i++) {
111981180db9Smartijn 		if (ax_pdu_add_uint32(ax, oid->aoi_id[i]) == -1)
112081180db9Smartijn 			return -1;
112181180db9Smartijn 	}
112281180db9Smartijn 
112381180db9Smartijn 	return 0;
112481180db9Smartijn }
112581180db9Smartijn 
112681180db9Smartijn static int
ax_pdu_add_str(struct ax * ax,struct ax_ostring * str)112781180db9Smartijn ax_pdu_add_str(struct ax *ax, struct ax_ostring *str)
112881180db9Smartijn {
112981180db9Smartijn 	size_t length, zeroes;
113081180db9Smartijn 
113181180db9Smartijn 	if (ax_pdu_add_uint32(ax, str->aos_slen) == -1)
113281180db9Smartijn 		return -1;
113381180db9Smartijn 
113481180db9Smartijn 	if ((zeroes = (4 - (str->aos_slen % 4))) == 4)
113581180db9Smartijn 		zeroes = 0;
113681180db9Smartijn 	length = str->aos_slen + zeroes;
113781180db9Smartijn 	if (ax_pdu_need(ax, length) == -1)
113881180db9Smartijn 		return -1;
113981180db9Smartijn 
114081180db9Smartijn 	memcpy(&(ax->ax_wbuf[ax->ax_wbtlen]), str->aos_string, str->aos_slen);
114181180db9Smartijn 	ax->ax_wbtlen += str->aos_slen;
114281180db9Smartijn 	memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, zeroes);
114381180db9Smartijn 	ax->ax_wbtlen += zeroes;
114481180db9Smartijn 	return 0;
114581180db9Smartijn }
114681180db9Smartijn 
114781180db9Smartijn static int
ax_pdu_add_varbindlist(struct ax * ax,struct ax_varbind * vblist,size_t nvb)114881180db9Smartijn ax_pdu_add_varbindlist(struct ax *ax,
114981180db9Smartijn     struct ax_varbind *vblist, size_t nvb)
115081180db9Smartijn {
115181180db9Smartijn 	size_t i;
115281180db9Smartijn 	uint16_t temp;
115381180db9Smartijn 
115481180db9Smartijn 	for (i = 0; i < nvb; i++) {
115581180db9Smartijn 		temp = (uint16_t) vblist[i].avb_type;
115681180db9Smartijn 		if (ax_pdu_add_uint16(ax, temp) == -1 ||
115781180db9Smartijn 		    ax_pdu_need(ax, 2))
115881180db9Smartijn 			return -1;
115981180db9Smartijn 		memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 2);
116081180db9Smartijn 		ax->ax_wbtlen += 2;
116181180db9Smartijn 		if (ax_pdu_add_oid(ax, &(vblist[i].avb_oid), 0) == -1)
116281180db9Smartijn 			return -1;
116381180db9Smartijn 		switch (vblist[i].avb_type) {
116481180db9Smartijn 		case AX_DATA_TYPE_INTEGER:
11651b6ededeSmartijn 			if (ax_pdu_add_uint32(ax,
11661b6ededeSmartijn 			    vblist[i].avb_data.avb_int32) == -1)
11671b6ededeSmartijn 				return -1;
11681b6ededeSmartijn 			break;
116981180db9Smartijn 		case AX_DATA_TYPE_COUNTER32:
117081180db9Smartijn 		case AX_DATA_TYPE_GAUGE32:
117181180db9Smartijn 		case AX_DATA_TYPE_TIMETICKS:
117281180db9Smartijn 			if (ax_pdu_add_uint32(ax,
117381180db9Smartijn 			    vblist[i].avb_data.avb_uint32) == -1)
117481180db9Smartijn 				return -1;
117581180db9Smartijn 			break;
117681180db9Smartijn 		case AX_DATA_TYPE_COUNTER64:
117781180db9Smartijn 			if (ax_pdu_add_uint64(ax,
117881180db9Smartijn 			    vblist[i].avb_data.avb_uint64) == -1)
117981180db9Smartijn 				return -1;
118081180db9Smartijn 			break;
118181180db9Smartijn 		case AX_DATA_TYPE_OCTETSTRING:
118281180db9Smartijn 		case AX_DATA_TYPE_IPADDRESS:
118381180db9Smartijn 		case AX_DATA_TYPE_OPAQUE:
118481180db9Smartijn 			if (ax_pdu_add_str(ax,
118581180db9Smartijn 			    &(vblist[i].avb_data.avb_ostring)) == -1)
118681180db9Smartijn 				return -1;
118781180db9Smartijn 			break;
118881180db9Smartijn 		case AX_DATA_TYPE_OID:
118981180db9Smartijn 			if (ax_pdu_add_oid(ax,
119081180db9Smartijn 			    &(vblist[i].avb_data.avb_oid), 1) == -1)
119181180db9Smartijn 				return -1;
119281180db9Smartijn 			break;
119381180db9Smartijn 		case AX_DATA_TYPE_NULL:
119481180db9Smartijn 		case AX_DATA_TYPE_NOSUCHOBJECT:
119581180db9Smartijn 		case AX_DATA_TYPE_NOSUCHINSTANCE:
119681180db9Smartijn 		case AX_DATA_TYPE_ENDOFMIBVIEW:
119781180db9Smartijn 			break;
119881180db9Smartijn 		default:
119981180db9Smartijn 			errno = EINVAL;
120081180db9Smartijn 			return -1;
120181180db9Smartijn 		}
120281180db9Smartijn 	}
120381180db9Smartijn 	return 0;
120481180db9Smartijn }
120581180db9Smartijn 
120681180db9Smartijn static uint16_t
ax_pdutoh16(struct ax_pdu_header * header,uint8_t * buf)120781180db9Smartijn ax_pdutoh16(struct ax_pdu_header *header, uint8_t *buf)
120881180db9Smartijn {
120981180db9Smartijn 	uint16_t value;
121081180db9Smartijn 
121181180db9Smartijn 	memcpy(&value, buf, sizeof(value));
121281180db9Smartijn 	if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER)
121381180db9Smartijn 		return be16toh(value);
121481180db9Smartijn 	return le16toh(value);
121581180db9Smartijn }
121681180db9Smartijn 
121781180db9Smartijn static uint32_t
ax_pdutoh32(struct ax_pdu_header * header,uint8_t * buf)121881180db9Smartijn ax_pdutoh32(struct ax_pdu_header *header, uint8_t *buf)
121981180db9Smartijn {
122081180db9Smartijn 	uint32_t value;
122181180db9Smartijn 
122281180db9Smartijn 	memcpy(&value, buf, sizeof(value));
122381180db9Smartijn 	if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER)
122481180db9Smartijn 		return be32toh(value);
122581180db9Smartijn 	return le32toh(value);
122681180db9Smartijn }
122781180db9Smartijn 
122881180db9Smartijn static uint64_t
ax_pdutoh64(struct ax_pdu_header * header,uint8_t * buf)122981180db9Smartijn ax_pdutoh64(struct ax_pdu_header *header, uint8_t *buf)
123081180db9Smartijn {
123181180db9Smartijn 	uint64_t value;
123281180db9Smartijn 
123381180db9Smartijn 	memcpy(&value, buf, sizeof(value));
123481180db9Smartijn 	if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER)
123581180db9Smartijn 		return be64toh(value);
123681180db9Smartijn 	return le64toh(value);
123781180db9Smartijn }
123881180db9Smartijn 
123981180db9Smartijn static ssize_t
ax_pdutooid(struct ax_pdu_header * header,struct ax_oid * oid,uint8_t * buf,size_t rawlen)124081180db9Smartijn ax_pdutooid(struct ax_pdu_header *header, struct ax_oid *oid,
124181180db9Smartijn     uint8_t *buf, size_t rawlen)
124281180db9Smartijn {
124381180db9Smartijn 	size_t i = 0;
124481180db9Smartijn 	ssize_t nread;
124581180db9Smartijn 
124681180db9Smartijn 	if (rawlen < 4)
124781180db9Smartijn 		goto fail;
124881180db9Smartijn 	rawlen -= 4;
124981180db9Smartijn 	nread = 4;
125081180db9Smartijn 	oid->aoi_idlen = *buf++;
125181180db9Smartijn 	if (rawlen < (oid->aoi_idlen * 4))
125281180db9Smartijn 		goto fail;
125381180db9Smartijn 	nread += oid->aoi_idlen * 4;
125481180db9Smartijn 	if (*buf != 0) {
125581180db9Smartijn 		oid->aoi_id[0] = 1;
125681180db9Smartijn 		oid->aoi_id[1] = 3;
125781180db9Smartijn 		oid->aoi_id[2] = 6;
125881180db9Smartijn 		oid->aoi_id[3] = 1;
125981180db9Smartijn 		oid->aoi_id[4] = *buf;
126081180db9Smartijn 		oid->aoi_idlen += 5;
126181180db9Smartijn 		i = 5;
126281180db9Smartijn 	}
126381180db9Smartijn 	buf++;
126481180db9Smartijn 	oid->aoi_include = *buf;
12655fd2bbf0Smartijn 	if (oid->aoi_idlen > AX_OID_MAX_LEN)
12665fd2bbf0Smartijn 		goto fail;
126781180db9Smartijn 	for (buf += 2; i < oid->aoi_idlen; i++, buf += 4)
126881180db9Smartijn 		oid->aoi_id[i] = ax_pdutoh32(header, buf);
126981180db9Smartijn 
127081180db9Smartijn 	return nread;
127181180db9Smartijn 
127281180db9Smartijn fail:
127381180db9Smartijn 	errno = EPROTO;
127481180db9Smartijn 	return -1;
127581180db9Smartijn }
127681180db9Smartijn 
127781180db9Smartijn static ssize_t
ax_pdutoostring(struct ax_pdu_header * header,struct ax_ostring * ostring,uint8_t * buf,size_t rawlen)127881180db9Smartijn ax_pdutoostring(struct ax_pdu_header *header,
127981180db9Smartijn     struct ax_ostring *ostring, uint8_t *buf, size_t rawlen)
128081180db9Smartijn {
128181180db9Smartijn 	ssize_t nread;
128281180db9Smartijn 
128381180db9Smartijn 	if (rawlen < 4)
128481180db9Smartijn 		goto fail;
128581180db9Smartijn 
128681180db9Smartijn 	ostring->aos_slen = ax_pdutoh32(header, buf);
128781180db9Smartijn 	rawlen -= 4;
128881180db9Smartijn 	buf += 4;
128981180db9Smartijn 	if (ostring->aos_slen > rawlen)
129081180db9Smartijn 		goto fail;
129181180db9Smartijn 	if ((ostring->aos_string = malloc(ostring->aos_slen + 1)) == NULL)
129281180db9Smartijn 		return -1;
129381180db9Smartijn 	memcpy(ostring->aos_string, buf, ostring->aos_slen);
129481180db9Smartijn 	ostring->aos_string[ostring->aos_slen] = '\0';
129581180db9Smartijn 
129681180db9Smartijn 	nread = 4 + ostring->aos_slen;
129781180db9Smartijn 	if (ostring->aos_slen % 4 != 0)
129881180db9Smartijn 		nread += 4 - (ostring->aos_slen % 4);
129981180db9Smartijn 
130081180db9Smartijn 	return nread;
130181180db9Smartijn 
130281180db9Smartijn fail:
130381180db9Smartijn 	errno = EPROTO;
130481180db9Smartijn 	return -1;
130581180db9Smartijn }
130681180db9Smartijn 
130781180db9Smartijn static ssize_t
ax_pdutovarbind(struct ax_pdu_header * header,struct ax_varbind * varbind,uint8_t * buf,size_t rawlen)130881180db9Smartijn ax_pdutovarbind(struct ax_pdu_header *header,
130981180db9Smartijn     struct ax_varbind *varbind, uint8_t *buf, size_t rawlen)
131081180db9Smartijn {
131181180db9Smartijn 	ssize_t nread, rread = 4;
131281180db9Smartijn 
131381180db9Smartijn 	if (rawlen == 0)
131481180db9Smartijn 		return 0;
131581180db9Smartijn 
131681180db9Smartijn 	if (rawlen < 8)
131781180db9Smartijn 		goto fail;
131881180db9Smartijn 	varbind->avb_type = ax_pdutoh16(header, buf);
131981180db9Smartijn 
132081180db9Smartijn 	buf += 4;
132181180db9Smartijn 	rawlen -= 4;
132281180db9Smartijn 	nread = ax_pdutooid(header, &(varbind->avb_oid), buf, rawlen);
132381180db9Smartijn 	if (nread == -1)
132481180db9Smartijn 		return -1;
132581180db9Smartijn 	rread += nread;
132681180db9Smartijn 	buf += nread;
132781180db9Smartijn 	rawlen -= nread;
132881180db9Smartijn 
132981180db9Smartijn 	switch(varbind->avb_type) {
133081180db9Smartijn 	case AX_DATA_TYPE_INTEGER:
13311b6ededeSmartijn 		if (rawlen < 4)
13321b6ededeSmartijn 			goto fail;
13331b6ededeSmartijn 		varbind->avb_data.avb_int32 = ax_pdutoh32(header, buf);
13341b6ededeSmartijn 		return rread + 4;
133581180db9Smartijn 	case AX_DATA_TYPE_COUNTER32:
133681180db9Smartijn 	case AX_DATA_TYPE_GAUGE32:
133781180db9Smartijn 	case AX_DATA_TYPE_TIMETICKS:
133881180db9Smartijn 		if (rawlen < 4)
133981180db9Smartijn 			goto fail;
134081180db9Smartijn 		varbind->avb_data.avb_uint32 = ax_pdutoh32(header, buf);
134181180db9Smartijn 		return rread + 4;
134281180db9Smartijn 	case AX_DATA_TYPE_COUNTER64:
134381180db9Smartijn 		if (rawlen < 8)
134481180db9Smartijn 			goto fail;
134581180db9Smartijn 		varbind->avb_data.avb_uint64 = ax_pdutoh64(header, buf);
134681180db9Smartijn 		return rread + 8;
134781180db9Smartijn 	case AX_DATA_TYPE_OCTETSTRING:
134881180db9Smartijn 	case AX_DATA_TYPE_IPADDRESS:
134981180db9Smartijn 	case AX_DATA_TYPE_OPAQUE:
135081180db9Smartijn 		nread = ax_pdutoostring(header,
135181180db9Smartijn 		    &(varbind->avb_data.avb_ostring), buf, rawlen);
135281180db9Smartijn 		if (nread == -1)
135381180db9Smartijn 			return -1;
135481180db9Smartijn 		return nread + rread;
135581180db9Smartijn 	case AX_DATA_TYPE_OID:
135681180db9Smartijn 		nread = ax_pdutooid(header, &(varbind->avb_data.avb_oid),
135781180db9Smartijn 		    buf, rawlen);
135881180db9Smartijn 		if (nread == -1)
135981180db9Smartijn 			return -1;
136081180db9Smartijn 		return nread + rread;
136181180db9Smartijn 	case AX_DATA_TYPE_NULL:
136281180db9Smartijn 	case AX_DATA_TYPE_NOSUCHOBJECT:
136381180db9Smartijn 	case AX_DATA_TYPE_NOSUCHINSTANCE:
136481180db9Smartijn 	case AX_DATA_TYPE_ENDOFMIBVIEW:
136581180db9Smartijn 		return rread;
136681180db9Smartijn 	}
136781180db9Smartijn 
136881180db9Smartijn fail:
136981180db9Smartijn 	errno = EPROTO;
137081180db9Smartijn 	return -1;
137181180db9Smartijn }
1372