13d3e3f2rrs/*-
24736ccfpfg * SPDX-License-Identifier: BSD-3-Clause
34736ccfpfg *
40f2b9darrs * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
525827adtuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
625827adtuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
73d3e3f2rrs *
83d3e3f2rrs * Redistribution and use in source and binary forms, with or without
93d3e3f2rrs * modification, are permitted provided that the following conditions are met:
103d3e3f2rrs *
113d3e3f2rrs * a) Redistributions of source code must retain the above copyright notice,
123a4d069tuexen *    this list of conditions and the following disclaimer.
133d3e3f2rrs *
143d3e3f2rrs * b) Redistributions in binary form must reproduce the above copyright
153d3e3f2rrs *    notice, this list of conditions and the following disclaimer in
163a4d069tuexen *    the documentation and/or other materials provided with the distribution.
173d3e3f2rrs *
183d3e3f2rrs * c) Neither the name of Cisco Systems, Inc. nor the names of its
193d3e3f2rrs *    contributors may be used to endorse or promote products derived
203d3e3f2rrs *    from this software without specific prior written permission.
213d3e3f2rrs *
223d3e3f2rrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
233d3e3f2rrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
243d3e3f2rrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
253d3e3f2rrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
263d3e3f2rrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
273d3e3f2rrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
283d3e3f2rrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
293d3e3f2rrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
303d3e3f2rrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
313d3e3f2rrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
323d3e3f2rrs * THE POSSIBILITY OF SUCH DAMAGE.
333d3e3f2rrs */
343d3e3f2rrs
353d3e3f2rrs#include <sys/cdefs.h>
363d3e3f2rrs__FBSDID("$FreeBSD$");
3725827adtuexen
383d3e3f2rrs#include <netinet/sctp_os.h>
391b18117rrs#include <sys/proc.h>
403d3e3f2rrs#include <netinet/sctp_pcb.h>
413d3e3f2rrs#include <netinet/sctp_header.h>
423d3e3f2rrs#include <netinet/sctp_var.h>
435895ecetuexen#ifdef INET6
448a74463tuexen#include <netinet6/sctp6_var.h>
45af970e3rrs#endif
46bd8786errs#include <netinet/sctp_sysctl.h>
473d3e3f2rrs#include <netinet/sctp_output.h>
483d3e3f2rrs#include <netinet/sctp_uio.h>
493d3e3f2rrs#include <netinet/sctp_asconf.h>
503d3e3f2rrs#include <netinet/sctputil.h>
513d3e3f2rrs#include <netinet/sctp_indata.h>
523d3e3f2rrs#include <netinet/sctp_timer.h>
533d3e3f2rrs#include <netinet/sctp_auth.h>
54f827c93rrs#include <netinet/sctp_bsd_addr.h>
550f2b9darrs#include <netinet/udp.h>
56e037f7ftuexen#include <sys/eventhandler.h>
57f827c93rrs
581bedc49rrs
593d3e3f2rrs
60785250etuexenextern const struct sctp_cc_functions sctp_cc_functions[];
61785250etuexenextern const struct sctp_ss_functions sctp_ss_functions[];
623d3e3f2rrs
633d3e3f2rrsvoid
643d3e3f2rrssctp_init(void)
653d3e3f2rrs{
663d3e3f2rrs	u_long sb_max_adj;
673d3e3f2rrs
687782c49rrs	/* Initialize and modify the sysctled variables */
697782c49rrs	sctp_init_sysctls();
703d3e3f2rrs	if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE)
717782c49rrs		SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue) = (nmbclusters / 8);
723d3e3f2rrs	/*
733d3e3f2rrs	 * Allow a user to take no more than 1/2 the number of clusters or
743d3e3f2rrs	 * the SB_MAX whichever is smaller for the send window.
753d3e3f2rrs	 */
7614de4a3tuexen	sb_max_adj = (u_long)((u_quad_t)(SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES));
777782c49rrs	SCTP_BASE_SYSCTL(sctp_sendspace) = min(sb_max_adj,
7814de4a3tuexen	    (((uint32_t)nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT));
793d3e3f2rrs	/*
803d3e3f2rrs	 * Now for the recv window, should we take the same amount? or
813d3e3f2rrs	 * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For
823d3e3f2rrs	 * now I will just copy.
833d3e3f2rrs	 */
847782c49rrs	SCTP_BASE_SYSCTL(sctp_recvspace) = SCTP_BASE_SYSCTL(sctp_sendspace);
857782c49rrs	SCTP_BASE_VAR(first_time) = 0;
867782c49rrs	SCTP_BASE_VAR(sctp_pcb_initialized) = 0;
877782c49rrs	sctp_pcb_init();
887782c49rrs#if defined(SCTP_PACKET_LOGGING)
897782c49rrs	SCTP_BASE_VAR(packet_log_writers) = 0;
907782c49rrs	SCTP_BASE_VAR(packet_log_end) = 0;
91425c1c5tuexen	memset(&SCTP_BASE_VAR(packet_log_buffer), 0, SCTP_PACKET_LOG_SIZE);
927782c49rrs#endif
93ddaae07tuexen	SCTP_BASE_VAR(eh_tag) = EVENTHANDLER_REGISTER(rt_addrmsg,
94ddaae07tuexen	    sctp_addr_change_event_handler, NULL, EVENTHANDLER_PRI_FIRST);
957782c49rrs}
967782c49rrs
97fac944abz#ifdef VIMAGE
98fac944abzstatic void
99fac944abzsctp_finish(void *unused __unused)
1007782c49rrs{
1017782c49rrs	sctp_pcb_finish();
1027782c49rrs}
1031f7e02atuexen
104fac944abzVNET_SYSUNINIT(sctp, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, sctp_finish, NULL);
105fac944abz#endif
1063d3e3f2rrs
1078a66346rrsvoid
1083a4d069tuexensctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz)
1093d3e3f2rrs{
1103d3e3f2rrs	struct sctp_tmit_chunk *chk;
1119695ccftuexen	uint16_t overhead;
1123d3e3f2rrs
1133d3e3f2rrs	/* Adjust that too */
1143d3e3f2rrs	stcb->asoc.smallest_mtu = nxtsz;
1153d3e3f2rrs	/* now off to subtract IP_DF flag if needed */
116695d1cctuexen	overhead = IP_HDR_SIZE + sizeof(struct sctphdr);
1179695ccftuexen	if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) {
1189695ccftuexen		overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id);
1199695ccftuexen	}
1203d3e3f2rrs	TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
1219695ccftuexen		if ((chk->send_size + overhead) > nxtsz) {
1223d3e3f2rrs			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
1233d3e3f2rrs		}
1243d3e3f2rrs	}
1253d3e3f2rrs	TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
1269695ccftuexen		if ((chk->send_size + overhead) > nxtsz) {
1273d3e3f2rrs			/*
1283d3e3f2rrs			 * For this guy we also mark for immediate resend
1293d3e3f2rrs			 * since we sent to big of chunk
1303d3e3f2rrs			 */
1313d3e3f2rrs			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
132f72ef57rrs			if (chk->sent < SCTP_DATAGRAM_RESEND) {
133f72ef57rrs				sctp_flight_size_decrease(chk);
134f72ef57rrs				sctp_total_flight_decrease(stcb, chk);
135aa1ba0ctuexen				chk->sent = SCTP_DATAGRAM_RESEND;
1363d3e3f2rrs				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
137aa1ba0ctuexen				chk->rec.data.doing_fast_retransmit = 0;
138aa1ba0ctuexen				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
139aa1ba0ctuexen					sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU,
140aa1ba0ctuexen					    chk->whoTo->flight_size,
141aa1ba0ctuexen					    chk->book_size,
14214de4a3tuexen					    (uint32_t)(uintptr_t)chk->whoTo,
143ec64726tuexen					    chk->rec.data.tsn);
144aa1ba0ctuexen				}
145aa1ba0ctuexen				/* Clear any time so NO RTT is being done */
146bca0a73tuexen				if (chk->do_rtt == 1) {
147bca0a73tuexen					chk->do_rtt = 0;
148bca0a73tuexen					chk->whoTo->rto_needed = 1;
149bca0a73tuexen				}
1503d3e3f2rrs			}
1513d3e3f2rrs		}
1523d3e3f2rrs	}
1533d3e3f2rrs}
1543d3e3f2rrs
155ad795d2tuexen#ifdef INET
15642159e8tuexenvoid
1573d3e3f2rrssctp_notify(struct sctp_inpcb *inp,
1583d3e3f2rrs    struct sctp_tcb *stcb,
159421a097tuexen    struct sctp_nets *net,
160421a097tuexen    uint8_t icmp_type,
161421a097tuexen    uint8_t icmp_code,
162421a097tuexen    uint16_t ip_len,
163fcb532btuexen    uint32_t next_mtu)
1643d3e3f2rrs{
1656e403cetuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
1664dd82bdrrs	struct socket *so;
1674dd82bdrrs#endif
168421a097tuexen	int timer_stopped;
169e1de0a1rrs
170421a097tuexen	if (icmp_type != ICMP_UNREACH) {
171e1de0a1rrs		/* We only care about unreachable */
172e1de0a1rrs		SCTP_TCB_UNLOCK(stcb);
173e1de0a1rrs		return;
174e1de0a1rrs	}
175421a097tuexen	if ((icmp_code == ICMP_UNREACH_NET) ||
176421a097tuexen	    (icmp_code == ICMP_UNREACH_HOST) ||
177421a097tuexen	    (icmp_code == ICMP_UNREACH_NET_UNKNOWN) ||
178421a097tuexen	    (icmp_code == ICMP_UNREACH_HOST_UNKNOWN) ||
179421a097tuexen	    (icmp_code == ICMP_UNREACH_ISOLATED) ||
180421a097tuexen	    (icmp_code == ICMP_UNREACH_NET_PROHIB) ||
181421a097tuexen	    (icmp_code == ICMP_UNREACH_HOST_PROHIB) ||
182421a097tuexen	    (icmp_code == ICMP_UNREACH_FILTER_PROHIB)) {
18342159e8tuexen		/* Mark the net unreachable. */
184e1de0a1rrs		if (net->dest_state & SCTP_ADDR_REACHABLE) {
185421a097tuexen			/* OK, that destination is NOT reachable. */
186e1de0a1rrs			net->dest_state &= ~SCTP_ADDR_REACHABLE;
187f47c615tuexen			net->dest_state &= ~SCTP_ADDR_PF;
188e1de0a1rrs			sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
1898b015cbtuexen			    stcb, 0,
190e1de0a1rrs			    (void *)net, SCTP_SO_NOT_LOCKED);
191e1de0a1rrs		}
192e1de0a1rrs		SCTP_TCB_UNLOCK(stcb);
193421a097tuexen	} else if ((icmp_code == ICMP_UNREACH_PROTOCOL) ||
194421a097tuexen	    (icmp_code == ICMP_UNREACH_PORT)) {
19542159e8tuexen		/* Treat it like an ABORT. */
196abe6735tuexen		sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED);
1976e403cetuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
198e1de0a1rrs		so = SCTP_INP_SO(inp);
199e1de0a1rrs		atomic_add_int(&stcb->asoc.refcnt, 1);
200e1de0a1rrs		SCTP_TCB_UNLOCK(stcb);
201e1de0a1rrs		SCTP_SOCKET_LOCK(so, 1);
202e1de0a1rrs		SCTP_TCB_LOCK(stcb);
203e1de0a1rrs		atomic_subtract_int(&stcb->asoc.refcnt, 1);
2044dd82bdrrs#endif
205a82f33etuexen		(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
206a82f33etuexen		    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
2076e403cetuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
208e1de0a1rrs		SCTP_SOCKET_UNLOCK(so, 1);
209e1de0a1rrs		/* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */
2104dd82bdrrs#endif
211e1de0a1rrs		/* no need to unlock here, since the TCB is gone */
212421a097tuexen	} else if (icmp_code == ICMP_UNREACH_NEEDFRAG) {
213c3e1813tuexen		if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
2142731e7etuexen			SCTP_TCB_UNLOCK(stcb);
2152731e7etuexen			return;
2162731e7etuexen		}
217421a097tuexen		/* Find the next (smaller) MTU */
218421a097tuexen		if (next_mtu == 0) {
219421a097tuexen			/*
220421a097tuexen			 * Old type router that does not tell us what the
221421a097tuexen			 * next MTU is. Rats we will have to guess (in a
222421a097tuexen			 * educated fashion of course).
223421a097tuexen			 */
224421a097tuexen			next_mtu = sctp_get_prev_mtu(ip_len);
225421a097tuexen		}
226421a097tuexen		/* Stop the PMTU timer. */
227421a097tuexen		if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
228421a097tuexen			timer_stopped = 1;
229421a097tuexen			sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
230421a097tuexen			    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
231421a097tuexen		} else {
232421a097tuexen			timer_stopped = 0;
233421a097tuexen		}
234421a097tuexen		/* Update the path MTU. */
23572585cftuexen		if (net->port) {
23672585cftuexen			next_mtu -= sizeof(struct udphdr);
23772585cftuexen		}
238421a097tuexen		if (net->mtu > next_mtu) {
239421a097tuexen			net->mtu = next_mtu;
2400deadectuexen			if (net->port) {
2410deadectuexen				sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu + sizeof(struct udphdr));
2420deadectuexen			} else {
2430deadectuexen				sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu);
2440deadectuexen			}
245421a097tuexen		}
246421a097tuexen		/* Update the association MTU */
247421a097tuexen		if (stcb->asoc.smallest_mtu > next_mtu) {
248421a097tuexen			sctp_pathmtu_adjustment(stcb, next_mtu);
249421a097tuexen		}
250421a097tuexen		/* Finally, start the PMTU timer if it was running before. */
251421a097tuexen		if (timer_stopped) {
252421a097tuexen			sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
253421a097tuexen		}
254421a097tuexen		SCTP_TCB_UNLOCK(stcb);
2553d3e3f2rrs	} else {
256e1de0a1rrs		SCTP_TCB_UNLOCK(stcb);
2573d3e3f2rrs	}
2583d3e3f2rrs}
2593d3e3f2rrs
2603d3e3f2rrsvoid
2618cd2183tuexensctp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
2623d3e3f2rrs{
263f788987tuexen	struct ip *outer_ip;
264f788987tuexen	struct ip *inner_ip;
2653d3e3f2rrs	struct sctphdr *sh;
266eb6d64dtuexen	struct icmp *icmp;
267eb6d64dtuexen	struct sctp_inpcb *inp;
268eb6d64dtuexen	struct sctp_tcb *stcb;
269eb6d64dtuexen	struct sctp_nets *net;
270eb6d64dtuexen	struct sctp_init_chunk *ch;
27142159e8tuexen	struct sockaddr_in src, dst;
2723d3e3f2rrs
2733d3e3f2rrs	if (sa->sa_family != AF_INET ||
2743d3e3f2rrs	    ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) {
2753d3e3f2rrs		return;
2763d3e3f2rrs	}
2773d3e3f2rrs	if (PRC_IS_REDIRECT(cmd)) {
278eb6d64dtuexen		vip = NULL;
2793d3e3f2rrs	} else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) {
2803d3e3f2rrs		return;
2813d3e3f2rrs	}
282eb6d64dtuexen	if (vip != NULL) {
283eb6d64dtuexen		inner_ip = (struct ip *)vip;
284eb6d64dtuexen		icmp = (struct icmp *)((caddr_t)inner_ip -
285eb6d64dtuexen		    (sizeof(struct icmp) - sizeof(struct ip)));
286eb6d64dtuexen		outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip));
287eb6d64dtuexen		sh = (struct sctphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2));
28842159e8tuexen		memset(&src, 0, sizeof(struct sockaddr_in));
28942159e8tuexen		src.sin_family = AF_INET;
29042159e8tuexen		src.sin_len = sizeof(struct sockaddr_in);
29142159e8tuexen		src.sin_port = sh->src_port;
29242159e8tuexen		src.sin_addr = inner_ip->ip_src;
29342159e8tuexen		memset(&dst, 0, sizeof(struct sockaddr_in));
29442159e8tuexen		dst.sin_family = AF_INET;
29542159e8tuexen		dst.sin_len = sizeof(struct sockaddr_in);
29642159e8tuexen		dst.sin_port = sh->dest_port;
29742159e8tuexen		dst.sin_addr = inner_ip->ip_dst;
2983d3e3f2rrs		/*
29942159e8tuexen		 * 'dst' holds the dest of the packet that failed to be
30042159e8tuexen		 * sent. 'src' holds our local endpoint address. Thus we
30142159e8tuexen		 * reverse the dst and the src in the lookup.
3023d3e3f2rrs		 */
303eb6d64dtuexen		inp = NULL;
304eb6d64dtuexen		net = NULL;
30542159e8tuexen		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
30642159e8tuexen		    (struct sockaddr *)&src,
307eb6d64dtuexen		    &inp, &net, 1,
308eb6d64dtuexen		    SCTP_DEFAULT_VRFID);
3098cd2183tuexen		if ((stcb != NULL) &&
310421a097tuexen		    (net != NULL) &&
311c2c8b26tuexen		    (inp != NULL)) {
3128cd2183tuexen			/* Check the verification tag */
3138cd2183tuexen			if (ntohl(sh->v_tag) != 0) {
3148cd2183tuexen				/*
3158cd2183tuexen				 * This must be the verification tag used
3168cd2183tuexen				 * for sending out packets. We don't
3178cd2183tuexen				 * consider packets reflecting the
3188cd2183tuexen				 * verification tag.
3198cd2183tuexen				 */
320421a097tuexen				if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) {
3218cd2183tuexen					SCTP_TCB_UNLOCK(stcb);
3228cd2183tuexen					return;
3238cd2183tuexen				}
3248cd2183tuexen			} else {
325eb6d64dtuexen				if (ntohs(outer_ip->ip_len) >=
326eb6d64dtuexen				    sizeof(struct ip) +
327eb6d64dtuexen				    8 + (inner_ip->ip_hl << 2) + 20) {
328eb6d64dtuexen					/*
329eb6d64dtuexen					 * In this case we can check if we
330eb6d64dtuexen					 * got an INIT chunk and if the
331eb6d64dtuexen					 * initiate tag matches.
332eb6d64dtuexen					 */
333eb6d64dtuexen					ch = (struct sctp_init_chunk *)(sh + 1);
334eb6d64dtuexen					if ((ch->ch.chunk_type != SCTP_INITIATION) ||
335eb6d64dtuexen					    (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) {
336eb6d64dtuexen						SCTP_TCB_UNLOCK(stcb);
337eb6d64dtuexen						return;
338eb6d64dtuexen					}
339eb6d64dtuexen				} else {
340eb6d64dtuexen					SCTP_TCB_UNLOCK(stcb);
341eb6d64dtuexen					return;
342eb6d64dtuexen				}
3438cd2183tuexen			}
344421a097tuexen			sctp_notify(inp, stcb, net,
345eb6d64dtuexen			    icmp->icmp_type,
346eb6d64dtuexen			    icmp->icmp_code,
347eb6d64dtuexen			    ntohs(inner_ip->ip_len),
34814de4a3tuexen			    (uint32_t)ntohs(icmp->icmp_nextmtu));
3493d3e3f2rrs		} else {
3503d3e3f2rrs			if ((stcb == NULL) && (inp != NULL)) {
3513d3e3f2rrs				/* reduce ref-count */
3523d3e3f2rrs				SCTP_INP_WLOCK(inp);
3533d3e3f2rrs				SCTP_INP_DECR_REF(inp);
3543d3e3f2rrs				SCTP_INP_WUNLOCK(inp);
3553d3e3f2rrs			}
356cd4e0b7rrs			if (stcb) {
357cd4e0b7rrs				SCTP_TCB_UNLOCK(stcb);
358cd4e0b7rrs			}
3593d3e3f2rrs		}
3603d3e3f2rrs	}
3613d3e3f2rrs	return;
3623d3e3f2rrs}
363ad795d2tuexen#endif
364ad795d2tuexen
3653d3e3f2rrsstatic int
3663d3e3f2rrssctp_getcred(SYSCTL_HANDLER_ARGS)
3673d3e3f2rrs{
3681bedc49rrs	struct xucred xuc;
3693d3e3f2rrs	struct sockaddr_in addrs[2];
3703d3e3f2rrs	struct sctp_inpcb *inp;
3713d3e3f2rrs	struct sctp_nets *net;
3723d3e3f2rrs	struct sctp_tcb *stcb;
3731bedc49rrs	int error;
374bd8786errs	uint32_t vrf_id;
3753d3e3f2rrs
376ad3d567rrs	/* FIX, for non-bsd is this right? */
377bd8786errs	vrf_id = SCTP_DEFAULT_VRFID;
378ad3d567rrs
37900b0234rwatson	error = priv_check(req->td, PRIV_NETINET_GETCRED);
38000b0234rwatson
3813d3e3f2rrs	if (error)
3823d3e3f2rrs		return (error);
383572da55rwatson
3843d3e3f2rrs	error = SYSCTL_IN(req, addrs, sizeof(addrs));
3853d3e3f2rrs	if (error)
3863d3e3f2rrs		return (error);
3873d3e3f2rrs
388d2f6540tuexen	stcb = sctp_findassociation_addr_sa(sintosa(&addrs[1]),
389d2f6540tuexen	    sintosa(&addrs[0]),
390bd8786errs	    &inp, &net, 1, vrf_id);
3913d3e3f2rrs	if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
3923d3e3f2rrs		if ((inp != NULL) && (stcb == NULL)) {
3933d3e3f2rrs			/* reduce ref-count */
3943d3e3f2rrs			SCTP_INP_WLOCK(inp);
3953d3e3f2rrs			SCTP_INP_DECR_REF(inp);
3961bedc49rrs			goto cred_can_cont;
3973d3e3f2rrs		}
3989bf2bb1tuexen
3991d0af67rrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4003d3e3f2rrs		error = ENOENT;
4013d3e3f2rrs		goto out;
402