xref: /illumos-gate/usr/src/uts/common/inet/sctp/sctp_snmp.c (revision 4e93fb0f6383eaac21897dcdae56b87118131e4d)
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 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/stream.h>
31 #include <sys/cmn_err.h>
32 #define	_SUN_TPI_VERSION 2
33 #include <sys/tihdr.h>
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/tsol/tndb.h>
37 
38 #include <netinet/in.h>
39 
40 #include <inet/common.h>
41 #include <inet/ip.h>
42 #include <inet/mib2.h>
43 #include <inet/snmpcom.h>
44 #include <inet/kstatcom.h>
45 #include <inet/ipclassifier.h>
46 #include "sctp_impl.h"
47 #include "sctp_addr.h"
48 
49 static int sctp_snmp_state(sctp_t *sctp);
50 
51 
52 static int
53 sctp_kstat_update(kstat_t *kp, int rw)
54 {
55 	sctp_named_kstat_t	*sctpkp;
56 	sctp_t			*sctp, *sctp_prev;
57 	zoneid_t	myzoneid;
58 	netstackid_t	stackid = (netstackid_t)(uintptr_t)kp->ks_private;
59 	netstack_t	*ns;
60 	sctp_stack_t	*sctps;
61 
62 	if (kp == NULL|| kp->ks_data == NULL)
63 		return (EIO);
64 
65 	if (rw == KSTAT_WRITE)
66 		return (EACCES);
67 
68 	ns = netstack_find_by_stackid(stackid);
69 	if (ns == NULL)
70 		return (-1);
71 	sctps = ns->netstack_sctp;
72 	if (sctps == NULL) {
73 		netstack_rele(ns);
74 		return (-1);
75 	}
76 	myzoneid = netstackid_to_zoneid(stackid);
77 
78 	/*
79 	 * Get the number of current associations and gather their
80 	 * individual set of statistics.
81 	 */
82 	SET_MIB(sctps->sctps_mib.sctpCurrEstab, 0);
83 	sctp = sctps->sctps_gsctp;
84 	sctp_prev = NULL;
85 	mutex_enter(&sctps->sctps_g_lock);
86 	while (sctp != NULL) {
87 		mutex_enter(&sctp->sctp_reflock);
88 		if (sctp->sctp_condemned) {
89 			mutex_exit(&sctp->sctp_reflock);
90 			sctp = list_next(&sctps->sctps_g_list, sctp);
91 			continue;
92 		}
93 		sctp->sctp_refcnt++;
94 		mutex_exit(&sctp->sctp_reflock);
95 		mutex_exit(&sctps->sctps_g_lock);
96 		if (sctp_prev != NULL)
97 			SCTP_REFRELE(sctp_prev);
98 		if (sctp->sctp_connp->conn_zoneid != myzoneid)
99 			goto next_sctp;
100 		if (sctp->sctp_state == SCTPS_ESTABLISHED ||
101 		    sctp->sctp_state == SCTPS_SHUTDOWN_PENDING ||
102 		    sctp->sctp_state == SCTPS_SHUTDOWN_RECEIVED) {
103 			BUMP_MIB(&sctps->sctps_mib, sctpCurrEstab);
104 		}
105 
106 		if (sctp->sctp_opkts) {
107 			UPDATE_MIB(&sctps->sctps_mib, sctpOutSCTPPkts,
108 			    sctp->sctp_opkts);
109 			sctp->sctp_opkts = 0;
110 		}
111 
112 		if (sctp->sctp_obchunks) {
113 			UPDATE_MIB(&sctps->sctps_mib, sctpOutCtrlChunks,
114 			    sctp->sctp_obchunks);
115 			sctp->sctp_obchunks = 0;
116 		}
117 
118 		if (sctp->sctp_odchunks) {
119 			UPDATE_MIB(&sctps->sctps_mib, sctpOutOrderChunks,
120 			    sctp->sctp_odchunks);
121 			sctp->sctp_odchunks = 0;
122 		}
123 
124 		if (sctp->sctp_oudchunks) {
125 			UPDATE_MIB(&sctps->sctps_mib, sctpOutUnorderChunks,
126 			    sctp->sctp_oudchunks);
127 			sctp->sctp_oudchunks = 0;
128 		}
129 
130 		if (sctp->sctp_rxtchunks) {
131 			UPDATE_MIB(&sctps->sctps_mib, sctpRetransChunks,
132 			    sctp->sctp_rxtchunks);
133 			sctp->sctp_rxtchunks = 0;
134 		}
135 
136 		if (sctp->sctp_ipkts) {
137 			UPDATE_MIB(&sctps->sctps_mib, sctpInSCTPPkts,
138 			    sctp->sctp_ipkts);
139 			sctp->sctp_ipkts = 0;
140 		}
141 
142 		if (sctp->sctp_ibchunks) {
143 			UPDATE_MIB(&sctps->sctps_mib, sctpInCtrlChunks,
144 			    sctp->sctp_ibchunks);
145 			sctp->sctp_ibchunks = 0;
146 		}
147 
148 		if (sctp->sctp_idchunks) {
149 			UPDATE_MIB(&sctps->sctps_mib, sctpInOrderChunks,
150 			    sctp->sctp_idchunks);
151 			sctp->sctp_idchunks = 0;
152 		}
153 
154 		if (sctp->sctp_iudchunks) {
155 			UPDATE_MIB(&sctps->sctps_mib, sctpInUnorderChunks,
156 			    sctp->sctp_iudchunks);
157 			sctp->sctp_iudchunks = 0;
158 		}
159 
160 		if (sctp->sctp_fragdmsgs) {
161 			UPDATE_MIB(&sctps->sctps_mib, sctpFragUsrMsgs,
162 			    sctp->sctp_fragdmsgs);
163 			sctp->sctp_fragdmsgs = 0;
164 		}
165 
166 		if (sctp->sctp_reassmsgs) {
167 			UPDATE_MIB(&sctps->sctps_mib, sctpReasmUsrMsgs,
168 			    sctp->sctp_reassmsgs);
169 			sctp->sctp_reassmsgs = 0;
170 		}
171 
172 next_sctp:
173 		sctp_prev = sctp;
174 		mutex_enter(&sctps->sctps_g_lock);
175 		sctp = list_next(&sctps->sctps_g_list, sctp);
176 	}
177 	mutex_exit(&sctps->sctps_g_lock);
178 	if (sctp_prev != NULL)
179 		SCTP_REFRELE(sctp_prev);
180 
181 	/* Copy data from the SCTP MIB */
182 	sctpkp = (sctp_named_kstat_t *)kp->ks_data;
183 
184 	/* These are from global ndd params. */
185 	sctpkp->sctpRtoMin.value.ui32 = sctps->sctps_rto_ming;
186 	sctpkp->sctpRtoMax.value.ui32 = sctps->sctps_rto_maxg;
187 	sctpkp->sctpRtoInitial.value.ui32 = sctps->sctps_rto_initialg;
188 	sctpkp->sctpValCookieLife.value.ui32 = sctps->sctps_cookie_life;
189 	sctpkp->sctpMaxInitRetr.value.ui32 = sctps->sctps_max_init_retr;
190 
191 	sctpkp->sctpCurrEstab.value.i32 = sctps->sctps_mib.sctpCurrEstab;
192 	sctpkp->sctpActiveEstab.value.i32 = sctps->sctps_mib.sctpActiveEstab;
193 	sctpkp->sctpPassiveEstab.value.i32 = sctps->sctps_mib.sctpPassiveEstab;
194 	sctpkp->sctpAborted.value.i32 = sctps->sctps_mib.sctpAborted;
195 	sctpkp->sctpShutdowns.value.i32 = sctps->sctps_mib.sctpShutdowns;
196 	sctpkp->sctpOutOfBlue.value.i32 = sctps->sctps_mib.sctpOutOfBlue;
197 	sctpkp->sctpChecksumError.value.i32 =
198 	    sctps->sctps_mib.sctpChecksumError;
199 	sctpkp->sctpOutCtrlChunks.value.i64 =
200 	    sctps->sctps_mib.sctpOutCtrlChunks;
201 	sctpkp->sctpOutOrderChunks.value.i64 =
202 	    sctps->sctps_mib.sctpOutOrderChunks;
203 	sctpkp->sctpOutUnorderChunks.value.i64 =
204 	    sctps->sctps_mib.sctpOutUnorderChunks;
205 	sctpkp->sctpRetransChunks.value.i64 =
206 	    sctps->sctps_mib.sctpRetransChunks;
207 	sctpkp->sctpOutAck.value.i32 = sctps->sctps_mib.sctpOutAck;
208 	sctpkp->sctpOutAckDelayed.value.i32 =
209 	    sctps->sctps_mib.sctpOutAckDelayed;
210 	sctpkp->sctpOutWinUpdate.value.i32 = sctps->sctps_mib.sctpOutWinUpdate;
211 	sctpkp->sctpOutFastRetrans.value.i32 =
212 	    sctps->sctps_mib.sctpOutFastRetrans;
213 	sctpkp->sctpOutWinProbe.value.i32 = sctps->sctps_mib.sctpOutWinProbe;
214 	sctpkp->sctpInCtrlChunks.value.i64 = sctps->sctps_mib.sctpInCtrlChunks;
215 	sctpkp->sctpInOrderChunks.value.i64 =
216 	    sctps->sctps_mib.sctpInOrderChunks;
217 	sctpkp->sctpInUnorderChunks.value.i64 =
218 	    sctps->sctps_mib.sctpInUnorderChunks;
219 	sctpkp->sctpInAck.value.i32 = sctps->sctps_mib.sctpInAck;
220 	sctpkp->sctpInDupAck.value.i32 = sctps->sctps_mib.sctpInDupAck;
221 	sctpkp->sctpInAckUnsent.value.i32 = sctps->sctps_mib.sctpInAckUnsent;
222 	sctpkp->sctpFragUsrMsgs.value.i64 = sctps->sctps_mib.sctpFragUsrMsgs;
223 	sctpkp->sctpReasmUsrMsgs.value.i64 = sctps->sctps_mib.sctpReasmUsrMsgs;
224 	sctpkp->sctpOutSCTPPkts.value.i64 = sctps->sctps_mib.sctpOutSCTPPkts;
225 	sctpkp->sctpInSCTPPkts.value.i64 = sctps->sctps_mib.sctpInSCTPPkts;
226 	sctpkp->sctpInInvalidCookie.value.i32 =
227 	    sctps->sctps_mib.sctpInInvalidCookie;
228 	sctpkp->sctpTimRetrans.value.i32 = sctps->sctps_mib.sctpTimRetrans;
229 	sctpkp->sctpTimRetransDrop.value.i32 =
230 	    sctps->sctps_mib.sctpTimRetransDrop;
231 	sctpkp->sctpTimHeartBeatProbe.value.i32 =
232 	    sctps->sctps_mib.sctpTimHeartBeatProbe;
233 	sctpkp->sctpTimHeartBeatDrop.value.i32 =
234 	    sctps->sctps_mib.sctpTimHeartBeatDrop;
235 	sctpkp->sctpListenDrop.value.i32 = sctps->sctps_mib.sctpListenDrop;
236 	sctpkp->sctpInClosed.value.i32 = sctps->sctps_mib.sctpInClosed;
237 
238 	netstack_rele(ns);
239 	return (0);
240 }
241 
242 void *
243 sctp_kstat_init(netstackid_t stackid)
244 {
245 	kstat_t	*ksp;
246 
247 	sctp_named_kstat_t template = {
248 		{ "sctpRtoAlgorithm",		KSTAT_DATA_INT32, 0 },
249 		{ "sctpRtoMin",			KSTAT_DATA_UINT32, 0 },
250 		{ "sctpRtoMax",			KSTAT_DATA_UINT32, 0 },
251 		{ "sctpRtoInitial",		KSTAT_DATA_UINT32, 0 },
252 		{ "sctpMaxAssocs",		KSTAT_DATA_INT32, 0 },
253 		{ "sctpValCookieLife",		KSTAT_DATA_UINT32, 0 },
254 		{ "sctpMaxInitRetr",		KSTAT_DATA_UINT32, 0 },
255 		{ "sctpCurrEstab",		KSTAT_DATA_INT32, 0 },
256 		{ "sctpActiveEstab",		KSTAT_DATA_INT32, 0 },
257 		{ "sctpPassiveEstab",		KSTAT_DATA_INT32, 0 },
258 		{ "sctpAborted",		KSTAT_DATA_INT32, 0 },
259 		{ "sctpShutdowns",		KSTAT_DATA_INT32, 0 },
260 		{ "sctpOutOfBlue",		KSTAT_DATA_INT32, 0 },
261 		{ "sctpChecksumError",		KSTAT_DATA_INT32, 0 },
262 		{ "sctpOutCtrlChunks",		KSTAT_DATA_INT64, 0 },
263 		{ "sctpOutOrderChunks",		KSTAT_DATA_INT64, 0 },
264 		{ "sctpOutUnorderChunks",	KSTAT_DATA_INT64, 0 },
265 		{ "sctpRetransChunks",		KSTAT_DATA_INT64, 0 },
266 		{ "sctpOutAck",			KSTAT_DATA_INT32, 0 },
267 		{ "sctpOutAckDelayed",		KSTAT_DATA_INT32, 0 },
268 		{ "sctpOutWinUpdate",		KSTAT_DATA_INT32, 0 },
269 		{ "sctpOutFastRetrans",		KSTAT_DATA_INT32, 0 },
270 		{ "sctpOutWinProbe",		KSTAT_DATA_INT32, 0 },
271 		{ "sctpInCtrlChunks",		KSTAT_DATA_INT64, 0 },
272 		{ "sctpInOrderChunks",		KSTAT_DATA_INT64, 0 },
273 		{ "sctpInUnorderChunks",	KSTAT_DATA_INT64, 0 },
274 		{ "sctpInAck",			KSTAT_DATA_INT32, 0 },
275 		{ "sctpInDupAck",		KSTAT_DATA_INT32, 0 },
276 		{ "sctpInAckUnsent",		KSTAT_DATA_INT32, 0 },
277 		{ "sctpFragUsrMsgs",		KSTAT_DATA_INT64, 0 },
278 		{ "sctpReasmUsrMsgs",		KSTAT_DATA_INT64, 0 },
279 		{ "sctpOutSCTPPkts",		KSTAT_DATA_INT64, 0 },
280 		{ "sctpInSCTPPkts",		KSTAT_DATA_INT64, 0 },
281 		{ "sctpInInvalidCookie",	KSTAT_DATA_INT32, 0 },
282 		{ "sctpTimRetrans",		KSTAT_DATA_INT32, 0 },
283 		{ "sctpTimRetransDrop",		KSTAT_DATA_INT32, 0 },
284 		{ "sctpTimHearBeatProbe",	KSTAT_DATA_INT32, 0 },
285 		{ "sctpTimHearBeatDrop",	KSTAT_DATA_INT32, 0 },
286 		{ "sctpListenDrop",		KSTAT_DATA_INT32, 0 },
287 		{ "sctpInClosed",		KSTAT_DATA_INT32, 0 }
288 	};
289 
290 	ksp = kstat_create_netstack(SCTP_MOD_NAME, 0, "sctp", "mib2",
291 	    KSTAT_TYPE_NAMED, NUM_OF_FIELDS(sctp_named_kstat_t), 0, stackid);
292 
293 	if (ksp == NULL || ksp->ks_data == NULL)
294 		return (NULL);
295 
296 	/* These won't change. */
297 	template.sctpRtoAlgorithm.value.i32 = MIB2_SCTP_RTOALGO_VANJ;
298 	template.sctpMaxAssocs.value.i32 = -1;
299 
300 	bcopy(&template, ksp->ks_data, sizeof (template));
301 	ksp->ks_update = sctp_kstat_update;
302 	ksp->ks_private = (void *)(uintptr_t)stackid;
303 
304 	kstat_install(ksp);
305 	return (ksp);
306 }
307 
308 /*
309  * The following kstats are for debugging purposes.  They keep
310  * track of problems which should not happen normally.  But in
311  * those cases which they do happen, these kstats would be handy
312  * for engineers to diagnose the problems.  They are not intended
313  * to be consumed by customers.
314  */
315 void *
316 sctp_kstat2_init(netstackid_t stackid, sctp_kstat_t *sctps_statisticsp)
317 {
318 	kstat_t *ksp;
319 
320 	sctp_kstat_t template = {
321 		{ "sctp_add_faddr",			KSTAT_DATA_UINT64 },
322 		{ "sctp_add_timer",			KSTAT_DATA_UINT64 },
323 		{ "sctp_conn_create",			KSTAT_DATA_UINT64 },
324 		{ "sctp_find_next_tq",			KSTAT_DATA_UINT64 },
325 		{ "sctp_fr_add_hdr",			KSTAT_DATA_UINT64 },
326 		{ "sctp_fr_not_found",			KSTAT_DATA_UINT64 },
327 		{ "sctp_output_failed",			KSTAT_DATA_UINT64 },
328 		{ "sctp_rexmit_failed",			KSTAT_DATA_UINT64 },
329 		{ "sctp_send_init_failed",		KSTAT_DATA_UINT64 },
330 		{ "sctp_send_cookie_failed",		KSTAT_DATA_UINT64 },
331 		{ "sctp_send_cookie_ack_failed",	KSTAT_DATA_UINT64 },
332 		{ "sctp_send_err_failed",		KSTAT_DATA_UINT64 },
333 		{ "sctp_send_sack_failed",		KSTAT_DATA_UINT64 },
334 		{ "sctp_send_shutdown_failed",		KSTAT_DATA_UINT64 },
335 		{ "sctp_send_shutdown_ack_failed",	KSTAT_DATA_UINT64 },
336 		{ "sctp_send_shutdown_comp_failed",	KSTAT_DATA_UINT64 },
337 		{ "sctp_send_user_abort_failed",	KSTAT_DATA_UINT64 },
338 		{ "sctp_send_asconf_failed",		KSTAT_DATA_UINT64 },
339 		{ "sctp_send_asconf_ack_failed",	KSTAT_DATA_UINT64 },
340 		{ "sctp_send_ftsn_failed",		KSTAT_DATA_UINT64 },
341 		{ "sctp_send_hb_failed",		KSTAT_DATA_UINT64 },
342 		{ "sctp_return_hb_failed",		KSTAT_DATA_UINT64 },
343 		{ "sctp_ss_rexmit_failed",		KSTAT_DATA_UINT64 },
344 		{ "sctp_cl_connect",			KSTAT_DATA_UINT64 },
345 		{ "sctp_cl_assoc_change",		KSTAT_DATA_UINT64 },
346 		{ "sctp_cl_check_addrs",		KSTAT_DATA_UINT64 },
347 	};
348 
349 	ksp = kstat_create_netstack(SCTP_MOD_NAME, 0, "sctpstat", "net",
350 	    KSTAT_TYPE_NAMED, NUM_OF_FIELDS(template), KSTAT_FLAG_VIRTUAL,
351 	    stackid);
352 
353 	if (ksp == NULL)
354 		return (NULL);
355 
356 	bcopy(&template, sctps_statisticsp, sizeof (template));
357 	ksp->ks_data = (void *)sctps_statisticsp;
358 	ksp->ks_private = (void *)(uintptr_t)stackid;
359 
360 	kstat_install(ksp);
361 	return (ksp);
362 }
363 
364 void
365 sctp_kstat_fini(netstackid_t stackid, kstat_t *ksp)
366 {
367 	if (ksp != NULL) {
368 		ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
369 		kstat_delete_netstack(ksp, stackid);
370 	}
371 }
372 
373 void
374 sctp_kstat2_fini(netstackid_t stackid, kstat_t *ksp)
375 {
376 	if (ksp != NULL) {
377 		ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
378 		kstat_delete_netstack(ksp, stackid);
379 	}
380 }
381 
382 /*
383  * Return SNMP global stats in buffer in mpdata.
384  * Return associatiation table in mp_conn_data,
385  * local address table in mp_local_data, and
386  * remote address table in mp_rem_data.
387  */
388 mblk_t *
389 sctp_snmp_get_mib2(queue_t *q, mblk_t *mpctl, sctp_stack_t *sctps)
390 {
391 	mblk_t			*mpdata, *mp_ret;
392 	mblk_t			*mp_conn_ctl = NULL;
393 	mblk_t			*mp_conn_data;
394 	mblk_t			*mp_conn_tail = NULL;
395 	mblk_t			*mp_local_ctl = NULL;
396 	mblk_t			*mp_local_data;
397 	mblk_t			*mp_local_tail = NULL;
398 	mblk_t			*mp_rem_ctl = NULL;
399 	mblk_t			*mp_rem_data;
400 	mblk_t			*mp_rem_tail = NULL;
401 	mblk_t			*mp_attr_ctl = NULL;
402 	mblk_t			*mp_attr_data;
403 	mblk_t			*mp_attr_tail = NULL;
404 	struct opthdr		*optp;
405 	sctp_t			*sctp, *sctp_prev = NULL;
406 	sctp_faddr_t		*fp;
407 	mib2_sctpConnEntry_t	sce;
408 	mib2_sctpConnLocalEntry_t	scle;
409 	mib2_sctpConnRemoteEntry_t	scre;
410 	mib2_transportMLPEntry_t	mlp;
411 	int			i;
412 	int			l;
413 	int			scanned = 0;
414 	zoneid_t		zoneid = Q_TO_CONN(q)->conn_zoneid;
415 	conn_t			*connp;
416 	boolean_t		needattr;
417 	int			idx;
418 
419 	/*
420 	 * Make copies of the original message.
421 	 * mpctl will hold SCTP counters,
422 	 * mp_conn_ctl will hold list of connections.
423 	 */
424 	mp_ret = copymsg(mpctl);
425 	mp_conn_ctl = copymsg(mpctl);
426 	mp_local_ctl = copymsg(mpctl);
427 	mp_rem_ctl = copymsg(mpctl);
428 	mp_attr_ctl = copymsg(mpctl);
429 
430 	mpdata = mpctl->b_cont;
431 
432 	if (mp_conn_ctl == NULL || mp_local_ctl == NULL ||
433 	    mp_rem_ctl == NULL || mp_attr_ctl == NULL || mpdata == NULL) {
434 		freemsg(mp_attr_ctl);
435 		freemsg(mp_rem_ctl);
436 		freemsg(mp_local_ctl);
437 		freemsg(mp_conn_ctl);
438 		freemsg(mp_ret);
439 		freemsg(mpctl);
440 		return (NULL);
441 	}
442 	mp_conn_data = mp_conn_ctl->b_cont;
443 	mp_local_data = mp_local_ctl->b_cont;
444 	mp_rem_data = mp_rem_ctl->b_cont;
445 	mp_attr_data = mp_attr_ctl->b_cont;
446 
447 	/* hostname address parameters are not supported in Solaris */
448 	sce.sctpAssocRemHostName.o_length = 0;
449 	sce.sctpAssocRemHostName.o_bytes[0] = 0;
450 
451 	/* build table of connections -- need count in fixed part */
452 	SET_MIB(sctps->sctps_mib.sctpRtoAlgorithm, MIB2_SCTP_RTOALGO_VANJ);
453 	SET_MIB(sctps->sctps_mib.sctpRtoMin, sctps->sctps_rto_ming);
454 	SET_MIB(sctps->sctps_mib.sctpRtoMax, sctps->sctps_rto_maxg);
455 	SET_MIB(sctps->sctps_mib.sctpRtoInitial, sctps->sctps_rto_initialg);
456 	SET_MIB(sctps->sctps_mib.sctpMaxAssocs, -1);
457 	SET_MIB(sctps->sctps_mib.sctpValCookieLife, sctps->sctps_cookie_life);
458 	SET_MIB(sctps->sctps_mib.sctpMaxInitRetr, sctps->sctps_max_init_retr);
459 	SET_MIB(sctps->sctps_mib.sctpCurrEstab, 0);
460 
461 	idx = 0;
462 	sctp = sctps->sctps_gsctp;
463 	mutex_enter(&sctps->sctps_g_lock);
464 	while (sctp != NULL) {
465 		mutex_enter(&sctp->sctp_reflock);
466 		if (sctp->sctp_condemned) {
467 			mutex_exit(&sctp->sctp_reflock);
468 			sctp = list_next(&sctps->sctps_g_list, sctp);
469 			continue;
470 		}
471 		sctp->sctp_refcnt++;
472 		mutex_exit(&sctp->sctp_reflock);
473 		mutex_exit(&sctps->sctps_g_lock);
474 		if (sctp_prev != NULL)
475 			SCTP_REFRELE(sctp_prev);
476 		if (sctp->sctp_connp->conn_zoneid != zoneid)
477 			goto next_sctp;
478 		if (sctp->sctp_state == SCTPS_ESTABLISHED ||
479 		    sctp->sctp_state == SCTPS_SHUTDOWN_PENDING ||
480 		    sctp->sctp_state == SCTPS_SHUTDOWN_RECEIVED) {
481 			BUMP_MIB(&sctps->sctps_mib, sctpCurrEstab);
482 		}
483 		UPDATE_MIB(&sctps->sctps_mib,
484 		    sctpOutSCTPPkts, sctp->sctp_opkts);
485 		sctp->sctp_opkts = 0;
486 		UPDATE_MIB(&sctps->sctps_mib,
487 		    sctpOutCtrlChunks, sctp->sctp_obchunks);
488 		sctp->sctp_obchunks = 0;
489 		UPDATE_MIB(&sctps->sctps_mib,
490 		    sctpOutOrderChunks, sctp->sctp_odchunks);
491 		sctp->sctp_odchunks = 0;
492 		UPDATE_MIB(&sctps->sctps_mib, sctpOutUnorderChunks,
493 		    sctp->sctp_oudchunks);
494 		sctp->sctp_oudchunks = 0;
495 		UPDATE_MIB(&sctps->sctps_mib,
496 		    sctpRetransChunks, sctp->sctp_rxtchunks);
497 		sctp->sctp_rxtchunks = 0;
498 		UPDATE_MIB(&sctps->sctps_mib,
499 		    sctpInSCTPPkts, sctp->sctp_ipkts);
500 		sctp->sctp_ipkts = 0;
501 		UPDATE_MIB(&sctps->sctps_mib,
502 		    sctpInCtrlChunks, sctp->sctp_ibchunks);
503 		sctp->sctp_ibchunks = 0;
504 		UPDATE_MIB(&sctps->sctps_mib,
505 		    sctpInOrderChunks, sctp->sctp_idchunks);
506 		sctp->sctp_idchunks = 0;
507 		UPDATE_MIB(&sctps->sctps_mib, sctpInUnorderChunks,
508 		    sctp->sctp_iudchunks);
509 		sctp->sctp_iudchunks = 0;
510 		UPDATE_MIB(&sctps->sctps_mib,
511 		    sctpFragUsrMsgs, sctp->sctp_fragdmsgs);
512 		sctp->sctp_fragdmsgs = 0;
513 		UPDATE_MIB(&sctps->sctps_mib,
514 		    sctpReasmUsrMsgs, sctp->sctp_reassmsgs);
515 		sctp->sctp_reassmsgs = 0;
516 
517 		sce.sctpAssocId = ntohl(sctp->sctp_lvtag);
518 		sce.sctpAssocLocalPort = ntohs(sctp->sctp_lport);
519 		sce.sctpAssocRemPort = ntohs(sctp->sctp_fport);
520 
521 		RUN_SCTP(sctp);
522 		if (sctp->sctp_primary != NULL) {
523 			fp = sctp->sctp_primary;
524 
525 			if (IN6_IS_ADDR_V4MAPPED(&fp->faddr)) {
526 				sce.sctpAssocRemPrimAddrType =
527 				    MIB2_SCTP_ADDR_V4;
528 			} else {
529 				sce.sctpAssocRemPrimAddrType =
530 				    MIB2_SCTP_ADDR_V6;
531 			}
532 			sce.sctpAssocRemPrimAddr = fp->faddr;
533 			sce.sctpAssocLocPrimAddr = fp->saddr;
534 			sce.sctpAssocHeartBeatInterval = TICK_TO_MSEC(
535 			    fp->hb_interval);
536 		} else {
537 			sce.sctpAssocRemPrimAddrType = MIB2_SCTP_ADDR_V4;
538 			bzero(&sce.sctpAssocRemPrimAddr,
539 			    sizeof (sce.sctpAssocRemPrimAddr));
540 			bzero(&sce.sctpAssocLocPrimAddr,
541 			    sizeof (sce.sctpAssocLocPrimAddr));
542 			sce.sctpAssocHeartBeatInterval =
543 			    sctps->sctps_heartbeat_interval;
544 		}
545 
546 		/*
547 		 * Table for local addresses
548 		 */
549 		scanned = 0;
550 		for (i = 0; i < SCTP_IPIF_HASH; i++) {
551 			sctp_saddr_ipif_t	*obj;
552 
553 			if (sctp->sctp_saddrs[i].ipif_count == 0)
554 				continue;
555 			obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
556 			for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
557 				sctp_ipif_t	*sctp_ipif;
558 				in6_addr_t	addr;
559 
560 				sctp_ipif = obj->saddr_ipifp;
561 				addr = sctp_ipif->sctp_ipif_saddr;
562 				scanned++;
563 				scle.sctpAssocId = ntohl(sctp->sctp_lvtag);
564 				if (IN6_IS_ADDR_V4MAPPED(&addr)) {
565 					scle.sctpAssocLocalAddrType =
566 					    MIB2_SCTP_ADDR_V4;
567 				} else {
568 					scle.sctpAssocLocalAddrType =
569 					    MIB2_SCTP_ADDR_V6;
570 				}
571 				scle.sctpAssocLocalAddr = addr;
572 				(void) snmp_append_data2(mp_local_data,
573 				    &mp_local_tail, (char *)&scle,
574 				    sizeof (scle));
575 				if (scanned >= sctp->sctp_nsaddrs)
576 					goto done;
577 				obj = list_next(&sctp->
578 				    sctp_saddrs[i].sctp_ipif_list, obj);
579 			}
580 		}
581 done:
582 		/*
583 		 * Table for remote addresses
584 		 */
585 		for (fp = sctp->sctp_faddrs; fp; fp = fp->next) {
586 			scre.sctpAssocId = ntohl(sctp->sctp_lvtag);
587 			if (IN6_IS_ADDR_V4MAPPED(&fp->faddr)) {
588 				scre.sctpAssocRemAddrType = MIB2_SCTP_ADDR_V4;
589 			} else {
590 				scre.sctpAssocRemAddrType = MIB2_SCTP_ADDR_V6;
591 			}
592 			scre.sctpAssocRemAddr = fp->faddr;
593 			if (fp->state == SCTP_FADDRS_ALIVE) {
594 				scre.sctpAssocRemAddrActive =
595 				    scre.sctpAssocRemAddrHBActive =
596 				    MIB2_SCTP_ACTIVE;
597 			} else {
598 				scre.sctpAssocRemAddrActive =
599 				    scre.sctpAssocRemAddrHBActive =
600 				    MIB2_SCTP_INACTIVE;
601 			}
602 			scre.sctpAssocRemAddrRTO = TICK_TO_MSEC(fp->rto);
603 			scre.sctpAssocRemAddrMaxPathRtx = fp->max_retr;
604 			scre.sctpAssocRemAddrRtx = fp->T3expire;
605 			(void) snmp_append_data2(mp_rem_data, &mp_rem_tail,
606 			    (char *)&scre, sizeof (scre));
607 		}
608 		connp = sctp->sctp_connp;
609 		needattr = B_FALSE;
610 		bzero(&mlp, sizeof (mlp));
611 		if (connp->conn_mlp_type != mlptSingle) {
612 			if (connp->conn_mlp_type == mlptShared ||
613 			    connp->conn_mlp_type == mlptBoth)
614 				mlp.tme_flags |= MIB2_TMEF_SHARED;
615 			if (connp->conn_mlp_type == mlptPrivate ||
616 			    connp->conn_mlp_type == mlptBoth)
617 				mlp.tme_flags |= MIB2_TMEF_PRIVATE;
618 			needattr = B_TRUE;
619 		}
620 		if (connp->conn_peercred != NULL) {
621 			ts_label_t *tsl;
622 
623 			tsl = crgetlabel(connp->conn_peercred);
624 			mlp.tme_doi = label2doi(tsl);
625 			mlp.tme_label = *label2bslabel(tsl);
626 			needattr = B_TRUE;
627 		}
628 		WAKE_SCTP(sctp);
629 		sce.sctpAssocState = sctp_snmp_state(sctp);
630 		sce.sctpAssocInStreams = sctp->sctp_num_istr;
631 		sce.sctpAssocOutStreams = sctp->sctp_num_ostr;
632 		sce.sctpAssocMaxRetr = sctp->sctp_pa_max_rxt;
633 		/* A 0 here indicates that no primary process is known */
634 		sce.sctpAssocPrimProcess = 0;
635 		sce.sctpAssocT1expired = sctp->sctp_T1expire;
636 		sce.sctpAssocT2expired = sctp->sctp_T2expire;
637 		sce.sctpAssocRtxChunks = sctp->sctp_T3expire;
638 		sce.sctpAssocStartTime = sctp->sctp_assoc_start_time;
639 		sce.sctpConnEntryInfo.ce_sendq = sctp->sctp_unacked +
640 		    sctp->sctp_unsent;
641 		sce.sctpConnEntryInfo.ce_recvq = sctp->sctp_rxqueued;
642 		sce.sctpConnEntryInfo.ce_swnd = sctp->sctp_frwnd;
643 		sce.sctpConnEntryInfo.ce_rwnd = sctp->sctp_rwnd;
644 		sce.sctpConnEntryInfo.ce_mss = sctp->sctp_mss;
645 		(void) snmp_append_data2(mp_conn_data, &mp_conn_tail,
646 		    (char *)&sce, sizeof (sce));
647 		mlp.tme_connidx = idx++;
648 		if (needattr)
649 			(void) snmp_append_data2(mp_attr_ctl->b_cont,
650 			    &mp_attr_tail, (char *)&mlp, sizeof (mlp));
651 next_sctp:
652 		sctp_prev = sctp;
653 		mutex_enter(&sctps->sctps_g_lock);
654 		sctp = list_next(&sctps->sctps_g_list, sctp);
655 	}
656 	mutex_exit(&sctps->sctps_g_lock);
657 	if (sctp_prev != NULL)
658 		SCTP_REFRELE(sctp_prev);
659 
660 	/* fixed length structure for IPv4 and IPv6 counters */
661 	SET_MIB(sctps->sctps_mib.sctpEntrySize, sizeof (sce));
662 	SET_MIB(sctps->sctps_mib.sctpLocalEntrySize, sizeof (scle));
663 	SET_MIB(sctps->sctps_mib.sctpRemoteEntrySize, sizeof (scre));
664 	optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)];
665 	optp->level = MIB2_SCTP;
666 	optp->name = 0;
667 	(void) snmp_append_data(mpdata, (char *)&sctps->sctps_mib,
668 	    sizeof (sctps->sctps_mib));
669 	optp->len = msgdsize(mpdata);
670 	qreply(q, mpctl);
671 
672 	/* table of connections... */
673 	optp = (struct opthdr *)&mp_conn_ctl->b_rptr[
674 	    sizeof (struct T_optmgmt_ack)];
675 	optp->level = MIB2_SCTP;
676 	optp->name = MIB2_SCTP_CONN;
677 	optp->len = msgdsize(mp_conn_data);
678 	qreply(q, mp_conn_ctl);
679 
680 	/* assoc local address table */
681 	optp = (struct opthdr *)&mp_local_ctl->b_rptr[
682 	    sizeof (struct T_optmgmt_ack)];
683 	optp->level = MIB2_SCTP;
684 	optp->name = MIB2_SCTP_CONN_LOCAL;
685 	optp->len = msgdsize(mp_local_data);
686 	qreply(q, mp_local_ctl);
687 
688 	/* assoc remote address table */
689 	optp = (struct opthdr *)&mp_rem_ctl->b_rptr[
690 	    sizeof (struct T_optmgmt_ack)];
691 	optp->level = MIB2_SCTP;
692 	optp->name = MIB2_SCTP_CONN_REMOTE;
693 	optp->len = msgdsize(mp_rem_data);
694 	qreply(q, mp_rem_ctl);
695 
696 	/* table of MLP attributes */
697 	optp = (struct opthdr *)&mp_attr_ctl->b_rptr[
698 	    sizeof (struct T_optmgmt_ack)];
699 	optp->level = MIB2_SCTP;
700 	optp->name = EXPER_XPORT_MLP;
701 	optp->len = msgdsize(mp_attr_data);
702 	if (optp->len == 0)
703 		freemsg(mp_attr_ctl);
704 	else
705 		qreply(q, mp_attr_ctl);
706 
707 	return (mp_ret);
708 }
709 
710 /* Translate SCTP state to MIB2 SCTP state. */
711 static int
712 sctp_snmp_state(sctp_t *sctp)
713 {
714 	if (sctp == NULL)
715 		return (0);
716 
717 	switch (sctp->sctp_state) {
718 	case SCTPS_IDLE:
719 	case SCTPS_BOUND:
720 		return (MIB2_SCTP_closed);
721 	case SCTPS_LISTEN:
722 		return (MIB2_SCTP_listen);
723 	case SCTPS_COOKIE_WAIT:
724 		return (MIB2_SCTP_cookieWait);
725 	case SCTPS_COOKIE_ECHOED:
726 		return (MIB2_SCTP_cookieEchoed);
727 	case SCTPS_ESTABLISHED:
728 		return (MIB2_SCTP_established);
729 	case SCTPS_SHUTDOWN_PENDING:
730 		return (MIB2_SCTP_shutdownPending);
731 	case SCTPS_SHUTDOWN_SENT:
732 		return (MIB2_SCTP_shutdownSent);
733 	case SCTPS_SHUTDOWN_RECEIVED:
734 		return (MIB2_SCTP_shutdownReceived);
735 	case SCTPS_SHUTDOWN_ACK_SENT:
736 		return (MIB2_SCTP_shutdownAckSent);
737 	default:
738 		return (0);
739 	}
740 }
741