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 }