1*a2f04351SSebastien Roy /*
2*a2f04351SSebastien Roy  * CDDL HEADER START
3*a2f04351SSebastien Roy  *
4*a2f04351SSebastien Roy  * This file and its contents are supplied under the terms of the
5*a2f04351SSebastien Roy  * Common Development and Distribution License ("CDDL"), version 1.0.
6*a2f04351SSebastien Roy  * You may only use this file in accordance with the terms of version
7*a2f04351SSebastien Roy  * 1.0 of the CDDL.
8*a2f04351SSebastien Roy  *
9*a2f04351SSebastien Roy  * A full copy of the text of the CDDL should have accompanied this
10*a2f04351SSebastien Roy  * source.  A copy of the CDDL is also available via the Internet at
11*a2f04351SSebastien Roy  * http://www.illumos.org/license/CDDL.
12*a2f04351SSebastien Roy  *
13*a2f04351SSebastien Roy  * CDDL HEADER END
14*a2f04351SSebastien Roy  */
15*a2f04351SSebastien Roy /*
16*a2f04351SSebastien Roy  * Copyright (c) 2015 by Delphix. All rights reserved.
17*a2f04351SSebastien Roy  */
18*a2f04351SSebastien Roy 
19*a2f04351SSebastien Roy #include <err.h>
20*a2f04351SSebastien Roy #include <stdio.h>
21*a2f04351SSebastien Roy #include <stdlib.h>
22*a2f04351SSebastien Roy #include <errno.h>
23*a2f04351SSebastien Roy #include <fcntl.h>
24*a2f04351SSebastien Roy #include <strings.h>
25*a2f04351SSebastien Roy #include <unistd.h>
26*a2f04351SSebastien Roy #include <stropts.h>
27*a2f04351SSebastien Roy #include <sys/debug.h>
28*a2f04351SSebastien Roy #include <sys/tihdr.h>
29*a2f04351SSebastien Roy #include "connstat.h"
30*a2f04351SSebastien Roy 
31*a2f04351SSebastien Roy int
mibopen(const char * proto)32*a2f04351SSebastien Roy mibopen(const char *proto)
33*a2f04351SSebastien Roy {
34*a2f04351SSebastien Roy 	int saved;
35*a2f04351SSebastien Roy 	int fd;
36*a2f04351SSebastien Roy 
37*a2f04351SSebastien Roy 	fd = open("/dev/arp", O_RDWR);
38*a2f04351SSebastien Roy 	if (fd == -1) {
39*a2f04351SSebastien Roy 		return (-1);
40*a2f04351SSebastien Roy 	}
41*a2f04351SSebastien Roy 
42*a2f04351SSebastien Roy 	if (ioctl(fd, I_PUSH, proto) == -1) {
43*a2f04351SSebastien Roy 		saved = errno;
44*a2f04351SSebastien Roy 		(void) close(fd);
45*a2f04351SSebastien Roy 		errno = saved;
46*a2f04351SSebastien Roy 		return (-1);
47*a2f04351SSebastien Roy 	}
48*a2f04351SSebastien Roy 
49*a2f04351SSebastien Roy 	return (fd);
50*a2f04351SSebastien Roy }
51*a2f04351SSebastien Roy 
52*a2f04351SSebastien Roy int
conn_walk(int fd,connstat_proto_t * proto,conn_walk_state_t * state)53*a2f04351SSebastien Roy conn_walk(int fd, connstat_proto_t *proto, conn_walk_state_t *state)
54*a2f04351SSebastien Roy {
55*a2f04351SSebastien Roy 	struct strbuf cbuf, dbuf;
56*a2f04351SSebastien Roy 	struct opthdr *hdr;
57*a2f04351SSebastien Roy 	int flags, r, err = 0;
58*a2f04351SSebastien Roy 	struct {
59*a2f04351SSebastien Roy 		struct T_optmgmt_req req;
60*a2f04351SSebastien Roy 		struct opthdr hdr;
61*a2f04351SSebastien Roy 	} req;
62*a2f04351SSebastien Roy 	union {
63*a2f04351SSebastien Roy 		struct T_optmgmt_ack ack;
64*a2f04351SSebastien Roy 		uint8_t space[sizeof (struct T_optmgmt_ack) +
65*a2f04351SSebastien Roy 		    sizeof (struct opthdr) * 2];
66*a2f04351SSebastien Roy 	} ack;
67*a2f04351SSebastien Roy 
68*a2f04351SSebastien Roy 	bzero(&cbuf, sizeof (cbuf));
69*a2f04351SSebastien Roy 	bzero(&dbuf, sizeof (dbuf));
70*a2f04351SSebastien Roy 
71*a2f04351SSebastien Roy 	req.req.PRIM_type = T_OPTMGMT_REQ;
72*a2f04351SSebastien Roy 	req.req.OPT_offset = (caddr_t)&req.hdr - (caddr_t)&req;
73*a2f04351SSebastien Roy 	req.req.OPT_length = sizeof (req.hdr);
74*a2f04351SSebastien Roy 	req.req.MGMT_flags = T_CURRENT;
75*a2f04351SSebastien Roy 
76*a2f04351SSebastien Roy 	req.hdr.level = proto->csp_miblevel;
77*a2f04351SSebastien Roy 	req.hdr.name = 0;
78*a2f04351SSebastien Roy 	req.hdr.len = 0;
79*a2f04351SSebastien Roy 
80*a2f04351SSebastien Roy 	cbuf.buf = (caddr_t)&req;
81*a2f04351SSebastien Roy 	cbuf.len = sizeof (req);
82*a2f04351SSebastien Roy 
83*a2f04351SSebastien Roy 	if (putmsg(fd, &cbuf, NULL, 0) == -1) {
84*a2f04351SSebastien Roy 		warn("failed to request connection info: putmsg");
85*a2f04351SSebastien Roy 		return (-1);
86*a2f04351SSebastien Roy 	}
87*a2f04351SSebastien Roy 
88*a2f04351SSebastien Roy 	/*
89*a2f04351SSebastien Roy 	 * Each reply consists of a control part for one fixed structure or
90*a2f04351SSebastien Roy 	 * table, as defined in mib2.h.  The format is a T_OPTMGMT_ACK
91*a2f04351SSebastien Roy 	 * containing an opthdr structure.  The level and name identify the
92*a2f04351SSebastien Roy 	 * entry, and len is the size of the data part of the message.
93*a2f04351SSebastien Roy 	 */
94*a2f04351SSebastien Roy 	for (;;) {
95*a2f04351SSebastien Roy 		cbuf.buf = (caddr_t)&ack;
96*a2f04351SSebastien Roy 		cbuf.maxlen = sizeof (ack);
97*a2f04351SSebastien Roy 		flags = 0;
98*a2f04351SSebastien Roy 
99*a2f04351SSebastien Roy 		/*
100*a2f04351SSebastien Roy 		 * We first do a getmsg() for the control part so that we
101*a2f04351SSebastien Roy 		 * can allocate a properly sized buffer to read the data
102*a2f04351SSebastien Roy 		 * part.
103*a2f04351SSebastien Roy 		 */
104*a2f04351SSebastien Roy 		do {
105*a2f04351SSebastien Roy 			r = getmsg(fd, &cbuf, NULL, &flags);
106*a2f04351SSebastien Roy 		} while (r < 0 && errno == EINTR);
107*a2f04351SSebastien Roy 
108*a2f04351SSebastien Roy 		if (r < 0) {
109*a2f04351SSebastien Roy 			warn("failed to fetch further connection info");
110*a2f04351SSebastien Roy 			err = -1;
111*a2f04351SSebastien Roy 			break;
112*a2f04351SSebastien Roy 		} else if ((r & MORECTL) != 0) {
113*a2f04351SSebastien Roy 			warnx("failed to fetch full control message");
114*a2f04351SSebastien Roy 			err = -1;
115*a2f04351SSebastien Roy 			break;
116*a2f04351SSebastien Roy 		}
117*a2f04351SSebastien Roy 
118*a2f04351SSebastien Roy 		if (cbuf.len < sizeof (struct T_optmgmt_ack) ||
119*a2f04351SSebastien Roy 		    ack.ack.PRIM_type != T_OPTMGMT_ACK ||
120*a2f04351SSebastien Roy 		    ack.ack.MGMT_flags != T_SUCCESS ||
121*a2f04351SSebastien Roy 		    ack.ack.OPT_length < sizeof (struct opthdr)) {
122*a2f04351SSebastien Roy 			warnx("cannot process invalid message from getmsg()");
123*a2f04351SSebastien Roy 			err = -1;
124*a2f04351SSebastien Roy 			break;
125*a2f04351SSebastien Roy 		}
126*a2f04351SSebastien Roy 
127*a2f04351SSebastien Roy 		/* LINTED E_BAD_PTR_CAST_ALIGN */
128*a2f04351SSebastien Roy 		hdr = (struct opthdr *)((caddr_t)&ack + ack.ack.OPT_offset);
129*a2f04351SSebastien Roy 		if (r == 0 && hdr->level == 0 && hdr->name == 0) {
130*a2f04351SSebastien Roy 			/*
131*a2f04351SSebastien Roy 			 * snmpcom_req() has sent us the final End-Of-Data
132*a2f04351SSebastien Roy 			 * message, so there's nothing further to read.
133*a2f04351SSebastien Roy 			 */
134*a2f04351SSebastien Roy 			break;
135*a2f04351SSebastien Roy 		}
136*a2f04351SSebastien Roy 
137*a2f04351SSebastien Roy 		/* Only data should remain. */
138*a2f04351SSebastien Roy 		VERIFY3S(r, ==, MOREDATA);
139*a2f04351SSebastien Roy 
140*a2f04351SSebastien Roy 		/* Allocate a buffer to hold the data portion of the message */
141*a2f04351SSebastien Roy 		if ((dbuf.buf = realloc(dbuf.buf, hdr->len)) == NULL) {
142*a2f04351SSebastien Roy 			warn("failed to realloc() buffer");
143*a2f04351SSebastien Roy 			err = -1;
144*a2f04351SSebastien Roy 			break;
145*a2f04351SSebastien Roy 		}
146*a2f04351SSebastien Roy 		dbuf.maxlen = hdr->len;
147*a2f04351SSebastien Roy 		dbuf.len = 0;
148*a2f04351SSebastien Roy 		flags = 0;
149*a2f04351SSebastien Roy 
150*a2f04351SSebastien Roy 		do {
151*a2f04351SSebastien Roy 			r = getmsg(fd, NULL, &dbuf, &flags);
152*a2f04351SSebastien Roy 		} while (r < 0 && errno == EINTR);
153*a2f04351SSebastien Roy 
154*a2f04351SSebastien Roy 		if (r < 0) {
155*a2f04351SSebastien Roy 			warn("failed to fetch connection data: getmsg()");
156*a2f04351SSebastien Roy 			err = -1;
157*a2f04351SSebastien Roy 			break;
158*a2f04351SSebastien Roy 		} else if (r != 0) {
159*a2f04351SSebastien Roy 			warnx("failed to fetch all data: "
160*a2f04351SSebastien Roy 			    "getmsg() returned %d", r);
161*a2f04351SSebastien Roy 			err = -1;
162*a2f04351SSebastien Roy 			break;
163*a2f04351SSebastien Roy 		}
164*a2f04351SSebastien Roy 
165*a2f04351SSebastien Roy 		if ((state->cws_flags & CS_IPV4) &&
166*a2f04351SSebastien Roy 		    hdr->name == proto->csp_mibv4name) {
167*a2f04351SSebastien Roy 			proto->csp_v4walk(&dbuf, state);
168*a2f04351SSebastien Roy 		} else if ((state->cws_flags & CS_IPV6) &&
169*a2f04351SSebastien Roy 		    hdr->name == proto->csp_mibv6name) {
170*a2f04351SSebastien Roy 			proto->csp_v6walk(&dbuf, state);
171*a2f04351SSebastien Roy 		}
172*a2f04351SSebastien Roy 	}
173*a2f04351SSebastien Roy 
174*a2f04351SSebastien Roy 	free(dbuf.buf);
175*a2f04351SSebastien Roy 
176*a2f04351SSebastien Roy 	return (err);
177*a2f04351SSebastien Roy }
178