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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/tihdr.h>
  28 #include <sys/policy.h>
  29 #include <sys/tsol/tnet.h>
  30 
  31 #include <inet/common.h>
  32 #include <inet/kstatcom.h>
  33 #include <inet/snmpcom.h>
  34 #include <inet/mib2.h>
  35 #include <inet/optcom.h>
  36 #include <inet/snmpcom.h>
  37 #include <inet/kstatcom.h>
  38 #include <inet/udp_impl.h>
  39 
  40 static int      udp_kstat_update(kstat_t *, int);
  41 static int      udp_kstat2_update(kstat_t *, int);
  42 static void     udp_sum_mib(udp_stack_t *, mib2_udp_t *);
  43 static void     udp_clr_stats(udp_stat_t *);
  44 static void     udp_add_stats(udp_stat_counter_t *, udp_stat_t *);
  45 static void     udp_add_mib(mib2_udp_t *, mib2_udp_t *);
  46 /*
  47  * return SNMP stuff in buffer in mpdata. We don't hold any lock and report
  48  * information that can be changing beneath us.
  49  */
  50 mblk_t *
  51 udp_snmp_get(queue_t *q, mblk_t *mpctl, boolean_t legacy_req)
  52 {
  53         mblk_t                  *mpdata;
  54         mblk_t                  *mp_conn_ctl;
  55         mblk_t                  *mp_attr_ctl;
  56         mblk_t                  *mp_pidnode_ctl;
  57         mblk_t                  *mp6_conn_ctl;
  58         mblk_t                  *mp6_attr_ctl;
  59         mblk_t                  *mp6_pidnode_ctl;
  60         mblk_t                  *mp_conn_tail;
  61         mblk_t                  *mp_attr_tail;
  62         mblk_t                  *mp_pidnode_tail;
  63         mblk_t                  *mp6_conn_tail;
  64         mblk_t                  *mp6_attr_tail;
  65         mblk_t                  *mp6_pidnode_tail;
  66         struct opthdr           *optp;
  67         mib2_udpEntry_t         ude;
  68         mib2_udp6Entry_t        ude6;
  69         mib2_transportMLPEntry_t mlp;
  70         int                     state;
  71         zoneid_t                zoneid;
  72         int                     i;
  73         connf_t                 *connfp;
  74         conn_t                  *connp = Q_TO_CONN(q);
  75         int                     v4_conn_idx;
  76         int                     v6_conn_idx;
  77         boolean_t               needattr;
  78         udp_t                   *udp;
  79         ip_stack_t              *ipst = connp->conn_netstack->netstack_ip;
  80         udp_stack_t             *us = connp->conn_netstack->netstack_udp;
  81         mblk_t                  *mp2ctl;
  82         mib2_udp_t              udp_mib;
  83         size_t                  udp_mib_size, ude_size, ude6_size;
  84 
  85         /*
  86          * make a copy of the original message
  87          */
  88         mp2ctl = copymsg(mpctl);
  89 
  90         mp_conn_ctl = mp_attr_ctl = mp6_conn_ctl = NULL;
  91         if (mpctl == NULL ||
  92             (mpdata = mpctl->b_cont) == NULL ||
  93             (mp_conn_ctl = copymsg(mpctl)) == NULL ||
  94             (mp_attr_ctl = copymsg(mpctl)) == NULL ||
  95             (mp_pidnode_ctl = copymsg(mpctl)) == NULL ||
  96             (mp6_conn_ctl = copymsg(mpctl)) == NULL ||
  97             (mp6_attr_ctl = copymsg(mpctl)) == NULL ||
  98             (mp6_pidnode_ctl = copymsg(mpctl)) == NULL) {
  99                 freemsg(mp_conn_ctl);
 100                 freemsg(mp_attr_ctl);
 101                 freemsg(mp_pidnode_ctl);
 102                 freemsg(mp6_conn_ctl);
 103                 freemsg(mp6_attr_ctl);
 104                 freemsg(mp6_pidnode_ctl);
 105                 freemsg(mpctl);
 106                 freemsg(mp2ctl);
 107                 return (0);
 108         }
 109 
 110         zoneid = connp->conn_zoneid;
 111 
 112         if (legacy_req) {
 113                 udp_mib_size = LEGACY_MIB_SIZE(&udp_mib, mib2_udp_t);
 114                 ude_size = LEGACY_MIB_SIZE(&ude, mib2_udpEntry_t);
 115                 ude6_size = LEGACY_MIB_SIZE(&ude6, mib2_udp6Entry_t);
 116         } else {
 117                 udp_mib_size = sizeof (mib2_udp_t);
 118                 ude_size = sizeof (mib2_udpEntry_t);
 119                 ude6_size = sizeof (mib2_udp6Entry_t);
 120         }
 121 
 122         bzero(&udp_mib, sizeof (udp_mib));
 123         /* fixed length structure for IPv4 and IPv6 counters */
 124         SET_MIB(udp_mib.udpEntrySize, ude_size);
 125         SET_MIB(udp_mib.udp6EntrySize, ude6_size);
 126 
 127         udp_sum_mib(us, &udp_mib);
 128 
 129         /*
 130          * Synchronize 32- and 64-bit counters.  Note that udpInDatagrams and
 131          * udpOutDatagrams are not updated anywhere in UDP.  The new 64 bits
 132          * counters are used.  Hence the old counters' values in us_sc_mib
 133          * are always 0.
 134          */
 135         SYNC32_MIB(&udp_mib, udpInDatagrams, udpHCInDatagrams);
 136         SYNC32_MIB(&udp_mib, udpOutDatagrams, udpHCOutDatagrams);
 137 
 138         optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)];
 139         optp->level = MIB2_UDP;
 140         optp->name = 0;
 141         (void) snmp_append_data(mpdata, (char *)&udp_mib, udp_mib_size);
 142         optp->len = msgdsize(mpdata);
 143         qreply(q, mpctl);
 144 
 145         mp_conn_tail = mp_attr_tail = mp6_conn_tail = mp6_attr_tail = NULL;
 146         mp_pidnode_tail = mp6_pidnode_tail = NULL;
 147         v4_conn_idx = v6_conn_idx = 0;
 148 
 149         for (i = 0; i < CONN_G_HASH_SIZE; i++) {
 150                 connfp = &ipst->ips_ipcl_globalhash_fanout[i];
 151                 connp = NULL;
 152 
 153                 while ((connp = ipcl_get_next_conn(connfp, connp,
 154                     IPCL_UDPCONN))) {
 155                         udp = connp->conn_udp;
 156                         if (zoneid != connp->conn_zoneid)
 157                                 continue;
 158 
 159                         /*
 160                          * Note that the port numbers are sent in
 161                          * host byte order
 162                          */
 163 
 164                         if (udp->udp_state == TS_UNBND)
 165                                 state = MIB2_UDP_unbound;
 166                         else if (udp->udp_state == TS_IDLE)
 167                                 state = MIB2_UDP_idle;
 168                         else if (udp->udp_state == TS_DATA_XFER)
 169                                 state = MIB2_UDP_connected;
 170                         else
 171                                 state = MIB2_UDP_unknown;
 172 
 173                         needattr = B_FALSE;
 174                         bzero(&mlp, sizeof (mlp));
 175                         if (connp->conn_mlp_type != mlptSingle) {
 176                                 if (connp->conn_mlp_type == mlptShared ||
 177                                     connp->conn_mlp_type == mlptBoth)
 178                                         mlp.tme_flags |= MIB2_TMEF_SHARED;
 179                                 if (connp->conn_mlp_type == mlptPrivate ||
 180                                     connp->conn_mlp_type == mlptBoth)
 181                                         mlp.tme_flags |= MIB2_TMEF_PRIVATE;
 182                                 needattr = B_TRUE;
 183                         }
 184                         if (connp->conn_anon_mlp) {
 185                                 mlp.tme_flags |= MIB2_TMEF_ANONMLP;
 186                                 needattr = B_TRUE;
 187                         }
 188                         switch (connp->conn_mac_mode) {
 189                         case CONN_MAC_DEFAULT:
 190                                 break;
 191                         case CONN_MAC_AWARE:
 192                                 mlp.tme_flags |= MIB2_TMEF_MACEXEMPT;
 193                                 needattr = B_TRUE;
 194                                 break;
 195                         case CONN_MAC_IMPLICIT:
 196                                 mlp.tme_flags |= MIB2_TMEF_MACIMPLICIT;
 197                                 needattr = B_TRUE;
 198                                 break;
 199                         }
 200                         mutex_enter(&connp->conn_lock);
 201                         if (udp->udp_state == TS_DATA_XFER &&
 202                             connp->conn_ixa->ixa_tsl != NULL) {
 203                                 ts_label_t *tsl;
 204 
 205                                 tsl = connp->conn_ixa->ixa_tsl;
 206                                 mlp.tme_flags |= MIB2_TMEF_IS_LABELED;
 207                                 mlp.tme_doi = label2doi(tsl);
 208                                 mlp.tme_label = *label2bslabel(tsl);
 209                                 needattr = B_TRUE;
 210                         }
 211                         mutex_exit(&connp->conn_lock);
 212 
 213                         /*
 214                          * Create an IPv4 table entry for IPv4 entries and also
 215                          * any IPv6 entries which are bound to in6addr_any
 216                          * (i.e. anything a IPv4 peer could connect/send to).
 217                          */
 218                         if (connp->conn_ipversion == IPV4_VERSION ||
 219                             (udp->udp_state <= TS_IDLE &&
 220                             IN6_IS_ADDR_UNSPECIFIED(&connp->conn_laddr_v6))) {
 221                                 ude.udpEntryInfo.ue_state = state;
 222                                 /*
 223                                  * If in6addr_any this will set it to
 224                                  * INADDR_ANY
 225                                  */
 226                                 ude.udpLocalAddress = connp->conn_laddr_v4;
 227                                 ude.udpLocalPort = ntohs(connp->conn_lport);
 228                                 if (udp->udp_state == TS_DATA_XFER) {
 229                                         /*
 230                                          * Can potentially get here for
 231                                          * v6 socket if another process
 232                                          * (say, ping) has just done a
 233                                          * sendto(), changing the state
 234                                          * from the TS_IDLE above to
 235                                          * TS_DATA_XFER by the time we hit
 236                                          * this part of the code.
 237                                          */
 238                                         ude.udpEntryInfo.ue_RemoteAddress =
 239                                             connp->conn_faddr_v4;
 240                                         ude.udpEntryInfo.ue_RemotePort =
 241                                             ntohs(connp->conn_fport);
 242                                 } else {
 243                                         ude.udpEntryInfo.ue_RemoteAddress = 0;
 244                                         ude.udpEntryInfo.ue_RemotePort = 0;
 245                                 }
 246 
 247                                 /*
 248                                  * We make the assumption that all udp_t
 249                                  * structs will be created within an address
 250                                  * region no larger than 32-bits.
 251                                  */
 252                                 ude.udpInstance = (uint32_t)(uintptr_t)udp;
 253                                 ude.udpCreationProcess =
 254                                     (connp->conn_cpid < 0) ?
 255                                     MIB2_UNKNOWN_PROCESS :
 256                                     connp->conn_cpid;
 257                                 ude.udpCreationTime = connp->conn_open_time;
 258 
 259                                 (void) snmp_append_data2(mp_conn_ctl->b_cont,
 260                                     &mp_conn_tail, (char *)&ude, ude_size);
 261 
 262                                 (void) snmp_append_data2(mp_pidnode_ctl->b_cont,
 263                                     &mp_pidnode_tail, (char *)&ude, ude_size);
 264 
 265                                 (void) snmp_append_mblk2(mp_pidnode_ctl->b_cont,
 266                                     &mp_pidnode_tail, conn_get_pid_mblk(connp));
 267 
 268                                 mlp.tme_connidx = v4_conn_idx++;
 269                                 if (needattr)
 270                                         (void) snmp_append_data2(
 271                                             mp_attr_ctl->b_cont, &mp_attr_tail,
 272                                             (char *)&mlp, sizeof (mlp));
 273                         }
 274                         if (connp->conn_ipversion == IPV6_VERSION) {
 275                                 ude6.udp6EntryInfo.ue_state  = state;
 276                                 ude6.udp6LocalAddress = connp->conn_laddr_v6;
 277                                 ude6.udp6LocalPort = ntohs(connp->conn_lport);
 278                                 mutex_enter(&connp->conn_lock);
 279                                 if (connp->conn_ixa->ixa_flags &
 280                                     IXAF_SCOPEID_SET) {
 281                                         ude6.udp6IfIndex =
 282                                             connp->conn_ixa->ixa_scopeid;
 283                                 } else {
 284                                         ude6.udp6IfIndex = connp->conn_bound_if;
 285                                 }
 286                                 mutex_exit(&connp->conn_lock);
 287                                 if (udp->udp_state == TS_DATA_XFER) {
 288                                         ude6.udp6EntryInfo.ue_RemoteAddress =
 289                                             connp->conn_faddr_v6;
 290                                         ude6.udp6EntryInfo.ue_RemotePort =
 291                                             ntohs(connp->conn_fport);
 292                                 } else {
 293                                         ude6.udp6EntryInfo.ue_RemoteAddress =
 294                                             sin6_null.sin6_addr;
 295                                         ude6.udp6EntryInfo.ue_RemotePort = 0;
 296                                 }
 297                                 /*
 298                                  * We make the assumption that all udp_t
 299                                  * structs will be created within an address
 300                                  * region no larger than 32-bits.
 301                                  */
 302                                 ude6.udp6Instance = (uint32_t)(uintptr_t)udp;
 303                                 ude6.udp6CreationProcess =
 304                                     (connp->conn_cpid < 0) ?
 305                                     MIB2_UNKNOWN_PROCESS :
 306                                     connp->conn_cpid;
 307                                 ude6.udp6CreationTime = connp->conn_open_time;
 308 
 309                                 (void) snmp_append_data2(mp6_conn_ctl->b_cont,
 310                                     &mp6_conn_tail, (char *)&ude6, ude6_size);
 311 
 312                                 (void) snmp_append_data2(
 313                                     mp6_pidnode_ctl->b_cont, &mp6_pidnode_tail,
 314                                     (char *)&ude6, ude6_size);
 315 
 316                                 (void) snmp_append_mblk2(
 317                                     mp6_pidnode_ctl->b_cont, &mp6_pidnode_tail,
 318                                     conn_get_pid_mblk(connp));
 319 
 320                                 mlp.tme_connidx = v6_conn_idx++;
 321                                 if (needattr)
 322                                         (void) snmp_append_data2(
 323                                             mp6_attr_ctl->b_cont,
 324                                             &mp6_attr_tail, (char *)&mlp,
 325                                             sizeof (mlp));
 326                         }
 327                 }
 328         }
 329 
 330         /* IPv4 UDP endpoints */
 331         optp = (struct opthdr *)&mp_conn_ctl->b_rptr[
 332             sizeof (struct T_optmgmt_ack)];
 333         optp->level = MIB2_UDP;
 334         optp->name = MIB2_UDP_ENTRY;
 335         optp->len = msgdsize(mp_conn_ctl->b_cont);
 336         qreply(q, mp_conn_ctl);
 337 
 338         /* table of MLP attributes... */
 339         optp = (struct opthdr *)&mp_attr_ctl->b_rptr[
 340             sizeof (struct T_optmgmt_ack)];
 341         optp->level = MIB2_UDP;
 342         optp->name = EXPER_XPORT_MLP;
 343         optp->len = msgdsize(mp_attr_ctl->b_cont);
 344         if (optp->len == 0)
 345                 freemsg(mp_attr_ctl);
 346         else
 347                 qreply(q, mp_attr_ctl);
 348 
 349         /* table of EXPER_XPORT_PROC_INFO ipv4 */
 350         optp = (struct opthdr *)&mp_pidnode_ctl->b_rptr[
 351             sizeof (struct T_optmgmt_ack)];
 352         optp->level = MIB2_UDP;
 353         optp->name = EXPER_XPORT_PROC_INFO;
 354         optp->len = msgdsize(mp_pidnode_ctl->b_cont);
 355         if (optp->len == 0)
 356                 freemsg(mp_pidnode_ctl);
 357         else
 358                 qreply(q, mp_pidnode_ctl);
 359 
 360         /* IPv6 UDP endpoints */
 361         optp = (struct opthdr *)&mp6_conn_ctl->b_rptr[
 362             sizeof (struct T_optmgmt_ack)];
 363         optp->level = MIB2_UDP6;
 364         optp->name = MIB2_UDP6_ENTRY;
 365         optp->len = msgdsize(mp6_conn_ctl->b_cont);
 366         qreply(q, mp6_conn_ctl);
 367 
 368         /* table of MLP attributes... */
 369         optp = (struct opthdr *)&mp6_attr_ctl->b_rptr[
 370             sizeof (struct T_optmgmt_ack)];
 371         optp->level = MIB2_UDP6;
 372         optp->name = EXPER_XPORT_MLP;
 373         optp->len = msgdsize(mp6_attr_ctl->b_cont);
 374         if (optp->len == 0)
 375                 freemsg(mp6_attr_ctl);
 376         else
 377                 qreply(q, mp6_attr_ctl);
 378 
 379         /* table of EXPER_XPORT_PROC_INFO ipv6 */
 380         optp = (struct opthdr *)&mp6_pidnode_ctl->b_rptr[
 381             sizeof (struct T_optmgmt_ack)];
 382         optp->level = MIB2_UDP6;
 383         optp->name = EXPER_XPORT_PROC_INFO;
 384         optp->len = msgdsize(mp6_pidnode_ctl->b_cont);
 385         if (optp->len == 0)
 386                 freemsg(mp6_pidnode_ctl);
 387         else
 388                 qreply(q, mp6_pidnode_ctl);
 389 
 390         return (mp2ctl);
 391 }
 392 
 393 /*
 394  * Return 0 if invalid set request, 1 otherwise, including non-udp requests.
 395  * NOTE: Per MIB-II, UDP has no writable data.
 396  * TODO:  If this ever actually tries to set anything, it needs to be
 397  * to do the appropriate locking.
 398  */
 399 /* ARGSUSED */
 400 int
 401 udp_snmp_set(queue_t *q, t_scalar_t level, t_scalar_t name,
 402     uchar_t *ptr, int len)
 403 {
 404         switch (level) {
 405         case MIB2_UDP:
 406                 return (0);
 407         default:
 408                 return (1);
 409         }
 410 }
 411 
 412 void
 413 udp_kstat_fini(netstackid_t stackid, kstat_t *ksp)
 414 {
 415         if (ksp != NULL) {
 416                 ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
 417                 kstat_delete_netstack(ksp, stackid);
 418         }
 419 }
 420 
 421 /*
 422  * To add stats from one mib2_udp_t to another.  Static fields are not added.
 423  * The caller should set them up propertly.
 424  */
 425 static void
 426 udp_add_mib(mib2_udp_t *from, mib2_udp_t *to)
 427 {
 428         to->udpHCInDatagrams += from->udpHCInDatagrams;
 429         to->udpInErrors += from->udpInErrors;
 430         to->udpHCOutDatagrams += from->udpHCOutDatagrams;
 431         to->udpOutErrors += from->udpOutErrors;
 432 }
 433 
 434 
 435 void *
 436 udp_kstat2_init(netstackid_t stackid)
 437 {
 438         kstat_t *ksp;
 439 
 440         udp_stat_t template = {
 441                 { "udp_sock_fallback",          KSTAT_DATA_UINT64 },
 442                 { "udp_out_opt",                KSTAT_DATA_UINT64 },
 443                 { "udp_out_err_notconn",        KSTAT_DATA_UINT64 },
 444                 { "udp_out_err_output",         KSTAT_DATA_UINT64 },
 445                 { "udp_out_err_tudr",           KSTAT_DATA_UINT64 },
 446 #ifdef DEBUG
 447                 { "udp_data_conn",              KSTAT_DATA_UINT64 },
 448                 { "udp_data_notconn",           KSTAT_DATA_UINT64 },
 449                 { "udp_out_lastdst",            KSTAT_DATA_UINT64 },
 450                 { "udp_out_diffdst",            KSTAT_DATA_UINT64 },
 451                 { "udp_out_ipv6",               KSTAT_DATA_UINT64 },
 452                 { "udp_out_mapped",             KSTAT_DATA_UINT64 },
 453                 { "udp_out_ipv4",               KSTAT_DATA_UINT64 },
 454 #endif
 455         };
 456 
 457         ksp = kstat_create_netstack(UDP_MOD_NAME, 0, "udpstat", "net",
 458             KSTAT_TYPE_NAMED, sizeof (template) / sizeof (kstat_named_t),
 459             0, stackid);
 460 
 461         if (ksp == NULL)
 462                 return (NULL);
 463 
 464         bcopy(&template, ksp->ks_data, sizeof (template));
 465         ksp->ks_update = udp_kstat2_update;
 466         ksp->ks_private = (void *)(uintptr_t)stackid;
 467 
 468         kstat_install(ksp);
 469         return (ksp);
 470 }
 471 
 472 void
 473 udp_kstat2_fini(netstackid_t stackid, kstat_t *ksp)
 474 {
 475         if (ksp != NULL) {
 476                 ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
 477                 kstat_delete_netstack(ksp, stackid);
 478         }
 479 }
 480 
 481 /*
 482  * To copy counters from the per CPU udpp_stat_counter_t to the stack
 483  * udp_stat_t.
 484  */
 485 static void
 486 udp_add_stats(udp_stat_counter_t *from, udp_stat_t *to)
 487 {
 488         to->udp_sock_fallback.value.ui64 += from->udp_sock_fallback;
 489         to->udp_out_opt.value.ui64 += from->udp_out_opt;
 490         to->udp_out_err_notconn.value.ui64 += from->udp_out_err_notconn;
 491         to->udp_out_err_output.value.ui64 += from->udp_out_err_output;
 492         to->udp_out_err_tudr.value.ui64 += from->udp_out_err_tudr;
 493 #ifdef DEBUG
 494         to->udp_data_conn.value.ui64 += from->udp_data_conn;
 495         to->udp_data_notconn.value.ui64 += from->udp_data_notconn;
 496         to->udp_out_lastdst.value.ui64 += from->udp_out_lastdst;
 497         to->udp_out_diffdst.value.ui64 += from->udp_out_diffdst;
 498         to->udp_out_ipv6.value.ui64 += from->udp_out_ipv6;
 499         to->udp_out_mapped.value.ui64 += from->udp_out_mapped;
 500         to->udp_out_ipv4.value.ui64 += from->udp_out_ipv4;
 501 #endif
 502 }
 503 
 504 /*
 505  * To set all udp_stat_t counters to 0.
 506  */
 507 static void
 508 udp_clr_stats(udp_stat_t *stats)
 509 {
 510         stats->udp_sock_fallback.value.ui64 = 0;
 511         stats->udp_out_opt.value.ui64 = 0;
 512         stats->udp_out_err_notconn.value.ui64 = 0;
 513         stats->udp_out_err_output.value.ui64 = 0;
 514         stats->udp_out_err_tudr.value.ui64 = 0;
 515 #ifdef DEBUG
 516         stats->udp_data_conn.value.ui64 = 0;
 517         stats->udp_data_notconn.value.ui64 = 0;
 518         stats->udp_out_lastdst.value.ui64 = 0;
 519         stats->udp_out_diffdst.value.ui64 = 0;
 520         stats->udp_out_ipv6.value.ui64 = 0;
 521         stats->udp_out_mapped.value.ui64 = 0;
 522         stats->udp_out_ipv4.value.ui64 = 0;
 523 #endif
 524 }
 525 
 526 int
 527 udp_kstat2_update(kstat_t *kp, int rw)
 528 {
 529         udp_stat_t      *stats;
 530         netstackid_t    stackid = (netstackid_t)(uintptr_t)kp->ks_private;
 531         netstack_t      *ns;
 532         udp_stack_t     *us;
 533         int             i;
 534         int             cnt;
 535 
 536         if (rw == KSTAT_WRITE)
 537                 return (EACCES);
 538 
 539         ns = netstack_find_by_stackid(stackid);
 540         if (ns == NULL)
 541                 return (-1);
 542         us = ns->netstack_udp;
 543         if (us == NULL) {
 544                 netstack_rele(ns);
 545                 return (-1);
 546         }
 547         stats = (udp_stat_t *)kp->ks_data;
 548         udp_clr_stats(stats);
 549 
 550         cnt = us->us_sc_cnt;
 551         for (i = 0; i < cnt; i++)
 552                 udp_add_stats(&us->us_sc[i]->udp_sc_stats, stats);
 553 
 554         netstack_rele(ns);
 555         return (0);
 556 }
 557 
 558 void *
 559 udp_kstat_init(netstackid_t stackid)
 560 {
 561         kstat_t *ksp;
 562 
 563         udp_named_kstat_t template = {
 564                 { "inDatagrams",        KSTAT_DATA_UINT64, 0 },
 565                 { "inErrors",           KSTAT_DATA_UINT32, 0 },
 566                 { "outDatagrams",       KSTAT_DATA_UINT64, 0 },
 567                 { "entrySize",          KSTAT_DATA_INT32, 0 },
 568                 { "entry6Size",         KSTAT_DATA_INT32, 0 },
 569                 { "outErrors",          KSTAT_DATA_UINT32, 0 },
 570         };
 571 
 572         ksp = kstat_create_netstack(UDP_MOD_NAME, 0, UDP_MOD_NAME, "mib2",
 573             KSTAT_TYPE_NAMED, NUM_OF_FIELDS(udp_named_kstat_t), 0, stackid);
 574 
 575         if (ksp == NULL)
 576                 return (NULL);
 577 
 578         template.entrySize.value.ui32 = sizeof (mib2_udpEntry_t);
 579         template.entry6Size.value.ui32 = sizeof (mib2_udp6Entry_t);
 580 
 581         bcopy(&template, ksp->ks_data, sizeof (template));
 582         ksp->ks_update = udp_kstat_update;
 583         ksp->ks_private = (void *)(uintptr_t)stackid;
 584 
 585         kstat_install(ksp);
 586         return (ksp);
 587 }
 588 
 589 /*
 590  * To sum up all MIB2 stats for a udp_stack_t from all per CPU stats.  The
 591  * caller should initialize the target mib2_udp_t properly as this function
 592  * just adds up all the per CPU stats.
 593  */
 594 static void
 595 udp_sum_mib(udp_stack_t *us, mib2_udp_t *udp_mib)
 596 {
 597         int i;
 598         int cnt;
 599 
 600         cnt = us->us_sc_cnt;
 601         for (i = 0; i < cnt; i++)
 602                 udp_add_mib(&us->us_sc[i]->udp_sc_mib, udp_mib);
 603 }
 604 
 605 static int
 606 udp_kstat_update(kstat_t *kp, int rw)
 607 {
 608         udp_named_kstat_t *udpkp;
 609         netstackid_t    stackid = (netstackid_t)(uintptr_t)kp->ks_private;
 610         netstack_t      *ns;
 611         udp_stack_t     *us;
 612         mib2_udp_t      udp_mib;
 613 
 614         if (rw == KSTAT_WRITE)
 615                 return (EACCES);
 616 
 617         ns = netstack_find_by_stackid(stackid);
 618         if (ns == NULL)
 619                 return (-1);
 620         us = ns->netstack_udp;
 621         if (us == NULL) {
 622                 netstack_rele(ns);
 623                 return (-1);
 624         }
 625         udpkp = (udp_named_kstat_t *)kp->ks_data;
 626 
 627         bzero(&udp_mib, sizeof (udp_mib));
 628         udp_sum_mib(us, &udp_mib);
 629 
 630         udpkp->inDatagrams.value.ui64 =      udp_mib.udpHCInDatagrams;
 631         udpkp->inErrors.value.ui32 = udp_mib.udpInErrors;
 632         udpkp->outDatagrams.value.ui64 = udp_mib.udpHCOutDatagrams;
 633         udpkp->outErrors.value.ui32 =        udp_mib.udpOutErrors;
 634         netstack_rele(ns);
 635         return (0);
 636 }