1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Copyright 2012 David Hoeppner.  All rights reserved.
  25  */
  26 
  27 /*
  28  * Functions related to MIB-II and kstat.
  29  */
  30 
  31 #include <sys/types.h>
  32 #include <sys/tihdr.h>
  33 #include <sys/policy.h>
  34 #include <sys/tsol/tnet.h>
  35 
  36 #include <inet/common.h>
  37 #include <inet/ip.h>
  38 #include <inet/kstatcom.h>
  39 #include <inet/snmpcom.h>
  40 
  41 #include <sys/cmn_err.h>
  42 
  43 #include "dccp_impl.h"
  44 
  45 static int      dccp_snmp_state(dccp_t *);
  46 static int      dccp_kstat_update(kstat_t *, int);
  47 
  48 /*
  49  * Translate DCCP state to MIB2 state.
  50  */
  51 static int
  52 dccp_snmp_state(dccp_t *dccp)
  53 {
  54         if (dccp == NULL) {
  55                 return (0);
  56         }
  57 
  58         switch(dccp->dccp_state) {
  59         case DCCPS_CLOSED:
  60                 return (MIB2_DCCP_closed);
  61         default:
  62                 return (0);
  63         }
  64 }
  65 
  66 /*
  67  * Get the MIB-II stats.
  68  */
  69 mblk_t *
  70 dccp_snmp_get(queue_t *q, mblk_t *mpctl, boolean_t legacy_req)
  71 {
  72         conn_t          *connp = Q_TO_CONN(q);
  73         connf_t         *connfp;
  74         ip_stack_t      *ipst;
  75         dccp_stack_t    *dccps;
  76         struct opthdr   *optp;
  77         mblk_t          *mp2ctl;
  78         mblk_t          *mpdata;
  79         mblk_t          *mp_conn_ctl = NULL;
  80         mblk_t          *mp_conn_tail;
  81         mblk_t          *mp_attr_ctl = NULL;
  82         mblk_t          *mp_attr_tail;
  83         mblk_t          *mp6_conn_ctl = NULL;
  84         mblk_t          *mp6_conn_tail;
  85         mblk_t          *mp6_attr_ctl = NULL;
  86         mblk_t          *mp6_attr_tail;
  87         size_t          dccp_mib_size;
  88         size_t          dce_size;
  89         size_t          dce6_size;
  90         zoneid_t        zoneid;
  91         int             i;
  92         mib2_dccp_t             dccp_mib;
  93         mib2_dccpConnEntry_t    dce;
  94         mib2_dccp6ConnEntry_t   dce6;
  95 
  96         /*
  97          * Make a copy of the original message.
  98          */
  99         mp2ctl = copymsg(mpctl);
 100 
 101         cmn_err(CE_NOTE, "dccp_stats.c: dccp_snmp_get");
 102 
 103         if (mpctl == NULL ||
 104             (mpdata = mpctl->b_cont) == NULL ||
 105             (mp_conn_ctl = copymsg(mpctl)) == NULL ||
 106             (mp_attr_ctl = copymsg(mpctl)) == NULL) {
 107                 freemsg(mp_conn_ctl);
 108                 freemsg(mp_attr_ctl);
 109                 freemsg(mpctl);
 110                 freemsg(mp2ctl);
 111                 return (NULL);
 112         }
 113 
 114         ipst = connp->conn_netstack->netstack_ip;
 115         dccps = connp->conn_netstack->netstack_dccp;
 116 
 117         if (legacy_req) {
 118                 dccp_mib_size = LEGACY_MIB_SIZE(&dccp_mib, mib2_dccp_t);
 119                 dce_size = LEGACY_MIB_SIZE(&dce, mib2_dccpConnEntry_t);
 120                 dce6_size = LEGACY_MIB_SIZE(&dce6, mib2_dccp6ConnEntry_t);
 121         } else {
 122                 dccp_mib_size = sizeof (mib2_dccp_t);
 123                 dce_size = sizeof (mib2_dccpConnEntry_t);
 124                 dce6_size = sizeof (mib2_dccp6ConnEntry_t);
 125         }
 126 
 127         bzero(&dccp_mib, sizeof (dccp_mib));
 128         zoneid = Q_TO_CONN(q)->conn_zoneid;
 129         mp_conn_tail = mp_attr_tail = mp6_conn_tail = mp6_attr_tail = NULL;
 130 
 131         for (i = 0; i < CONN_G_HASH_SIZE; i++) {
 132                 ipst = dccps->dccps_netstack->netstack_ip;
 133 
 134                 connfp = &ipst->ips_ipcl_globalhash_fanout[i];
 135                 connp = NULL;
 136 
 137                 while ((connp = ipcl_get_next_conn(connfp, connp,
 138                     IPCL_DCCPCONN)) != NULL) {
 139                         dccp_t  *dccp;
 140 
 141                         if (connp->conn_zoneid != zoneid) {
 142                                 continue;
 143                         }
 144 
 145                         dccp = connp->conn_dccp;
 146 
 147                         dce.dccpConnState = dccp_snmp_state(dccp);
 148 
 149                         if (connp->conn_ipversion == IPV4_VERSION ||
 150                             (dccp->dccp_state <= DCCPS_LISTEN)) {
 151 
 152                                 if (connp->conn_ipversion == IPV6_VERSION) {
 153                                         dce.dccpConnRemAddress = INADDR_ANY;
 154                                         dce.dccpConnLocalAddress = INADDR_ANY;
 155                                 } else {
 156                                         dce.dccpConnRemAddress =
 157                                             connp->conn_faddr_v4;
 158                                         dce.dccpConnLocalAddress =
 159                                             connp->conn_laddr_v4;
 160                                 }
 161 
 162                         dce.dccpConnLocalPort = ntohs(connp->conn_lport);
 163                         dce.dccpConnRemPort = ntohs(connp->conn_fport);
 164 /*
 165                         dce.dccpConnCreationProcess = (connp->conn_cpid < 0) ?
 166                             MIB2_UNKNOWN_PROCESS : connp->conn_cpid;
 167                         dce.dccpConnCreationTime = connp->conn_open_time;
 168 */
 169                         (void) snmp_append_data2(mp_conn_ctl->b_cont,
 170                             &mp_conn_tail, (char *)&dce, dce_size);
 171 
 172                         }
 173                 }
 174         }
 175 
 176         SET_MIB(dccp_mib.dccpConnTableSize, dce_size);
 177         SET_MIB(dccp_mib.dccp6ConnTableSize, dce6_size);
 178 
 179         optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)];
 180         optp->level = MIB2_DCCP;
 181         optp->name = 0;
 182         (void) snmp_append_data(mpdata, (char *)&dccp_mib, dccp_mib_size);
 183         optp->len = msgdsize(mpdata);
 184         qreply(q, mpctl);
 185 
 186         optp = (struct opthdr *)&mp_conn_ctl->b_rptr[
 187             sizeof (struct T_optmgmt_ack)];
 188         optp->level = MIB2_DCCP;
 189         optp->name = MIB2_DCCP_CONN;
 190         optp->len = msgdsize(mp_conn_ctl->b_cont);
 191         qreply(q, mp_conn_ctl);
 192 
 193         optp = (struct opthdr *)&mp_attr_ctl->b_rptr[
 194             sizeof (struct T_optmgmt_ack)];
 195         optp->level = MIB2_DCCP;
 196         optp->name = EXPER_XPORT_MLP;
 197         optp->len = msgdsize(mp_attr_ctl->b_cont);
 198         if (optp->len == 0) {
 199                 freemsg(mp_attr_ctl);
 200         } else {
 201                 qreply(q, mp_attr_ctl);
 202         }
 203 
 204         return (mp2ctl);
 205 }
 206 
 207 /*
 208  * DCCP kernel statistics.
 209  */
 210 void *
 211 dccp_kstat_init(netstackid_t stackid)
 212 {
 213         kstat_t *ksp;
 214 
 215         dccp_named_kstat_t template = {
 216                 { "activeOpens",        KSTAT_DATA_UINT32, 0 },
 217                 { "passiveOpens",       KSTAT_DATA_UINT32, 0 },
 218                 { "inSegs",             KSTAT_DATA_UINT64, 0 },
 219                 { "outSegs",            KSTAT_DATA_UINT64, 0 },
 220         };
 221 
 222         ksp = kstat_create_netstack(DCCP_MOD_NAME, 0, DCCP_MOD_NAME, "mib2",
 223             KSTAT_TYPE_NAMED, NUM_OF_FIELDS(dccp_named_kstat_t), 0, stackid);
 224         if (ksp == NULL) {
 225                 return (NULL);
 226         }
 227 
 228         bcopy(&template, ksp->ks_data, sizeof (template));
 229         ksp->ks_update = dccp_kstat_update;
 230         ksp->ks_private = (void *)(uintptr_t)stackid;
 231 
 232         kstat_install(ksp);
 233 
 234         return (ksp);
 235 }
 236 
 237 /*
 238  * Destroy DCCP kernel statistics.
 239  */
 240 void
 241 dccp_kstat_fini(netstackid_t stackid, kstat_t *ksp)
 242 {
 243 
 244         if (ksp != NULL) {
 245                 ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
 246                 kstat_delete_netstack(ksp, stackid);
 247         }
 248 }
 249 
 250 /*
 251  * Update DCCP kernel statistics.
 252  */
 253 static int
 254 dccp_kstat_update(kstat_t *ksp, int rw)
 255 {
 256 
 257         if (rw == KSTAT_WRITE) {
 258                 return (EACCES);
 259         }
 260 
 261         return (0);
 262 }