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