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