15dd46ab5SKacheong Poon /*
25dd46ab5SKacheong Poon  * CDDL HEADER START
35dd46ab5SKacheong Poon  *
45dd46ab5SKacheong Poon  * The contents of this file are subject to the terms of the
55dd46ab5SKacheong Poon  * Common Development and Distribution License (the "License").
65dd46ab5SKacheong Poon  * You may not use this file except in compliance with the License.
75dd46ab5SKacheong Poon  *
85dd46ab5SKacheong Poon  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95dd46ab5SKacheong Poon  * or http://www.opensolaris.org/os/licensing.
105dd46ab5SKacheong Poon  * See the License for the specific language governing permissions
115dd46ab5SKacheong Poon  * and limitations under the License.
125dd46ab5SKacheong Poon  *
135dd46ab5SKacheong Poon  * When distributing Covered Code, include this CDDL HEADER in each
145dd46ab5SKacheong Poon  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155dd46ab5SKacheong Poon  * If applicable, add the following below this CDDL HEADER, with the
165dd46ab5SKacheong Poon  * fields enclosed by brackets "[]" replaced with your own identifying
175dd46ab5SKacheong Poon  * information: Portions Copyright [yyyy] [name of copyright owner]
185dd46ab5SKacheong Poon  *
195dd46ab5SKacheong Poon  * CDDL HEADER END
205dd46ab5SKacheong Poon  */
215dd46ab5SKacheong Poon 
225dd46ab5SKacheong Poon /*
235dd46ab5SKacheong Poon  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2478a2e113SAndy Fiddaman  * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
255dd46ab5SKacheong Poon  */
265dd46ab5SKacheong Poon 
275dd46ab5SKacheong Poon #include <sys/types.h>
285dd46ab5SKacheong Poon #include <sys/tihdr.h>
295dd46ab5SKacheong Poon #include <sys/policy.h>
305dd46ab5SKacheong Poon #include <sys/tsol/tnet.h>
3178a2e113SAndy Fiddaman #include <sys/stropts.h>
3278a2e113SAndy Fiddaman #include <sys/strsubr.h>
3378a2e113SAndy Fiddaman #include <sys/socket.h>
3478a2e113SAndy Fiddaman #include <sys/socketvar.h>
355dd46ab5SKacheong Poon 
365dd46ab5SKacheong Poon #include <inet/common.h>
375dd46ab5SKacheong Poon #include <inet/kstatcom.h>
385dd46ab5SKacheong Poon #include <inet/snmpcom.h>
395dd46ab5SKacheong Poon #include <inet/mib2.h>
405dd46ab5SKacheong Poon #include <inet/optcom.h>
415dd46ab5SKacheong Poon #include <inet/snmpcom.h>
425dd46ab5SKacheong Poon #include <inet/kstatcom.h>
435dd46ab5SKacheong Poon #include <inet/udp_impl.h>
445dd46ab5SKacheong Poon 
455dd46ab5SKacheong Poon static int	udp_kstat_update(kstat_t *, int);
465dd46ab5SKacheong Poon static int	udp_kstat2_update(kstat_t *, int);
475dd46ab5SKacheong Poon static void	udp_sum_mib(udp_stack_t *, mib2_udp_t *);
485dd46ab5SKacheong Poon static void	udp_clr_stats(udp_stat_t *);
495dd46ab5SKacheong Poon static void	udp_add_stats(udp_stat_counter_t *, udp_stat_t *);
505dd46ab5SKacheong Poon static void	udp_add_mib(mib2_udp_t *, mib2_udp_t *);
515dd46ab5SKacheong Poon /*
525dd46ab5SKacheong Poon  * return SNMP stuff in buffer in mpdata. We don't hold any lock and report
535dd46ab5SKacheong Poon  * information that can be changing beneath us.
545dd46ab5SKacheong Poon  */
555dd46ab5SKacheong Poon mblk_t *
udp_snmp_get(queue_t * q,mblk_t * mpctl,boolean_t legacy_req)566f773e29SBaban Kenkre udp_snmp_get(queue_t *q, mblk_t *mpctl, boolean_t legacy_req)
575dd46ab5SKacheong Poon {
585dd46ab5SKacheong Poon 	mblk_t			*mpdata;
595dd46ab5SKacheong Poon 	mblk_t			*mp_conn_ctl;
605dd46ab5SKacheong Poon 	mblk_t			*mp_attr_ctl;
6178a2e113SAndy Fiddaman 	mblk_t			*mp_info_ctl;
625dd46ab5SKacheong Poon 	mblk_t			*mp6_conn_ctl;
635dd46ab5SKacheong Poon 	mblk_t			*mp6_attr_ctl;
6478a2e113SAndy Fiddaman 	mblk_t			*mp6_info_ctl;
655dd46ab5SKacheong Poon 	mblk_t			*mp_conn_tail;
665dd46ab5SKacheong Poon 	mblk_t			*mp_attr_tail;
6778a2e113SAndy Fiddaman 	mblk_t			*mp_info_tail;
685dd46ab5SKacheong Poon 	mblk_t			*mp6_conn_tail;
695dd46ab5SKacheong Poon 	mblk_t			*mp6_attr_tail;
7078a2e113SAndy Fiddaman 	mblk_t			*mp6_info_tail;
715dd46ab5SKacheong Poon 	struct opthdr		*optp;
725dd46ab5SKacheong Poon 	mib2_udpEntry_t		ude;
735dd46ab5SKacheong Poon 	mib2_udp6Entry_t	ude6;
745dd46ab5SKacheong Poon 	mib2_transportMLPEntry_t mlp;
7578a2e113SAndy Fiddaman 	mib2_socketInfoEntry_t	*sie, psie;
765dd46ab5SKacheong Poon 	int			state;
775dd46ab5SKacheong Poon 	zoneid_t		zoneid;
785dd46ab5SKacheong Poon 	int			i;
795dd46ab5SKacheong Poon 	connf_t			*connfp;
805dd46ab5SKacheong Poon 	conn_t			*connp = Q_TO_CONN(q);
815dd46ab5SKacheong Poon 	int			v4_conn_idx;
825dd46ab5SKacheong Poon 	int			v6_conn_idx;
835dd46ab5SKacheong Poon 	boolean_t		needattr;
845dd46ab5SKacheong Poon 	udp_t			*udp;
855dd46ab5SKacheong Poon 	ip_stack_t		*ipst = connp->conn_netstack->netstack_ip;
865dd46ab5SKacheong Poon 	udp_stack_t		*us = connp->conn_netstack->netstack_udp;
875dd46ab5SKacheong Poon 	mblk_t			*mp2ctl;
885dd46ab5SKacheong Poon 	mib2_udp_t		udp_mib;
896f773e29SBaban Kenkre 	size_t			udp_mib_size, ude_size, ude6_size;
906f773e29SBaban Kenkre 
915dd46ab5SKacheong Poon 	/*
925dd46ab5SKacheong Poon 	 * make a copy of the original message
935dd46ab5SKacheong Poon 	 */
945dd46ab5SKacheong Poon 	mp2ctl = copymsg(mpctl);
955dd46ab5SKacheong Poon 
96*ab82c29bSToomas Soome 	mp6_info_ctl = NULL;
97*ab82c29bSToomas Soome 	mp6_attr_ctl = NULL;
98*ab82c29bSToomas Soome 	mp6_conn_ctl = NULL;
99*ab82c29bSToomas Soome 	mp_info_ctl = NULL;
100*ab82c29bSToomas Soome 	mp_attr_ctl = NULL;
101*ab82c29bSToomas Soome 	mp_conn_ctl = NULL;
1025dd46ab5SKacheong Poon 	if (mpctl == NULL ||
1035dd46ab5SKacheong Poon 	    (mpdata = mpctl->b_cont) == NULL ||
1045dd46ab5SKacheong Poon 	    (mp_conn_ctl = copymsg(mpctl)) == NULL ||
1055dd46ab5SKacheong Poon 	    (mp_attr_ctl = copymsg(mpctl)) == NULL ||
10678a2e113SAndy Fiddaman 	    (mp_info_ctl = copymsg(mpctl)) == NULL ||
1075dd46ab5SKacheong Poon 	    (mp6_conn_ctl = copymsg(mpctl)) == NULL ||
10878a2e113SAndy Fiddaman 	    (mp6_attr_ctl = copymsg(mpctl)) == NULL ||
10978a2e113SAndy Fiddaman 	    (mp6_info_ctl = copymsg(mpctl)) == NULL) {
1105dd46ab5SKacheong Poon 		freemsg(mp_conn_ctl);
1115dd46ab5SKacheong Poon 		freemsg(mp_attr_ctl);
11278a2e113SAndy Fiddaman 		freemsg(mp_info_ctl);
1135dd46ab5SKacheong Poon 		freemsg(mp6_conn_ctl);
11478a2e113SAndy Fiddaman 		freemsg(mp6_attr_ctl);
11578a2e113SAndy Fiddaman 		freemsg(mp6_info_ctl);
1165dd46ab5SKacheong Poon 		freemsg(mpctl);
1175dd46ab5SKacheong Poon 		freemsg(mp2ctl);
1185dd46ab5SKacheong Poon 		return (0);
1195dd46ab5SKacheong Poon 	}
1205dd46ab5SKacheong Poon 
1215dd46ab5SKacheong Poon 	zoneid = connp->conn_zoneid;
1225dd46ab5SKacheong Poon 
1236f773e29SBaban Kenkre 	if (legacy_req) {
1246f773e29SBaban Kenkre 		udp_mib_size = LEGACY_MIB_SIZE(&udp_mib, mib2_udp_t);
1256f773e29SBaban Kenkre 		ude_size = LEGACY_MIB_SIZE(&ude, mib2_udpEntry_t);
1266f773e29SBaban Kenkre 		ude6_size = LEGACY_MIB_SIZE(&ude6, mib2_udp6Entry_t);
1276f773e29SBaban Kenkre 	} else {
1286f773e29SBaban Kenkre 		udp_mib_size = sizeof (mib2_udp_t);
1296f773e29SBaban Kenkre 		ude_size = sizeof (mib2_udpEntry_t);
1306f773e29SBaban Kenkre 		ude6_size = sizeof (mib2_udp6Entry_t);
1316f773e29SBaban Kenkre 	}
1326f773e29SBaban Kenkre 
1335dd46ab5SKacheong Poon 	bzero(&udp_mib, sizeof (udp_mib));
1345dd46ab5SKacheong Poon 	/* fixed length structure for IPv4 and IPv6 counters */
1356f773e29SBaban Kenkre 	SET_MIB(udp_mib.udpEntrySize, ude_size);
1366f773e29SBaban Kenkre 	SET_MIB(udp_mib.udp6EntrySize, ude6_size);
1375dd46ab5SKacheong Poon 
1385dd46ab5SKacheong Poon 	udp_sum_mib(us, &udp_mib);
1395dd46ab5SKacheong Poon 
1405dd46ab5SKacheong Poon 	/*
1415dd46ab5SKacheong Poon 	 * Synchronize 32- and 64-bit counters.  Note that udpInDatagrams and
1425dd46ab5SKacheong Poon 	 * udpOutDatagrams are not updated anywhere in UDP.  The new 64 bits
1435dd46ab5SKacheong Poon 	 * counters are used.  Hence the old counters' values in us_sc_mib
1445dd46ab5SKacheong Poon 	 * are always 0.
1455dd46ab5SKacheong Poon 	 */
1465dd46ab5SKacheong Poon 	SYNC32_MIB(&udp_mib, udpInDatagrams, udpHCInDatagrams);
1475dd46ab5SKacheong Poon 	SYNC32_MIB(&udp_mib, udpOutDatagrams, udpHCOutDatagrams);
1485dd46ab5SKacheong Poon 
1495dd46ab5SKacheong Poon 	optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)];
1505dd46ab5SKacheong Poon 	optp->level = MIB2_UDP;
1515dd46ab5SKacheong Poon 	optp->name = 0;
1526f773e29SBaban Kenkre 	(void) snmp_append_data(mpdata, (char *)&udp_mib, udp_mib_size);
1535dd46ab5SKacheong Poon 	optp->len = msgdsize(mpdata);
1545dd46ab5SKacheong Poon 	qreply(q, mpctl);
1555dd46ab5SKacheong Poon 
1565dd46ab5SKacheong Poon 	mp_conn_tail = mp_attr_tail = mp6_conn_tail = mp6_attr_tail = NULL;
15778a2e113SAndy Fiddaman 	mp_info_tail = mp6_info_tail = NULL;
1585dd46ab5SKacheong Poon 	v4_conn_idx = v6_conn_idx = 0;
1595dd46ab5SKacheong Poon 
1605dd46ab5SKacheong Poon 	for (i = 0; i < CONN_G_HASH_SIZE; i++) {
1615dd46ab5SKacheong Poon 		connfp = &ipst->ips_ipcl_globalhash_fanout[i];
1625dd46ab5SKacheong Poon 		connp = NULL;
1635dd46ab5SKacheong Poon 
1645dd46ab5SKacheong Poon 		while ((connp = ipcl_get_next_conn(connfp, connp,
1655dd46ab5SKacheong Poon 		    IPCL_UDPCONN))) {
16678a2e113SAndy Fiddaman 			sonode_t *so = (sonode_t *)connp->conn_upper_handle;
16778a2e113SAndy Fiddaman 
1685dd46ab5SKacheong Poon 			udp = connp->conn_udp;
1695dd46ab5SKacheong Poon 			if (zoneid != connp->conn_zoneid)
1705dd46ab5SKacheong Poon 				continue;
1715dd46ab5SKacheong Poon 
1725dd46ab5SKacheong Poon 			/*
1735dd46ab5SKacheong Poon 			 * Note that the port numbers are sent in
1745dd46ab5SKacheong Poon 			 * host byte order
1755dd46ab5SKacheong Poon 			 */
1765dd46ab5SKacheong Poon 
1775dd46ab5SKacheong Poon 			if (udp->udp_state == TS_UNBND)
1785dd46ab5SKacheong Poon 				state = MIB2_UDP_unbound;
1795dd46ab5SKacheong Poon 			else if (udp->udp_state == TS_IDLE)
1805dd46ab5SKacheong Poon 				state = MIB2_UDP_idle;
1815dd46ab5SKacheong Poon 			else if (udp->udp_state == TS_DATA_XFER)
1825dd46ab5SKacheong Poon 				state = MIB2_UDP_connected;
1835dd46ab5SKacheong Poon 			else
1845dd46ab5SKacheong Poon 				state = MIB2_UDP_unknown;
1855dd46ab5SKacheong Poon 
1865dd46ab5SKacheong Poon 			needattr = B_FALSE;
1875dd46ab5SKacheong Poon 			bzero(&mlp, sizeof (mlp));
1885dd46ab5SKacheong Poon 			if (connp->conn_mlp_type != mlptSingle) {
1895dd46ab5SKacheong Poon 				if (connp->conn_mlp_type == mlptShared ||
1905dd46ab5SKacheong Poon 				    connp->conn_mlp_type == mlptBoth)
1915dd46ab5SKacheong Poon 					mlp.tme_flags |= MIB2_TMEF_SHARED;
1925dd46ab5SKacheong Poon 				if (connp->conn_mlp_type == mlptPrivate ||
1935dd46ab5SKacheong Poon 				    connp->conn_mlp_type == mlptBoth)
1945dd46ab5SKacheong Poon 					mlp.tme_flags |= MIB2_TMEF_PRIVATE;
1955dd46ab5SKacheong Poon 				needattr = B_TRUE;
1965dd46ab5SKacheong Poon 			}
1975dd46ab5SKacheong Poon 			if (connp->conn_anon_mlp) {
1985dd46ab5SKacheong Poon 				mlp.tme_flags |= MIB2_TMEF_ANONMLP;
1995dd46ab5SKacheong Poon 				needattr = B_TRUE;
2005dd46ab5SKacheong Poon 			}
2015dd46ab5SKacheong Poon 			switch (connp->conn_mac_mode) {
2025dd46ab5SKacheong Poon 			case CONN_MAC_DEFAULT:
2035dd46ab5SKacheong Poon 				break;
2045dd46ab5SKacheong Poon 			case CONN_MAC_AWARE:
2055dd46ab5SKacheong Poon 				mlp.tme_flags |= MIB2_TMEF_MACEXEMPT;
2065dd46ab5SKacheong Poon 				needattr = B_TRUE;
2075dd46ab5SKacheong Poon 				break;
2085dd46ab5SKacheong Poon 			case CONN_MAC_IMPLICIT:
2095dd46ab5SKacheong Poon 				mlp.tme_flags |= MIB2_TMEF_MACIMPLICIT;
2105dd46ab5SKacheong Poon 				needattr = B_TRUE;
2115dd46ab5SKacheong Poon 				break;
2125dd46ab5SKacheong Poon 			}
2135dd46ab5SKacheong Poon 			mutex_enter(&connp->conn_lock);
2145dd46ab5SKacheong Poon 			if (udp->udp_state == TS_DATA_XFER &&
2155dd46ab5SKacheong Poon 			    connp->conn_ixa->ixa_tsl != NULL) {
2165dd46ab5SKacheong Poon 				ts_label_t *tsl;
2175dd46ab5SKacheong Poon 
2185dd46ab5SKacheong Poon 				tsl = connp->conn_ixa->ixa_tsl;
2195dd46ab5SKacheong Poon 				mlp.tme_flags |= MIB2_TMEF_IS_LABELED;
2205dd46ab5SKacheong Poon 				mlp.tme_doi = label2doi(tsl);
2215dd46ab5SKacheong Poon 				mlp.tme_label = *label2bslabel(tsl);
2225dd46ab5SKacheong Poon 				needattr = B_TRUE;
2235dd46ab5SKacheong Poon 			}
2245dd46ab5SKacheong Poon 			mutex_exit(&connp->conn_lock);
2255dd46ab5SKacheong Poon 
2265dd46ab5SKacheong Poon 			/*
2275dd46ab5SKacheong Poon 			 * Create an IPv4 table entry for IPv4 entries and also
2285dd46ab5SKacheong Poon 			 * any IPv6 entries which are bound to in6addr_any
2295dd46ab5SKacheong Poon 			 * (i.e. anything a IPv4 peer could connect/send to).
2305dd46ab5SKacheong Poon 			 */
2315dd46ab5SKacheong Poon 			if (connp->conn_ipversion == IPV4_VERSION ||
2325dd46ab5SKacheong Poon 			    (udp->udp_state <= TS_IDLE &&
2335dd46ab5SKacheong Poon 			    IN6_IS_ADDR_UNSPECIFIED(&connp->conn_laddr_v6))) {
2345dd46ab5SKacheong Poon 				ude.udpEntryInfo.ue_state = state;
2355dd46ab5SKacheong Poon 				/*
2365dd46ab5SKacheong Poon 				 * If in6addr_any this will set it to
2375dd46ab5SKacheong Poon 				 * INADDR_ANY
2385dd46ab5SKacheong Poon 				 */
2395dd46ab5SKacheong Poon 				ude.udpLocalAddress = connp->conn_laddr_v4;
2405dd46ab5SKacheong Poon 				ude.udpLocalPort = ntohs(connp->conn_lport);
2415dd46ab5SKacheong Poon 				if (udp->udp_state == TS_DATA_XFER) {
2425dd46ab5SKacheong Poon 					/*
2435dd46ab5SKacheong Poon 					 * Can potentially get here for
2445dd46ab5SKacheong Poon 					 * v6 socket if another process
2455dd46ab5SKacheong Poon 					 * (say, ping) has just done a
2465dd46ab5SKacheong Poon 					 * sendto(), changing the state
2475dd46ab5SKacheong Poon 					 * from the TS_IDLE above to
2485dd46ab5SKacheong Poon 					 * TS_DATA_XFER by the time we hit
2495dd46ab5SKacheong Poon 					 * this part of the code.
2505dd46ab5SKacheong Poon 					 */
2515dd46ab5SKacheong Poon 					ude.udpEntryInfo.ue_RemoteAddress =
2525dd46ab5SKacheong Poon 					    connp->conn_faddr_v4;
2535dd46ab5SKacheong Poon 					ude.udpEntryInfo.ue_RemotePort =
2545dd46ab5SKacheong Poon 					    ntohs(connp->conn_fport);
2555dd46ab5SKacheong Poon 				} else {
2565dd46ab5SKacheong Poon 					ude.udpEntryInfo.ue_RemoteAddress = 0;
2575dd46ab5SKacheong Poon 					ude.udpEntryInfo.ue_RemotePort = 0;
2585dd46ab5SKacheong Poon 				}
2595dd46ab5SKacheong Poon 
2605dd46ab5SKacheong Poon 				/*
2615dd46ab5SKacheong Poon 				 * We make the assumption that all udp_t
2625dd46ab5SKacheong Poon 				 * structs will be created within an address
2635dd46ab5SKacheong Poon 				 * region no larger than 32-bits.
2645dd46ab5SKacheong Poon 				 */
2655dd46ab5SKacheong Poon 				ude.udpInstance = (uint32_t)(uintptr_t)udp;
2665dd46ab5SKacheong Poon 				ude.udpCreationProcess =
2675dd46ab5SKacheong Poon 				    (connp->conn_cpid < 0) ?
2685dd46ab5SKacheong Poon 				    MIB2_UNKNOWN_PROCESS :
2695dd46ab5SKacheong Poon 				    connp->conn_cpid;
2705dd46ab5SKacheong Poon 				ude.udpCreationTime = connp->conn_open_time;
2715dd46ab5SKacheong Poon 
2725dd46ab5SKacheong Poon 				(void) snmp_append_data2(mp_conn_ctl->b_cont,
2736f773e29SBaban Kenkre 				    &mp_conn_tail, (char *)&ude, ude_size);
27478a2e113SAndy Fiddaman 
27578a2e113SAndy Fiddaman 				if (needattr) {
27678a2e113SAndy Fiddaman 					mlp.tme_connidx = v4_conn_idx;
2775dd46ab5SKacheong Poon 					(void) snmp_append_data2(
2785dd46ab5SKacheong Poon 					    mp_attr_ctl->b_cont, &mp_attr_tail,
2795dd46ab5SKacheong Poon 					    (char *)&mlp, sizeof (mlp));
28078a2e113SAndy Fiddaman 				}
28178a2e113SAndy Fiddaman 
28278a2e113SAndy Fiddaman 				if ((sie = conn_get_socket_info(connp, &psie))
28378a2e113SAndy Fiddaman 				    != NULL) {
28478a2e113SAndy Fiddaman 					sie->sie_connidx = v4_conn_idx;
28578a2e113SAndy Fiddaman 					if (connp->conn_ipversion ==
28678a2e113SAndy Fiddaman 					    IPV6_VERSION)
28778a2e113SAndy Fiddaman 						sie->sie_flags |=
28878a2e113SAndy Fiddaman 						    MIB2_SOCKINFO_IPV6;
28978a2e113SAndy Fiddaman 					(void) snmp_append_data2(
29078a2e113SAndy Fiddaman 					    mp_info_ctl->b_cont, &mp_info_tail,
29178a2e113SAndy Fiddaman 					    (char *)sie, sizeof (*sie));
29278a2e113SAndy Fiddaman 				}
29378a2e113SAndy Fiddaman 
29478a2e113SAndy Fiddaman 				v4_conn_idx++;
2955dd46ab5SKacheong Poon 			}
2965dd46ab5SKacheong Poon 			if (connp->conn_ipversion == IPV6_VERSION) {
2975dd46ab5SKacheong Poon 				ude6.udp6EntryInfo.ue_state  = state;
2985dd46ab5SKacheong Poon 				ude6.udp6LocalAddress = connp->conn_laddr_v6;
2995dd46ab5SKacheong Poon 				ude6.udp6LocalPort = ntohs(connp->conn_lport);
3005dd46ab5SKacheong Poon 				mutex_enter(&connp->conn_lock);
3015dd46ab5SKacheong Poon 				if (connp->conn_ixa->ixa_flags &
3025dd46ab5SKacheong Poon 				    IXAF_SCOPEID_SET) {
3035dd46ab5SKacheong Poon 					ude6.udp6IfIndex =
3045dd46ab5SKacheong Poon 					    connp->conn_ixa->ixa_scopeid;
3055dd46ab5SKacheong Poon 				} else {
3065dd46ab5SKacheong Poon 					ude6.udp6IfIndex = connp->conn_bound_if;
3075dd46ab5SKacheong Poon 				}
3085dd46ab5SKacheong Poon 				mutex_exit(&connp->conn_lock);
3095dd46ab5SKacheong Poon 				if (udp->udp_state == TS_DATA_XFER) {
3105dd46ab5SKacheong Poon 					ude6.udp6EntryInfo.ue_RemoteAddress =
3115dd46ab5SKacheong Poon 					    connp->conn_faddr_v6;
3125dd46ab5SKacheong Poon 					ude6.udp6EntryInfo.ue_RemotePort =
3135dd46ab5SKacheong Poon 					    ntohs(connp->conn_fport);
3145dd46ab5SKacheong Poon 				} else {
3155dd46ab5SKacheong Poon 					ude6.udp6EntryInfo.ue_RemoteAddress =
3165dd46ab5SKacheong Poon 					    sin6_null.sin6_addr;
3175dd46ab5SKacheong Poon 					ude6.udp6EntryInfo.ue_RemotePort = 0;
3185dd46ab5SKacheong Poon 				}
3195dd46ab5SKacheong Poon 				/*
3205dd46ab5SKacheong Poon 				 * We make the assumption that all udp_t
3215dd46ab5SKacheong Poon 				 * structs will be created within an address
3225dd46ab5SKacheong Poon 				 * region no larger than 32-bits.
3235dd46ab5SKacheong Poon 				 */
3245dd46ab5SKacheong Poon 				ude6.udp6Instance = (uint32_t)(uintptr_t)udp;
3255dd46ab5SKacheong Poon 				ude6.udp6CreationProcess =
3265dd46ab5SKacheong Poon 				    (connp->conn_cpid < 0) ?
3275dd46ab5SKacheong Poon 				    MIB2_UNKNOWN_PROCESS :
3285dd46ab5SKacheong Poon 				    connp->conn_cpid;
3295dd46ab5SKacheong Poon 				ude6.udp6CreationTime = connp->conn_open_time;
3305dd46ab5SKacheong Poon 
3315dd46ab5SKacheong Poon 				(void) snmp_append_data2(mp6_conn_ctl->b_cont,
3326f773e29SBaban Kenkre 				    &mp6_conn_tail, (char *)&ude6, ude6_size);
33378a2e113SAndy Fiddaman 
33478a2e113SAndy Fiddaman 				if (needattr) {
33578a2e113SAndy Fiddaman 					mlp.tme_connidx = v6_conn_idx;
3365dd46ab5SKacheong Poon 					(void) snmp_append_data2(
3375dd46ab5SKacheong Poon 					    mp6_attr_ctl->b_cont,
3385dd46ab5SKacheong Poon 					    &mp6_attr_tail, (char *)&mlp,
3395dd46ab5SKacheong Poon 					    sizeof (mlp));
34078a2e113SAndy Fiddaman 				}
34178a2e113SAndy Fiddaman 
34278a2e113SAndy Fiddaman 				if ((sie = conn_get_socket_info(connp,
34378a2e113SAndy Fiddaman 				    &psie)) != NULL) {
34478a2e113SAndy Fiddaman 					sie->sie_connidx = v6_conn_idx;
34578a2e113SAndy Fiddaman 					(void) snmp_append_data2(
34678a2e113SAndy Fiddaman 					    mp6_info_ctl->b_cont,
34778a2e113SAndy Fiddaman 					    &mp6_info_tail,
34878a2e113SAndy Fiddaman 					    (char *)sie, sizeof (*sie));
34978a2e113SAndy Fiddaman 				}
35078a2e113SAndy Fiddaman 
35178a2e113SAndy Fiddaman 				v6_conn_idx++;
3525dd46ab5SKacheong Poon 			}
3535dd46ab5SKacheong Poon 		}
3545dd46ab5SKacheong Poon 	}
3555dd46ab5SKacheong Poon 
3565dd46ab5SKacheong Poon 	/* IPv4 UDP endpoints */
3575dd46ab5SKacheong Poon 	optp = (struct opthdr *)&mp_conn_ctl->b_rptr[
3585dd46ab5SKacheong Poon 	    sizeof (struct T_optmgmt_ack)];
3595dd46ab5SKacheong Poon 	optp->level = MIB2_UDP;
3605dd46ab5SKacheong Poon 	optp->name = MIB2_UDP_ENTRY;
3615dd46ab5SKacheong Poon 	optp->len = msgdsize(mp_conn_ctl->b_cont);
3625dd46ab5SKacheong Poon 	qreply(q, mp_conn_ctl);
3635dd46ab5SKacheong Poon 
3645dd46ab5SKacheong Poon 	/* table of MLP attributes... */
3655dd46ab5SKacheong Poon 	optp = (struct opthdr *)&mp_attr_ctl->b_rptr[
3665dd46ab5SKacheong Poon 	    sizeof (struct T_optmgmt_ack)];
3675dd46ab5SKacheong Poon 	optp->level = MIB2_UDP;
3685dd46ab5SKacheong Poon 	optp->name = EXPER_XPORT_MLP;
3695dd46ab5SKacheong Poon 	optp->len = msgdsize(mp_attr_ctl->b_cont);
3705dd46ab5SKacheong Poon 	if (optp->len == 0)
3715dd46ab5SKacheong Poon 		freemsg(mp_attr_ctl);
3725dd46ab5SKacheong Poon 	else
3735dd46ab5SKacheong Poon 		qreply(q, mp_attr_ctl);
3745dd46ab5SKacheong Poon 
37578a2e113SAndy Fiddaman 	/* table of socket info... */
37678a2e113SAndy Fiddaman 	optp = (struct opthdr *)&mp_info_ctl->b_rptr[
37778a2e113SAndy Fiddaman 	    sizeof (struct T_optmgmt_ack)];
37878a2e113SAndy Fiddaman 	optp->level = MIB2_UDP;
37978a2e113SAndy Fiddaman 	optp->name = EXPER_SOCK_INFO;
38078a2e113SAndy Fiddaman 	optp->len = msgdsize(mp_info_ctl->b_cont);
38178a2e113SAndy Fiddaman 	if (optp->len == 0)
38278a2e113SAndy Fiddaman 		freemsg(mp_info_ctl);
38378a2e113SAndy Fiddaman 	else
38478a2e113SAndy Fiddaman 		qreply(q, mp_info_ctl);
38578a2e113SAndy Fiddaman 
3865dd46ab5SKacheong Poon 	/* IPv6 UDP endpoints */
3875dd46ab5SKacheong Poon 	optp = (struct opthdr *)&mp6_conn_ctl->b_rptr[
3885dd46ab5SKacheong Poon 	    sizeof (struct T_optmgmt_ack)];
3895dd46ab5SKacheong Poon 	optp->level = MIB2_UDP6;
3905dd46ab5SKacheong Poon 	optp->name = MIB2_UDP6_ENTRY;
3915dd46ab5SKacheong Poon 	optp->len = msgdsize(mp6_conn_ctl->b_cont);
3925dd46ab5SKacheong Poon 	qreply(q, mp6_conn_ctl);
3935dd46ab5SKacheong Poon 
3945dd46ab5SKacheong Poon 	/* table of MLP attributes... */
3955dd46ab5SKacheong Poon 	optp = (struct opthdr *)&mp6_attr_ctl->b_rptr[
3965dd46ab5SKacheong Poon 	    sizeof (struct T_optmgmt_ack)];
3975dd46ab5SKacheong Poon 	optp->level = MIB2_UDP6;
3985dd46ab5SKacheong Poon 	optp->name = EXPER_XPORT_MLP;
3995dd46ab5SKacheong Poon 	optp->len = msgdsize(mp6_attr_ctl->b_cont);
4005dd46ab5SKacheong Poon 	if (optp->len == 0)
4015dd46ab5SKacheong Poon 		freemsg(mp6_attr_ctl);
4025dd46ab5SKacheong Poon 	else
4035dd46ab5SKacheong Poon 		qreply(q, mp6_attr_ctl);
4045dd46ab5SKacheong Poon 
40578a2e113SAndy Fiddaman 	/* table of socket info... */
40678a2e113SAndy Fiddaman 	optp = (struct opthdr *)&mp6_info_ctl->b_rptr[
40778a2e113SAndy Fiddaman 	    sizeof (struct T_optmgmt_ack)];
40878a2e113SAndy Fiddaman 	optp->level = MIB2_UDP6;
40978a2e113SAndy Fiddaman 	optp->name = EXPER_SOCK_INFO;
41078a2e113SAndy Fiddaman 	optp->len = msgdsize(mp6_info_ctl->b_cont);
41178a2e113SAndy Fiddaman 	if (optp->len == 0)
41278a2e113SAndy Fiddaman 		freemsg(mp6_info_ctl);
41378a2e113SAndy Fiddaman 	else
41478a2e113SAndy Fiddaman 		qreply(q, mp6_info_ctl);
41578a2e113SAndy Fiddaman 
4165dd46ab5SKacheong Poon 	return (mp2ctl);
4175dd46ab5SKacheong Poon }
4185dd46ab5SKacheong Poon 
4195dd46ab5SKacheong Poon /*
4205dd46ab5SKacheong Poon  * Return 0 if invalid set request, 1 otherwise, including non-udp requests.
4215dd46ab5SKacheong Poon  * NOTE: Per MIB-II, UDP has no writable data.
4225dd46ab5SKacheong Poon  * TODO:  If this ever actually tries to set anything, it needs to be
4235dd46ab5SKacheong Poon  * to do the appropriate locking.
4245dd46ab5SKacheong Poon  */
4255dd46ab5SKacheong Poon /* ARGSUSED */
4265dd46ab5SKacheong Poon int
udp_snmp_set(queue_t * q,t_scalar_t level,t_scalar_t name,uchar_t * ptr,int len)4275dd46ab5SKacheong Poon udp_snmp_set(queue_t *q, t_scalar_t level, t_scalar_t name,
4285dd46ab5SKacheong Poon     uchar_t *ptr, int len)
4295dd46ab5SKacheong Poon {
4305dd46ab5SKacheong Poon 	switch (level) {
4315dd46ab5SKacheong Poon 	case MIB2_UDP:
4325dd46ab5SKacheong Poon 		return (0);
4335dd46ab5SKacheong Poon 	default:
4345dd46ab5SKacheong Poon 		return (1);
4355dd46ab5SKacheong Poon 	}
4365dd46ab5SKacheong Poon }
4375dd46ab5SKacheong Poon 
4385dd46ab5SKacheong Poon void
udp_kstat_fini(netstackid_t stackid,kstat_t * ksp)4395dd46ab5SKacheong Poon udp_kstat_fini(netstackid_t stackid, kstat_t *ksp)
4405dd46ab5SKacheong Poon {
4415dd46ab5SKacheong Poon 	if (ksp != NULL) {
4425dd46ab5SKacheong Poon 		ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
4435dd46ab5SKacheong Poon 		kstat_delete_netstack(ksp, stackid);
4445dd46ab5SKacheong Poon 	}
4455dd46ab5SKacheong Poon }
4465dd46ab5SKacheong Poon 
4475dd46ab5SKacheong Poon /*
4485dd46ab5SKacheong Poon  * To add stats from one mib2_udp_t to another.  Static fields are not added.
4495dd46ab5SKacheong Poon  * The caller should set them up propertly.
4505dd46ab5SKacheong Poon  */
4515dd46ab5SKacheong Poon static void
udp_add_mib(mib2_udp_t * from,mib2_udp_t * to)4525dd46ab5SKacheong Poon udp_add_mib(mib2_udp_t *from, mib2_udp_t *to)
4535dd46ab5SKacheong Poon {
4545dd46ab5SKacheong Poon 	to->udpHCInDatagrams += from->udpHCInDatagrams;
4555dd46ab5SKacheong Poon 	to->udpInErrors += from->udpInErrors;
4565dd46ab5SKacheong Poon 	to->udpHCOutDatagrams += from->udpHCOutDatagrams;
4575dd46ab5SKacheong Poon 	to->udpOutErrors += from->udpOutErrors;
4585dd46ab5SKacheong Poon }
4595dd46ab5SKacheong Poon 
4605dd46ab5SKacheong Poon 
4615dd46ab5SKacheong Poon void *
udp_kstat2_init(netstackid_t stackid)4625dd46ab5SKacheong Poon udp_kstat2_init(netstackid_t stackid)
4635dd46ab5SKacheong Poon {
4645dd46ab5SKacheong Poon 	kstat_t *ksp;
4655dd46ab5SKacheong Poon 
4665dd46ab5SKacheong Poon 	udp_stat_t template = {
4675dd46ab5SKacheong Poon 		{ "udp_sock_fallback",		KSTAT_DATA_UINT64 },
4685dd46ab5SKacheong Poon 		{ "udp_out_opt",		KSTAT_DATA_UINT64 },
4695dd46ab5SKacheong Poon 		{ "udp_out_err_notconn",	KSTAT_DATA_UINT64 },
4705dd46ab5SKacheong Poon 		{ "udp_out_err_output",		KSTAT_DATA_UINT64 },
4715dd46ab5SKacheong Poon 		{ "udp_out_err_tudr",		KSTAT_DATA_UINT64 },
4725dd46ab5SKacheong Poon #ifdef DEBUG
4735dd46ab5SKacheong Poon 		{ "udp_data_conn",		KSTAT_DATA_UINT64 },
4745dd46ab5SKacheong Poon 		{ "udp_data_notconn",		KSTAT_DATA_UINT64 },
4755dd46ab5SKacheong Poon 		{ "udp_out_lastdst",		KSTAT_DATA_UINT64 },
4765dd46ab5SKacheong Poon 		{ "udp_out_diffdst",		KSTAT_DATA_UINT64 },
4775dd46ab5SKacheong Poon 		{ "udp_out_ipv6",		KSTAT_DATA_UINT64 },
4785dd46ab5SKacheong Poon 		{ "udp_out_mapped",		KSTAT_DATA_UINT64 },
4795dd46ab5SKacheong Poon 		{ "udp_out_ipv4",		KSTAT_DATA_UINT64 },
4805dd46ab5SKacheong Poon #endif
4815dd46ab5SKacheong Poon 	};
4825dd46ab5SKacheong Poon 
4835dd46ab5SKacheong Poon 	ksp = kstat_create_netstack(UDP_MOD_NAME, 0, "udpstat", "net",
4845dd46ab5SKacheong Poon 	    KSTAT_TYPE_NAMED, sizeof (template) / sizeof (kstat_named_t),
4855dd46ab5SKacheong Poon 	    0, stackid);
4865dd46ab5SKacheong Poon 
4875dd46ab5SKacheong Poon 	if (ksp == NULL)
4885dd46ab5SKacheong Poon 		return (NULL);
4895dd46ab5SKacheong Poon 
4905dd46ab5SKacheong Poon 	bcopy(&template, ksp->ks_data, sizeof (template));
4915dd46ab5SKacheong Poon 	ksp->ks_update = udp_kstat2_update;
4925dd46ab5SKacheong Poon 	ksp->ks_private = (void *)(uintptr_t)stackid;
4935dd46ab5SKacheong Poon 
4945dd46ab5SKacheong Poon 	kstat_install(ksp);
4955dd46ab5SKacheong Poon 	return (ksp);
4965dd46ab5SKacheong Poon }
4975dd46ab5SKacheong Poon 
4985dd46ab5SKacheong Poon void
udp_kstat2_fini(netstackid_t stackid,kstat_t * ksp)4995dd46ab5SKacheong Poon udp_kstat2_fini(netstackid_t stackid, kstat_t *ksp)
5005dd46ab5SKacheong Poon {
5015dd46ab5SKacheong Poon 	if (ksp != NULL) {
5025dd46ab5SKacheong Poon 		ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
5035dd46ab5SKacheong Poon 		kstat_delete_netstack(ksp, stackid);
5045dd46ab5SKacheong Poon 	}
5055dd46ab5SKacheong Poon }
5065dd46ab5SKacheong Poon 
5075dd46ab5SKacheong Poon /*
5085dd46ab5SKacheong Poon  * To copy counters from the per CPU udpp_stat_counter_t to the stack
5095dd46ab5SKacheong Poon  * udp_stat_t.
5105dd46ab5SKacheong Poon  */
5115dd46ab5SKacheong Poon static void
udp_add_stats(udp_stat_counter_t * from,udp_stat_t * to)5125dd46ab5SKacheong Poon udp_add_stats(udp_stat_counter_t *from, udp_stat_t *to)
5135dd46ab5SKacheong Poon {
5145dd46ab5SKacheong Poon 	to->udp_sock_fallback.value.ui64 += from->udp_sock_fallback;
5155dd46ab5SKacheong Poon 	to->udp_out_opt.value.ui64 += from->udp_out_opt;
5165dd46ab5SKacheong Poon 	to->udp_out_err_notconn.value.ui64 += from->udp_out_err_notconn;
5175dd46ab5SKacheong Poon 	to->udp_out_err_output.value.ui64 += from->udp_out_err_output;
5185dd46ab5SKacheong Poon 	to->udp_out_err_tudr.value.ui64 += from->udp_out_err_tudr;
5195dd46ab5SKacheong Poon #ifdef DEBUG
5205dd46ab5SKacheong Poon 	to->udp_data_conn.value.ui64 += from->udp_data_conn;
5215dd46ab5SKacheong Poon 	to->udp_data_notconn.value.ui64 += from->udp_data_notconn;
5225dd46ab5SKacheong Poon 	to->udp_out_lastdst.value.ui64 += from->udp_out_lastdst;
5235dd46ab5SKacheong Poon 	to->udp_out_diffdst.value.ui64 += from->udp_out_diffdst;
5245dd46ab5SKacheong Poon 	to->udp_out_ipv6.value.ui64 += from->udp_out_ipv6;
5255dd46ab5SKacheong Poon 	to->udp_out_mapped.value.ui64 += from->udp_out_mapped;
5265dd46ab5SKacheong Poon 	to->udp_out_ipv4.value.ui64 += from->udp_out_ipv4;
5275dd46ab5SKacheong Poon #endif
5285dd46ab5SKacheong Poon }
5295dd46ab5SKacheong Poon 
5305dd46ab5SKacheong Poon /*
5315dd46ab5SKacheong Poon  * To set all udp_stat_t counters to 0.
5325dd46ab5SKacheong Poon  */
5335dd46ab5SKacheong Poon static void
udp_clr_stats(udp_stat_t * stats)5345dd46ab5SKacheong Poon udp_clr_stats(udp_stat_t *stats)
5355dd46ab5SKacheong Poon {
5365dd46ab5SKacheong Poon 	stats->udp_sock_fallback.value.ui64 = 0;
5375dd46ab5SKacheong Poon 	stats->udp_out_opt.value.ui64 = 0;
5385dd46ab5SKacheong Poon 	stats->udp_out_err_notconn.value.ui64 = 0;
5395dd46ab5SKacheong Poon 	stats->udp_out_err_output.value.ui64 = 0;
5405dd46ab5SKacheong Poon 	stats->udp_out_err_tudr.value.ui64 = 0;
5415dd46ab5SKacheong Poon #ifdef DEBUG
5425dd46ab5SKacheong Poon 	stats->udp_data_conn.value.ui64 = 0;
5435dd46ab5SKacheong Poon 	stats->udp_data_notconn.value.ui64 = 0;
5445dd46ab5SKacheong Poon 	stats->udp_out_lastdst.value.ui64 = 0;
5455dd46ab5SKacheong Poon 	stats->udp_out_diffdst.value.ui64 = 0;
5465dd46ab5SKacheong Poon 	stats->udp_out_ipv6.value.ui64 = 0;
5475dd46ab5SKacheong Poon 	stats->udp_out_mapped.value.ui64 = 0;
5485dd46ab5SKacheong Poon 	stats->udp_out_ipv4.value.ui64 = 0;
5495dd46ab5SKacheong Poon #endif
5505dd46ab5SKacheong Poon }
5515dd46ab5SKacheong Poon 
5525dd46ab5SKacheong Poon int
udp_kstat2_update(kstat_t * kp,int rw)5535dd46ab5SKacheong Poon udp_kstat2_update(kstat_t *kp, int rw)
5545dd46ab5SKacheong Poon {
5555dd46ab5SKacheong Poon 	udp_stat_t	*stats;
5565dd46ab5SKacheong Poon 	netstackid_t	stackid = (netstackid_t)(uintptr_t)kp->ks_private;
5575dd46ab5SKacheong Poon 	netstack_t	*ns;
5585dd46ab5SKacheong Poon 	udp_stack_t	*us;
5595dd46ab5SKacheong Poon 	int		i;
5605dd46ab5SKacheong Poon 	int		cnt;
5615dd46ab5SKacheong Poon 
5625dd46ab5SKacheong Poon 	if (rw == KSTAT_WRITE)
5635dd46ab5SKacheong Poon 		return (EACCES);
5645dd46ab5SKacheong Poon 
5655dd46ab5SKacheong Poon 	ns = netstack_find_by_stackid(stackid);
5665dd46ab5SKacheong Poon 	if (ns == NULL)
5675dd46ab5SKacheong Poon 		return (-1);
5685dd46ab5SKacheong Poon 	us = ns->netstack_udp;
5695dd46ab5SKacheong Poon 	if (us == NULL) {
5705dd46ab5SKacheong Poon 		netstack_rele(ns);
5715dd46ab5SKacheong Poon 		return (-1);
5725dd46ab5SKacheong Poon 	}
5735dd46ab5SKacheong Poon 	stats = (udp_stat_t *)kp->ks_data;
5745dd46ab5SKacheong Poon 	udp_clr_stats(stats);
5755dd46ab5SKacheong Poon 
5765dd46ab5SKacheong Poon 	cnt = us->us_sc_cnt;
5775dd46ab5SKacheong Poon 	for (i = 0; i < cnt; i++)
5785dd46ab5SKacheong Poon 		udp_add_stats(&us->us_sc[i]->udp_sc_stats, stats);
5795dd46ab5SKacheong Poon 
5805dd46ab5SKacheong Poon 	netstack_rele(ns);
5815dd46ab5SKacheong Poon 	return (0);
5825dd46ab5SKacheong Poon }
5835dd46ab5SKacheong Poon 
5845dd46ab5SKacheong Poon void *
udp_kstat_init(netstackid_t stackid)5855dd46ab5SKacheong Poon udp_kstat_init(netstackid_t stackid)
5865dd46ab5SKacheong Poon {
5875dd46ab5SKacheong Poon 	kstat_t	*ksp;
5885dd46ab5SKacheong Poon 
5895dd46ab5SKacheong Poon 	udp_named_kstat_t template = {
5905dd46ab5SKacheong Poon 		{ "inDatagrams",	KSTAT_DATA_UINT64, 0 },
5915dd46ab5SKacheong Poon 		{ "inErrors",		KSTAT_DATA_UINT32, 0 },
5925dd46ab5SKacheong Poon 		{ "outDatagrams",	KSTAT_DATA_UINT64, 0 },
5935dd46ab5SKacheong Poon 		{ "entrySize",		KSTAT_DATA_INT32, 0 },
5945dd46ab5SKacheong Poon 		{ "entry6Size",		KSTAT_DATA_INT32, 0 },
5955dd46ab5SKacheong Poon 		{ "outErrors",		KSTAT_DATA_UINT32, 0 },
5965dd46ab5SKacheong Poon 	};
5975dd46ab5SKacheong Poon 
5985dd46ab5SKacheong Poon 	ksp = kstat_create_netstack(UDP_MOD_NAME, 0, UDP_MOD_NAME, "mib2",
5995dd46ab5SKacheong Poon 	    KSTAT_TYPE_NAMED, NUM_OF_FIELDS(udp_named_kstat_t), 0, stackid);
6005dd46ab5SKacheong Poon 
6015dd46ab5SKacheong Poon 	if (ksp == NULL)
6025dd46ab5SKacheong Poon 		return (NULL);
6035dd46ab5SKacheong Poon 
6045dd46ab5SKacheong Poon 	template.entrySize.value.ui32 = sizeof (mib2_udpEntry_t);
6055dd46ab5SKacheong Poon 	template.entry6Size.value.ui32 = sizeof (mib2_udp6Entry_t);
6065dd46ab5SKacheong Poon 
6075dd46ab5SKacheong Poon 	bcopy(&template, ksp->ks_data, sizeof (template));
6085dd46ab5SKacheong Poon 	ksp->ks_update = udp_kstat_update;
6095dd46ab5SKacheong Poon 	ksp->ks_private = (void *)(uintptr_t)stackid;
6105dd46ab5SKacheong Poon 
6115dd46ab5SKacheong Poon 	kstat_install(ksp);
6125dd46ab5SKacheong Poon 	return (ksp);
6135dd46ab5SKacheong Poon }
6145dd46ab5SKacheong Poon 
6155dd46ab5SKacheong Poon /*
6165dd46ab5SKacheong Poon  * To sum up all MIB2 stats for a udp_stack_t from all per CPU stats.  The
6175dd46ab5SKacheong Poon  * caller should initialize the target mib2_udp_t properly as this function
6185dd46ab5SKacheong Poon  * just adds up all the per CPU stats.
6195dd46ab5SKacheong Poon  */
6205dd46ab5SKacheong Poon static void
udp_sum_mib(udp_stack_t * us,mib2_udp_t * udp_mib)6215dd46ab5SKacheong Poon udp_sum_mib(udp_stack_t *us, mib2_udp_t *udp_mib)
6225dd46ab5SKacheong Poon {
6235dd46ab5SKacheong Poon 	int i;
6245dd46ab5SKacheong Poon 	int cnt;
6255dd46ab5SKacheong Poon 
6265dd46ab5SKacheong Poon 	cnt = us->us_sc_cnt;
6275dd46ab5SKacheong Poon 	for (i = 0; i < cnt; i++)
6285dd46ab5SKacheong Poon 		udp_add_mib(&us->us_sc[i]->udp_sc_mib, udp_mib);
6295dd46ab5SKacheong Poon }
6305dd46ab5SKacheong Poon 
6315dd46ab5SKacheong Poon static int
udp_kstat_update(kstat_t * kp,int rw)6325dd46ab5SKacheong Poon udp_kstat_update(kstat_t *kp, int rw)
6335dd46ab5SKacheong Poon {
6345dd46ab5SKacheong Poon 	udp_named_kstat_t *udpkp;
6355dd46ab5SKacheong Poon 	netstackid_t	stackid = (netstackid_t)(uintptr_t)kp->ks_private;
6365dd46ab5SKacheong Poon 	netstack_t	*ns;
6375dd46ab5SKacheong Poon 	udp_stack_t	*us;
6385dd46ab5SKacheong Poon 	mib2_udp_t	udp_mib;
6395dd46ab5SKacheong Poon 
6405dd46ab5SKacheong Poon 	if (rw == KSTAT_WRITE)
6415dd46ab5SKacheong Poon 		return (EACCES);
6425dd46ab5SKacheong Poon 
6435dd46ab5SKacheong Poon 	ns = netstack_find_by_stackid(stackid);
6445dd46ab5SKacheong Poon 	if (ns == NULL)
6455dd46ab5SKacheong Poon 		return (-1);
6465dd46ab5SKacheong Poon 	us = ns->netstack_udp;
6475dd46ab5SKacheong Poon 	if (us == NULL) {
6485dd46ab5SKacheong Poon 		netstack_rele(ns);
6495dd46ab5SKacheong Poon 		return (-1);
6505dd46ab5SKacheong Poon 	}
6515dd46ab5SKacheong Poon 	udpkp = (udp_named_kstat_t *)kp->ks_data;
6525dd46ab5SKacheong Poon 
6535dd46ab5SKacheong Poon 	bzero(&udp_mib, sizeof (udp_mib));
6545dd46ab5SKacheong Poon 	udp_sum_mib(us, &udp_mib);
6555dd46ab5SKacheong Poon 
6565dd46ab5SKacheong Poon 	udpkp->inDatagrams.value.ui64 =	udp_mib.udpHCInDatagrams;
6575dd46ab5SKacheong Poon 	udpkp->inErrors.value.ui32 =	udp_mib.udpInErrors;
6585dd46ab5SKacheong Poon 	udpkp->outDatagrams.value.ui64 = udp_mib.udpHCOutDatagrams;
6595dd46ab5SKacheong Poon 	udpkp->outErrors.value.ui32 =	udp_mib.udpOutErrors;
6605dd46ab5SKacheong Poon 	netstack_rele(ns);
6615dd46ab5SKacheong Poon 	return (0);
6625dd46ab5SKacheong Poon }
663