1 /*
2 * CDDL HEADER START
3 *
4 * This file and its contents are supplied under the terms of the
5 * Common Development and Distribution License ("CDDL"), version 1.0.
6 * You may only use this file in accordance with the terms of version
7 * 1.0 of the CDDL.
8 *
9 * A full copy of the text of the CDDL should have accompanied this
10 * source. A copy of the CDDL is also available via the Internet at
11 * http://www.illumos.org/license/CDDL.
12 *
13 * CDDL HEADER END
14 */
15 /*
16 * Copyright (c) 2015 by Delphix. All rights reserved.
17 */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <strings.h>
24 #include <unistd.h>
25 #include <stropts.h>
26 #include <sys/tihdr.h>
27 #include "connstat.h"
28
29 int
30 mibopen(const char *proto)
31 {
32 int fd;
33
34 fd = open("/dev/arp", O_RDWR);
35 if (fd == -1) {
36 return (-1);
37 }
38
39 if (ioctl(fd, I_PUSH, proto) == -1) {
40 (void) close(fd);
41 return (-1);
42 }
43
44 return (fd);
45 }
46
47 void
48 conn_walk(int fd, connstat_proto_t *proto, conn_walk_state_t *state)
49 {
50 struct strbuf cbuf, dbuf;
51 struct opthdr *hdr;
52 int flags, r;
53 struct {
54 struct T_optmgmt_req req;
55 struct opthdr hdr;
56 } req;
57 union {
58 struct T_optmgmt_ack ack;
59 uint8_t space[sizeof (struct T_optmgmt_ack) +
60 sizeof (struct opthdr) * 2];
61 } ack;
62
63 req.req.PRIM_type = T_OPTMGMT_REQ;
64 req.req.OPT_offset = (caddr_t)&req.hdr - (caddr_t)&req;
65 req.req.OPT_length = sizeof (req.hdr);
66 req.req.MGMT_flags = T_CURRENT;
67
68 req.hdr.level = proto->csp_miblevel;
69 req.hdr.name = 0;
70 req.hdr.len = 0;
71
72 cbuf.buf = (caddr_t)&req;
73 cbuf.len = sizeof (req);
74
75 if (putmsg(fd, &cbuf, NULL, 0) == -1) {
76 perror("putmsg");
77 return;
78 }
79
80 /*
81 * Each reply consists of a control part for one fixed structure or
82 * table, as defined in mib2.h. The format is a T_OPTMGMT_ACK
83 * containing an opthdr structure. The level and name identify the
84 * entry, and len is the size of the data part of the message.
85 */
86 for (;;) {
87 cbuf.buf = (caddr_t)&ack;
88 cbuf.maxlen = sizeof (ack);
89 flags = 0;
90
91 /*
92 * We first do a getmsg() for the control part so that we
93 * can allocate a properly sized buffer to read the data
94 * part.
95 */
96 if ((r = getmsg(fd, &cbuf, NULL, &flags)) < 0) {
97 perror("getmsg");
98 break;
99 }
100 if (r == 0) {
101 break;
102 }
103
104 if (cbuf.len < sizeof (struct T_optmgmt_ack) ||
105 ack.ack.PRIM_type != T_OPTMGMT_ACK ||
106 ack.ack.MGMT_flags != T_SUCCESS ||
107 ack.ack.OPT_length < sizeof (struct opthdr)) {
108 (void) fprintf(stderr, "invalid message\n");
109 break;
110 }
111
112 /* LINTED E_BAD_PTR_CAST_ALIGN */
113 hdr = (struct opthdr *)((caddr_t)&ack + ack.ack.OPT_offset);
114 if (hdr->level == 0 && hdr->name == 0)
115 break;
116
117 /* Allocate a buffer to hold the data portion of the message */
118 if ((dbuf.buf = malloc(hdr->len)) == NULL) {
119 perror("malloc");
120 break;
121 }
122 dbuf.maxlen = hdr->len;
123 dbuf.len = 0;
124 flags = 0;
125 r = getmsg(fd, NULL, &dbuf, &flags);
126
127 if ((state->cws_flags & CS_IPV4) &&
128 hdr->name == proto->csp_mibv4name) {
129 proto->csp_v4walk(&dbuf, state);
130 } else if ((state->cws_flags & CS_IPV6) &&
131 hdr->name == proto->csp_mibv6name) {
132 proto->csp_v6walk(&dbuf, state);
133 }
134
135 free(dbuf.buf);
136 }
137 }