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