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