#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <strings.h>
#include <unistd.h>
#include <stropts.h>
#include <sys/debug.h>
#include <sys/tihdr.h>
#include "connstat.h"
int
mibopen(const char *proto)
{
int saved;
int fd;
fd = open("/dev/arp", O_RDWR);
if (fd == -1) {
return (-1);
}
if (ioctl(fd, I_PUSH, proto) == -1) {
saved = errno;
(void) close(fd);
errno = saved;
return (-1);
}
return (fd);
}
int
conn_walk(int fd, connstat_proto_t *proto, conn_walk_state_t *state)
{
struct strbuf cbuf, dbuf;
struct opthdr *hdr;
int flags, r, err = 0;
struct {
struct T_optmgmt_req req;
struct opthdr hdr;
} req;
union {
struct T_optmgmt_ack ack;
uint8_t space[sizeof (struct T_optmgmt_ack) +
sizeof (struct opthdr) * 2];
} ack;
bzero(&cbuf, sizeof (cbuf));
bzero(&dbuf, sizeof (dbuf));
req.req.PRIM_type = T_OPTMGMT_REQ;
req.req.OPT_offset = (caddr_t)&req.hdr - (caddr_t)&req;
req.req.OPT_length = sizeof (req.hdr);
req.req.MGMT_flags = T_CURRENT;
req.hdr.level = proto->csp_miblevel;
req.hdr.name = 0;
req.hdr.len = 0;
cbuf.buf = (caddr_t)&req;
cbuf.len = sizeof (req);
if (putmsg(fd, &cbuf, NULL, 0) == -1) {
warn("failed to request connection info: putmsg");
return (-1);
}
for (;;) {
cbuf.buf = (caddr_t)&ack;
cbuf.maxlen = sizeof (ack);
flags = 0;
do {
r = getmsg(fd, &cbuf, NULL, &flags);
} while (r < 0 && errno == EINTR);
if (r < 0) {
warn("failed to fetch further connection info");
err = -1;
break;
} else if ((r & MORECTL) != 0) {
warnx("failed to fetch full control message");
err = -1;
break;
}
if (cbuf.len < sizeof (struct T_optmgmt_ack) ||
ack.ack.PRIM_type != T_OPTMGMT_ACK ||
ack.ack.MGMT_flags != T_SUCCESS ||
ack.ack.OPT_length < sizeof (struct opthdr)) {
warnx("cannot process invalid message from getmsg()");
err = -1;
break;
}
hdr = (struct opthdr *)((caddr_t)&ack + ack.ack.OPT_offset);
if (r == 0 && hdr->level == 0 && hdr->name == 0) {
break;
}
VERIFY3S(r, ==, MOREDATA);
if ((dbuf.buf = realloc(dbuf.buf, hdr->len)) == NULL) {
warn("failed to realloc() buffer");
err = -1;
break;
}
dbuf.maxlen = hdr->len;
dbuf.len = 0;
flags = 0;
do {
r = getmsg(fd, NULL, &dbuf, &flags);
} while (r < 0 && errno == EINTR);
if (r < 0) {
warn("failed to fetch connection data: getmsg()");
err = -1;
break;
} else if (r != 0) {
warnx("failed to fetch all data: "
"getmsg() returned %d", r);
err = -1;
break;
}
if ((state->cws_flags & CS_IPV4) &&
hdr->name == proto->csp_mibv4name) {
proto->csp_v4walk(&dbuf, state);
} else if ((state->cws_flags & CS_IPV6) &&
hdr->name == proto->csp_mibv6name) {
proto->csp_v6walk(&dbuf, state);
}
}
free(dbuf.buf);
return (err);
}