18c2654abSrjs /* $KAME: sctp_pcb.c,v 1.39 2005/06/16 18:29:25 jinmei Exp $ */
2*481d3881Srin /* $NetBSD: sctp_pcb.c,v 1.27 2024/07/05 04:31:54 rin Exp $ */
38c2654abSrjs
48c2654abSrjs /*
58c2654abSrjs * Copyright (c) 2001, 2002, 2003, 2004 Cisco Systems, Inc.
68c2654abSrjs * All rights reserved.
78c2654abSrjs *
88c2654abSrjs * Redistribution and use in source and binary forms, with or without
98c2654abSrjs * modification, are permitted provided that the following conditions
108c2654abSrjs * are met:
118c2654abSrjs * 1. Redistributions of source code must retain the above copyright
128c2654abSrjs * notice, this list of conditions and the following disclaimer.
138c2654abSrjs * 2. Redistributions in binary form must reproduce the above copyright
148c2654abSrjs * notice, this list of conditions and the following disclaimer in the
158c2654abSrjs * documentation and/or other materials provided with the distribution.
168c2654abSrjs * 3. All advertising materials mentioning features or use of this software
178c2654abSrjs * must display the following acknowledgement:
188c2654abSrjs * This product includes software developed by Cisco Systems, Inc.
198c2654abSrjs * 4. Neither the name of the project nor the names of its contributors
208c2654abSrjs * may be used to endorse or promote products derived from this software
218c2654abSrjs * without specific prior written permission.
228c2654abSrjs *
238c2654abSrjs * THIS SOFTWARE IS PROVIDED BY CISCO SYSTEMS AND CONTRIBUTORS ``AS IS'' AND
248c2654abSrjs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
258c2654abSrjs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
268c2654abSrjs * ARE DISCLAIMED. IN NO EVENT SHALL CISCO SYSTEMS OR CONTRIBUTORS BE LIABLE
278c2654abSrjs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
288c2654abSrjs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
298c2654abSrjs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
308c2654abSrjs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
318c2654abSrjs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
328c2654abSrjs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
338c2654abSrjs * SUCH DAMAGE.
348c2654abSrjs */
358c2654abSrjs #include <sys/cdefs.h>
36*481d3881Srin __KERNEL_RCSID(0, "$NetBSD: sctp_pcb.c,v 1.27 2024/07/05 04:31:54 rin Exp $");
378c2654abSrjs
388c2654abSrjs #ifdef _KERNEL_OPT
398c2654abSrjs #include "opt_inet.h"
4001b82b52Srjs #include "opt_ipsec.h"
418c2654abSrjs #include "opt_sctp.h"
428c2654abSrjs #endif /* _KERNEL_OPT */
438c2654abSrjs
448c2654abSrjs #include <sys/param.h>
458c2654abSrjs #include <sys/systm.h>
468c2654abSrjs #include <sys/malloc.h>
478c2654abSrjs #include <sys/mbuf.h>
488c2654abSrjs #include <sys/domain.h>
498c2654abSrjs #include <sys/protosw.h>
508c2654abSrjs #include <sys/socket.h>
518c2654abSrjs #include <sys/socketvar.h>
528c2654abSrjs #include <sys/proc.h>
538c2654abSrjs #include <sys/kauth.h>
548c2654abSrjs #include <sys/kernel.h>
558c2654abSrjs #include <sys/sysctl.h>
568c2654abSrjs #include <sys/callout.h>
578c2654abSrjs
588c2654abSrjs #include <machine/limits.h>
598c2654abSrjs #include <machine/cpu.h>
608c2654abSrjs
618c2654abSrjs #include <net/if.h>
628c2654abSrjs #include <net/if_types.h>
638c2654abSrjs #include <net/route.h>
648c2654abSrjs #include <netinet/in.h>
658c2654abSrjs #include <netinet/in_systm.h>
668c2654abSrjs #include <netinet/ip.h>
678c2654abSrjs #include <netinet/in_pcb.h>
688c2654abSrjs #include <netinet/in_var.h>
698c2654abSrjs #include <netinet/ip_var.h>
708c2654abSrjs
718c2654abSrjs #ifdef INET6
728c2654abSrjs #include <netinet/ip6.h>
738c2654abSrjs #include <netinet6/ip6_var.h>
748c2654abSrjs #include <netinet6/scope6_var.h>
758c2654abSrjs #include <netinet6/in6_pcb.h>
768c2654abSrjs #endif /* INET6 */
778c2654abSrjs
788c2654abSrjs #ifdef IPSEC
79505ea976Srjs #include <netipsec/ipsec.h>
80505ea976Srjs #include <netipsec/key.h>
818c2654abSrjs #endif /* IPSEC */
828c2654abSrjs
838c2654abSrjs #include <netinet/sctp_var.h>
848c2654abSrjs #include <netinet/sctp_pcb.h>
858c2654abSrjs #include <netinet/sctputil.h>
868c2654abSrjs #include <netinet/sctp.h>
878c2654abSrjs #include <netinet/sctp_header.h>
888c2654abSrjs #include <netinet/sctp_asconf.h>
898c2654abSrjs #include <netinet/sctp_output.h>
908c2654abSrjs #include <netinet/sctp_timer.h>
918c2654abSrjs
928c2654abSrjs #ifndef SCTP_PCBHASHSIZE
938c2654abSrjs /* default number of association hash buckets in each endpoint */
948c2654abSrjs #define SCTP_PCBHASHSIZE 256
958c2654abSrjs #endif
968c2654abSrjs
978c2654abSrjs #ifdef SCTP_DEBUG
988c2654abSrjs u_int32_t sctp_debug_on = SCTP_DEBUG_ALL;
998c2654abSrjs #endif /* SCTP_DEBUG */
1008c2654abSrjs
1018c2654abSrjs u_int32_t sctp_pegs[SCTP_NUMBER_OF_PEGS];
1028c2654abSrjs
1038c2654abSrjs int sctp_pcbtblsize = SCTP_PCBHASHSIZE;
1048c2654abSrjs
1058c2654abSrjs struct sctp_epinfo sctppcbinfo;
1068c2654abSrjs
1078c2654abSrjs /* FIX: we don't handle multiple link local scopes */
1088c2654abSrjs /* "scopeless" replacement IN6_ARE_ADDR_EQUAL */
1098c2654abSrjs int
SCTP6_ARE_ADDR_EQUAL(const struct in6_addr * a,const struct in6_addr * b)1108c2654abSrjs SCTP6_ARE_ADDR_EQUAL(const struct in6_addr *a, const struct in6_addr *b)
1118c2654abSrjs {
1128c2654abSrjs struct in6_addr tmp_a, tmp_b;
1138c2654abSrjs /* use a copy of a and b */
1148c2654abSrjs tmp_a = *a;
1158c2654abSrjs tmp_b = *b;
1168c2654abSrjs in6_clearscope(&tmp_a);
1178c2654abSrjs in6_clearscope(&tmp_b);
1188c2654abSrjs return (IN6_ARE_ADDR_EQUAL(&tmp_a, &tmp_b));
1198c2654abSrjs }
1208c2654abSrjs
1218c2654abSrjs #if defined(__FreeBSD__) && __FreeBSD_version > 500000
1228c2654abSrjs
1238c2654abSrjs #ifndef xyzzy
1248c2654abSrjs void sctp_validate_no_locks(void);
1258c2654abSrjs
1268c2654abSrjs void
SCTP_INP_RLOCK(struct sctp_inpcb * inp)1278c2654abSrjs SCTP_INP_RLOCK(struct sctp_inpcb *inp)
1288c2654abSrjs {
1298c2654abSrjs struct sctp_tcb *stcb;
1308c2654abSrjs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1318c2654abSrjs if (mtx_owned(&(stcb)->tcb_mtx))
1328c2654abSrjs panic("I own TCB lock?");
1338c2654abSrjs }
1348c2654abSrjs if (mtx_owned(&(inp)->inp_mtx))
1358c2654abSrjs panic("INP Recursive Lock-R");
1368c2654abSrjs mtx_lock(&(inp)->inp_mtx);
1378c2654abSrjs }
1388c2654abSrjs
1398c2654abSrjs void
SCTP_INP_WLOCK(struct sctp_inpcb * inp)1408c2654abSrjs SCTP_INP_WLOCK(struct sctp_inpcb *inp)
1418c2654abSrjs {
1428c2654abSrjs SCTP_INP_RLOCK(inp);
1438c2654abSrjs }
1448c2654abSrjs
1458c2654abSrjs void
SCTP_INP_INFO_RLOCK()1468c2654abSrjs SCTP_INP_INFO_RLOCK()
1478c2654abSrjs {
1488c2654abSrjs struct sctp_inpcb *inp;
1498c2654abSrjs struct sctp_tcb *stcb;
1508c2654abSrjs LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) {
1518c2654abSrjs if (mtx_owned(&(inp)->inp_mtx))
1528c2654abSrjs panic("info-lock and own inp lock?");
1538c2654abSrjs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1548c2654abSrjs if (mtx_owned(&(stcb)->tcb_mtx))
1558c2654abSrjs panic("Info lock and own a tcb lock?");
1568c2654abSrjs }
1578c2654abSrjs }
1588c2654abSrjs if (mtx_owned(&sctppcbinfo.ipi_ep_mtx))
1598c2654abSrjs panic("INP INFO Recursive Lock-R");
1608c2654abSrjs mtx_lock(&sctppcbinfo.ipi_ep_mtx);
1618c2654abSrjs }
1628c2654abSrjs
1638c2654abSrjs void
SCTP_INP_INFO_WLOCK()1648c2654abSrjs SCTP_INP_INFO_WLOCK()
1658c2654abSrjs {
1668c2654abSrjs SCTP_INP_INFO_RLOCK();
1678c2654abSrjs }
1688c2654abSrjs
1698c2654abSrjs
sctp_validate_no_locks()1708c2654abSrjs void sctp_validate_no_locks()
1718c2654abSrjs {
1728c2654abSrjs struct sctp_inpcb *inp;
1738c2654abSrjs struct sctp_tcb *stcb;
1748c2654abSrjs
1758c2654abSrjs if (mtx_owned(&sctppcbinfo.ipi_ep_mtx))
1768c2654abSrjs panic("INP INFO lock is owned?");
1778c2654abSrjs
1788c2654abSrjs LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) {
1798c2654abSrjs if (mtx_owned(&(inp)->inp_mtx))
1808c2654abSrjs panic("You own an INP lock?");
1818c2654abSrjs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1828c2654abSrjs if (mtx_owned(&(stcb)->tcb_mtx))
1838c2654abSrjs panic("You own a TCB lock?");
1848c2654abSrjs }
1858c2654abSrjs }
1868c2654abSrjs }
1878c2654abSrjs
1888c2654abSrjs #endif
1898c2654abSrjs #endif
1908c2654abSrjs
1918c2654abSrjs void
sctp_fill_pcbinfo(struct sctp_pcbinfo * spcb)1928c2654abSrjs sctp_fill_pcbinfo(struct sctp_pcbinfo *spcb)
1938c2654abSrjs {
1948c2654abSrjs /* We really don't need
1958c2654abSrjs * to lock this, but I will
1968c2654abSrjs * just because it does not hurt.
1978c2654abSrjs */
1988c2654abSrjs SCTP_INP_INFO_RLOCK();
1998c2654abSrjs spcb->ep_count = sctppcbinfo.ipi_count_ep;
2008c2654abSrjs spcb->asoc_count = sctppcbinfo.ipi_count_asoc;
2018c2654abSrjs spcb->laddr_count = sctppcbinfo.ipi_count_laddr;
2028c2654abSrjs spcb->raddr_count = sctppcbinfo.ipi_count_raddr;
2038c2654abSrjs spcb->chk_count = sctppcbinfo.ipi_count_chunk;
2048c2654abSrjs spcb->sockq_count = sctppcbinfo.ipi_count_sockq;
2058c2654abSrjs spcb->mbuf_track = sctppcbinfo.mbuf_track;
2068c2654abSrjs SCTP_INP_INFO_RUNLOCK();
2078c2654abSrjs }
2088c2654abSrjs
2098c2654abSrjs
2108c2654abSrjs /*
2118c2654abSrjs * Notes on locks for FreeBSD 5 and up. All association
2128c2654abSrjs * lookups that have a definte ep, the INP structure is
2138c2654abSrjs * assumed to be locked for reading. If we need to go
214fd433086Smsaitoh * find the INP (usually when a **inp is passed) then
2158c2654abSrjs * we must lock the INFO structure first and if needed
2168c2654abSrjs * lock the INP too. Note that if we lock it we must
2178c2654abSrjs *
2188c2654abSrjs */
2198c2654abSrjs
2208c2654abSrjs
2218c2654abSrjs /*
2228c2654abSrjs * Given a endpoint, look and find in its association list any association
2238c2654abSrjs * with the "to" address given. This can be a "from" address, too, for
2248c2654abSrjs * inbound packets. For outbound packets it is a true "to" address.
2258c2654abSrjs */
2268c2654abSrjs static struct sctp_tcb *
sctp_tcb_special_locate(struct sctp_inpcb ** inp_p,struct sockaddr * from,struct sockaddr * to,struct sctp_nets ** netp)2278c2654abSrjs sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
2288c2654abSrjs struct sockaddr *to, struct sctp_nets **netp)
2298c2654abSrjs {
2308c2654abSrjs /**** ASSUMSES THE CALLER holds the INP_INFO_RLOCK */
2318c2654abSrjs
2328c2654abSrjs /*
2338c2654abSrjs * Note for this module care must be taken when observing what to is
2348c2654abSrjs * for. In most of the rest of the code the TO field represents my
2358c2654abSrjs * peer and the FROM field represents my address. For this module it
2368c2654abSrjs * is reversed of that.
2378c2654abSrjs */
2388c2654abSrjs /*
2398c2654abSrjs * If we support the TCP model, then we must now dig through to
2408c2654abSrjs * see if we can find our endpoint in the list of tcp ep's.
2418c2654abSrjs */
2428c2654abSrjs uint16_t lport, rport;
2438c2654abSrjs struct sctppcbhead *ephead;
2448c2654abSrjs struct sctp_inpcb *inp;
2458c2654abSrjs struct sctp_laddr *laddr;
2468c2654abSrjs struct sctp_tcb *stcb;
2478c2654abSrjs struct sctp_nets *net;
2488c2654abSrjs
2498c2654abSrjs if ((to == NULL) || (from == NULL)) {
2508c2654abSrjs return (NULL);
2518c2654abSrjs }
2528c2654abSrjs
2538c2654abSrjs if (to->sa_family == AF_INET && from->sa_family == AF_INET) {
2548c2654abSrjs lport = ((struct sockaddr_in *)to)->sin_port;
2558c2654abSrjs rport = ((struct sockaddr_in *)from)->sin_port;
2568c2654abSrjs } else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) {
2578c2654abSrjs lport = ((struct sockaddr_in6 *)to)->sin6_port;
2588c2654abSrjs rport = ((struct sockaddr_in6 *)from)->sin6_port;
2598c2654abSrjs } else {
2608c2654abSrjs return NULL;
2618c2654abSrjs }
2628c2654abSrjs ephead = &sctppcbinfo.sctp_tcpephash[SCTP_PCBHASH_ALLADDR(
2638c2654abSrjs (lport + rport), sctppcbinfo.hashtcpmark)];
2648c2654abSrjs /*
2658c2654abSrjs * Ok now for each of the guys in this bucket we must look
2668c2654abSrjs * and see:
2678c2654abSrjs * - Does the remote port match.
2688c2654abSrjs * - Does there single association's addresses match this
2698c2654abSrjs * address (to).
2708c2654abSrjs * If so we update p_ep to point to this ep and return the
2718c2654abSrjs * tcb from it.
2728c2654abSrjs */
2738c2654abSrjs LIST_FOREACH(inp, ephead, sctp_hash) {
2748c2654abSrjs if (lport != inp->sctp_lport) {
2758c2654abSrjs continue;
2768c2654abSrjs }
2778c2654abSrjs SCTP_INP_RLOCK(inp);
2788c2654abSrjs /* check to see if the ep has one of the addresses */
2798c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
2808c2654abSrjs /* We are NOT bound all, so look further */
2818c2654abSrjs int match = 0;
2828c2654abSrjs
2838c2654abSrjs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
2848c2654abSrjs if (laddr->ifa == NULL) {
2858c2654abSrjs #ifdef SCTP_DEBUG
2868c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
2878c2654abSrjs printf("An ounce of prevention is worth a pound of cure\n");
2888c2654abSrjs }
2898c2654abSrjs #endif
2908c2654abSrjs continue;
2918c2654abSrjs }
2928c2654abSrjs if (laddr->ifa->ifa_addr == NULL) {
2938c2654abSrjs #ifdef SCTP_DEBUG
2948c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
2958c2654abSrjs printf("ifa with a NULL address\n");
2968c2654abSrjs }
2978c2654abSrjs #endif
2988c2654abSrjs continue;
2998c2654abSrjs }
3008c2654abSrjs if (laddr->ifa->ifa_addr->sa_family ==
3018c2654abSrjs to->sa_family) {
3028c2654abSrjs /* see if it matches */
3038c2654abSrjs struct sockaddr_in *intf_addr, *sin;
3048c2654abSrjs intf_addr = (struct sockaddr_in *)
3058c2654abSrjs laddr->ifa->ifa_addr;
3068c2654abSrjs sin = (struct sockaddr_in *)to;
3078c2654abSrjs if (from->sa_family == AF_INET) {
3088c2654abSrjs if (sin->sin_addr.s_addr ==
3098c2654abSrjs intf_addr->sin_addr.s_addr) {
3108c2654abSrjs match = 1;
3118c2654abSrjs SCTP_INP_RUNLOCK(inp);
3128c2654abSrjs break;
3138c2654abSrjs }
3148c2654abSrjs } else {
3158c2654abSrjs struct sockaddr_in6 *intf_addr6;
3168c2654abSrjs struct sockaddr_in6 *sin6;
3178c2654abSrjs sin6 = (struct sockaddr_in6 *)
3188c2654abSrjs to;
3198c2654abSrjs intf_addr6 = (struct sockaddr_in6 *)
3208c2654abSrjs laddr->ifa->ifa_addr;
3218c2654abSrjs
3228c2654abSrjs if (SCTP6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
3238c2654abSrjs &intf_addr6->sin6_addr)) {
3248c2654abSrjs match = 1;
3258c2654abSrjs SCTP_INP_RUNLOCK(inp);
3268c2654abSrjs break;
3278c2654abSrjs }
3288c2654abSrjs }
3298c2654abSrjs }
3308c2654abSrjs }
3318c2654abSrjs if (match == 0) {
3328c2654abSrjs /* This endpoint does not have this address */
3338c2654abSrjs SCTP_INP_RUNLOCK(inp);
3348c2654abSrjs continue;
3358c2654abSrjs }
3368c2654abSrjs }
3378c2654abSrjs /*
3388c2654abSrjs * Ok if we hit here the ep has the address, does it hold the
3398c2654abSrjs * tcb?
3408c2654abSrjs */
3418c2654abSrjs
3428c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list);
3438c2654abSrjs if (stcb == NULL) {
3448c2654abSrjs SCTP_INP_RUNLOCK(inp);
3458c2654abSrjs continue;
3468c2654abSrjs }
3478c2654abSrjs SCTP_TCB_LOCK(stcb);
3488c2654abSrjs if (stcb->rport != rport) {
3498c2654abSrjs /* remote port does not match. */
3508c2654abSrjs SCTP_TCB_UNLOCK(stcb);
3518c2654abSrjs SCTP_INP_RUNLOCK(inp);
3528c2654abSrjs continue;
3538c2654abSrjs }
3548c2654abSrjs /* Does this TCB have a matching address? */
3558c2654abSrjs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
3568c2654abSrjs if (sctp_cmpaddr(from, rtcache_getdst(&net->ro))) {
3578c2654abSrjs /* found it */
3588c2654abSrjs if (netp != NULL) {
3598c2654abSrjs *netp = net;
3608c2654abSrjs }
3618c2654abSrjs /* Update the endpoint pointer */
3628c2654abSrjs *inp_p = inp;
3638c2654abSrjs SCTP_INP_RUNLOCK(inp);
3648c2654abSrjs return (stcb);
3658c2654abSrjs }
3668c2654abSrjs }
3678c2654abSrjs SCTP_TCB_UNLOCK(stcb);
3688c2654abSrjs
3698c2654abSrjs SCTP_INP_RUNLOCK(inp);
3708c2654abSrjs }
3718c2654abSrjs return (NULL);
3728c2654abSrjs }
3738c2654abSrjs
3748c2654abSrjs struct sctp_tcb *
sctp_findassociation_ep_asconf(struct mbuf * m,int iphlen,int offset,struct sctphdr * sh,struct sctp_inpcb ** inp_p,struct sctp_nets ** netp)3758c2654abSrjs sctp_findassociation_ep_asconf(struct mbuf *m, int iphlen, int offset,
3768c2654abSrjs struct sctphdr *sh, struct sctp_inpcb **inp_p, struct sctp_nets **netp)
3778c2654abSrjs {
3788c2654abSrjs struct sctp_tcb *stcb;
3798c2654abSrjs struct sockaddr_in *sin;
3808c2654abSrjs struct sockaddr_in6 *sin6;
3818c2654abSrjs struct sockaddr_storage local_store, remote_store;
3828c2654abSrjs struct ip *iph;
3838c2654abSrjs struct sctp_paramhdr parm_buf, *phdr;
3848c2654abSrjs int ptype;
3858c2654abSrjs
3868c2654abSrjs memset(&local_store, 0, sizeof(local_store));
3878c2654abSrjs memset(&remote_store, 0, sizeof(remote_store));
3888c2654abSrjs
3898c2654abSrjs /* First get the destination address setup too. */
3908c2654abSrjs iph = mtod(m, struct ip *);
3918c2654abSrjs if (iph->ip_v == IPVERSION) {
3928c2654abSrjs /* its IPv4 */
3938c2654abSrjs sin = (struct sockaddr_in *)&local_store;
3948c2654abSrjs sin->sin_family = AF_INET;
3958c2654abSrjs sin->sin_len = sizeof(*sin);
3968c2654abSrjs sin->sin_port = sh->dest_port;
3978c2654abSrjs sin->sin_addr.s_addr = iph->ip_dst.s_addr ;
3988c2654abSrjs } else if (iph->ip_v == (IPV6_VERSION >> 4)) {
3998c2654abSrjs /* its IPv6 */
4008c2654abSrjs struct ip6_hdr *ip6;
4018c2654abSrjs ip6 = mtod(m, struct ip6_hdr *);
4028c2654abSrjs sin6 = (struct sockaddr_in6 *)&local_store;
4038c2654abSrjs sin6->sin6_family = AF_INET6;
4048c2654abSrjs sin6->sin6_len = sizeof(*sin6);
4058c2654abSrjs sin6->sin6_port = sh->dest_port;
4068c2654abSrjs sin6->sin6_addr = ip6->ip6_dst;
4078c2654abSrjs } else {
4088c2654abSrjs return NULL;
4098c2654abSrjs }
4108c2654abSrjs
4118c2654abSrjs phdr = sctp_get_next_param(m, offset + sizeof(struct sctp_asconf_chunk),
4128c2654abSrjs &parm_buf, sizeof(struct sctp_paramhdr));
4138c2654abSrjs if (phdr == NULL) {
4148c2654abSrjs #ifdef SCTP_DEBUG
4158c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INPUT3) {
4168c2654abSrjs printf("sctp_process_control: failed to get asconf lookup addr\n");
4178c2654abSrjs }
4188c2654abSrjs #endif /* SCTP_DEBUG */
4198c2654abSrjs return NULL;
4208c2654abSrjs }
4218c2654abSrjs ptype = (int)((u_int)ntohs(phdr->param_type));
4228c2654abSrjs /* get the correlation address */
4238c2654abSrjs if (ptype == SCTP_IPV6_ADDRESS) {
4248c2654abSrjs /* ipv6 address param */
4258c2654abSrjs struct sctp_ipv6addr_param *p6, p6_buf;
4268c2654abSrjs if (ntohs(phdr->param_length) != sizeof(struct sctp_ipv6addr_param)) {
4278c2654abSrjs return NULL;
4288c2654abSrjs }
4298c2654abSrjs
4308c2654abSrjs p6 = (struct sctp_ipv6addr_param *)sctp_get_next_param(m,
4318c2654abSrjs offset + sizeof(struct sctp_asconf_chunk),
4328c2654abSrjs &p6_buf.ph, sizeof(*p6));
4338c2654abSrjs if (p6 == NULL) {
4348c2654abSrjs #ifdef SCTP_DEBUG
4358c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INPUT3) {
4368c2654abSrjs printf("sctp_process_control: failed to get asconf v6 lookup addr\n");
4378c2654abSrjs }
4388c2654abSrjs #endif /* SCTP_DEBUG */
4398c2654abSrjs return (NULL);
4408c2654abSrjs }
4418c2654abSrjs sin6 = (struct sockaddr_in6 *)&remote_store;
4428c2654abSrjs sin6->sin6_family = AF_INET6;
4438c2654abSrjs sin6->sin6_len = sizeof(*sin6);
4448c2654abSrjs sin6->sin6_port = sh->src_port;
4458c2654abSrjs memcpy(&sin6->sin6_addr, &p6->addr, sizeof(struct in6_addr));
4468c2654abSrjs } else if (ptype == SCTP_IPV4_ADDRESS) {
4478c2654abSrjs /* ipv4 address param */
4488c2654abSrjs struct sctp_ipv4addr_param *p4, p4_buf;
4498c2654abSrjs if (ntohs(phdr->param_length) != sizeof(struct sctp_ipv4addr_param)) {
4508c2654abSrjs return NULL;
4518c2654abSrjs }
4528c2654abSrjs
4538c2654abSrjs p4 = (struct sctp_ipv4addr_param *)sctp_get_next_param(m,
4548c2654abSrjs offset + sizeof(struct sctp_asconf_chunk),
4558c2654abSrjs &p4_buf.ph, sizeof(*p4));
4568c2654abSrjs if (p4 == NULL) {
4578c2654abSrjs #ifdef SCTP_DEBUG
4588c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_INPUT3) {
4598c2654abSrjs printf("sctp_process_control: failed to get asconf v4 lookup addr\n");
4608c2654abSrjs }
4618c2654abSrjs #endif /* SCTP_DEBUG */
4628c2654abSrjs return (NULL);
4638c2654abSrjs }
4648c2654abSrjs sin = (struct sockaddr_in *)&remote_store;
4658c2654abSrjs sin->sin_family = AF_INET;
4668c2654abSrjs sin->sin_len = sizeof(*sin);
4678c2654abSrjs sin->sin_port = sh->src_port;
4688c2654abSrjs memcpy(&sin->sin_addr, &p4->addr, sizeof(struct in_addr));
4698c2654abSrjs } else {
4708c2654abSrjs /* invalid address param type */
4718c2654abSrjs return NULL;
4728c2654abSrjs }
4738c2654abSrjs
4748c2654abSrjs stcb = sctp_findassociation_ep_addr(inp_p,
4758c2654abSrjs (struct sockaddr *)&remote_store, netp,
4768c2654abSrjs (struct sockaddr *)&local_store, NULL);
4778c2654abSrjs return (stcb);
4788c2654abSrjs }
4798c2654abSrjs
4808c2654abSrjs struct sctp_tcb *
sctp_findassociation_ep_addr(struct sctp_inpcb ** inp_p,struct sockaddr * remote,struct sctp_nets ** netp,struct sockaddr * local,struct sctp_tcb * locked_tcb)4818c2654abSrjs sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
4828c2654abSrjs struct sctp_nets **netp, struct sockaddr *local, struct sctp_tcb *locked_tcb)
4838c2654abSrjs {
4848c2654abSrjs struct sctpasochead *head;
4858c2654abSrjs struct sctp_inpcb *inp;
4868c2654abSrjs struct sctp_tcb *stcb;
4878c2654abSrjs struct sctp_nets *net;
4888c2654abSrjs uint16_t rport;
4898c2654abSrjs
4908c2654abSrjs inp = *inp_p;
4918c2654abSrjs if (remote->sa_family == AF_INET) {
4928c2654abSrjs rport = (((struct sockaddr_in *)remote)->sin_port);
4938c2654abSrjs } else if (remote->sa_family == AF_INET6) {
4948c2654abSrjs rport = (((struct sockaddr_in6 *)remote)->sin6_port);
4958c2654abSrjs } else {
4968c2654abSrjs return (NULL);
4978c2654abSrjs }
4988c2654abSrjs if (locked_tcb) {
4998c2654abSrjs /* UN-lock so we can do proper locking here
5008c2654abSrjs * this occurs when called from load_addresses_from_init.
5018c2654abSrjs */
5028c2654abSrjs SCTP_TCB_UNLOCK(locked_tcb);
5038c2654abSrjs }
5048c2654abSrjs SCTP_INP_INFO_RLOCK();
5058c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
5068c2654abSrjs /*
5078c2654abSrjs * Now either this guy is our listner or it's the connector.
5088c2654abSrjs * If it is the one that issued the connect, then it's only
5098c2654abSrjs * chance is to be the first TCB in the list. If it is the
5108c2654abSrjs * acceptor, then do the special_lookup to hash and find the
5118c2654abSrjs * real inp.
5128c2654abSrjs */
5138c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_ACCEPTING) {
5148c2654abSrjs /* to is peer addr, from is my addr */
5158c2654abSrjs stcb = sctp_tcb_special_locate(inp_p, remote, local,
5168c2654abSrjs netp);
5178c2654abSrjs if ((stcb != NULL) && (locked_tcb == NULL)){
5188c2654abSrjs /* we have a locked tcb, lower refcount */
5198c2654abSrjs SCTP_INP_WLOCK(inp);
5208c2654abSrjs SCTP_INP_DECR_REF(inp);
5218c2654abSrjs SCTP_INP_WUNLOCK(inp);
5228c2654abSrjs }
5238c2654abSrjs if (locked_tcb != NULL) {
5248c2654abSrjs SCTP_INP_RLOCK(locked_tcb->sctp_ep);
5258c2654abSrjs SCTP_TCB_LOCK(locked_tcb);
5268c2654abSrjs SCTP_INP_RUNLOCK(locked_tcb->sctp_ep);
5278c2654abSrjs if (stcb != NULL) {
5288c2654abSrjs SCTP_TCB_UNLOCK(stcb);
5298c2654abSrjs }
5308c2654abSrjs }
5318c2654abSrjs SCTP_INP_INFO_RUNLOCK();
5328c2654abSrjs return (stcb);
5338c2654abSrjs } else {
5348c2654abSrjs SCTP_INP_WLOCK(inp);
5358c2654abSrjs stcb = LIST_FIRST(&inp->sctp_asoc_list);
5368c2654abSrjs if (stcb == NULL) {
5378c2654abSrjs goto null_return;
5388c2654abSrjs }
5398c2654abSrjs SCTP_TCB_LOCK(stcb);
5408c2654abSrjs if (stcb->rport != rport) {
5418c2654abSrjs /* remote port does not match. */
5428c2654abSrjs SCTP_TCB_UNLOCK(stcb);
5438c2654abSrjs goto null_return;
5448c2654abSrjs }
5458c2654abSrjs /* now look at the list of remote addresses */
5468c2654abSrjs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5478c2654abSrjs if (sctp_cmpaddr(remote, rtcache_getdst(&net->ro))) {
5488c2654abSrjs /* found it */
5498c2654abSrjs if (netp != NULL) {
5508c2654abSrjs *netp = net;
5518c2654abSrjs }
5528c2654abSrjs if (locked_tcb == NULL) {
5538c2654abSrjs SCTP_INP_DECR_REF(inp);
5548c2654abSrjs }
5558c2654abSrjs SCTP_INP_WUNLOCK(inp);
5568c2654abSrjs SCTP_INP_INFO_RUNLOCK();
5578c2654abSrjs return (stcb);
5588c2654abSrjs }
5598c2654abSrjs }
5608c2654abSrjs SCTP_TCB_UNLOCK(stcb);
5618c2654abSrjs }
5628c2654abSrjs } else {
5638c2654abSrjs SCTP_INP_WLOCK(inp);
5648c2654abSrjs head = &inp->sctp_tcbhash[SCTP_PCBHASH_ALLADDR(rport,
5658c2654abSrjs inp->sctp_hashmark)];
5668c2654abSrjs if (head == NULL) {
5678c2654abSrjs goto null_return;
5688c2654abSrjs }
5698c2654abSrjs LIST_FOREACH(stcb, head, sctp_tcbhash) {
5708c2654abSrjs if (stcb->rport != rport) {
5718c2654abSrjs /* remote port does not match */
5728c2654abSrjs continue;
5738c2654abSrjs }
5748c2654abSrjs /* now look at the list of remote addresses */
5758c2654abSrjs SCTP_TCB_LOCK(stcb);
5768c2654abSrjs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5778c2654abSrjs if (sctp_cmpaddr(remote, rtcache_getdst(&net->ro))) {
5788c2654abSrjs /* found it */
5798c2654abSrjs if (netp != NULL) {
5808c2654abSrjs *netp = net;
5818c2654abSrjs }
5828c2654abSrjs if (locked_tcb == NULL) {
5838c2654abSrjs SCTP_INP_DECR_REF(inp);
5848c2654abSrjs }
5858c2654abSrjs SCTP_INP_WUNLOCK(inp);
5868c2654abSrjs SCTP_INP_INFO_RUNLOCK();
5878c2654abSrjs return (stcb);
5888c2654abSrjs }
5898c2654abSrjs }
5908c2654abSrjs SCTP_TCB_UNLOCK(stcb);
5918c2654abSrjs }
5928c2654abSrjs }
5938c2654abSrjs null_return:
5948c2654abSrjs /* clean up for returning null */
5958c2654abSrjs if (locked_tcb){
5968c2654abSrjs if (locked_tcb->sctp_ep != inp) {
5978c2654abSrjs SCTP_INP_RLOCK(locked_tcb->sctp_ep);
5988c2654abSrjs SCTP_TCB_LOCK(locked_tcb);
5998c2654abSrjs SCTP_INP_RUNLOCK(locked_tcb->sctp_ep);
6008c2654abSrjs } else {
6018c2654abSrjs SCTP_TCB_LOCK(locked_tcb);
6028c2654abSrjs }
6038c2654abSrjs }
6048c2654abSrjs SCTP_INP_WUNLOCK(inp);
6058c2654abSrjs SCTP_INP_INFO_RUNLOCK();
6068c2654abSrjs /* not found */
6078c2654abSrjs return (NULL);
6088c2654abSrjs }
6098c2654abSrjs
6108c2654abSrjs /*
6118c2654abSrjs * Find an association for a specific endpoint using the association id
6128c2654abSrjs * given out in the COMM_UP notification
6138c2654abSrjs */
6148c2654abSrjs struct sctp_tcb *
sctp_findassociation_ep_asocid(struct sctp_inpcb * inp,vaddr_t asoc_id)6158c2654abSrjs sctp_findassociation_ep_asocid(struct sctp_inpcb *inp, vaddr_t asoc_id)
6168c2654abSrjs {
6178c2654abSrjs /*
6188c2654abSrjs * Use my the assoc_id to find a endpoint
6198c2654abSrjs */
6208c2654abSrjs struct sctpasochead *head;
6218c2654abSrjs struct sctp_tcb *stcb;
6228c2654abSrjs u_int32_t vtag;
6238c2654abSrjs
6248c2654abSrjs if (asoc_id == 0 || inp == NULL) {
6258c2654abSrjs return (NULL);
6268c2654abSrjs }
6278c2654abSrjs SCTP_INP_INFO_RLOCK();
6288c2654abSrjs vtag = (u_int32_t)asoc_id;
6298c2654abSrjs head = &sctppcbinfo.sctp_asochash[SCTP_PCBHASH_ASOC(vtag,
6308c2654abSrjs sctppcbinfo.hashasocmark)];
6318c2654abSrjs if (head == NULL) {
6328c2654abSrjs /* invalid vtag */
6338c2654abSrjs SCTP_INP_INFO_RUNLOCK();
6348c2654abSrjs return (NULL);
6358c2654abSrjs }
6368c2654abSrjs LIST_FOREACH(stcb, head, sctp_asocs) {
6378c2654abSrjs SCTP_INP_RLOCK(stcb->sctp_ep);
6388c2654abSrjs SCTP_TCB_LOCK(stcb);
6398c2654abSrjs SCTP_INP_RUNLOCK(stcb->sctp_ep);
6408c2654abSrjs if (stcb->asoc.my_vtag == vtag) {
6418c2654abSrjs /* candidate */
6428c2654abSrjs if (inp != stcb->sctp_ep) {
6438c2654abSrjs /* some other guy has the
6448c2654abSrjs * same vtag active (vtag collision).
6458c2654abSrjs */
6468c2654abSrjs sctp_pegs[SCTP_VTAG_BOGUS]++;
6478c2654abSrjs SCTP_TCB_UNLOCK(stcb);
6488c2654abSrjs continue;
6498c2654abSrjs }
6508c2654abSrjs sctp_pegs[SCTP_VTAG_EXPR]++;
6518c2654abSrjs SCTP_INP_INFO_RUNLOCK();
6528c2654abSrjs return (stcb);
6538c2654abSrjs }
6548c2654abSrjs SCTP_TCB_UNLOCK(stcb);
6558c2654abSrjs }
6568c2654abSrjs SCTP_INP_INFO_RUNLOCK();
6578c2654abSrjs return (NULL);
6588c2654abSrjs }
6598c2654abSrjs
6608c2654abSrjs static struct sctp_inpcb *
sctp_endpoint_probe(struct sockaddr * nam,struct sctppcbhead * head,uint16_t lport)6618c2654abSrjs sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
6628c2654abSrjs uint16_t lport)
6638c2654abSrjs {
6648c2654abSrjs struct sctp_inpcb *inp;
6658c2654abSrjs struct sockaddr_in *sin;
6668c2654abSrjs struct sockaddr_in6 *sin6;
6678c2654abSrjs struct sctp_laddr *laddr;
6688c2654abSrjs
6698c2654abSrjs /* Endpoing probe expects
6708c2654abSrjs * that the INP_INFO is locked.
6718c2654abSrjs */
6728c2654abSrjs if (nam->sa_family == AF_INET) {
6738c2654abSrjs sin = (struct sockaddr_in *)nam;
6748c2654abSrjs sin6 = NULL;
6758c2654abSrjs } else if (nam->sa_family == AF_INET6) {
6768c2654abSrjs sin6 = (struct sockaddr_in6 *)nam;
6778c2654abSrjs sin = NULL;
6788c2654abSrjs } else {
6798c2654abSrjs /* unsupported family */
6808c2654abSrjs return (NULL);
6818c2654abSrjs }
6828c2654abSrjs if (head == NULL)
6838c2654abSrjs return (NULL);
6848c2654abSrjs
6858c2654abSrjs LIST_FOREACH(inp, head, sctp_hash) {
6868c2654abSrjs SCTP_INP_RLOCK(inp);
6878c2654abSrjs
6888c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) &&
6898c2654abSrjs (inp->sctp_lport == lport)) {
6908c2654abSrjs /* got it */
6918c2654abSrjs if ((nam->sa_family == AF_INET) &&
6928c2654abSrjs (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
6938c2654abSrjs (((struct in6pcb *)inp)->in6p_flags & IN6P_IPV6_V6ONLY)
6948c2654abSrjs ) {
6958c2654abSrjs /* IPv4 on a IPv6 socket with ONLY IPv6 set */
6968c2654abSrjs SCTP_INP_RUNLOCK(inp);
6978c2654abSrjs continue;
6988c2654abSrjs }
6998c2654abSrjs /* A V6 address and the endpoint is NOT bound V6 */
7008c2654abSrjs if (nam->sa_family == AF_INET6 &&
7018c2654abSrjs (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
7028c2654abSrjs SCTP_INP_RUNLOCK(inp);
7038c2654abSrjs continue;
7048c2654abSrjs }
7058c2654abSrjs SCTP_INP_RUNLOCK(inp);
7068c2654abSrjs return (inp);
7078c2654abSrjs }
7088c2654abSrjs SCTP_INP_RUNLOCK(inp);
7098c2654abSrjs }
7108c2654abSrjs
7118c2654abSrjs if ((nam->sa_family == AF_INET) &&
7128c2654abSrjs (sin->sin_addr.s_addr == INADDR_ANY)) {
7138c2654abSrjs /* Can't hunt for one that has no address specified */
7148c2654abSrjs return (NULL);
7158c2654abSrjs } else if ((nam->sa_family == AF_INET6) &&
7168c2654abSrjs (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))) {
7178c2654abSrjs /* Can't hunt for one that has no address specified */
7188c2654abSrjs return (NULL);
7198c2654abSrjs }
7208c2654abSrjs /*
7218c2654abSrjs * ok, not bound to all so see if we can find a EP bound to this
7228c2654abSrjs * address.
7238c2654abSrjs */
7248c2654abSrjs #ifdef SCTP_DEBUG
7258c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
7268c2654abSrjs printf("Ok, there is NO bound-all available for port:%x\n", ntohs(lport));
7278c2654abSrjs }
7288c2654abSrjs #endif
7298c2654abSrjs LIST_FOREACH(inp, head, sctp_hash) {
7308c2654abSrjs SCTP_INP_RLOCK(inp);
7318c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL)) {
7328c2654abSrjs SCTP_INP_RUNLOCK(inp);
7338c2654abSrjs continue;
7348c2654abSrjs }
7358c2654abSrjs /*
7368c2654abSrjs * Ok this could be a likely candidate, look at all of
7378c2654abSrjs * its addresses
7388c2654abSrjs */
7398c2654abSrjs if (inp->sctp_lport != lport) {
7408c2654abSrjs SCTP_INP_RUNLOCK(inp);
7418c2654abSrjs continue;
7428c2654abSrjs }
7438c2654abSrjs #ifdef SCTP_DEBUG
7448c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
745a136e22aSandvar printf("Ok, found matching local port\n");
7468c2654abSrjs }
7478c2654abSrjs #endif
7488c2654abSrjs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
7498c2654abSrjs if (laddr->ifa == NULL) {
7508c2654abSrjs #ifdef SCTP_DEBUG
7518c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
7528c2654abSrjs printf("An ounce of prevention is worth a pound of cure\n");
7538c2654abSrjs }
7548c2654abSrjs #endif
7558c2654abSrjs continue;
7568c2654abSrjs }
7578c2654abSrjs #ifdef SCTP_DEBUG
7588c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
7598c2654abSrjs printf("Ok laddr->ifa:%p is possible, ",
7608c2654abSrjs laddr->ifa);
7618c2654abSrjs }
7628c2654abSrjs #endif
7638c2654abSrjs if (laddr->ifa->ifa_addr == NULL) {
7648c2654abSrjs #ifdef SCTP_DEBUG
7658c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
7668c2654abSrjs printf("Huh IFA as an ifa_addr=NULL, ");
7678c2654abSrjs }
7688c2654abSrjs #endif
7698c2654abSrjs continue;
7708c2654abSrjs }
7718c2654abSrjs #ifdef SCTP_DEBUG
7728c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
7738c2654abSrjs printf("Ok laddr->ifa:%p is possible, ",
7748c2654abSrjs laddr->ifa->ifa_addr);
7758c2654abSrjs sctp_print_address(laddr->ifa->ifa_addr);
7768c2654abSrjs printf("looking for ");
7778c2654abSrjs sctp_print_address(nam);
7788c2654abSrjs }
7798c2654abSrjs #endif
7808c2654abSrjs if (laddr->ifa->ifa_addr->sa_family == nam->sa_family) {
7818c2654abSrjs /* possible, see if it matches */
7828c2654abSrjs struct sockaddr_in *intf_addr;
7838c2654abSrjs intf_addr = (struct sockaddr_in *)
7848c2654abSrjs laddr->ifa->ifa_addr;
7858c2654abSrjs if (nam->sa_family == AF_INET) {
7868c2654abSrjs if (sin->sin_addr.s_addr ==
7878c2654abSrjs intf_addr->sin_addr.s_addr) {
7888c2654abSrjs #ifdef SCTP_DEBUG
7898c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
7908c2654abSrjs printf("YES, return ep:%p\n", inp);
7918c2654abSrjs }
7928c2654abSrjs #endif
7938c2654abSrjs SCTP_INP_RUNLOCK(inp);
7948c2654abSrjs return (inp);
7958c2654abSrjs }
7968c2654abSrjs } else if (nam->sa_family == AF_INET6) {
7978c2654abSrjs struct sockaddr_in6 *intf_addr6;
7988c2654abSrjs intf_addr6 = (struct sockaddr_in6 *)
7998c2654abSrjs laddr->ifa->ifa_addr;
8008c2654abSrjs if (SCTP6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
8018c2654abSrjs &intf_addr6->sin6_addr)) {
8028c2654abSrjs #ifdef SCTP_DEBUG
8038c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
8048c2654abSrjs printf("YES, return ep:%p\n", inp);
8058c2654abSrjs }
8068c2654abSrjs #endif
8078c2654abSrjs SCTP_INP_RUNLOCK(inp);
8088c2654abSrjs return (inp);
8098c2654abSrjs }
8108c2654abSrjs }
8118c2654abSrjs }
8128c2654abSrjs SCTP_INP_RUNLOCK(inp);
8138c2654abSrjs }
8148c2654abSrjs }
8158c2654abSrjs #ifdef SCTP_DEBUG
8168c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
8178c2654abSrjs printf("NO, Falls out to NULL\n");
8188c2654abSrjs }
8198c2654abSrjs #endif
8208c2654abSrjs return (NULL);
8218c2654abSrjs }
8228c2654abSrjs
8238c2654abSrjs
8248c2654abSrjs struct sctp_inpcb *
sctp_pcb_findep(struct sockaddr * nam,int find_tcp_pool,int have_lock)8258c2654abSrjs sctp_pcb_findep(struct sockaddr *nam, int find_tcp_pool, int have_lock)
8268c2654abSrjs {
8278c2654abSrjs /*
8288c2654abSrjs * First we check the hash table to see if someone has this port
8298c2654abSrjs * bound with just the port.
8308c2654abSrjs */
8318c2654abSrjs struct sctp_inpcb *inp;
8328c2654abSrjs struct sctppcbhead *head;
8338c2654abSrjs int lport;
8348c2654abSrjs #ifdef SCTP_DEBUG
8358c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
8368c2654abSrjs printf("Looking for endpoint %d :",
8378c2654abSrjs ntohs(((struct sockaddr_in *)nam)->sin_port));
8388c2654abSrjs sctp_print_address(nam);
8398c2654abSrjs }
8408c2654abSrjs #endif
8418c2654abSrjs if (nam->sa_family == AF_INET) {
8428c2654abSrjs lport = ((struct sockaddr_in *)nam)->sin_port;
8438c2654abSrjs } else if (nam->sa_family == AF_INET6) {
8448c2654abSrjs lport = ((struct sockaddr_in6 *)nam)->sin6_port;
8458c2654abSrjs } else {
8468c2654abSrjs /* unsupported family */
8478c2654abSrjs return (NULL);
8488c2654abSrjs }
8498c2654abSrjs /*
8508c2654abSrjs * I could cheat here and just cast to one of the types but we will
8518c2654abSrjs * do it right. It also provides the check against an Unsupported
8528c2654abSrjs * type too.
8538c2654abSrjs */
8548c2654abSrjs /* Find the head of the ALLADDR chain */
8558c2654abSrjs if (have_lock == 0) {
8568c2654abSrjs SCTP_INP_INFO_RLOCK();
8578c2654abSrjs }
8588c2654abSrjs head = &sctppcbinfo.sctp_ephash[SCTP_PCBHASH_ALLADDR(lport,
8598c2654abSrjs sctppcbinfo.hashmark)];
8608c2654abSrjs #ifdef SCTP_DEBUG
8618c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
8628c2654abSrjs printf("Main hash to lookup at head:%p\n", head);
8638c2654abSrjs }
8648c2654abSrjs #endif
8658c2654abSrjs inp = sctp_endpoint_probe(nam, head, lport);
8668c2654abSrjs
8678c2654abSrjs /*
8688c2654abSrjs * If the TCP model exists it could be that the main listening
8698c2654abSrjs * endpoint is gone but there exists a connected socket for this
8708c2654abSrjs * guy yet. If so we can return the first one that we find. This
8718c2654abSrjs * may NOT be the correct one but the sctp_findassociation_ep_addr
8728c2654abSrjs * has further code to look at all TCP models.
8738c2654abSrjs */
8748c2654abSrjs if (inp == NULL && find_tcp_pool) {
8758c2654abSrjs unsigned int i;
8768c2654abSrjs #ifdef SCTP_DEBUG
8778c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
8788c2654abSrjs printf("EP was NULL and TCP model is supported\n");
8798c2654abSrjs }
8808c2654abSrjs #endif
8818c2654abSrjs for (i = 0; i < sctppcbinfo.hashtblsize; i++) {
8828c2654abSrjs /*
8838c2654abSrjs * This is real gross, but we do NOT have a remote
8848c2654abSrjs * port at this point depending on who is calling. We
8858c2654abSrjs * must therefore look for ANY one that matches our
8868c2654abSrjs * local port :/
8878c2654abSrjs */
8888c2654abSrjs head = &sctppcbinfo.sctp_tcpephash[i];
8898c2654abSrjs if (LIST_FIRST(head)) {
8908c2654abSrjs inp = sctp_endpoint_probe(nam, head, lport);
8918c2654abSrjs if (inp) {
8928c2654abSrjs /* Found one */
8938c2654abSrjs break;
8948c2654abSrjs }
8958c2654abSrjs }
8968c2654abSrjs }
8978c2654abSrjs }
8988c2654abSrjs #ifdef SCTP_DEBUG
8998c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
9008c2654abSrjs printf("EP to return is %p\n", inp);
9018c2654abSrjs }
9028c2654abSrjs #endif
9038c2654abSrjs if (have_lock == 0) {
9048c2654abSrjs if (inp) {
9058c2654abSrjs SCTP_INP_WLOCK(inp);
9068c2654abSrjs SCTP_INP_INCR_REF(inp);
9078c2654abSrjs SCTP_INP_WUNLOCK(inp);
9088c2654abSrjs }
9098c2654abSrjs SCTP_INP_INFO_RUNLOCK();
9108c2654abSrjs } else {
9118c2654abSrjs if (inp) {
9128c2654abSrjs SCTP_INP_WLOCK(inp);
9138c2654abSrjs SCTP_INP_INCR_REF(inp);
9148c2654abSrjs SCTP_INP_WUNLOCK(inp);
9158c2654abSrjs }
9168c2654abSrjs }
9178c2654abSrjs return (inp);
9188c2654abSrjs }
9198c2654abSrjs
9208c2654abSrjs /*
9218c2654abSrjs * Find an association for an endpoint with the pointer to whom you want
9228c2654abSrjs * to send to and the endpoint pointer. The address can be IPv4 or IPv6.
9238c2654abSrjs * We may need to change the *to to some other struct like a mbuf...
9248c2654abSrjs */
9258c2654abSrjs struct sctp_tcb *
sctp_findassociation_addr_sa(struct sockaddr * to,struct sockaddr * from,struct sctp_inpcb ** inp_p,struct sctp_nets ** netp,int find_tcp_pool)9268c2654abSrjs sctp_findassociation_addr_sa(struct sockaddr *to, struct sockaddr *from,
9278c2654abSrjs struct sctp_inpcb **inp_p, struct sctp_nets **netp, int find_tcp_pool)
9288c2654abSrjs {
9298c2654abSrjs struct sctp_inpcb *inp;
9308c2654abSrjs struct sctp_tcb *retval;
9318c2654abSrjs
9328c2654abSrjs SCTP_INP_INFO_RLOCK();
9338c2654abSrjs if (find_tcp_pool) {
9348c2654abSrjs if (inp_p != NULL) {
9358c2654abSrjs retval = sctp_tcb_special_locate(inp_p, from, to, netp);
9368c2654abSrjs } else {
9378c2654abSrjs retval = sctp_tcb_special_locate(&inp, from, to, netp);
9388c2654abSrjs }
9398c2654abSrjs if (retval != NULL) {
9408c2654abSrjs SCTP_INP_INFO_RUNLOCK();
9418c2654abSrjs return (retval);
9428c2654abSrjs }
9438c2654abSrjs }
9448c2654abSrjs inp = sctp_pcb_findep(to, 0, 1);
9458c2654abSrjs if (inp_p != NULL) {
9468c2654abSrjs *inp_p = inp;
9478c2654abSrjs }
9488c2654abSrjs SCTP_INP_INFO_RUNLOCK();
9498c2654abSrjs
9508c2654abSrjs if (inp == NULL) {
9518c2654abSrjs return (NULL);
9528c2654abSrjs }
9538c2654abSrjs
9548c2654abSrjs /*
9558c2654abSrjs * ok, we have an endpoint, now lets find the assoc for it (if any)
9568c2654abSrjs * we now place the source address or from in the to of the find
9578c2654abSrjs * endpoint call. Since in reality this chain is used from the
9588c2654abSrjs * inbound packet side.
9598c2654abSrjs */
9608c2654abSrjs if (inp_p != NULL) {
9618c2654abSrjs return (sctp_findassociation_ep_addr(inp_p, from, netp, to, NULL));
9628c2654abSrjs } else {
9638c2654abSrjs return (sctp_findassociation_ep_addr(&inp, from, netp, to, NULL));
9648c2654abSrjs }
9658c2654abSrjs }
9668c2654abSrjs
9678c2654abSrjs
9688c2654abSrjs /*
9698c2654abSrjs * This routine will grub through the mbuf that is a INIT or INIT-ACK and
9708c2654abSrjs * find all addresses that the sender has specified in any address list.
9718c2654abSrjs * Each address will be used to lookup the TCB and see if one exits.
9728c2654abSrjs */
9738c2654abSrjs static struct sctp_tcb *
sctp_findassociation_special_addr(struct mbuf * m,int iphlen,int offset,struct sctphdr * sh,struct sctp_inpcb ** inp_p,struct sctp_nets ** netp,struct sockaddr * dest)9748c2654abSrjs sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset,
9758c2654abSrjs struct sctphdr *sh, struct sctp_inpcb **inp_p, struct sctp_nets **netp,
9768c2654abSrjs struct sockaddr *dest)
9778c2654abSrjs {
9788c2654abSrjs struct sockaddr_in sin4;
9798c2654abSrjs struct sockaddr_in6 sin6;
9808c2654abSrjs struct sctp_paramhdr *phdr, parm_buf;
9818c2654abSrjs struct sctp_tcb *retval;
9828c2654abSrjs u_int32_t ptype, plen;
9838c2654abSrjs
9848c2654abSrjs memset(&sin4, 0, sizeof(sin4));
9858c2654abSrjs memset(&sin6, 0, sizeof(sin6));
9868c2654abSrjs sin4.sin_len = sizeof(sin4);
9878c2654abSrjs sin4.sin_family = AF_INET;
9888c2654abSrjs sin4.sin_port = sh->src_port;
9898c2654abSrjs sin6.sin6_len = sizeof(sin6);
9908c2654abSrjs sin6.sin6_family = AF_INET6;
9918c2654abSrjs sin6.sin6_port = sh->src_port;
9928c2654abSrjs
9938c2654abSrjs retval = NULL;
9948c2654abSrjs offset += sizeof(struct sctp_init_chunk);
9958c2654abSrjs
9968c2654abSrjs phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf));
9978c2654abSrjs while (phdr != NULL) {
9988c2654abSrjs /* now we must see if we want the parameter */
9998c2654abSrjs ptype = ntohs(phdr->param_type);
10008c2654abSrjs plen = ntohs(phdr->param_length);
10018c2654abSrjs if (plen == 0) {
10028c2654abSrjs #ifdef SCTP_DEBUG
10038c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
10048c2654abSrjs printf("sctp_findassociation_special_addr: Impossible length in parameter\n");
10058c2654abSrjs }
10068c2654abSrjs #endif /* SCTP_DEBUG */
10078c2654abSrjs break;
10088c2654abSrjs }
10098c2654abSrjs if (ptype == SCTP_IPV4_ADDRESS &&
10108c2654abSrjs plen == sizeof(struct sctp_ipv4addr_param)) {
10118c2654abSrjs /* Get the rest of the address */
10128c2654abSrjs struct sctp_ipv4addr_param ip4_parm, *p4;
10138c2654abSrjs
10148c2654abSrjs phdr = sctp_get_next_param(m, offset,
10158c2654abSrjs (struct sctp_paramhdr *)&ip4_parm, plen);
10168c2654abSrjs if (phdr == NULL) {
10178c2654abSrjs return (NULL);
10188c2654abSrjs }
10198c2654abSrjs p4 = (struct sctp_ipv4addr_param *)phdr;
10208c2654abSrjs memcpy(&sin4.sin_addr, &p4->addr, sizeof(p4->addr));
10218c2654abSrjs /* look it up */
10228c2654abSrjs retval = sctp_findassociation_ep_addr(inp_p,
10238c2654abSrjs (struct sockaddr *)&sin4, netp, dest, NULL);
10248c2654abSrjs if (retval != NULL) {
10258c2654abSrjs return (retval);
10268c2654abSrjs }
10278c2654abSrjs } else if (ptype == SCTP_IPV6_ADDRESS &&
10288c2654abSrjs plen == sizeof(struct sctp_ipv6addr_param)) {
10298c2654abSrjs /* Get the rest of the address */
10308c2654abSrjs struct sctp_ipv6addr_param ip6_parm, *p6;
10318c2654abSrjs
10328c2654abSrjs phdr = sctp_get_next_param(m, offset,
10338c2654abSrjs (struct sctp_paramhdr *)&ip6_parm, plen);
10348c2654abSrjs if (phdr == NULL) {
10358c2654abSrjs return (NULL);
10368c2654abSrjs }
10378c2654abSrjs p6 = (struct sctp_ipv6addr_param *)phdr;
10388c2654abSrjs memcpy(&sin6.sin6_addr, &p6->addr, sizeof(p6->addr));
10398c2654abSrjs /* look it up */
10408c2654abSrjs retval = sctp_findassociation_ep_addr(inp_p,
10418c2654abSrjs (struct sockaddr *)&sin6, netp, dest, NULL);
10428c2654abSrjs if (retval != NULL) {
10438c2654abSrjs return (retval);
10448c2654abSrjs }
10458c2654abSrjs }
10468c2654abSrjs offset += SCTP_SIZE32(plen);
10478c2654abSrjs phdr = sctp_get_next_param(m, offset, &parm_buf,
10488c2654abSrjs sizeof(parm_buf));
10498c2654abSrjs }
10508c2654abSrjs return (NULL);
10518c2654abSrjs }
10528c2654abSrjs
10538c2654abSrjs static struct sctp_tcb *
sctp_findassoc_by_vtag(struct sockaddr * from,uint32_t vtag,struct sctp_inpcb ** inp_p,struct sctp_nets ** netp,uint16_t rport,uint16_t lport)10548c2654abSrjs sctp_findassoc_by_vtag(struct sockaddr *from, uint32_t vtag,
10558c2654abSrjs struct sctp_inpcb **inp_p, struct sctp_nets **netp, uint16_t rport,
10568c2654abSrjs uint16_t lport)
10578c2654abSrjs {
10588c2654abSrjs /*
10598c2654abSrjs * Use my vtag to hash. If we find it we then verify the source addr
10608c2654abSrjs * is in the assoc. If all goes well we save a bit on rec of a packet.
10618c2654abSrjs */
10628c2654abSrjs struct sctpasochead *head;
10638c2654abSrjs struct sctp_nets *net;
10648c2654abSrjs struct sctp_tcb *stcb;
10658c2654abSrjs
10668c2654abSrjs SCTP_INP_INFO_RLOCK();
10678c2654abSrjs head = &sctppcbinfo.sctp_asochash[SCTP_PCBHASH_ASOC(vtag,
10688c2654abSrjs sctppcbinfo.hashasocmark)];
10698c2654abSrjs if (head == NULL) {
10708c2654abSrjs /* invalid vtag */
10718c2654abSrjs SCTP_INP_INFO_RUNLOCK();
10728c2654abSrjs return (NULL);
10738c2654abSrjs }
10748c2654abSrjs LIST_FOREACH(stcb, head, sctp_asocs) {
10758c2654abSrjs SCTP_INP_RLOCK(stcb->sctp_ep);
10768c2654abSrjs SCTP_TCB_LOCK(stcb);
10778c2654abSrjs SCTP_INP_RUNLOCK(stcb->sctp_ep);
10788c2654abSrjs if (stcb->asoc.my_vtag == vtag) {
10798c2654abSrjs /* candidate */
10808c2654abSrjs if (stcb->rport != rport) {
10818c2654abSrjs /*
10828c2654abSrjs * we could remove this if vtags are unique
10838c2654abSrjs * across the system.
10848c2654abSrjs */
10858c2654abSrjs SCTP_TCB_UNLOCK(stcb);
10868c2654abSrjs continue;
10878c2654abSrjs }
10888c2654abSrjs if (stcb->sctp_ep->sctp_lport != lport) {
10898c2654abSrjs /*
10908c2654abSrjs * we could remove this if vtags are unique
10918c2654abSrjs * across the system.
10928c2654abSrjs */
10938c2654abSrjs SCTP_TCB_UNLOCK(stcb);
10948c2654abSrjs continue;
10958c2654abSrjs }
10968c2654abSrjs net = sctp_findnet(stcb, from);
10978c2654abSrjs if (net) {
10988c2654abSrjs /* yep its him. */
10998c2654abSrjs *netp = net;
11008c2654abSrjs sctp_pegs[SCTP_VTAG_EXPR]++;
11018c2654abSrjs *inp_p = stcb->sctp_ep;
11028c2654abSrjs SCTP_INP_INFO_RUNLOCK();
11038c2654abSrjs return (stcb);
11048c2654abSrjs } else {
11058c2654abSrjs /* not him, this should only
11068c2654abSrjs * happen in rare cases so
11078c2654abSrjs * I peg it.
11088c2654abSrjs */
11098c2654abSrjs sctp_pegs[SCTP_VTAG_BOGUS]++;
11108c2654abSrjs }
11118c2654abSrjs }
11128c2654abSrjs SCTP_TCB_UNLOCK(stcb);
11138c2654abSrjs }
11148c2654abSrjs SCTP_INP_INFO_RUNLOCK();
11158c2654abSrjs return (NULL);
11168c2654abSrjs }
11178c2654abSrjs
11188c2654abSrjs /*
11198c2654abSrjs * Find an association with the pointer to the inbound IP packet. This
11208c2654abSrjs * can be a IPv4 or IPv6 packet.
11218c2654abSrjs */
11228c2654abSrjs struct sctp_tcb *
sctp_findassociation_addr(struct mbuf * m,int iphlen,int offset,struct sctphdr * sh,struct sctp_chunkhdr * ch,struct sctp_inpcb ** inp_p,struct sctp_nets ** netp)11238c2654abSrjs sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset,
11248c2654abSrjs struct sctphdr *sh, struct sctp_chunkhdr *ch,
11258c2654abSrjs struct sctp_inpcb **inp_p, struct sctp_nets **netp)
11268c2654abSrjs {
11278c2654abSrjs int find_tcp_pool;
11288c2654abSrjs struct ip *iph;
11298c2654abSrjs struct sctp_tcb *retval;
11308c2654abSrjs struct sockaddr_storage to_store, from_store;
11318c2654abSrjs struct sockaddr *to = (struct sockaddr *)&to_store;
11328c2654abSrjs struct sockaddr *from = (struct sockaddr *)&from_store;
11338c2654abSrjs struct sctp_inpcb *inp;
11348c2654abSrjs
11358c2654abSrjs
11368c2654abSrjs iph = mtod(m, struct ip *);
11378c2654abSrjs if (iph->ip_v == IPVERSION) {
11388c2654abSrjs /* its IPv4 */
11398c2654abSrjs struct sockaddr_in *to4, *from4;
11408c2654abSrjs
11418c2654abSrjs to4 = (struct sockaddr_in *)&to_store;
11428c2654abSrjs from4 = (struct sockaddr_in *)&from_store;
11438c2654abSrjs memset(to4, 0, sizeof(*to4));
11448c2654abSrjs memset(from4, 0, sizeof(*from4));
11458c2654abSrjs from4->sin_family = to4->sin_family = AF_INET;
11468c2654abSrjs from4->sin_len = to4->sin_len = sizeof(struct sockaddr_in);
11478c2654abSrjs from4->sin_addr.s_addr = iph->ip_src.s_addr;
11488c2654abSrjs to4->sin_addr.s_addr = iph->ip_dst.s_addr ;
11498c2654abSrjs from4->sin_port = sh->src_port;
11508c2654abSrjs to4->sin_port = sh->dest_port;
11518c2654abSrjs } else if (iph->ip_v == (IPV6_VERSION >> 4)) {
11528c2654abSrjs /* its IPv6 */
11538c2654abSrjs struct ip6_hdr *ip6;
11548c2654abSrjs struct sockaddr_in6 *to6, *from6;
11558c2654abSrjs
11568c2654abSrjs ip6 = mtod(m, struct ip6_hdr *);
11578c2654abSrjs to6 = (struct sockaddr_in6 *)&to_store;
11588c2654abSrjs from6 = (struct sockaddr_in6 *)&from_store;
11598c2654abSrjs memset(to6, 0, sizeof(*to6));
11608c2654abSrjs memset(from6, 0, sizeof(*from6));
11618c2654abSrjs from6->sin6_family = to6->sin6_family = AF_INET6;
11628c2654abSrjs from6->sin6_len = to6->sin6_len = sizeof(struct sockaddr_in6);
11638c2654abSrjs from6->sin6_addr = ip6->ip6_src;
11648c2654abSrjs to6->sin6_addr = ip6->ip6_dst;
11658c2654abSrjs from6->sin6_port = sh->src_port;
11668c2654abSrjs to6->sin6_port = sh->dest_port;
11678c2654abSrjs /* Get the scopes in properly to the sin6 addr's */
11688c2654abSrjs #if defined(SCTP_BASE_FREEBSD) || defined(__APPLE__)
11698c2654abSrjs /* We probably don't need this operation (jinmei@kame) */
11708c2654abSrjs (void)in6_recoverscope(to6, &to6->sin6_addr, NULL);
11718c2654abSrjs (void)in6_embedscope(&to6->sin6_addr, to6, NULL, NULL);
11728c2654abSrjs
11738c2654abSrjs (void)in6_recoverscope(from6, &from6->sin6_addr, NULL);
11748c2654abSrjs (void)in6_embedscope(&from6->sin6_addr, from6, NULL, NULL);
11758c2654abSrjs #endif
11768c2654abSrjs } else {
11778c2654abSrjs /* Currently not supported. */
11788c2654abSrjs return (NULL);
11798c2654abSrjs }
11808c2654abSrjs #ifdef SCTP_DEBUG
11818c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
11828c2654abSrjs printf("Looking for port %d address :",
11838c2654abSrjs ntohs(((struct sockaddr_in *)to)->sin_port));
11848c2654abSrjs sctp_print_address(to);
11858c2654abSrjs printf("From for port %d address :",
11868c2654abSrjs ntohs(((struct sockaddr_in *)from)->sin_port));
11878c2654abSrjs sctp_print_address(from);
11888c2654abSrjs }
11898c2654abSrjs #endif
11908c2654abSrjs
11918c2654abSrjs if (sh->v_tag) {
11928c2654abSrjs /* we only go down this path if vtag is non-zero */
11938c2654abSrjs retval = sctp_findassoc_by_vtag(from, ntohl(sh->v_tag),
11948c2654abSrjs inp_p, netp, sh->src_port, sh->dest_port);
11958c2654abSrjs if (retval) {
11968c2654abSrjs return (retval);
11978c2654abSrjs }
11988c2654abSrjs }
11998c2654abSrjs find_tcp_pool = 0;
12008c2654abSrjs if ((ch->chunk_type != SCTP_INITIATION) &&
12018c2654abSrjs (ch->chunk_type != SCTP_INITIATION_ACK) &&
12028c2654abSrjs (ch->chunk_type != SCTP_COOKIE_ACK) &&
12038c2654abSrjs (ch->chunk_type != SCTP_COOKIE_ECHO)) {
12048c2654abSrjs /* Other chunk types go to the tcp pool. */
12058c2654abSrjs find_tcp_pool = 1;
12068c2654abSrjs }
12078c2654abSrjs if (inp_p) {
12088c2654abSrjs retval = sctp_findassociation_addr_sa(to, from, inp_p, netp,
12098c2654abSrjs find_tcp_pool);
12108c2654abSrjs inp = *inp_p;
12118c2654abSrjs } else {
12128c2654abSrjs retval = sctp_findassociation_addr_sa(to, from, &inp, netp,
12138c2654abSrjs find_tcp_pool);
12148c2654abSrjs }
12158c2654abSrjs #ifdef SCTP_DEBUG
12168c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
12178c2654abSrjs printf("retval:%p inp:%p\n", retval, inp);
12188c2654abSrjs }
12198c2654abSrjs #endif
12208c2654abSrjs if (retval == NULL && inp) {
12218c2654abSrjs /* Found a EP but not this address */
12228c2654abSrjs #ifdef SCTP_DEBUG
12238c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
12248c2654abSrjs printf("Found endpoint %p but no asoc - ep state:%x\n",
12258c2654abSrjs inp, inp->sctp_flags);
12268c2654abSrjs }
12278c2654abSrjs #endif
12288c2654abSrjs if ((ch->chunk_type == SCTP_INITIATION) ||
12298c2654abSrjs (ch->chunk_type == SCTP_INITIATION_ACK)) {
12308c2654abSrjs /*
12318c2654abSrjs * special hook, we do NOT return linp or an
12328c2654abSrjs * association that is linked to an existing
12338c2654abSrjs * association that is under the TCP pool (i.e. no
12348c2654abSrjs * listener exists). The endpoint finding routine
12358c2654abSrjs * will always find a listner before examining the
12368c2654abSrjs * TCP pool.
12378c2654abSrjs */
12388c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) {
12398c2654abSrjs #ifdef SCTP_DEBUG
12408c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
12418c2654abSrjs printf("Gak, its in the TCP pool... return NULL");
12428c2654abSrjs }
12438c2654abSrjs #endif
12448c2654abSrjs if (inp_p) {
12458c2654abSrjs *inp_p = NULL;
12468c2654abSrjs }
12478c2654abSrjs return (NULL);
12488c2654abSrjs }
12498c2654abSrjs #ifdef SCTP_DEBUG
12508c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
12518c2654abSrjs printf("Now doing SPECIAL find\n");
12528c2654abSrjs }
12538c2654abSrjs #endif
12548c2654abSrjs retval = sctp_findassociation_special_addr(m, iphlen,
12558c2654abSrjs offset, sh, inp_p, netp, to);
12568c2654abSrjs }
12578c2654abSrjs }
12588c2654abSrjs #ifdef SCTP_DEBUG
12598c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
12608c2654abSrjs printf("retval is %p\n", retval);
12618c2654abSrjs }
12628c2654abSrjs #endif
12638c2654abSrjs return (retval);
12648c2654abSrjs }
12658c2654abSrjs
12668c2654abSrjs extern int sctp_max_burst_default;
12678c2654abSrjs
12688c2654abSrjs extern unsigned int sctp_delayed_sack_time_default;
12698c2654abSrjs extern unsigned int sctp_heartbeat_interval_default;
12708c2654abSrjs extern unsigned int sctp_pmtu_raise_time_default;
12718c2654abSrjs extern unsigned int sctp_shutdown_guard_time_default;
12728c2654abSrjs extern unsigned int sctp_secret_lifetime_default;
12738c2654abSrjs
12748c2654abSrjs extern unsigned int sctp_rto_max_default;
12758c2654abSrjs extern unsigned int sctp_rto_min_default;
12768c2654abSrjs extern unsigned int sctp_rto_initial_default;
12778c2654abSrjs extern unsigned int sctp_init_rto_max_default;
12788c2654abSrjs extern unsigned int sctp_valid_cookie_life_default;
12798c2654abSrjs extern unsigned int sctp_init_rtx_max_default;
12808c2654abSrjs extern unsigned int sctp_assoc_rtx_max_default;
12818c2654abSrjs extern unsigned int sctp_path_rtx_max_default;
12828c2654abSrjs extern unsigned int sctp_nr_outgoing_streams_default;
12838c2654abSrjs
12848c2654abSrjs /*
12858c2654abSrjs * allocate a sctp_inpcb and setup a temporary binding to a port/all
12868c2654abSrjs * addresses. This way if we don't get a bind we by default pick a ephemeral
12878c2654abSrjs * port with all addresses bound.
12888c2654abSrjs */
12898c2654abSrjs int
sctp_inpcb_alloc(struct socket * so)12908c2654abSrjs sctp_inpcb_alloc(struct socket *so)
12918c2654abSrjs {
12928c2654abSrjs /*
12938c2654abSrjs * we get called when a new endpoint starts up. We need to allocate
12948c2654abSrjs * the sctp_inpcb structure from the zone and init it. Mark it as
12958c2654abSrjs * unbound and find a port that we can use as an ephemeral with
12968c2654abSrjs * INADDR_ANY. If the user binds later no problem we can then add
12978c2654abSrjs * in the specific addresses. And setup the default parameters for
12988c2654abSrjs * the EP.
12998c2654abSrjs */
13008c2654abSrjs int i, error;
1301b08ca904Srjs struct sctp_inpcb *inp;
1302b08ca904Srjs #ifdef DEBUG
1303b08ca904Srjs struct sctp_inpcb *n_inp;
1304b08ca904Srjs #endif
130501b82b52Srjs #ifdef IPSEC
130601b82b52Srjs struct inpcbpolicy *pcb_sp = NULL;
130701b82b52Srjs #endif
13088c2654abSrjs struct sctp_pcb *m;
13098c2654abSrjs struct timeval time;
13108c2654abSrjs
13118c2654abSrjs error = 0;
13128c2654abSrjs
13138c2654abSrjs /* Hack alert:
13148c2654abSrjs *
13158c2654abSrjs * This code audits the entire INP list to see if
13168c2654abSrjs * any ep's that are in the GONE state are now
13178c2654abSrjs * all free. This should not happen really since when
13188c2654abSrjs * the last association if freed we should end up deleting
13198c2654abSrjs * the inpcb. This code including the locks should
13208c2654abSrjs * be taken out ... since the last set of fixes I
13218c2654abSrjs * have not seen the "Found a GONE on list" has not
13228c2654abSrjs * came out. But i am paranoid and we will leave this
1323cdc507f0Sandvar * in at the cost of efficiency on allocation of PCB's.
13248c2654abSrjs * Probably we should move this to the invariant
13258c2654abSrjs * compile options
13268c2654abSrjs */
1327b08ca904Srjs #ifdef DEBUG
13288c2654abSrjs SCTP_INP_INFO_RLOCK();
13298c2654abSrjs inp = LIST_FIRST(&sctppcbinfo.listhead);
13308c2654abSrjs while (inp) {
13318c2654abSrjs n_inp = LIST_NEXT(inp, sctp_list);
13328c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
13338c2654abSrjs if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) {
13348c2654abSrjs /* finish the job now */
13358c2654abSrjs printf("Found a GONE on list\n");
13368c2654abSrjs SCTP_INP_INFO_RUNLOCK();
13378c2654abSrjs sctp_inpcb_free(inp, 1);
13388c2654abSrjs SCTP_INP_INFO_RLOCK();
13398c2654abSrjs }
13408c2654abSrjs }
13418c2654abSrjs inp = n_inp;
13428c2654abSrjs }
13438c2654abSrjs SCTP_INP_INFO_RUNLOCK();
1344b08ca904Srjs #endif /* DEBUG */
13458c2654abSrjs
13468c2654abSrjs SCTP_INP_INFO_WLOCK();
13478c2654abSrjs inp = (struct sctp_inpcb *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_ep);
13488c2654abSrjs if (inp == NULL) {
13498c2654abSrjs printf("Out of SCTP-INPCB structures - no resources\n");
13508c2654abSrjs SCTP_INP_INFO_WUNLOCK();
13518c2654abSrjs return (ENOBUFS);
13528c2654abSrjs }
13538c2654abSrjs
13548c2654abSrjs /* zap it */
13558c2654abSrjs memset(inp, 0, sizeof(*inp));
13568c2654abSrjs
13578c2654abSrjs /* setup socket pointers */
13588c2654abSrjs inp->sctp_socket = so;
13598c2654abSrjs
13608c2654abSrjs /* setup inpcb socket too */
13618c2654abSrjs inp->ip_inp.inp.inp_socket = so;
13628c2654abSrjs inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
13638c2654abSrjs #ifdef IPSEC
136401b82b52Srjs if (ipsec_enabled) {
13658c2654abSrjs error = ipsec_init_pcbpolicy(so, &pcb_sp);
13668c2654abSrjs if (error != 0) {
13678c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp);
13688c2654abSrjs SCTP_INP_INFO_WUNLOCK();
13698c2654abSrjs return error;
13708c2654abSrjs }
137101b82b52Srjs /* Arrange to share the policy */
137201b82b52Srjs inp->ip_inp.inp.inp_sp = pcb_sp;
137301b82b52Srjs pcb_sp->sp_inph = (struct inpcb_hdr *)inp;
137401b82b52Srjs }
13758c2654abSrjs #endif /* IPSEC */
13768c2654abSrjs sctppcbinfo.ipi_count_ep++;
13778c2654abSrjs inp->inp_ip_ttl = ip_defttl;
13788c2654abSrjs inp->inp_ip_tos = 0;
13798c2654abSrjs
13808c2654abSrjs so->so_pcb = (void *)inp;
13818c2654abSrjs
13828c2654abSrjs if ((so->so_type == SOCK_DGRAM) ||
13838c2654abSrjs (so->so_type == SOCK_SEQPACKET)) {
13848c2654abSrjs /* UDP style socket */
13858c2654abSrjs inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE |
13868c2654abSrjs SCTP_PCB_FLAGS_UNBOUND);
13878c2654abSrjs inp->sctp_flags |= (SCTP_PCB_FLAGS_RECVDATAIOEVNT);
13888c2654abSrjs /* Be sure it is NON-BLOCKING IO for UDP */
13898c2654abSrjs /*so->so_state |= SS_NBIO;*/
13908c2654abSrjs } else if (so->so_type == SOCK_STREAM) {
13918c2654abSrjs /* TCP style socket */
13928c2654abSrjs inp->sctp_flags = (SCTP_PCB_FLAGS_TCPTYPE |
13938c2654abSrjs SCTP_PCB_FLAGS_UNBOUND);
13948c2654abSrjs inp->sctp_flags |= (SCTP_PCB_FLAGS_RECVDATAIOEVNT);
13958c2654abSrjs /* Be sure we have blocking IO bu default */
13968c2654abSrjs so->so_state &= ~SS_NBIO;
13978c2654abSrjs } else {
13988c2654abSrjs /*
13998c2654abSrjs * unsupported socket type (RAW, etc)- in case we missed
14008c2654abSrjs * it in protosw
14018c2654abSrjs */
14028c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp);
14038c2654abSrjs SCTP_INP_INFO_WUNLOCK();
14048c2654abSrjs return (EOPNOTSUPP);
14058c2654abSrjs }
14068c2654abSrjs inp->sctp_tcbhash = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_hash);
14078c2654abSrjs if (inp->sctp_tcbhash == NULL) {
14088c2654abSrjs printf("Out of SCTP-INPCB->hashinit - no resources\n");
14098c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp);
14108c2654abSrjs SCTP_INP_INFO_WUNLOCK();
14118c2654abSrjs return (ENOBUFS);
14128c2654abSrjs } else {
14138c2654abSrjs for (i = 0; i < sctp_pcbtblsize; i++)
14148c2654abSrjs LIST_INIT(&inp->sctp_tcbhash[i]);
14158c2654abSrjs for (i = 1; i < sctp_pcbtblsize; i <<= 1)
14168c2654abSrjs continue;
14178c2654abSrjs inp->sctp_hashmark = i - 1;
14188c2654abSrjs }
14198c2654abSrjs /* LOCK init's */
14208c2654abSrjs SCTP_INP_LOCK_INIT(inp);
14218c2654abSrjs SCTP_ASOC_CREATE_LOCK_INIT(inp);
14228c2654abSrjs /* lock the new ep */
14238c2654abSrjs SCTP_INP_WLOCK(inp);
14248c2654abSrjs
14258c2654abSrjs /* add it to the info area */
14268c2654abSrjs LIST_INSERT_HEAD(&sctppcbinfo.listhead, inp, sctp_list);
14278c2654abSrjs SCTP_INP_INFO_WUNLOCK();
14288c2654abSrjs
14298c2654abSrjs LIST_INIT(&inp->sctp_addr_list);
14308c2654abSrjs LIST_INIT(&inp->sctp_asoc_list);
14318c2654abSrjs TAILQ_INIT(&inp->sctp_queue_list);
14328c2654abSrjs /* Init the timer structure for signature change */
14338c2654abSrjs callout_init(&inp->sctp_ep.signature_change.timer, 0);
14348c2654abSrjs inp->sctp_ep.signature_change.type = SCTP_TIMER_TYPE_NEWCOOKIE;
14358c2654abSrjs
14368c2654abSrjs /* now init the actual endpoint default data */
14378c2654abSrjs m = &inp->sctp_ep;
14388c2654abSrjs
14398c2654abSrjs /* setup the base timeout information */
14408c2654abSrjs m->sctp_timeoutticks[SCTP_TIMER_SEND] = SEC_TO_TICKS(SCTP_SEND_SEC); /* needed ? */
14418c2654abSrjs m->sctp_timeoutticks[SCTP_TIMER_INIT] = SEC_TO_TICKS(SCTP_INIT_SEC); /* needed ? */
14428c2654abSrjs m->sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sctp_delayed_sack_time_default);
14438c2654abSrjs m->sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = sctp_heartbeat_interval_default; /* this is in MSEC */
14448c2654abSrjs m->sctp_timeoutticks[SCTP_TIMER_PMTU] = SEC_TO_TICKS(sctp_pmtu_raise_time_default);
14458c2654abSrjs m->sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN] = SEC_TO_TICKS(sctp_shutdown_guard_time_default);
14468c2654abSrjs m->sctp_timeoutticks[SCTP_TIMER_SIGNATURE] = SEC_TO_TICKS(sctp_secret_lifetime_default);
14478c2654abSrjs /* all max/min max are in ms */
14488c2654abSrjs m->sctp_maxrto = sctp_rto_max_default;
14498c2654abSrjs m->sctp_minrto = sctp_rto_min_default;
14508c2654abSrjs m->initial_rto = sctp_rto_initial_default;
14518c2654abSrjs m->initial_init_rto_max = sctp_init_rto_max_default;
14528c2654abSrjs
14538c2654abSrjs m->max_open_streams_intome = MAX_SCTP_STREAMS;
14548c2654abSrjs
14558c2654abSrjs m->max_init_times = sctp_init_rtx_max_default;
14568c2654abSrjs m->max_send_times = sctp_assoc_rtx_max_default;
14578c2654abSrjs m->def_net_failure = sctp_path_rtx_max_default;
14588c2654abSrjs m->sctp_sws_sender = SCTP_SWS_SENDER_DEF;
14598c2654abSrjs m->sctp_sws_receiver = SCTP_SWS_RECEIVER_DEF;
14608c2654abSrjs m->max_burst = sctp_max_burst_default;
14618c2654abSrjs /* number of streams to pre-open on a association */
14628c2654abSrjs m->pre_open_stream_count = sctp_nr_outgoing_streams_default;
14638c2654abSrjs
14648c2654abSrjs /* Add adaption cookie */
14658c2654abSrjs m->adaption_layer_indicator = 0x504C5253;
14668c2654abSrjs
14678c2654abSrjs /* Minimum cookie size */
14688c2654abSrjs m->size_of_a_cookie = (sizeof(struct sctp_init_msg) * 2) +
14698c2654abSrjs sizeof(struct sctp_state_cookie);
14708c2654abSrjs m->size_of_a_cookie += SCTP_SIGNATURE_SIZE;
14718c2654abSrjs
14728c2654abSrjs /* Setup the initial secret */
14738c2654abSrjs SCTP_GETTIME_TIMEVAL(&time);
14748c2654abSrjs m->time_of_secret_change = time.tv_sec;
14758c2654abSrjs
14768c2654abSrjs for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) {
14778c2654abSrjs m->secret_key[0][i] = sctp_select_initial_TSN(m);
14788c2654abSrjs }
14798c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL);
14808c2654abSrjs
14818c2654abSrjs /* How long is a cookie good for ? */
14828c2654abSrjs m->def_cookie_life = sctp_valid_cookie_life_default;
14838c2654abSrjs SCTP_INP_WUNLOCK(inp);
14848c2654abSrjs return (error);
14858c2654abSrjs }
14868c2654abSrjs
14878c2654abSrjs
14888c2654abSrjs void
sctp_move_pcb_and_assoc(struct sctp_inpcb * old_inp,struct sctp_inpcb * new_inp,struct sctp_tcb * stcb)14898c2654abSrjs sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
14908c2654abSrjs struct sctp_tcb *stcb)
14918c2654abSrjs {
14928c2654abSrjs uint16_t lport, rport;
14938c2654abSrjs struct sctppcbhead *head;
14948c2654abSrjs struct sctp_laddr *laddr, *oladdr;
14958c2654abSrjs
14968c2654abSrjs SCTP_TCB_UNLOCK(stcb);
14978c2654abSrjs SCTP_INP_INFO_WLOCK();
14988c2654abSrjs SCTP_INP_WLOCK(old_inp);
14998c2654abSrjs SCTP_INP_WLOCK(new_inp);
15008c2654abSrjs SCTP_TCB_LOCK(stcb);
15018c2654abSrjs
15028c2654abSrjs new_inp->sctp_ep.time_of_secret_change =
15038c2654abSrjs old_inp->sctp_ep.time_of_secret_change;
15048c2654abSrjs memcpy(new_inp->sctp_ep.secret_key, old_inp->sctp_ep.secret_key,
15058c2654abSrjs sizeof(old_inp->sctp_ep.secret_key));
15068c2654abSrjs new_inp->sctp_ep.current_secret_number =
15078c2654abSrjs old_inp->sctp_ep.current_secret_number;
15088c2654abSrjs new_inp->sctp_ep.last_secret_number =
15098c2654abSrjs old_inp->sctp_ep.last_secret_number;
15108c2654abSrjs new_inp->sctp_ep.size_of_a_cookie = old_inp->sctp_ep.size_of_a_cookie;
15118c2654abSrjs
15128c2654abSrjs /* Copy the port across */
15138c2654abSrjs lport = new_inp->sctp_lport = old_inp->sctp_lport;
15148c2654abSrjs rport = stcb->rport;
15158c2654abSrjs /* Pull the tcb from the old association */
15168c2654abSrjs LIST_REMOVE(stcb, sctp_tcbhash);
15178c2654abSrjs LIST_REMOVE(stcb, sctp_tcblist);
15188c2654abSrjs
15198c2654abSrjs /* Now insert the new_inp into the TCP connected hash */
15208c2654abSrjs head = &sctppcbinfo.sctp_tcpephash[SCTP_PCBHASH_ALLADDR((lport + rport),
15218c2654abSrjs sctppcbinfo.hashtcpmark)];
15228c2654abSrjs
15238c2654abSrjs LIST_INSERT_HEAD(head, new_inp, sctp_hash);
15248c2654abSrjs
15258c2654abSrjs /* Now move the tcb into the endpoint list */
15268c2654abSrjs LIST_INSERT_HEAD(&new_inp->sctp_asoc_list, stcb, sctp_tcblist);
15278c2654abSrjs /*
15288c2654abSrjs * Question, do we even need to worry about the ep-hash since
15298c2654abSrjs * we only have one connection? Probably not :> so lets
15308c2654abSrjs * get rid of it and not suck up any kernel memory in that.
15318c2654abSrjs */
15328c2654abSrjs SCTP_INP_INFO_WUNLOCK();
15338c2654abSrjs stcb->sctp_socket = new_inp->sctp_socket;
15348c2654abSrjs stcb->sctp_ep = new_inp;
15358c2654abSrjs if (new_inp->sctp_tcbhash != NULL) {
15368c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_hash,
15378c2654abSrjs new_inp->sctp_tcbhash);
15388c2654abSrjs new_inp->sctp_tcbhash = NULL;
15398c2654abSrjs }
15408c2654abSrjs if ((new_inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
15418c2654abSrjs /* Subset bound, so copy in the laddr list from the old_inp */
15428c2654abSrjs LIST_FOREACH(oladdr, &old_inp->sctp_addr_list, sctp_nxt_addr) {
15438c2654abSrjs laddr = (struct sctp_laddr *)SCTP_ZONE_GET(
15448c2654abSrjs sctppcbinfo.ipi_zone_laddr);
15458c2654abSrjs if (laddr == NULL) {
15468c2654abSrjs /*
15478c2654abSrjs * Gak, what can we do? This assoc is really
15488c2654abSrjs * HOSED. We probably should send an abort
15498c2654abSrjs * here.
15508c2654abSrjs */
15518c2654abSrjs #ifdef SCTP_DEBUG
15528c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
15538c2654abSrjs printf("Association hosed in TCP model, out of laddr memory\n");
15548c2654abSrjs }
15558c2654abSrjs #endif /* SCTP_DEBUG */
15568c2654abSrjs continue;
15578c2654abSrjs }
15588c2654abSrjs sctppcbinfo.ipi_count_laddr++;
15598c2654abSrjs sctppcbinfo.ipi_gencnt_laddr++;
15608c2654abSrjs memset(laddr, 0, sizeof(*laddr));
15618c2654abSrjs laddr->ifa = oladdr->ifa;
15628c2654abSrjs LIST_INSERT_HEAD(&new_inp->sctp_addr_list, laddr,
15638c2654abSrjs sctp_nxt_addr);
15648c2654abSrjs new_inp->laddr_count++;
15658c2654abSrjs }
15668c2654abSrjs }
15678c2654abSrjs SCTP_INP_WUNLOCK(new_inp);
15688c2654abSrjs SCTP_INP_WUNLOCK(old_inp);
15698c2654abSrjs }
15708c2654abSrjs
15718c2654abSrjs static int
sctp_isport_inuse(struct sctp_inpcb * inp,uint16_t lport)15728c2654abSrjs sctp_isport_inuse(struct sctp_inpcb *inp, uint16_t lport)
15738c2654abSrjs {
15748c2654abSrjs struct sctppcbhead *head;
15758c2654abSrjs struct sctp_inpcb *t_inp;
15768c2654abSrjs
15778c2654abSrjs head = &sctppcbinfo.sctp_ephash[SCTP_PCBHASH_ALLADDR(lport,
15788c2654abSrjs sctppcbinfo.hashmark)];
15798c2654abSrjs LIST_FOREACH(t_inp, head, sctp_hash) {
15808c2654abSrjs if (t_inp->sctp_lport != lport) {
15818c2654abSrjs continue;
15828c2654abSrjs }
15838c2654abSrjs /* This one is in use. */
15848c2654abSrjs /* check the v6/v4 binding issue */
15858c2654abSrjs if ((t_inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
15863fb74706Srjs (((struct in6pcb *)t_inp)->in6p_flags & IN6P_IPV6_V6ONLY)) {
15878c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
15888c2654abSrjs /* collision in V6 space */
15898c2654abSrjs return (1);
15908c2654abSrjs } else {
15918c2654abSrjs /* inp is BOUND_V4 no conflict */
15928c2654abSrjs continue;
15938c2654abSrjs }
15948c2654abSrjs } else if (t_inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
15958c2654abSrjs /* t_inp is bound v4 and v6, conflict always */
15968c2654abSrjs return (1);
15978c2654abSrjs } else {
15988c2654abSrjs /* t_inp is bound only V4 */
15998c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
16008c2654abSrjs (((struct in6pcb *)inp)->in6p_flags & IN6P_IPV6_V6ONLY)
16018c2654abSrjs ) {
16028c2654abSrjs /* no conflict */
16038c2654abSrjs continue;
16048c2654abSrjs }
16058c2654abSrjs /* else fall through to conflict */
16068c2654abSrjs }
16078c2654abSrjs return (1);
16088c2654abSrjs }
16098c2654abSrjs return (0);
16108c2654abSrjs }
16118c2654abSrjs
16128c2654abSrjs int
sctp_inpcb_bind(struct socket * so,struct sockaddr * addr,struct lwp * l)16138c2654abSrjs sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, struct lwp *l)
16148c2654abSrjs {
16158c2654abSrjs /* bind a ep to a socket address */
16168c2654abSrjs struct sctppcbhead *head;
16178c2654abSrjs struct sctp_inpcb *inp, *inp_tmp;
16188c2654abSrjs int bindall;
16198c2654abSrjs uint16_t lport;
16208c2654abSrjs int error;
16218c2654abSrjs
16228c2654abSrjs lport = 0;
16238c2654abSrjs error = 0;
16248c2654abSrjs bindall = 1;
16258c2654abSrjs inp = (struct sctp_inpcb *)so->so_pcb;
16268c2654abSrjs #ifdef SCTP_DEBUG
16278c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
16288c2654abSrjs if (addr) {
16298c2654abSrjs printf("Bind called port:%d\n",
16308c2654abSrjs ntohs(((struct sockaddr_in *)addr)->sin_port));
16318c2654abSrjs printf("Addr :");
16328c2654abSrjs sctp_print_address(addr);
16338c2654abSrjs }
16348c2654abSrjs }
16358c2654abSrjs #endif /* SCTP_DEBUG */
16368c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
16378c2654abSrjs /* already did a bind, subsequent binds NOT allowed ! */
16388c2654abSrjs return (EINVAL);
16398c2654abSrjs }
16408c2654abSrjs
16418c2654abSrjs if (addr != NULL) {
16428c2654abSrjs if (addr->sa_family == AF_INET) {
16438c2654abSrjs struct sockaddr_in *sin;
16448c2654abSrjs
16458c2654abSrjs /* IPV6_V6ONLY socket? */
16468c2654abSrjs if (((struct in6pcb *)inp)->in6p_flags & IN6P_IPV6_V6ONLY) {
16478c2654abSrjs return (EINVAL);
16488c2654abSrjs }
16498c2654abSrjs
16508c2654abSrjs if (addr->sa_len != sizeof(*sin))
16518c2654abSrjs return (EINVAL);
16528c2654abSrjs
16538c2654abSrjs sin = (struct sockaddr_in *)addr;
16548c2654abSrjs lport = sin->sin_port;
16558c2654abSrjs
16568c2654abSrjs if (sin->sin_addr.s_addr != INADDR_ANY) {
16578c2654abSrjs bindall = 0;
16588c2654abSrjs }
165901b82b52Srjs #ifdef IPSEC
166001b82b52Srjs inp->ip_inp.inp.inp_af = AF_INET;
166101b82b52Srjs #endif
16628c2654abSrjs } else if (addr->sa_family == AF_INET6) {
16638c2654abSrjs /* Only for pure IPv6 Address. (No IPv4 Mapped!) */
16648c2654abSrjs struct sockaddr_in6 *sin6;
16658c2654abSrjs
16668c2654abSrjs sin6 = (struct sockaddr_in6 *)addr;
16678c2654abSrjs
16688c2654abSrjs if (addr->sa_len != sizeof(*sin6))
16698c2654abSrjs return (EINVAL);
16708c2654abSrjs
16718c2654abSrjs lport = sin6->sin6_port;
16728c2654abSrjs if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
16738c2654abSrjs bindall = 0;
16748c2654abSrjs /* KAME hack: embed scopeid */
16758c2654abSrjs error = sa6_embedscope(sin6, ip6_use_defzone);
16768c2654abSrjs if (error != 0)
16778c2654abSrjs return (error);
16788c2654abSrjs }
16798c2654abSrjs #ifndef SCOPEDROUTING
16808c2654abSrjs /* this must be cleared for ifa_ifwithaddr() */
16818c2654abSrjs sin6->sin6_scope_id = 0;
16828c2654abSrjs #endif /* SCOPEDROUTING */
168301b82b52Srjs #ifdef IPSEC
168401b82b52Srjs inp->ip_inp.inp.inp_af = AF_INET6;
168501b82b52Srjs #endif
16868c2654abSrjs } else {
16878c2654abSrjs return (EAFNOSUPPORT);
16888c2654abSrjs }
168901b82b52Srjs #ifdef IPSEC
169001b82b52Srjs if (ipsec_enabled) {
169101b82b52Srjs inp->ip_inp.inp.inp_socket = so;
169201b82b52Srjs error = ipsec_init_pcbpolicy(so, &inp->ip_inp.inp.inp_sp);
169301b82b52Srjs if (error != 0)
169401b82b52Srjs return (error);
169501b82b52Srjs inp->ip_inp.inp.inp_sp->sp_inph = (struct inpcb_hdr *)inp;
169601b82b52Srjs }
169701b82b52Srjs #endif
16988c2654abSrjs }
16998c2654abSrjs SCTP_INP_INFO_WLOCK();
17008c2654abSrjs #ifdef SCTP_DEBUG
17018c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
17028c2654abSrjs printf("sctp_inpcb_bind: after SCTP_INP_INFO_WLOCK\n");
17038c2654abSrjs }
17048c2654abSrjs #endif /* SCTP_DEBUG */
17058c2654abSrjs SCTP_INP_WLOCK(inp);
17068c2654abSrjs /* increase our count due to the unlock we do */
17078c2654abSrjs SCTP_INP_INCR_REF(inp);
17088c2654abSrjs if (lport) {
17098c2654abSrjs enum kauth_network_req req;
17108c2654abSrjs /*
17118c2654abSrjs * Did the caller specify a port? if so we must see if a
17128c2654abSrjs * ep already has this one bound.
17138c2654abSrjs */
17148c2654abSrjs if (ntohs(lport) < IPPORT_RESERVED)
17158c2654abSrjs req = KAUTH_REQ_NETWORK_BIND_PRIVPORT;
17168c2654abSrjs else
17178c2654abSrjs req = KAUTH_REQ_NETWORK_BIND_PORT;
17188c2654abSrjs
17198c2654abSrjs error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_BIND,
17208c2654abSrjs req, so, addr, NULL);
17218c2654abSrjs if (error) {
17228c2654abSrjs SCTP_INP_DECR_REF(inp);
17238c2654abSrjs SCTP_INP_WUNLOCK(inp);
17248c2654abSrjs SCTP_INP_INFO_WUNLOCK();
17258c2654abSrjs return (EACCES);
17268c2654abSrjs }
17278c2654abSrjs SCTP_INP_WUNLOCK(inp);
17288c2654abSrjs inp_tmp = sctp_pcb_findep(addr, 0, 1);
17298c2654abSrjs if (inp_tmp != NULL) {
17308c2654abSrjs /* lock guy returned and lower count
17318c2654abSrjs * note that we are not bound so inp_tmp
17328c2654abSrjs * should NEVER be inp. And it is this
17338c2654abSrjs * inp (inp_tmp) that gets the reference
17348c2654abSrjs * bump, so we must lower it.
17358c2654abSrjs */
17368c2654abSrjs SCTP_INP_WLOCK(inp_tmp);
17378c2654abSrjs SCTP_INP_DECR_REF(inp_tmp);
17388c2654abSrjs SCTP_INP_WUNLOCK(inp_tmp);
17398c2654abSrjs
17408c2654abSrjs /* unlock info */
17418c2654abSrjs SCTP_INP_INFO_WUNLOCK();
1742957d655dSchristos return EADDRINUSE;
17438c2654abSrjs }
17448c2654abSrjs SCTP_INP_WLOCK(inp);
17458c2654abSrjs if (bindall) {
17468c2654abSrjs /* verify that no lport is not used by a singleton */
17478c2654abSrjs if (sctp_isport_inuse(inp, lport)) {
17488c2654abSrjs /* Sorry someone already has this one bound */
17498c2654abSrjs SCTP_INP_DECR_REF(inp);
17508c2654abSrjs SCTP_INP_WUNLOCK(inp);
17518c2654abSrjs SCTP_INP_INFO_WUNLOCK();
1752957d655dSchristos return EADDRINUSE;
17538c2654abSrjs }
17548c2654abSrjs }
17558c2654abSrjs } else {
17568c2654abSrjs /*
17578c2654abSrjs * get any port but lets make sure no one has any address
17588c2654abSrjs * with this port bound
17598c2654abSrjs */
17608c2654abSrjs
17618c2654abSrjs /*
17628c2654abSrjs * setup the inp to the top (I could use the union but this
17638c2654abSrjs * is just as easy
17648c2654abSrjs */
17658c2654abSrjs uint32_t port_guess;
17668c2654abSrjs uint16_t port_attempt;
17678c2654abSrjs int not_done=1;
17688c2654abSrjs
17698c2654abSrjs while (not_done) {
17708c2654abSrjs port_guess = sctp_select_initial_TSN(&inp->sctp_ep);
17718c2654abSrjs port_attempt = (port_guess & 0x0000ffff);
17728c2654abSrjs if (port_attempt == 0) {
17738c2654abSrjs goto next_half;
17748c2654abSrjs }
17758c2654abSrjs if (port_attempt < IPPORT_RESERVED) {
17768c2654abSrjs port_attempt += IPPORT_RESERVED;
17778c2654abSrjs }
17788c2654abSrjs
17798c2654abSrjs if (sctp_isport_inuse(inp, htons(port_attempt)) == 0) {
17808c2654abSrjs /* got a port we can use */
17818c2654abSrjs not_done = 0;
17828c2654abSrjs continue;
17838c2654abSrjs }
17848c2654abSrjs /* try upper half */
17858c2654abSrjs next_half:
17868c2654abSrjs port_attempt = ((port_guess >> 16) & 0x0000ffff);
17878c2654abSrjs if (port_attempt == 0) {
17888c2654abSrjs goto last_try;
17898c2654abSrjs }
17908c2654abSrjs if (port_attempt < IPPORT_RESERVED) {
17918c2654abSrjs port_attempt += IPPORT_RESERVED;
17928c2654abSrjs }
17938c2654abSrjs if (sctp_isport_inuse(inp, htons(port_attempt)) == 0) {
17948c2654abSrjs /* got a port we can use */
17958c2654abSrjs not_done = 0;
17968c2654abSrjs continue;
17978c2654abSrjs }
17988c2654abSrjs /* try two half's added together */
17998c2654abSrjs last_try:
18008c2654abSrjs port_attempt = (((port_guess >> 16) & 0x0000ffff) + (port_guess & 0x0000ffff));
18018c2654abSrjs if (port_attempt == 0) {
18028c2654abSrjs /* get a new random number */
18038c2654abSrjs continue;
18048c2654abSrjs }
18058c2654abSrjs if (port_attempt < IPPORT_RESERVED) {
18068c2654abSrjs port_attempt += IPPORT_RESERVED;
18078c2654abSrjs }
18088c2654abSrjs if (sctp_isport_inuse(inp, htons(port_attempt)) == 0) {
18098c2654abSrjs /* got a port we can use */
18108c2654abSrjs not_done = 0;
18118c2654abSrjs continue;
18128c2654abSrjs }
18138c2654abSrjs }
18148c2654abSrjs /* we don't get out of the loop until we have a port */
18158c2654abSrjs lport = htons(port_attempt);
18168c2654abSrjs }
18178c2654abSrjs SCTP_INP_DECR_REF(inp);
18188c2654abSrjs if (inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE|SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
18198c2654abSrjs /* this really should not happen. The guy
18208c2654abSrjs * did a non-blocking bind and then did a close
18218c2654abSrjs * at the same time.
18228c2654abSrjs */
18238c2654abSrjs SCTP_INP_WUNLOCK(inp);
18248c2654abSrjs SCTP_INP_INFO_WUNLOCK();
18258c2654abSrjs return (EINVAL);
18268c2654abSrjs }
18278c2654abSrjs /* ok we look clear to give out this port, so lets setup the binding */
18288c2654abSrjs if (bindall) {
18298c2654abSrjs /* binding to all addresses, so just set in the proper flags */
18308c2654abSrjs inp->sctp_flags |= (SCTP_PCB_FLAGS_BOUNDALL |
18318c2654abSrjs SCTP_PCB_FLAGS_DO_ASCONF);
18328c2654abSrjs /* set the automatic addr changes from kernel flag */
18338c2654abSrjs if (sctp_auto_asconf == 0) {
18348c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_AUTO_ASCONF;
18358c2654abSrjs } else {
18368c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_AUTO_ASCONF;
18378c2654abSrjs }
18388c2654abSrjs } else {
18398c2654abSrjs /*
18408c2654abSrjs * bind specific, make sure flags is off and add a new address
18418c2654abSrjs * structure to the sctp_addr_list inside the ep structure.
18428c2654abSrjs *
18438c2654abSrjs * We will need to allocate one and insert it at the head.
18448c2654abSrjs * The socketopt call can just insert new addresses in there
18458c2654abSrjs * as well. It will also have to do the embed scope kame hack
18468c2654abSrjs * too (before adding).
18478c2654abSrjs */
18488c2654abSrjs struct ifaddr *ifa;
18498c2654abSrjs struct sockaddr_storage store_sa;
18508c2654abSrjs
18518c2654abSrjs memset(&store_sa, 0, sizeof(store_sa));
18528c2654abSrjs if (addr->sa_family == AF_INET) {
18538c2654abSrjs struct sockaddr_in *sin;
18548c2654abSrjs
18558c2654abSrjs sin = (struct sockaddr_in *)&store_sa;
18568c2654abSrjs memcpy(sin, addr, sizeof(struct sockaddr_in));
18578c2654abSrjs sin->sin_port = 0;
18588c2654abSrjs } else if (addr->sa_family == AF_INET6) {
18598c2654abSrjs struct sockaddr_in6 *sin6;
18608c2654abSrjs
18618c2654abSrjs sin6 = (struct sockaddr_in6 *)&store_sa;
18628c2654abSrjs memcpy(sin6, addr, sizeof(struct sockaddr_in6));
18638c2654abSrjs sin6->sin6_port = 0;
18648c2654abSrjs }
18658c2654abSrjs /*
18668c2654abSrjs * first find the interface with the bound address
18678c2654abSrjs * need to zero out the port to find the address! yuck!
18688c2654abSrjs * can't do this earlier since need port for sctp_pcb_findep()
18698c2654abSrjs */
18708c2654abSrjs ifa = sctp_find_ifa_by_addr((struct sockaddr *)&store_sa);
18718c2654abSrjs if (ifa == NULL) {
18728c2654abSrjs /* Can't find an interface with that address */
18738c2654abSrjs SCTP_INP_WUNLOCK(inp);
18748c2654abSrjs SCTP_INP_INFO_WUNLOCK();
18758c2654abSrjs return (EADDRNOTAVAIL);
18768c2654abSrjs }
18778c2654abSrjs if (addr->sa_family == AF_INET6) {
18788c2654abSrjs struct in6_ifaddr *ifa6;
18798c2654abSrjs ifa6 = (struct in6_ifaddr *)ifa;
18808c2654abSrjs /*
18818c2654abSrjs * allow binding of deprecated addresses as per
18828c2654abSrjs * RFC 2462 and ipng discussion
18838c2654abSrjs */
18848c2654abSrjs if (ifa6->ia6_flags & (IN6_IFF_DETACHED |
18858c2654abSrjs IN6_IFF_ANYCAST |
18868c2654abSrjs IN6_IFF_NOTREADY)) {
18878c2654abSrjs /* Can't bind a non-existent addr. */
18888c2654abSrjs SCTP_INP_WUNLOCK(inp);
18898c2654abSrjs SCTP_INP_INFO_WUNLOCK();
18908c2654abSrjs return (EINVAL);
18918c2654abSrjs }
18928c2654abSrjs }
18938c2654abSrjs /* we're not bound all */
18948c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUNDALL;
18958c2654abSrjs #if 0 /* use sysctl now */
18968c2654abSrjs /* don't allow automatic addr changes from kernel */
18978c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_AUTO_ASCONF;
18988c2654abSrjs #endif
18998c2654abSrjs /* set the automatic addr changes from kernel flag */
19008c2654abSrjs if (sctp_auto_asconf == 0) {
19018c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_AUTO_ASCONF;
19028c2654abSrjs } else {
19038c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_AUTO_ASCONF;
19048c2654abSrjs }
19058c2654abSrjs /* allow bindx() to send ASCONF's for binding changes */
19068c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_DO_ASCONF;
19078c2654abSrjs /* add this address to the endpoint list */
19088c2654abSrjs error = sctp_insert_laddr(&inp->sctp_addr_list, ifa);
19098c2654abSrjs if (error != 0) {
19108c2654abSrjs SCTP_INP_WUNLOCK(inp);
19118c2654abSrjs SCTP_INP_INFO_WUNLOCK();
19128c2654abSrjs return (error);
19138c2654abSrjs }
19148c2654abSrjs inp->laddr_count++;
19158c2654abSrjs }
19168c2654abSrjs /* find the bucket */
19178c2654abSrjs head = &sctppcbinfo.sctp_ephash[SCTP_PCBHASH_ALLADDR(lport,
19188c2654abSrjs sctppcbinfo.hashmark)];
19198c2654abSrjs /* put it in the bucket */
19208c2654abSrjs LIST_INSERT_HEAD(head, inp, sctp_hash);
19218c2654abSrjs #ifdef SCTP_DEBUG
19228c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
19238c2654abSrjs printf("Main hash to bind at head:%p, bound port:%d\n", head, ntohs(lport));
19248c2654abSrjs }
19258c2654abSrjs #endif
19268c2654abSrjs /* set in the port */
19278c2654abSrjs inp->sctp_lport = lport;
19288c2654abSrjs
19298c2654abSrjs /* turn off just the unbound flag */
19308c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_UNBOUND;
19318c2654abSrjs SCTP_INP_WUNLOCK(inp);
19328c2654abSrjs SCTP_INP_INFO_WUNLOCK();
19338c2654abSrjs return (0);
19348c2654abSrjs }
19358c2654abSrjs
19368c2654abSrjs
19378c2654abSrjs static void
sctp_iterator_inp_being_freed(struct sctp_inpcb * inp,struct sctp_inpcb * inp_next)19388c2654abSrjs sctp_iterator_inp_being_freed(struct sctp_inpcb *inp, struct sctp_inpcb *inp_next)
19398c2654abSrjs {
19408c2654abSrjs struct sctp_iterator *it;
19418c2654abSrjs /* We enter with the only the ITERATOR_LOCK in place and
19428c2654abSrjs * A write lock on the inp_info stuff.
19438c2654abSrjs */
19448c2654abSrjs
19458c2654abSrjs /* Go through all iterators, we must do this since
19468c2654abSrjs * it is possible that some iterator does NOT have
19478c2654abSrjs * the lock, but is waiting for it. And the one that
19488c2654abSrjs * had the lock has either moved in the last iteration
19498c2654abSrjs * or we just cleared it above. We need to find all
19508c2654abSrjs * of those guys. The list of iterators should never
19518c2654abSrjs * be very big though.
19528c2654abSrjs */
19538c2654abSrjs LIST_FOREACH(it, &sctppcbinfo.iteratorhead, sctp_nxt_itr) {
19548c2654abSrjs if (it == inp->inp_starting_point_for_iterator)
19558c2654abSrjs /* skip this guy, he's special */
19568c2654abSrjs continue;
19578c2654abSrjs if (it->inp == inp) {
19588c2654abSrjs /* This is tricky and we DON'T lock the iterator.
19598c2654abSrjs * Reason is he's running but waiting for me since
19608c2654abSrjs * inp->inp_starting_point_for_iterator has the lock
19618c2654abSrjs * on me (the guy above we skipped). This tells us
19628c2654abSrjs * its is not running but waiting for inp->inp_starting_point_for_iterator
19638c2654abSrjs * to be released by the guy that does have our INP in a lock.
19648c2654abSrjs */
19658c2654abSrjs if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
19668c2654abSrjs it->inp = NULL;
19678c2654abSrjs it->stcb = NULL;
19688c2654abSrjs } else {
19698c2654abSrjs /* set him up to do the next guy not me */
19708c2654abSrjs it->inp = inp_next;
19718c2654abSrjs it->stcb = NULL;
19728c2654abSrjs }
19738c2654abSrjs }
19748c2654abSrjs }
19758c2654abSrjs it = inp->inp_starting_point_for_iterator;
19768c2654abSrjs if (it) {
19778c2654abSrjs if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
19788c2654abSrjs it->inp = NULL;
19798c2654abSrjs } else {
19808c2654abSrjs it->inp = inp_next;
19818c2654abSrjs }
19828c2654abSrjs it->stcb = NULL;
19838c2654abSrjs }
19848c2654abSrjs }
19858c2654abSrjs
19868c2654abSrjs /* release sctp_inpcb unbind the port */
19878c2654abSrjs void
sctp_inpcb_free(struct sctp_inpcb * inp,int immediate)19888c2654abSrjs sctp_inpcb_free(struct sctp_inpcb *inp, int immediate)
19898c2654abSrjs {
19908c2654abSrjs /*
19918c2654abSrjs * Here we free a endpoint. We must find it (if it is in the Hash
19928c2654abSrjs * table) and remove it from there. Then we must also find it in
19938c2654abSrjs * the overall list and remove it from there. After all removals are
19948c2654abSrjs * complete then any timer has to be stopped. Then start the actual
19958c2654abSrjs * freeing.
19968c2654abSrjs * a) Any local lists.
19978c2654abSrjs * b) Any associations.
19988c2654abSrjs * c) The hash of all associations.
19998c2654abSrjs * d) finally the ep itself.
20008c2654abSrjs */
20018c2654abSrjs struct sctp_inpcb *inp_save;
20028c2654abSrjs struct sctp_tcb *asoc, *nasoc;
20038c2654abSrjs struct sctp_laddr *laddr, *nladdr;
20048c2654abSrjs struct inpcb *ip_pcb;
20058c2654abSrjs struct socket *so;
20068c2654abSrjs struct sctp_socket_q_list *sq;
20078c2654abSrjs int s, cnt;
20084c25fb2fSozaki-r struct rtentry *rt;
20098c2654abSrjs
20108c2654abSrjs s = splsoftnet();
20118c2654abSrjs SCTP_ASOC_CREATE_LOCK(inp);
20128c2654abSrjs SCTP_INP_WLOCK(inp);
20138c2654abSrjs
20148c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
20158c2654abSrjs /* been here before */
20168c2654abSrjs splx(s);
20178c2654abSrjs printf("Endpoint was all gone (dup free)?\n");
20188c2654abSrjs SCTP_INP_WUNLOCK(inp);
20198c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp);
20208c2654abSrjs return;
20218c2654abSrjs }
20228c2654abSrjs sctp_timer_stop(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL);
20238c2654abSrjs
20248c2654abSrjs sctp_m_freem(inp->control);
20258c2654abSrjs inp->control = NULL;
20268c2654abSrjs sctp_m_freem(inp->pkt);
20278c2654abSrjs inp->pkt = NULL;
20288c2654abSrjs so = inp->sctp_socket;
20298c2654abSrjs ip_pcb = &inp->ip_inp.inp; /* we could just cast the main
20308c2654abSrjs * pointer here but I will
20318c2654abSrjs * be nice :> (i.e. ip_pcb = ep;)
20328c2654abSrjs */
20338c2654abSrjs
20348c2654abSrjs if (immediate == 0) {
20358c2654abSrjs int cnt_in_sd;
20368c2654abSrjs cnt_in_sd = 0;
20378c2654abSrjs for ((asoc = LIST_FIRST(&inp->sctp_asoc_list)); asoc != NULL;
20388c2654abSrjs asoc = nasoc) {
20398c2654abSrjs nasoc = LIST_NEXT(asoc, sctp_tcblist);
20408c2654abSrjs if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_COOKIE_WAIT) ||
20418c2654abSrjs (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_COOKIE_ECHOED)) {
20428c2654abSrjs /* Just abandon things in the front states */
20438c2654abSrjs SCTP_TCB_LOCK(asoc);
20448c2654abSrjs SCTP_INP_WUNLOCK(inp);
20458c2654abSrjs sctp_free_assoc(inp, asoc);
20468c2654abSrjs SCTP_INP_WLOCK(inp);
20478c2654abSrjs continue;
20488c2654abSrjs } else {
20498c2654abSrjs asoc->asoc.state |= SCTP_STATE_CLOSED_SOCKET;
20508c2654abSrjs }
20518c2654abSrjs if ((asoc->asoc.size_on_delivery_queue > 0) ||
20528c2654abSrjs (asoc->asoc.size_on_reasm_queue > 0) ||
20538c2654abSrjs (asoc->asoc.size_on_all_streams > 0) ||
20548c2654abSrjs (so && (so->so_rcv.sb_cc > 0))
20558c2654abSrjs ) {
20568c2654abSrjs /* Left with Data unread */
20578c2654abSrjs struct mbuf *op_err;
20588c2654abSrjs MGET(op_err, M_DONTWAIT, MT_DATA);
20598c2654abSrjs if (op_err) {
20608c2654abSrjs /* Fill in the user initiated abort */
20618c2654abSrjs struct sctp_paramhdr *ph;
20628c2654abSrjs op_err->m_len =
20638c2654abSrjs sizeof(struct sctp_paramhdr);
20648c2654abSrjs ph = mtod(op_err,
20658c2654abSrjs struct sctp_paramhdr *);
20668c2654abSrjs ph->param_type = htons(
20678c2654abSrjs SCTP_CAUSE_USER_INITIATED_ABT);
20688c2654abSrjs ph->param_length = htons(op_err->m_len);
20698c2654abSrjs }
20708c2654abSrjs SCTP_TCB_LOCK(asoc);
20718c2654abSrjs sctp_send_abort_tcb(asoc, op_err);
20728c2654abSrjs
20738c2654abSrjs SCTP_INP_WUNLOCK(inp);
20748c2654abSrjs sctp_free_assoc(inp, asoc);
20758c2654abSrjs SCTP_INP_WLOCK(inp);
20768c2654abSrjs continue;
20778c2654abSrjs } else if (TAILQ_EMPTY(&asoc->asoc.send_queue) &&
20788c2654abSrjs TAILQ_EMPTY(&asoc->asoc.sent_queue)) {
20798c2654abSrjs if ((SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
20808c2654abSrjs (SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
20818c2654abSrjs /* there is nothing queued to send, so I send shutdown */
20828c2654abSrjs SCTP_TCB_LOCK(asoc);
20838c2654abSrjs sctp_send_shutdown(asoc, asoc->asoc.primary_destination);
20848c2654abSrjs asoc->asoc.state = SCTP_STATE_SHUTDOWN_SENT;
20858c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, asoc->sctp_ep, asoc,
20868c2654abSrjs asoc->asoc.primary_destination);
20878c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc,
20888c2654abSrjs asoc->asoc.primary_destination);
20898c2654abSrjs sctp_chunk_output(inp, asoc, 1);
20908c2654abSrjs SCTP_TCB_UNLOCK(asoc);
20918c2654abSrjs }
20928c2654abSrjs } else {
20938c2654abSrjs /* mark into shutdown pending */
20948c2654abSrjs asoc->asoc.state |= SCTP_STATE_SHUTDOWN_PENDING;
20958c2654abSrjs }
20968c2654abSrjs cnt_in_sd++;
20978c2654abSrjs }
20988c2654abSrjs /* now is there some left in our SHUTDOWN state? */
20998c2654abSrjs if (cnt_in_sd) {
21008c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_GONE;
21018c2654abSrjs splx(s);
21028c2654abSrjs SCTP_INP_WUNLOCK(inp);
21038c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp);
21048c2654abSrjs return;
21058c2654abSrjs }
21068c2654abSrjs }
21078c2654abSrjs #if defined(__FreeBSD__) && __FreeBSD_version >= 503000
21088c2654abSrjs if (inp->refcount) {
21098c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL);
21108c2654abSrjs SCTP_INP_WUNLOCK(inp);
21118c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp);
21128c2654abSrjs return;
21138c2654abSrjs }
21148c2654abSrjs #endif
21158c2654abSrjs inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_ALLGONE;
21168c2654abSrjs
21174c25fb2fSozaki-r /* XXX */
21184c25fb2fSozaki-r rt = rtcache_validate(&ip_pcb->inp_route);
21194c25fb2fSozaki-r rtcache_unref(rt, &ip_pcb->inp_route);
21208c2654abSrjs
21218c2654abSrjs callout_stop(&inp->sctp_ep.signature_change.timer);
21228c2654abSrjs callout_destroy(&inp->sctp_ep.signature_change.timer);
21238c2654abSrjs
21248c2654abSrjs if (so) {
21258c2654abSrjs /* First take care of socket level things */
21268c2654abSrjs #ifdef IPSEC
212701b82b52Srjs if (ipsec_enabled)
2128580ac4beSmaxv ipsec_delete_pcbpolicy(ip_pcb);
21298c2654abSrjs #endif /*IPSEC*/
21308c2654abSrjs so->so_pcb = 0;
21318c2654abSrjs }
21328c2654abSrjs
21338c2654abSrjs if (ip_pcb->inp_options) {
21348c2654abSrjs (void)m_free(ip_pcb->inp_options);
21358c2654abSrjs ip_pcb->inp_options = 0;
21368c2654abSrjs }
21378c2654abSrjs rtcache_free(&ip_pcb->inp_route);
21388c2654abSrjs if (ip_pcb->inp_moptions) {
21398c2654abSrjs ip_freemoptions(ip_pcb->inp_moptions);
21408c2654abSrjs ip_pcb->inp_moptions = 0;
21418c2654abSrjs }
21428c2654abSrjs inp->inp_vflag = 0;
21438c2654abSrjs
21448c2654abSrjs /* Now the sctp_pcb things */
21458c2654abSrjs /*
21468c2654abSrjs * free each asoc if it is not already closed/free. we can't use
21478c2654abSrjs * the macro here since le_next will get freed as part of the
21488c2654abSrjs * sctp_free_assoc() call.
21498c2654abSrjs */
21508c2654abSrjs cnt = 0;
21518c2654abSrjs for ((asoc = LIST_FIRST(&inp->sctp_asoc_list)); asoc != NULL;
21528c2654abSrjs asoc = nasoc) {
21538c2654abSrjs nasoc = LIST_NEXT(asoc, sctp_tcblist);
21548c2654abSrjs SCTP_TCB_LOCK(asoc);
21558c2654abSrjs if (SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_COOKIE_WAIT) {
21568c2654abSrjs struct mbuf *op_err;
21578c2654abSrjs MGET(op_err, M_DONTWAIT, MT_DATA);
21588c2654abSrjs if (op_err) {
21598c2654abSrjs /* Fill in the user initiated abort */
21608c2654abSrjs struct sctp_paramhdr *ph;
21618c2654abSrjs op_err->m_len = sizeof(struct sctp_paramhdr);
21628c2654abSrjs ph = mtod(op_err, struct sctp_paramhdr *);
21638c2654abSrjs ph->param_type = htons(
21648c2654abSrjs SCTP_CAUSE_USER_INITIATED_ABT);
21658c2654abSrjs ph->param_length = htons(op_err->m_len);
21668c2654abSrjs }
21678c2654abSrjs sctp_send_abort_tcb(asoc, op_err);
21688c2654abSrjs }
21698c2654abSrjs cnt++;
21708c2654abSrjs /*
21718c2654abSrjs * sctp_free_assoc() will call sctp_inpcb_free(),
21728c2654abSrjs * if SCTP_PCB_FLAGS_SOCKET_GONE set.
21738c2654abSrjs * So, we clear it before sctp_free_assoc() making sure
21748c2654abSrjs * no double sctp_inpcb_free().
21758c2654abSrjs */
21768c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_SOCKET_GONE;
21778c2654abSrjs SCTP_INP_WUNLOCK(inp);
21788c2654abSrjs sctp_free_assoc(inp, asoc);
21798c2654abSrjs SCTP_INP_WLOCK(inp);
21808c2654abSrjs }
21818c2654abSrjs while ((sq = TAILQ_FIRST(&inp->sctp_queue_list)) != NULL) {
21828c2654abSrjs TAILQ_REMOVE(&inp->sctp_queue_list, sq, next_sq);
21838c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_sockq, sq);
21848c2654abSrjs sctppcbinfo.ipi_count_sockq--;
21858c2654abSrjs sctppcbinfo.ipi_gencnt_sockq++;
21868c2654abSrjs }
21878c2654abSrjs inp->sctp_socket = 0;
21888c2654abSrjs /* Now first we remove ourselves from the overall list of all EP's */
21898c2654abSrjs
21908c2654abSrjs /* Unlock inp first, need correct order */
21918c2654abSrjs SCTP_INP_WUNLOCK(inp);
21928c2654abSrjs /* now iterator lock */
21938c2654abSrjs SCTP_ITERATOR_LOCK();
21948c2654abSrjs /* now info lock */
21958c2654abSrjs SCTP_INP_INFO_WLOCK();
21968c2654abSrjs /* now reget the inp lock */
21978c2654abSrjs SCTP_INP_WLOCK(inp);
21988c2654abSrjs
21998c2654abSrjs inp_save = LIST_NEXT(inp, sctp_list);
22008c2654abSrjs LIST_REMOVE(inp, sctp_list);
22018c2654abSrjs /*
22028c2654abSrjs * Now the question comes as to if this EP was ever bound at all.
22038c2654abSrjs * If it was, then we must pull it out of the EP hash list.
22048c2654abSrjs */
22058c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) !=
22068c2654abSrjs SCTP_PCB_FLAGS_UNBOUND) {
22078c2654abSrjs /*
22088c2654abSrjs * ok, this guy has been bound. It's port is somewhere
22098c2654abSrjs * in the sctppcbinfo hash table. Remove it!
22108c2654abSrjs */
22118c2654abSrjs LIST_REMOVE(inp, sctp_hash);
22128c2654abSrjs }
22138c2654abSrjs /* fix any iterators only after out of the list */
22148c2654abSrjs sctp_iterator_inp_being_freed(inp, inp_save);
22158c2654abSrjs SCTP_ITERATOR_UNLOCK();
22168c2654abSrjs /*
22178c2654abSrjs * if we have an address list the following will free the list of
22188c2654abSrjs * ifaddr's that are set into this ep. Again macro limitations here,
22198c2654abSrjs * since the LIST_FOREACH could be a bad idea.
22208c2654abSrjs */
22218c2654abSrjs for ((laddr = LIST_FIRST(&inp->sctp_addr_list)); laddr != NULL;
22228c2654abSrjs laddr = nladdr) {
22238c2654abSrjs nladdr = LIST_NEXT(laddr, sctp_nxt_addr);
22248c2654abSrjs LIST_REMOVE(laddr, sctp_nxt_addr);
22258c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_laddr, laddr);
22268c2654abSrjs sctppcbinfo.ipi_gencnt_laddr++;
22278c2654abSrjs sctppcbinfo.ipi_count_laddr--;
22288c2654abSrjs }
22298c2654abSrjs
22308c2654abSrjs /* Now lets see about freeing the EP hash table. */
22318c2654abSrjs if (inp->sctp_tcbhash != NULL) {
22328c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_hash, inp->sctp_tcbhash);
22338c2654abSrjs inp->sctp_tcbhash = NULL;
22348c2654abSrjs }
22358c2654abSrjs SCTP_INP_WUNLOCK(inp);
22368c2654abSrjs SCTP_ASOC_CREATE_UNLOCK(inp);
22378c2654abSrjs SCTP_INP_LOCK_DESTROY(inp);
22388c2654abSrjs SCTP_ASOC_CREATE_LOCK_DESTROY(inp);
22398c2654abSrjs
22408c2654abSrjs /* Now we must put the ep memory back into the zone pool */
22418c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp);
22428c2654abSrjs sctppcbinfo.ipi_count_ep--;
22438c2654abSrjs
22448c2654abSrjs SCTP_INP_INFO_WUNLOCK();
22458c2654abSrjs splx(s);
2246a6a6d823Srjs
2247a6a6d823Srjs sofree(so);
2248a6a6d823Srjs mutex_enter(softnet_lock);
22498c2654abSrjs }
22508c2654abSrjs
22518c2654abSrjs
22528c2654abSrjs struct sctp_nets *
sctp_findnet(struct sctp_tcb * stcb,struct sockaddr * addr)22538c2654abSrjs sctp_findnet(struct sctp_tcb *stcb, struct sockaddr *addr)
22548c2654abSrjs {
22558c2654abSrjs struct sctp_nets *net;
22568c2654abSrjs
22578c2654abSrjs /* use the peer's/remote port for lookup if unspecified */
22588c2654abSrjs #if 0 /* why do we need to check the port for a nets list on an assoc? */
22598c2654abSrjs if (stcb->rport != sin->sin_port) {
22608c2654abSrjs /* we cheat and just a sin for this test */
22618c2654abSrjs return (NULL);
22628c2654abSrjs }
22638c2654abSrjs #endif
22648c2654abSrjs /* locate the address */
22658c2654abSrjs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
22668c2654abSrjs if (sctp_cmpaddr(addr, rtcache_getdst(&net->ro)))
22678c2654abSrjs return (net);
22688c2654abSrjs }
22698c2654abSrjs return (NULL);
22708c2654abSrjs }
22718c2654abSrjs
22728c2654abSrjs
22738c2654abSrjs /*
22748c2654abSrjs * add's a remote endpoint address, done with the INIT/INIT-ACK
22758c2654abSrjs * as well as when a ASCONF arrives that adds it. It will also
22768c2654abSrjs * initialize all the cwnd stats of stuff.
22778c2654abSrjs */
22788c2654abSrjs int
sctp_is_address_on_local_host(struct sockaddr * addr)22798c2654abSrjs sctp_is_address_on_local_host(struct sockaddr *addr)
22808c2654abSrjs {
22818c2654abSrjs struct ifnet *ifn;
22828c2654abSrjs struct ifaddr *ifa;
2283040205aeSozaki-r int s;
2284040205aeSozaki-r
2285040205aeSozaki-r s = pserialize_read_enter();
2286040205aeSozaki-r IFNET_READER_FOREACH(ifn) {
22879e4c2bdaSozaki-r IFADDR_READER_FOREACH(ifa, ifn) {
22888c2654abSrjs if (addr->sa_family == ifa->ifa_addr->sa_family) {
22898c2654abSrjs /* same family */
22908c2654abSrjs if (addr->sa_family == AF_INET) {
22918c2654abSrjs struct sockaddr_in *sin, *sin_c;
22928c2654abSrjs sin = (struct sockaddr_in *)addr;
22938c2654abSrjs sin_c = (struct sockaddr_in *)
22948c2654abSrjs ifa->ifa_addr;
22958c2654abSrjs if (sin->sin_addr.s_addr ==
22968c2654abSrjs sin_c->sin_addr.s_addr) {
22978c2654abSrjs /* we are on the same machine */
2298040205aeSozaki-r pserialize_read_exit(s);
22998c2654abSrjs return (1);
23008c2654abSrjs }
23018c2654abSrjs } else if (addr->sa_family == AF_INET6) {
23028c2654abSrjs struct sockaddr_in6 *sin6, *sin_c6;
23038c2654abSrjs sin6 = (struct sockaddr_in6 *)addr;
23048c2654abSrjs sin_c6 = (struct sockaddr_in6 *)
23058c2654abSrjs ifa->ifa_addr;
23068c2654abSrjs if (SCTP6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
23078c2654abSrjs &sin_c6->sin6_addr)) {
23088c2654abSrjs /* we are on the same machine */
2309040205aeSozaki-r pserialize_read_exit(s);
23108c2654abSrjs return (1);
23118c2654abSrjs }
23128c2654abSrjs }
23138c2654abSrjs }
23148c2654abSrjs }
23158c2654abSrjs }
2316040205aeSozaki-r pserialize_read_exit(s);
2317040205aeSozaki-r
23188c2654abSrjs return (0);
23198c2654abSrjs }
23208c2654abSrjs
23218c2654abSrjs int
sctp_add_remote_addr(struct sctp_tcb * stcb,struct sockaddr * newaddr,int set_scope,int from)23228c2654abSrjs sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
23238c2654abSrjs int set_scope, int from)
23248c2654abSrjs {
23258c2654abSrjs /*
23268c2654abSrjs * The following is redundant to the same lines in the
23278c2654abSrjs * sctp_aloc_assoc() but is needed since other's call the add
23288c2654abSrjs * address function
23298c2654abSrjs */
23308c2654abSrjs struct sctp_nets *net, *netfirst;
23318c2654abSrjs struct rtentry *rt, *netfirst_rt;
23328c2654abSrjs int addr_inscope;
23338c2654abSrjs
23348c2654abSrjs #ifdef SCTP_DEBUG
23358c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
23368c2654abSrjs printf("Adding an address (from:%d) to the peer: ", from);
23378c2654abSrjs sctp_print_address(newaddr);
23388c2654abSrjs }
23398c2654abSrjs #endif
23408c2654abSrjs netfirst = sctp_findnet(stcb, newaddr);
23418c2654abSrjs if (netfirst) {
23428c2654abSrjs /*
23438c2654abSrjs * Lie and return ok, we don't want to make the association
23448c2654abSrjs * go away for this behavior. It will happen in the TCP model
23458c2654abSrjs * in a connected socket. It does not reach the hash table
23468c2654abSrjs * until after the association is built so it can't be found.
23478c2654abSrjs * Mark as reachable, since the initial creation will have
23488c2654abSrjs * been cleared and the NOT_IN_ASSOC flag will have been
23498c2654abSrjs * added... and we don't want to end up removing it back out.
23508c2654abSrjs */
23518c2654abSrjs if (netfirst->dest_state & SCTP_ADDR_UNCONFIRMED) {
23528c2654abSrjs netfirst->dest_state = (SCTP_ADDR_REACHABLE|
23538c2654abSrjs SCTP_ADDR_UNCONFIRMED);
23548c2654abSrjs } else {
23558c2654abSrjs netfirst->dest_state = SCTP_ADDR_REACHABLE;
23568c2654abSrjs }
23578c2654abSrjs
23588c2654abSrjs return (0);
23598c2654abSrjs }
23608c2654abSrjs addr_inscope = 1;
23618c2654abSrjs if (newaddr->sa_family == AF_INET) {
23628c2654abSrjs struct sockaddr_in *sin;
23638c2654abSrjs sin = (struct sockaddr_in *)newaddr;
23648c2654abSrjs if (sin->sin_addr.s_addr == 0) {
23658c2654abSrjs /* Invalid address */
23668c2654abSrjs return (-1);
23678c2654abSrjs }
23688c2654abSrjs /* zero out the bzero area */
23698c2654abSrjs memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
23708c2654abSrjs
23718c2654abSrjs /* assure len is set */
23728c2654abSrjs sin->sin_len = sizeof(struct sockaddr_in);
23738c2654abSrjs if (set_scope) {
23748c2654abSrjs #ifdef SCTP_DONT_DO_PRIVADDR_SCOPE
23758c2654abSrjs stcb->ipv4_local_scope = 1;
23768c2654abSrjs #else
23778c2654abSrjs if (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) {
23788c2654abSrjs stcb->asoc.ipv4_local_scope = 1;
23798c2654abSrjs }
23808c2654abSrjs #endif /* SCTP_DONT_DO_PRIVADDR_SCOPE */
23818c2654abSrjs
23828c2654abSrjs if (sctp_is_address_on_local_host(newaddr)) {
23838c2654abSrjs stcb->asoc.loopback_scope = 1;
23848c2654abSrjs stcb->asoc.ipv4_local_scope = 1;
23858c2654abSrjs stcb->asoc.local_scope = 1;
23868c2654abSrjs stcb->asoc.site_scope = 1;
23878c2654abSrjs }
23888c2654abSrjs } else {
23898c2654abSrjs if (from == 8) {
23908c2654abSrjs /* From connectx */
23918c2654abSrjs if (sctp_is_address_on_local_host(newaddr)) {
23928c2654abSrjs stcb->asoc.loopback_scope = 1;
23938c2654abSrjs stcb->asoc.ipv4_local_scope = 1;
23948c2654abSrjs stcb->asoc.local_scope = 1;
23958c2654abSrjs stcb->asoc.site_scope = 1;
23968c2654abSrjs }
23978c2654abSrjs }
23988c2654abSrjs /* Validate the address is in scope */
23998c2654abSrjs if ((IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) &&
24008c2654abSrjs (stcb->asoc.ipv4_local_scope == 0)) {
24018c2654abSrjs addr_inscope = 0;
24028c2654abSrjs }
24038c2654abSrjs }
24048c2654abSrjs } else if (newaddr->sa_family == AF_INET6) {
24058c2654abSrjs struct sockaddr_in6 *sin6;
24068c2654abSrjs sin6 = (struct sockaddr_in6 *)newaddr;
24078c2654abSrjs if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
24088c2654abSrjs /* Invalid address */
24098c2654abSrjs return (-1);
24108c2654abSrjs }
24118c2654abSrjs /* assure len is set */
24128c2654abSrjs sin6->sin6_len = sizeof(struct sockaddr_in6);
24138c2654abSrjs if (set_scope) {
24148c2654abSrjs if (sctp_is_address_on_local_host(newaddr)) {
24158c2654abSrjs stcb->asoc.loopback_scope = 1;
24168c2654abSrjs stcb->asoc.local_scope = 1;
24178c2654abSrjs stcb->asoc.ipv4_local_scope = 1;
24188c2654abSrjs stcb->asoc.site_scope = 1;
24198c2654abSrjs } else if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
24208c2654abSrjs /*
24218c2654abSrjs * If the new destination is a LINK_LOCAL
24228c2654abSrjs * we must have common site scope. Don't set
24238c2654abSrjs * the local scope since we may not share all
24248c2654abSrjs * links, only loopback can do this.
24258c2654abSrjs * Links on the local network would also
24268c2654abSrjs * be on our private network for v4 too.
24278c2654abSrjs */
24288c2654abSrjs stcb->asoc.ipv4_local_scope = 1;
24298c2654abSrjs stcb->asoc.site_scope = 1;
24308c2654abSrjs } else if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
24318c2654abSrjs /*
24328c2654abSrjs * If the new destination is SITE_LOCAL
24338c2654abSrjs * then we must have site scope in common.
24348c2654abSrjs */
24358c2654abSrjs stcb->asoc.site_scope = 1;
24368c2654abSrjs }
24378c2654abSrjs } else {
24388c2654abSrjs if (from == 8) {
24398c2654abSrjs /* From connectx */
24408c2654abSrjs if (sctp_is_address_on_local_host(newaddr)) {
24418c2654abSrjs stcb->asoc.loopback_scope = 1;
24428c2654abSrjs stcb->asoc.ipv4_local_scope = 1;
24438c2654abSrjs stcb->asoc.local_scope = 1;
24448c2654abSrjs stcb->asoc.site_scope = 1;
24458c2654abSrjs }
24468c2654abSrjs }
24478c2654abSrjs /* Validate the address is in scope */
24488c2654abSrjs if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) &&
24498c2654abSrjs (stcb->asoc.loopback_scope == 0)) {
24508c2654abSrjs addr_inscope = 0;
24518c2654abSrjs } else if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
24528c2654abSrjs (stcb->asoc.local_scope == 0)) {
24538c2654abSrjs addr_inscope = 0;
24548c2654abSrjs } else if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
24558c2654abSrjs (stcb->asoc.site_scope == 0)) {
24568c2654abSrjs addr_inscope = 0;
24578c2654abSrjs }
24588c2654abSrjs }
24598c2654abSrjs } else {
24608c2654abSrjs /* not supported family type */
24618c2654abSrjs return (-1);
24628c2654abSrjs }
24638c2654abSrjs net = (struct sctp_nets *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_net);
24648c2654abSrjs if (net == NULL) {
24658c2654abSrjs return (-1);
24668c2654abSrjs }
24678c2654abSrjs sctppcbinfo.ipi_count_raddr++;
24688c2654abSrjs sctppcbinfo.ipi_gencnt_raddr++;
24698c2654abSrjs memset(net, 0, sizeof(*net));
24708c2654abSrjs if (newaddr->sa_family == AF_INET) {
24718c2654abSrjs ((struct sockaddr_in *)newaddr)->sin_port = stcb->rport;
24728c2654abSrjs } else if (newaddr->sa_family == AF_INET6) {
24738c2654abSrjs ((struct sockaddr_in6 *)newaddr)->sin6_port = stcb->rport;
24748c2654abSrjs }
24758c2654abSrjs net->addr_is_local = sctp_is_address_on_local_host(newaddr);
24768c2654abSrjs net->failure_threshold = stcb->asoc.def_net_failure;
24778c2654abSrjs if (addr_inscope == 0) {
24788c2654abSrjs #ifdef SCTP_DEBUG
24798c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
24808c2654abSrjs printf("Adding an address which is OUT OF SCOPE\n");
24818c2654abSrjs }
24828c2654abSrjs #endif /* SCTP_DEBUG */
24838c2654abSrjs net->dest_state = (SCTP_ADDR_REACHABLE |
24848c2654abSrjs SCTP_ADDR_OUT_OF_SCOPE);
24858c2654abSrjs } else {
24868c2654abSrjs if (from == 8)
24878c2654abSrjs /* 8 is passed by connect_x */
24888c2654abSrjs net->dest_state = SCTP_ADDR_REACHABLE;
24898c2654abSrjs else
24908c2654abSrjs net->dest_state = SCTP_ADDR_REACHABLE |
24918c2654abSrjs SCTP_ADDR_UNCONFIRMED;
24928c2654abSrjs }
24938c2654abSrjs net->RTO = stcb->asoc.initial_rto;
24948c2654abSrjs stcb->asoc.numnets++;
24958c2654abSrjs net->ref_count = 1;
24968c2654abSrjs
24978c2654abSrjs /* Init the timer structure */
24988c2654abSrjs callout_init(&net->rxt_timer.timer, 0);
24998c2654abSrjs callout_init(&net->pmtu_timer.timer, 0);
25008c2654abSrjs
25018c2654abSrjs /* Now generate a route for this guy */
25028c2654abSrjs /* KAME hack: embed scope zone ID */
25038c2654abSrjs if (newaddr->sa_family == AF_INET6) {
25048c2654abSrjs struct sockaddr_in6 *sin6;
25058c2654abSrjs sin6 = (struct sockaddr_in6 *)newaddr;
25068c2654abSrjs if (sa6_embedscope(sin6, ip6_use_defzone) != 0)
25078c2654abSrjs return (-1);
25088c2654abSrjs }
25098c2654abSrjs rt = rtcache_lookup(&net->ro, newaddr);
25108c2654abSrjs if (rt) {
25118c2654abSrjs net->mtu = rt->rt_ifp->if_mtu;
25128c2654abSrjs if (from == 1) {
25138c2654abSrjs stcb->asoc.smallest_mtu = net->mtu;
25148c2654abSrjs }
25158c2654abSrjs /* start things off to match mtu of interface please. */
25168c2654abSrjs rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu;
25178c2654abSrjs } else {
25188c2654abSrjs net->mtu = stcb->asoc.smallest_mtu;
25198c2654abSrjs }
25208c2654abSrjs #ifdef SCTP_DEBUG
25218c2654abSrjs printf("After lookup\n");
25228c2654abSrjs #endif
25238c2654abSrjs if (stcb->asoc.smallest_mtu > net->mtu) {
25248c2654abSrjs stcb->asoc.smallest_mtu = net->mtu;
25258c2654abSrjs }
25268c2654abSrjs /* We take the max of the burst limit times a MTU or the INITIAL_CWND.
25278c2654abSrjs * We then limit this to 4 MTU's of sending.
25288c2654abSrjs */
2529d1579b2dSriastradh net->cwnd = uimin((net->mtu * 4), uimax((stcb->asoc.max_burst * net->mtu), SCTP_INITIAL_CWND));
25308c2654abSrjs
25318c2654abSrjs /* we always get at LEAST 2 MTU's */
25328c2654abSrjs if (net->cwnd < (2 * net->mtu)) {
25338c2654abSrjs net->cwnd = 2 * net->mtu;
25348c2654abSrjs }
25358c2654abSrjs
25368c2654abSrjs net->ssthresh = stcb->asoc.peers_rwnd;
25378c2654abSrjs
25388c2654abSrjs net->src_addr_selected = 0;
25398c2654abSrjs netfirst = TAILQ_FIRST(&stcb->asoc.nets);
25408c2654abSrjs if (rt == NULL) {
25418c2654abSrjs /* Since we have no route put it at the back */
25428c2654abSrjs TAILQ_INSERT_TAIL(&stcb->asoc.nets, net, sctp_next);
25438c2654abSrjs } else if (netfirst == NULL) {
25448c2654abSrjs /* We are the first one in the pool. */
25458c2654abSrjs TAILQ_INSERT_HEAD(&stcb->asoc.nets, net, sctp_next);
25468c2654abSrjs } else if ((netfirst_rt = rtcache_validate(&netfirst->ro)) == NULL) {
25478c2654abSrjs /*
25488c2654abSrjs * First one has NO route. Place this one ahead of the
25498c2654abSrjs * first one.
25508c2654abSrjs */
25518c2654abSrjs TAILQ_INSERT_HEAD(&stcb->asoc.nets, net, sctp_next);
25528c2654abSrjs } else if (rt->rt_ifp != netfirst_rt->rt_ifp) {
25534c25fb2fSozaki-r rtcache_unref(netfirst_rt, &netfirst->ro);
25548c2654abSrjs /*
25558c2654abSrjs * This one has a different interface than the one at the
25568c2654abSrjs * top of the list. Place it ahead.
25578c2654abSrjs */
25588c2654abSrjs TAILQ_INSERT_HEAD(&stcb->asoc.nets, net, sctp_next);
25598c2654abSrjs } else {
25608c2654abSrjs /*
25618c2654abSrjs * Ok we have the same interface as the first one. Move
25628c2654abSrjs * forward until we find either
25638c2654abSrjs * a) one with a NULL route... insert ahead of that
25648c2654abSrjs * b) one with a different ifp.. insert after that.
25658c2654abSrjs * c) end of the list.. insert at the tail.
25668c2654abSrjs */
25678c2654abSrjs struct sctp_nets *netlook;
25688c2654abSrjs struct rtentry *netlook_rt;
25698c2654abSrjs do {
25708c2654abSrjs netlook = TAILQ_NEXT(netfirst, sctp_next);
25718c2654abSrjs if (netlook == NULL) {
25728c2654abSrjs /* End of the list */
25738c2654abSrjs TAILQ_INSERT_TAIL(&stcb->asoc.nets, net,
25748c2654abSrjs sctp_next);
25758c2654abSrjs break;
25768c2654abSrjs } else if ((netlook_rt = rtcache_validate(&netlook->ro)) == NULL) {
25778c2654abSrjs /* next one has NO route */
25788c2654abSrjs TAILQ_INSERT_BEFORE(netfirst, net, sctp_next);
25798c2654abSrjs break;
25808c2654abSrjs } else if (netlook_rt->rt_ifp != rt->rt_ifp) {
25814c25fb2fSozaki-r rtcache_unref(netlook_rt, &netlook->ro);
25828c2654abSrjs TAILQ_INSERT_AFTER(&stcb->asoc.nets, netlook,
25838c2654abSrjs net, sctp_next);
25848c2654abSrjs break;
25858c2654abSrjs }
25864c25fb2fSozaki-r rtcache_unref(netlook_rt, &netlook->ro);
25878c2654abSrjs /* Shift forward */
25888c2654abSrjs netfirst = netlook;
25898c2654abSrjs } while (netlook != NULL);
25904c25fb2fSozaki-r rtcache_unref(netfirst_rt, &netfirst->ro);
25918c2654abSrjs }
25928c2654abSrjs /* got to have a primary set */
25938c2654abSrjs if (stcb->asoc.primary_destination == 0) {
25948c2654abSrjs stcb->asoc.primary_destination = net;
25958c2654abSrjs } else if (!rtcache_validate(&stcb->asoc.primary_destination->ro)) {
25968c2654abSrjs /* No route to current primary adopt new primary */
25978c2654abSrjs stcb->asoc.primary_destination = net;
25988c2654abSrjs }
25998c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb,
26008c2654abSrjs net);
26018c2654abSrjs
26028c2654abSrjs return (0);
26038c2654abSrjs }
26048c2654abSrjs
26058c2654abSrjs
26068c2654abSrjs /*
26078c2654abSrjs * allocate an association and add it to the endpoint. The caller must
26088c2654abSrjs * be careful to add all additional addresses once they are know right
26098c2654abSrjs * away or else the assoc will be may experience a blackout scenario.
26108c2654abSrjs */
26118c2654abSrjs struct sctp_tcb *
sctp_aloc_assoc(struct sctp_inpcb * inp,struct sockaddr * firstaddr,int for_a_init,int * error,uint32_t override_tag)26128c2654abSrjs sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
26138c2654abSrjs int for_a_init, int *error, uint32_t override_tag)
26148c2654abSrjs {
26158c2654abSrjs struct sctp_tcb *stcb;
26168c2654abSrjs struct sctp_association *asoc;
26178c2654abSrjs struct sctpasochead *head;
26188c2654abSrjs uint16_t rport;
26198c2654abSrjs int err;
26208c2654abSrjs
26218c2654abSrjs /*
26228c2654abSrjs * Assumption made here:
26238c2654abSrjs * Caller has done a sctp_findassociation_ep_addr(ep, addr's);
26248c2654abSrjs * to make sure the address does not exist already.
26258c2654abSrjs */
26268c2654abSrjs if (sctppcbinfo.ipi_count_asoc >= SCTP_MAX_NUM_OF_ASOC) {
26278c2654abSrjs /* Hit max assoc, sorry no more */
26288c2654abSrjs *error = ENOBUFS;
26298c2654abSrjs return (NULL);
26308c2654abSrjs }
26318c2654abSrjs SCTP_INP_RLOCK(inp);
26328c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) {
26338c2654abSrjs /*
26348c2654abSrjs * If its in the TCP pool, its NOT allowed to create an
26358c2654abSrjs * association. The parent listener needs to call
26368c2654abSrjs * sctp_aloc_assoc.. or the one-2-many socket. If a
26378c2654abSrjs * peeled off, or connected one does this.. its an error.
26388c2654abSrjs */
26398c2654abSrjs SCTP_INP_RUNLOCK(inp);
26408c2654abSrjs *error = EINVAL;
26418c2654abSrjs return (NULL);
26428c2654abSrjs }
26438c2654abSrjs
26448c2654abSrjs #ifdef SCTP_DEBUG
26458c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB3) {
26468c2654abSrjs printf("Allocate an association for peer:");
26478c2654abSrjs if (firstaddr)
26488c2654abSrjs sctp_print_address(firstaddr);
26498c2654abSrjs else
26508c2654abSrjs printf("None\n");
26518c2654abSrjs printf("Port:%d\n",
26528c2654abSrjs ntohs(((struct sockaddr_in *)firstaddr)->sin_port));
26538c2654abSrjs }
26548c2654abSrjs #endif /* SCTP_DEBUG */
26558c2654abSrjs if (firstaddr->sa_family == AF_INET) {
26568c2654abSrjs struct sockaddr_in *sin;
26578c2654abSrjs sin = (struct sockaddr_in *)firstaddr;
26588c2654abSrjs if ((sin->sin_port == 0) || (sin->sin_addr.s_addr == 0)) {
26598c2654abSrjs /* Invalid address */
26608c2654abSrjs #ifdef SCTP_DEBUG
26618c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB3) {
26628c2654abSrjs printf("peer address invalid\n");
26638c2654abSrjs }
26648c2654abSrjs #endif
26658c2654abSrjs SCTP_INP_RUNLOCK(inp);
26668c2654abSrjs *error = EINVAL;
26678c2654abSrjs return (NULL);
26688c2654abSrjs }
26698c2654abSrjs rport = sin->sin_port;
26708c2654abSrjs } else if (firstaddr->sa_family == AF_INET6) {
26718c2654abSrjs struct sockaddr_in6 *sin6;
26728c2654abSrjs sin6 = (struct sockaddr_in6 *)firstaddr;
26738c2654abSrjs if ((sin6->sin6_port == 0) ||
26748c2654abSrjs (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))) {
26758c2654abSrjs /* Invalid address */
26768c2654abSrjs #ifdef SCTP_DEBUG
26778c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB3) {
26788c2654abSrjs printf("peer address invalid\n");
26798c2654abSrjs }
26808c2654abSrjs #endif
26818c2654abSrjs SCTP_INP_RUNLOCK(inp);
26828c2654abSrjs *error = EINVAL;
26838c2654abSrjs return (NULL);
26848c2654abSrjs }
26858c2654abSrjs rport = sin6->sin6_port;
26868c2654abSrjs } else {
26878c2654abSrjs /* not supported family type */
26888c2654abSrjs #ifdef SCTP_DEBUG
26898c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB3) {
26908c2654abSrjs printf("BAD family %d\n", firstaddr->sa_family);
26918c2654abSrjs }
26928c2654abSrjs #endif
26938c2654abSrjs SCTP_INP_RUNLOCK(inp);
26948c2654abSrjs *error = EINVAL;
26958c2654abSrjs return (NULL);
26968c2654abSrjs }
26978c2654abSrjs SCTP_INP_RUNLOCK(inp);
26988c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
26998c2654abSrjs /*
27008c2654abSrjs * If you have not performed a bind, then we need to do
27018c2654abSrjs * the ephemerial bind for you.
27028c2654abSrjs */
27038c2654abSrjs #ifdef SCTP_DEBUG
27048c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB3) {
27058c2654abSrjs printf("Doing implicit BIND\n");
27068c2654abSrjs }
27078c2654abSrjs #endif
27088c2654abSrjs
27098c2654abSrjs if ((err = sctp_inpcb_bind(inp->sctp_socket,
27108c2654abSrjs (struct sockaddr *)NULL, (struct lwp *)NULL))){
27118c2654abSrjs /* bind error, probably perm */
27128c2654abSrjs #ifdef SCTP_DEBUG
27138c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB3) {
27148c2654abSrjs printf("BIND FAILS ret:%d\n", err);
27158c2654abSrjs }
27168c2654abSrjs #endif
27178c2654abSrjs
27188c2654abSrjs *error = err;
27198c2654abSrjs return (NULL);
27208c2654abSrjs }
27218c2654abSrjs }
27228c2654abSrjs stcb = (struct sctp_tcb *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_asoc);
27238c2654abSrjs if (stcb == NULL) {
27248c2654abSrjs /* out of memory? */
27258c2654abSrjs #ifdef SCTP_DEBUG
27268c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB3) {
27278c2654abSrjs printf("aloc_assoc: no assoc mem left, stcb=NULL\n");
27288c2654abSrjs }
27298c2654abSrjs #endif
27308c2654abSrjs *error = ENOMEM;
27318c2654abSrjs return (NULL);
27328c2654abSrjs }
27338c2654abSrjs sctppcbinfo.ipi_count_asoc++;
27348c2654abSrjs sctppcbinfo.ipi_gencnt_asoc++;
27358c2654abSrjs
27368c2654abSrjs memset(stcb, 0, sizeof(*stcb));
27378c2654abSrjs asoc = &stcb->asoc;
27388c2654abSrjs SCTP_TCB_LOCK_INIT(stcb);
27398c2654abSrjs /* setup back pointers */
27408c2654abSrjs #ifdef SCTP_DEBUG
27418c2654abSrjs printf("Before back pointers\n");
27428c2654abSrjs #endif
27438c2654abSrjs stcb->sctp_ep = inp;
27448c2654abSrjs stcb->sctp_socket = inp->sctp_socket;
27458c2654abSrjs if ((err = sctp_init_asoc(inp, asoc, for_a_init, override_tag))) {
27468c2654abSrjs /* failed */
27478c2654abSrjs SCTP_TCB_LOCK_DESTROY (stcb);
27488c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_asoc, stcb);
27498c2654abSrjs sctppcbinfo.ipi_count_asoc--;
27508c2654abSrjs #ifdef SCTP_DEBUG
27518c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB3) {
27528c2654abSrjs printf("aloc_assoc: couldn't init asoc, out of mem?!\n");
27538c2654abSrjs }
27548c2654abSrjs #endif
27558c2654abSrjs *error = err;
27568c2654abSrjs return (NULL);
27578c2654abSrjs }
27588c2654abSrjs /* and the port */
27598c2654abSrjs stcb->rport = rport;
27608c2654abSrjs SCTP_INP_INFO_WLOCK();
27618c2654abSrjs SCTP_INP_WLOCK(inp);
27628c2654abSrjs if (inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE|SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
27638c2654abSrjs /* inpcb freed while alloc going on */
27648c2654abSrjs SCTP_TCB_LOCK_DESTROY (stcb);
27658c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_asoc, stcb);
27668c2654abSrjs SCTP_INP_WUNLOCK(inp);
27678c2654abSrjs SCTP_INP_INFO_WUNLOCK();
27688c2654abSrjs sctppcbinfo.ipi_count_asoc--;
27698c2654abSrjs #ifdef SCTP_DEBUG
27708c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB3) {
27718c2654abSrjs printf("aloc_assoc: couldn't init asoc, out of mem?!\n");
27728c2654abSrjs }
27738c2654abSrjs #endif
27748c2654abSrjs *error = EINVAL;
27758c2654abSrjs return (NULL);
27768c2654abSrjs }
27778c2654abSrjs SCTP_TCB_LOCK(stcb);
27788c2654abSrjs
27798c2654abSrjs /* now that my_vtag is set, add it to the hash */
27808c2654abSrjs head = &sctppcbinfo.sctp_asochash[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag,
27818c2654abSrjs sctppcbinfo.hashasocmark)];
27828c2654abSrjs /* put it in the bucket in the vtag hash of assoc's for the system */
27838c2654abSrjs LIST_INSERT_HEAD(head, stcb, sctp_asocs);
27848c2654abSrjs SCTP_INP_INFO_WUNLOCK();
27858c2654abSrjs
27868c2654abSrjs
27878c2654abSrjs if ((err = sctp_add_remote_addr(stcb, firstaddr, 1, 1))) {
27888c2654abSrjs /* failure.. memory error? */
27898c2654abSrjs if (asoc->strmout)
27908c2654abSrjs free(asoc->strmout, M_PCB);
27918c2654abSrjs if (asoc->mapping_array)
27928c2654abSrjs free(asoc->mapping_array, M_PCB);
27938c2654abSrjs
27948c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_asoc, stcb);
27958c2654abSrjs sctppcbinfo.ipi_count_asoc--;
27968c2654abSrjs #ifdef SCTP_DEBUG
27978c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB3) {
27988c2654abSrjs printf("aloc_assoc: couldn't add remote addr!\n");
27998c2654abSrjs }
28008c2654abSrjs #endif
28018c2654abSrjs SCTP_TCB_LOCK_DESTROY (stcb);
28028c2654abSrjs *error = ENOBUFS;
28038c2654abSrjs return (NULL);
28048c2654abSrjs }
28058c2654abSrjs /* Init all the timers */
28068c2654abSrjs callout_init(&asoc->hb_timer.timer, 0);
28078c2654abSrjs callout_init(&asoc->dack_timer.timer, 0);
28088c2654abSrjs callout_init(&asoc->asconf_timer.timer, 0);
28098c2654abSrjs callout_init(&asoc->shut_guard_timer.timer, 0);
28108c2654abSrjs callout_init(&asoc->autoclose_timer.timer, 0);
28118c2654abSrjs callout_init(&asoc->delayed_event_timer.timer, 0);
28128c2654abSrjs LIST_INSERT_HEAD(&inp->sctp_asoc_list, stcb, sctp_tcblist);
28138c2654abSrjs /* now file the port under the hash as well */
28148c2654abSrjs #ifdef SCTP_DEBUG
28158c2654abSrjs printf("Before hashing %ld size %d\n",
28168c2654abSrjs inp->sctp_hashmark, sctp_pcbtblsize);
28178c2654abSrjs #endif
28188c2654abSrjs if (inp->sctp_tcbhash != NULL) {
28198c2654abSrjs head = &inp->sctp_tcbhash[SCTP_PCBHASH_ALLADDR(stcb->rport,
28208c2654abSrjs inp->sctp_hashmark)];
28218c2654abSrjs LIST_INSERT_HEAD(head, stcb, sctp_tcbhash);
28228c2654abSrjs }
28238c2654abSrjs #ifdef SCTP_DEBUG
28248c2654abSrjs printf("After hashing\n");
28258c2654abSrjs #endif
28268c2654abSrjs SCTP_INP_WUNLOCK(inp);
28278c2654abSrjs #ifdef SCTP_DEBUG
28288c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
28298c2654abSrjs printf("Association %p now allocated\n", stcb);
28308c2654abSrjs }
28318c2654abSrjs #endif
28328c2654abSrjs return (stcb);
28338c2654abSrjs }
28348c2654abSrjs
28358c2654abSrjs void
sctp_free_remote_addr(struct sctp_nets * net)28368c2654abSrjs sctp_free_remote_addr(struct sctp_nets *net)
28378c2654abSrjs {
28388c2654abSrjs if (net == NULL)
28398c2654abSrjs return;
28408c2654abSrjs net->ref_count--;
28418c2654abSrjs if (net->ref_count <= 0) {
28428c2654abSrjs /* stop timer if running */
28438c2654abSrjs callout_stop(&net->rxt_timer.timer);
28448c2654abSrjs callout_stop(&net->pmtu_timer.timer);
28458c2654abSrjs callout_destroy(&net->rxt_timer.timer);
28468c2654abSrjs callout_destroy(&net->pmtu_timer.timer);
28478c2654abSrjs net->dest_state = SCTP_ADDR_NOT_REACHABLE;
2848b65559a5Srjs rtcache_free(&net->ro);
28498c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_net, net);
28508c2654abSrjs sctppcbinfo.ipi_count_raddr--;
28518c2654abSrjs }
28528c2654abSrjs }
28538c2654abSrjs
28548c2654abSrjs /*
28558c2654abSrjs * remove a remote endpoint address from an association, it
28568c2654abSrjs * will fail if the address does not exist.
28578c2654abSrjs */
28588c2654abSrjs int
sctp_del_remote_addr(struct sctp_tcb * stcb,struct sockaddr * remaddr)28598c2654abSrjs sctp_del_remote_addr(struct sctp_tcb *stcb, struct sockaddr *remaddr)
28608c2654abSrjs {
28618c2654abSrjs /*
28628c2654abSrjs * Here we need to remove a remote address. This is quite simple, we
28638c2654abSrjs * first find it in the list of address for the association
28648c2654abSrjs * (tasoc->asoc.nets) and then if it is there, we do a LIST_REMOVE on
28658c2654abSrjs * that item.
28668c2654abSrjs * Note we do not allow it to be removed if there are no other
28678c2654abSrjs * addresses.
28688c2654abSrjs */
28698c2654abSrjs struct sctp_association *asoc;
28708c2654abSrjs struct sctp_nets *net, *net_tmp;
28718c2654abSrjs asoc = &stcb->asoc;
28728c2654abSrjs if (asoc->numnets < 2) {
28738c2654abSrjs /* Must have at LEAST two remote addresses */
28748c2654abSrjs return (-1);
28758c2654abSrjs }
28768c2654abSrjs /* locate the address */
28778c2654abSrjs for (net = TAILQ_FIRST(&asoc->nets); net != NULL; net = net_tmp) {
28788c2654abSrjs net_tmp = TAILQ_NEXT(net, sctp_next);
28798c2654abSrjs if (rtcache_getdst(&net->ro)->sa_family != remaddr->sa_family) {
28808c2654abSrjs continue;
28818c2654abSrjs }
28828c2654abSrjs if (sctp_cmpaddr(rtcache_getdst(&net->ro), remaddr)) {
28838c2654abSrjs /* we found the guy */
28848c2654abSrjs asoc->numnets--;
28858c2654abSrjs TAILQ_REMOVE(&asoc->nets, net, sctp_next);
28868c2654abSrjs sctp_free_remote_addr(net);
28878c2654abSrjs if (net == asoc->primary_destination) {
28888c2654abSrjs /* Reset primary */
28898c2654abSrjs struct sctp_nets *lnet;
28908c2654abSrjs lnet = TAILQ_FIRST(&asoc->nets);
28918c2654abSrjs /* Try to find a confirmed primary */
28928c2654abSrjs asoc->primary_destination =
28938c2654abSrjs sctp_find_alternate_net(stcb, lnet);
28948c2654abSrjs }
28958c2654abSrjs if (net == asoc->last_data_chunk_from) {
28968c2654abSrjs /* Reset primary */
28978c2654abSrjs asoc->last_data_chunk_from =
28988c2654abSrjs TAILQ_FIRST(&asoc->nets);
28998c2654abSrjs }
29008c2654abSrjs if (net == asoc->last_control_chunk_from) {
29018c2654abSrjs /* Reset primary */
29028c2654abSrjs asoc->last_control_chunk_from =
29038c2654abSrjs TAILQ_FIRST(&asoc->nets);
29048c2654abSrjs }
29058c2654abSrjs if (net == asoc->asconf_last_sent_to) {
29068c2654abSrjs /* Reset primary */
29078c2654abSrjs asoc->asconf_last_sent_to =
29088c2654abSrjs TAILQ_FIRST(&asoc->nets);
29098c2654abSrjs }
29108c2654abSrjs return (0);
29118c2654abSrjs }
29128c2654abSrjs }
29138c2654abSrjs /* not found. */
29148c2654abSrjs return (-2);
29158c2654abSrjs }
29168c2654abSrjs
29178c2654abSrjs
29188c2654abSrjs static void
sctp_add_vtag_to_timewait(struct sctp_inpcb * inp,u_int32_t tag)29198c2654abSrjs sctp_add_vtag_to_timewait(struct sctp_inpcb *inp, u_int32_t tag)
29208c2654abSrjs {
29218c2654abSrjs struct sctpvtaghead *chain;
29228c2654abSrjs struct sctp_tagblock *twait_block;
29238c2654abSrjs struct timeval now;
29248c2654abSrjs int set, i;
29258c2654abSrjs SCTP_GETTIME_TIMEVAL(&now);
29268c2654abSrjs chain = &sctppcbinfo.vtag_timewait[(tag % SCTP_STACK_VTAG_HASH_SIZE)];
29278c2654abSrjs set = 0;
29288c2654abSrjs if (!LIST_EMPTY(chain)) {
29298c2654abSrjs /* Block(s) present, lets find space, and expire on the fly */
29308c2654abSrjs LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) {
29318c2654abSrjs for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) {
29328c2654abSrjs if ((twait_block->vtag_block[i].v_tag == 0) &&
29338c2654abSrjs !set) {
29348c2654abSrjs twait_block->vtag_block[0].tv_sec_at_expire =
29358c2654abSrjs now.tv_sec + SCTP_TIME_WAIT;
29368c2654abSrjs twait_block->vtag_block[0].v_tag = tag;
29378c2654abSrjs set = 1;
29388c2654abSrjs } else if ((twait_block->vtag_block[i].v_tag) &&
29398c2654abSrjs ((long)twait_block->vtag_block[i].tv_sec_at_expire >
29408c2654abSrjs now.tv_sec)) {
29418c2654abSrjs /* Audit expires this guy */
29428c2654abSrjs twait_block->vtag_block[i].tv_sec_at_expire = 0;
29438c2654abSrjs twait_block->vtag_block[i].v_tag = 0;
29448c2654abSrjs if (set == 0) {
29458c2654abSrjs /* Reuse it for my new tag */
29468c2654abSrjs twait_block->vtag_block[0].tv_sec_at_expire = now.tv_sec + SCTP_TIME_WAIT;
29478c2654abSrjs twait_block->vtag_block[0].v_tag = tag;
29488c2654abSrjs set = 1;
29498c2654abSrjs }
29508c2654abSrjs }
29518c2654abSrjs }
29528c2654abSrjs if (set) {
29538c2654abSrjs /*
29548c2654abSrjs * We only do up to the block where we can
29558c2654abSrjs * place our tag for audits
29568c2654abSrjs */
29578c2654abSrjs break;
29588c2654abSrjs }
29598c2654abSrjs }
29608c2654abSrjs }
29618c2654abSrjs /* Need to add a new block to chain */
29628c2654abSrjs if (!set) {
29638c2654abSrjs twait_block = malloc(sizeof(struct sctp_tagblock), M_PCB, M_NOWAIT);
29648c2654abSrjs if (twait_block == NULL) {
29658c2654abSrjs return;
29668c2654abSrjs }
29678c2654abSrjs memset(twait_block, 0, sizeof(struct sctp_timewait));
29688c2654abSrjs LIST_INSERT_HEAD(chain, twait_block, sctp_nxt_tagblock);
29698c2654abSrjs twait_block->vtag_block[0].tv_sec_at_expire = now.tv_sec +
29708c2654abSrjs SCTP_TIME_WAIT;
29718c2654abSrjs twait_block->vtag_block[0].v_tag = tag;
29728c2654abSrjs }
29738c2654abSrjs }
29748c2654abSrjs
29758c2654abSrjs
29768c2654abSrjs static void
sctp_iterator_asoc_being_freed(struct sctp_inpcb * inp,struct sctp_tcb * stcb)29778c2654abSrjs sctp_iterator_asoc_being_freed(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
29788c2654abSrjs {
29798c2654abSrjs struct sctp_iterator *it;
29808c2654abSrjs
29818c2654abSrjs
29828c2654abSrjs
29838c2654abSrjs /* Unlock the tcb lock we do this so
29848c2654abSrjs * we avoid a dead lock scenario where
29858c2654abSrjs * the iterator is waiting on the TCB lock
29868c2654abSrjs * and the TCB lock is waiting on the iterator
29878c2654abSrjs * lock.
29888c2654abSrjs */
29898c2654abSrjs SCTP_ITERATOR_LOCK();
29908c2654abSrjs SCTP_INP_INFO_WLOCK();
29918c2654abSrjs SCTP_INP_WLOCK(inp);
29928c2654abSrjs SCTP_TCB_LOCK(stcb);
29938c2654abSrjs
29948c2654abSrjs it = stcb->asoc.stcb_starting_point_for_iterator;
29958c2654abSrjs if (it == NULL) {
29968c2654abSrjs return;
29978c2654abSrjs }
29988c2654abSrjs if (it->inp != stcb->sctp_ep) {
29998c2654abSrjs /* hm, focused on the wrong one? */
30008c2654abSrjs return;
30018c2654abSrjs }
30028c2654abSrjs if (it->stcb != stcb) {
30038c2654abSrjs return;
30048c2654abSrjs }
30058c2654abSrjs it->stcb = LIST_NEXT(stcb, sctp_tcblist);
30068c2654abSrjs if (it->stcb == NULL) {
30078c2654abSrjs /* done with all asoc's in this assoc */
30088c2654abSrjs if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
30098c2654abSrjs it->inp = NULL;
30108c2654abSrjs } else {
30118c2654abSrjs
30128c2654abSrjs it->inp = LIST_NEXT(inp, sctp_list);
30138c2654abSrjs }
30148c2654abSrjs }
30158c2654abSrjs }
30168c2654abSrjs
30178c2654abSrjs /*
30188c2654abSrjs * Free the association after un-hashing the remote port.
30198c2654abSrjs */
30208c2654abSrjs void
sctp_free_assoc(struct sctp_inpcb * inp,struct sctp_tcb * stcb)30218c2654abSrjs sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
30228c2654abSrjs {
30238c2654abSrjs struct sctp_association *asoc;
30248c2654abSrjs struct sctp_nets *net, *prev;
30258c2654abSrjs struct sctp_laddr *laddr;
30268c2654abSrjs struct sctp_tmit_chunk *chk;
30278c2654abSrjs struct sctp_asconf_addr *aparam;
30288c2654abSrjs struct sctp_socket_q_list *sq;
30298c2654abSrjs int s;
30308c2654abSrjs
30318c2654abSrjs /* first, lets purge the entry from the hash table. */
30328c2654abSrjs s = splsoftnet();
30338c2654abSrjs if (stcb->asoc.state == 0) {
30348c2654abSrjs printf("Freeing already free association:%p - huh??\n",
30358c2654abSrjs stcb);
30368c2654abSrjs splx(s);
30378c2654abSrjs return;
30388c2654abSrjs }
30398c2654abSrjs asoc = &stcb->asoc;
30408c2654abSrjs asoc->state = 0;
30418c2654abSrjs /* now clean up any other timers */
30428c2654abSrjs callout_stop(&asoc->hb_timer.timer);
30438c2654abSrjs callout_destroy(&asoc->hb_timer.timer);
30448c2654abSrjs callout_stop(&asoc->dack_timer.timer);
30458c2654abSrjs callout_destroy(&asoc->dack_timer.timer);
30468c2654abSrjs callout_stop(&asoc->asconf_timer.timer);
30478c2654abSrjs callout_destroy(&asoc->asconf_timer.timer);
30488c2654abSrjs callout_stop(&asoc->shut_guard_timer.timer);
30498c2654abSrjs callout_destroy(&asoc->shut_guard_timer.timer);
30508c2654abSrjs callout_stop(&asoc->autoclose_timer.timer);
30518c2654abSrjs callout_destroy(&asoc->autoclose_timer.timer);
30528c2654abSrjs callout_stop(&asoc->delayed_event_timer.timer);
30538c2654abSrjs callout_destroy(&asoc->delayed_event_timer.timer);
30548c2654abSrjs TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
30558c2654abSrjs callout_stop(&net->rxt_timer.timer);
30568c2654abSrjs callout_stop(&net->pmtu_timer.timer);
30578c2654abSrjs callout_destroy(&net->rxt_timer.timer);
30588c2654abSrjs callout_destroy(&net->pmtu_timer.timer);
30598c2654abSrjs }
30608c2654abSrjs
30618c2654abSrjs /* Iterator asoc being freed we send an
30628c2654abSrjs * unlocked TCB. It returns with INP_INFO
30638c2654abSrjs * and INP write locked and the TCB locked
30648c2654abSrjs * too and of course the iterator lock
30658c2654abSrjs * in place as well..
30668c2654abSrjs */
30678c2654abSrjs SCTP_TCB_UNLOCK(stcb);
30688c2654abSrjs sctp_iterator_asoc_being_freed(inp, stcb);
30698c2654abSrjs
30708c2654abSrjs /* Null all of my entry's on the socket q */
30718c2654abSrjs TAILQ_FOREACH(sq, &inp->sctp_queue_list, next_sq) {
30728c2654abSrjs if (sq->tcb == stcb) {
30738c2654abSrjs sq->tcb = NULL;
30748c2654abSrjs }
30758c2654abSrjs }
30768c2654abSrjs
30778c2654abSrjs if (inp->sctp_tcb_at_block == (void *)stcb) {
30788c2654abSrjs inp->error_on_block = ECONNRESET;
30798c2654abSrjs }
30808c2654abSrjs
30818c2654abSrjs if (inp->sctp_tcbhash) {
30828c2654abSrjs LIST_REMOVE(stcb, sctp_tcbhash);
30838c2654abSrjs }
30848c2654abSrjs /* Now lets remove it from the list of ALL associations in the EP */
30858c2654abSrjs LIST_REMOVE(stcb, sctp_tcblist);
30868c2654abSrjs SCTP_INP_WUNLOCK(inp);
30878c2654abSrjs SCTP_ITERATOR_UNLOCK();
30888c2654abSrjs
30898c2654abSrjs
30908c2654abSrjs /* pull from vtag hash */
30918c2654abSrjs LIST_REMOVE(stcb, sctp_asocs);
30928c2654abSrjs
30938c2654abSrjs /*
30948c2654abSrjs * Now before we can free the assoc, we must remove all of the
30958c2654abSrjs * networks and any other allocated space.. i.e. add removes here
30968c2654abSrjs * before the SCTP_ZONE_FREE() of the tasoc entry.
30978c2654abSrjs */
30988c2654abSrjs
30998c2654abSrjs sctp_add_vtag_to_timewait(inp, asoc->my_vtag);
31008c2654abSrjs SCTP_INP_INFO_WUNLOCK();
31018c2654abSrjs prev = NULL;
31028c2654abSrjs while (!TAILQ_EMPTY(&asoc->nets)) {
31038c2654abSrjs net = TAILQ_FIRST(&asoc->nets);
31048c2654abSrjs /* pull from list */
31058c2654abSrjs if ((sctppcbinfo.ipi_count_raddr == 0) || (prev == net)) {
31068c2654abSrjs break;
31078c2654abSrjs }
31088c2654abSrjs prev = net;
31098c2654abSrjs TAILQ_REMOVE(&asoc->nets, net, sctp_next);
3110b65559a5Srjs rtcache_free(&net->ro);
31118c2654abSrjs /* free it */
31128c2654abSrjs net->ref_count = 0;
31138c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_net, net);
31148c2654abSrjs sctppcbinfo.ipi_count_raddr--;
31158c2654abSrjs }
31168c2654abSrjs /*
31178c2654abSrjs * The chunk lists and such SHOULD be empty but we check them
31188c2654abSrjs * just in case.
31198c2654abSrjs */
31208c2654abSrjs /* anything on the wheel needs to be removed */
31218c2654abSrjs while (!TAILQ_EMPTY(&asoc->out_wheel)) {
31228c2654abSrjs struct sctp_stream_out *outs;
31238c2654abSrjs outs = TAILQ_FIRST(&asoc->out_wheel);
31248c2654abSrjs TAILQ_REMOVE(&asoc->out_wheel, outs, next_spoke);
31258c2654abSrjs /* now clean up any chunks here */
31268c2654abSrjs chk = TAILQ_FIRST(&outs->outqueue);
31278c2654abSrjs while (chk) {
31288c2654abSrjs TAILQ_REMOVE(&outs->outqueue, chk, sctp_next);
31298c2654abSrjs sctp_m_freem(chk->data);
31308c2654abSrjs chk->data = NULL;
31318c2654abSrjs chk->whoTo = NULL;
31328c2654abSrjs chk->asoc = NULL;
31338c2654abSrjs /* Free the chunk */
31348c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
31358c2654abSrjs sctppcbinfo.ipi_count_chunk--;
31368c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++;
31378c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) {
31388c2654abSrjs panic("Chunk count is negative");
31398c2654abSrjs }
31408c2654abSrjs chk = TAILQ_FIRST(&outs->outqueue);
31418c2654abSrjs }
31428c2654abSrjs outs = TAILQ_FIRST(&asoc->out_wheel);
31438c2654abSrjs }
31448c2654abSrjs
31458c2654abSrjs if (asoc->pending_reply) {
31468c2654abSrjs free(asoc->pending_reply, M_PCB);
31478c2654abSrjs asoc->pending_reply = NULL;
31488c2654abSrjs }
31498c2654abSrjs chk = TAILQ_FIRST(&asoc->pending_reply_queue);
31508c2654abSrjs while (chk) {
31518c2654abSrjs TAILQ_REMOVE(&asoc->pending_reply_queue, chk, sctp_next);
31528c2654abSrjs sctp_m_freem(chk->data);
31538c2654abSrjs chk->data = NULL;
31548c2654abSrjs chk->whoTo = NULL;
31558c2654abSrjs chk->asoc = NULL;
31568c2654abSrjs /* Free the chunk */
31578c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
31588c2654abSrjs sctppcbinfo.ipi_count_chunk--;
31598c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++;
31608c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) {
31618c2654abSrjs panic("Chunk count is negative");
31628c2654abSrjs }
31638c2654abSrjs chk = TAILQ_FIRST(&asoc->pending_reply_queue);
31648c2654abSrjs }
31658c2654abSrjs /* pending send queue SHOULD be empty */
31668c2654abSrjs if (!TAILQ_EMPTY(&asoc->send_queue)) {
31678c2654abSrjs chk = TAILQ_FIRST(&asoc->send_queue);
31688c2654abSrjs while (chk) {
31698c2654abSrjs TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next);
31708c2654abSrjs sctp_m_freem(chk->data);
31718c2654abSrjs chk->data = NULL;
31728c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
31738c2654abSrjs sctppcbinfo.ipi_count_chunk--;
31748c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) {
31758c2654abSrjs panic("Chunk count is negative");
31768c2654abSrjs }
31778c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++;
31788c2654abSrjs chk = TAILQ_FIRST(&asoc->send_queue);
31798c2654abSrjs }
31808c2654abSrjs }
31818c2654abSrjs /* sent queue SHOULD be empty */
31828c2654abSrjs if (!TAILQ_EMPTY(&asoc->sent_queue)) {
31838c2654abSrjs chk = TAILQ_FIRST(&asoc->sent_queue);
31848c2654abSrjs while (chk) {
31858c2654abSrjs TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
31868c2654abSrjs sctp_m_freem(chk->data);
31878c2654abSrjs chk->data = NULL;
31888c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
31898c2654abSrjs sctppcbinfo.ipi_count_chunk--;
31908c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) {
31918c2654abSrjs panic("Chunk count is negative");
31928c2654abSrjs }
31938c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++;
31948c2654abSrjs chk = TAILQ_FIRST(&asoc->sent_queue);
31958c2654abSrjs }
31968c2654abSrjs }
31978c2654abSrjs /* control queue MAY not be empty */
31988c2654abSrjs if (!TAILQ_EMPTY(&asoc->control_send_queue)) {
31998c2654abSrjs chk = TAILQ_FIRST(&asoc->control_send_queue);
32008c2654abSrjs while (chk) {
32018c2654abSrjs TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next);
32028c2654abSrjs sctp_m_freem(chk->data);
32038c2654abSrjs chk->data = NULL;
32048c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
32058c2654abSrjs sctppcbinfo.ipi_count_chunk--;
32068c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) {
32078c2654abSrjs panic("Chunk count is negative");
32088c2654abSrjs }
32098c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++;
32108c2654abSrjs chk = TAILQ_FIRST(&asoc->control_send_queue);
32118c2654abSrjs }
32128c2654abSrjs }
32138c2654abSrjs if (!TAILQ_EMPTY(&asoc->reasmqueue)) {
32148c2654abSrjs chk = TAILQ_FIRST(&asoc->reasmqueue);
32158c2654abSrjs while (chk) {
32168c2654abSrjs TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
32178c2654abSrjs sctp_m_freem(chk->data);
32188c2654abSrjs chk->data = NULL;
32198c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
32208c2654abSrjs sctppcbinfo.ipi_count_chunk--;
32218c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) {
32228c2654abSrjs panic("Chunk count is negative");
32238c2654abSrjs }
32248c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++;
32258c2654abSrjs chk = TAILQ_FIRST(&asoc->reasmqueue);
32268c2654abSrjs }
32278c2654abSrjs }
32288c2654abSrjs if (!TAILQ_EMPTY(&asoc->delivery_queue)) {
32298c2654abSrjs chk = TAILQ_FIRST(&asoc->delivery_queue);
32308c2654abSrjs while (chk) {
32318c2654abSrjs TAILQ_REMOVE(&asoc->delivery_queue, chk, sctp_next);
32328c2654abSrjs sctp_m_freem(chk->data);
32338c2654abSrjs chk->data = NULL;
32348c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
32358c2654abSrjs sctppcbinfo.ipi_count_chunk--;
32368c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) {
32378c2654abSrjs panic("Chunk count is negative");
32388c2654abSrjs }
32398c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++;
32408c2654abSrjs chk = TAILQ_FIRST(&asoc->delivery_queue);
32418c2654abSrjs }
32428c2654abSrjs }
32438c2654abSrjs if (asoc->mapping_array) {
32448c2654abSrjs free(asoc->mapping_array, M_PCB);
32458c2654abSrjs asoc->mapping_array = NULL;
32468c2654abSrjs }
32478c2654abSrjs
32488c2654abSrjs /* the stream outs */
32498c2654abSrjs if (asoc->strmout) {
32508c2654abSrjs free(asoc->strmout, M_PCB);
32518c2654abSrjs asoc->strmout = NULL;
32528c2654abSrjs }
32538c2654abSrjs asoc->streamoutcnt = 0;
32548c2654abSrjs if (asoc->strmin) {
32558c2654abSrjs int i;
32568c2654abSrjs for (i = 0; i < asoc->streamincnt; i++) {
32578c2654abSrjs if (!TAILQ_EMPTY(&asoc->strmin[i].inqueue)) {
32588c2654abSrjs /* We have somethings on the streamin queue */
32598c2654abSrjs chk = TAILQ_FIRST(&asoc->strmin[i].inqueue);
32608c2654abSrjs while (chk) {
32618c2654abSrjs TAILQ_REMOVE(&asoc->strmin[i].inqueue,
32628c2654abSrjs chk, sctp_next);
32638c2654abSrjs sctp_m_freem(chk->data);
32648c2654abSrjs chk->data = NULL;
32658c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk,
32668c2654abSrjs chk);
32678c2654abSrjs sctppcbinfo.ipi_count_chunk--;
32688c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) {
32698c2654abSrjs panic("Chunk count is negative");
32708c2654abSrjs }
32718c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++;
32728c2654abSrjs chk = TAILQ_FIRST(&asoc->strmin[i].inqueue);
32738c2654abSrjs }
32748c2654abSrjs }
32758c2654abSrjs }
32768c2654abSrjs free(asoc->strmin, M_PCB);
32778c2654abSrjs asoc->strmin = NULL;
32788c2654abSrjs }
32798c2654abSrjs asoc->streamincnt = 0;
32808c2654abSrjs /* local addresses, if any */
32818c2654abSrjs while (!LIST_EMPTY(&asoc->sctp_local_addr_list)) {
32828c2654abSrjs laddr = LIST_FIRST(&asoc->sctp_local_addr_list);
32838c2654abSrjs LIST_REMOVE(laddr, sctp_nxt_addr);
32848c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_laddr, laddr);
32858c2654abSrjs sctppcbinfo.ipi_count_laddr--;
32868c2654abSrjs }
32878c2654abSrjs /* pending asconf (address) parameters */
32888c2654abSrjs while (!TAILQ_EMPTY(&asoc->asconf_queue)) {
32898c2654abSrjs aparam = TAILQ_FIRST(&asoc->asconf_queue);
32908c2654abSrjs TAILQ_REMOVE(&asoc->asconf_queue, aparam, next);
32918c2654abSrjs free(aparam, M_PCB);
32928c2654abSrjs }
32938c2654abSrjs sctp_m_freem(asoc->last_asconf_ack_sent);
32948c2654abSrjs asoc->last_asconf_ack_sent = NULL;
32958c2654abSrjs /* Insert new items here :> */
32968c2654abSrjs
32978c2654abSrjs /* Get rid of LOCK */
32988c2654abSrjs SCTP_TCB_LOCK_DESTROY(stcb);
32998c2654abSrjs
33008c2654abSrjs /* now clean up the tasoc itself */
33018c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_asoc, stcb);
33028c2654abSrjs sctppcbinfo.ipi_count_asoc--;
33038c2654abSrjs if ((inp->sctp_socket->so_snd.sb_cc) ||
33048c2654abSrjs (inp->sctp_socket->so_snd.sb_mbcnt)) {
33058c2654abSrjs /* This will happen when a abort is done */
33068c2654abSrjs inp->sctp_socket->so_snd.sb_cc = 0;
33078c2654abSrjs inp->sctp_socket->so_snd.sb_mbcnt = 0;
33088c2654abSrjs }
33098c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
33108c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) {
33118c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
33128c2654abSrjs /*
33138c2654abSrjs * For the base fd, that is NOT in TCP pool we
33148c2654abSrjs * turn off the connected flag. This allows
33158c2654abSrjs * non-listening endpoints to connect/shutdown/
33168c2654abSrjs * connect.
33178c2654abSrjs */
33188c2654abSrjs inp->sctp_flags &= ~SCTP_PCB_FLAGS_CONNECTED;
33198c2654abSrjs soisdisconnected(inp->sctp_socket);
33208c2654abSrjs }
33218c2654abSrjs /*
33228c2654abSrjs * For those that are in the TCP pool we just leave
33238c2654abSrjs * so it cannot be used. When they close the fd we
33248c2654abSrjs * will free it all.
33258c2654abSrjs */
33268c2654abSrjs }
33278c2654abSrjs }
33288c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
33298c2654abSrjs sctp_inpcb_free(inp, 0);
33308c2654abSrjs }
33318c2654abSrjs splx(s);
33328c2654abSrjs }
33338c2654abSrjs
33348c2654abSrjs
33358c2654abSrjs /*
33368c2654abSrjs * determine if a destination is "reachable" based upon the addresses
33378c2654abSrjs * bound to the current endpoint (e.g. only v4 or v6 currently bound)
33388c2654abSrjs */
33398c2654abSrjs /*
33408c2654abSrjs * FIX: if we allow assoc-level bindx(), then this needs to be fixed
33418c2654abSrjs * to use assoc level v4/v6 flags, as the assoc *may* not have the
33428c2654abSrjs * same address types bound as its endpoint
33438c2654abSrjs */
33448c2654abSrjs int
sctp_destination_is_reachable(struct sctp_tcb * stcb,const struct sockaddr * destaddr)33458c2654abSrjs sctp_destination_is_reachable(struct sctp_tcb *stcb, const struct sockaddr *destaddr)
33468c2654abSrjs {
33478c2654abSrjs struct sctp_inpcb *inp;
33488c2654abSrjs int answer;
33498c2654abSrjs
33508c2654abSrjs /* No locks here, the TCB, in all cases is already
33518c2654abSrjs * locked and an assoc is up. There is either a
33528c2654abSrjs * INP lock by the caller applied (in asconf case when
33538c2654abSrjs * deleting an address) or NOT in the HB case, however
33548c2654abSrjs * if HB then the INP increment is up and the INP
33558c2654abSrjs * will not be removed (on top of the fact that
33568c2654abSrjs * we have a TCB lock). So we only want to
33578c2654abSrjs * read the sctp_flags, which is either bound-all
33588c2654abSrjs * or not.. no protection needed since once an
33598c2654abSrjs * assoc is up you can't be changing your binding.
33608c2654abSrjs */
33618c2654abSrjs inp = stcb->sctp_ep;
33628c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
33638c2654abSrjs /* if bound all, destination is not restricted */
33648c2654abSrjs /* RRS: Question during lock work: Is this
33658c2654abSrjs * correct? If you are bound-all you still
33668c2654abSrjs * might need to obey the V4--V6 flags???
33678c2654abSrjs * IMO this bound-all stuff needs to be removed!
33688c2654abSrjs */
33698c2654abSrjs return (1);
33708c2654abSrjs }
33718c2654abSrjs /* NOTE: all "scope" checks are done when local addresses are added */
33728c2654abSrjs if (destaddr->sa_family == AF_INET6) {
33738c2654abSrjs answer = inp->inp_vflag & INP_IPV6;
33748c2654abSrjs } else if (destaddr->sa_family == AF_INET) {
33758c2654abSrjs answer = inp->inp_vflag & INP_IPV4;
33768c2654abSrjs } else {
33778c2654abSrjs /* invalid family, so it's unreachable */
33788c2654abSrjs answer = 0;
33798c2654abSrjs }
33808c2654abSrjs return (answer);
33818c2654abSrjs }
33828c2654abSrjs
33838c2654abSrjs /*
33848c2654abSrjs * update the inp_vflags on an endpoint
33858c2654abSrjs */
33868c2654abSrjs static void
sctp_update_ep_vflag(struct sctp_inpcb * inp)33878c2654abSrjs sctp_update_ep_vflag(struct sctp_inpcb *inp) {
33888c2654abSrjs struct sctp_laddr *laddr;
33898c2654abSrjs
33908c2654abSrjs /* first clear the flag */
33918c2654abSrjs inp->inp_vflag = 0;
33923fb74706Srjs
33938c2654abSrjs /* set the flag based on addresses on the ep list */
33948c2654abSrjs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
33958c2654abSrjs if (laddr->ifa == NULL) {
33968c2654abSrjs #ifdef SCTP_DEBUG
33978c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
33988c2654abSrjs printf("An ounce of prevention is worth a pound of cure\n");
33998c2654abSrjs }
34008c2654abSrjs #endif /* SCTP_DEBUG */
34018c2654abSrjs continue;
34028c2654abSrjs }
34038c2654abSrjs if (laddr->ifa->ifa_addr) {
34048c2654abSrjs continue;
34058c2654abSrjs }
34068c2654abSrjs if (laddr->ifa->ifa_addr->sa_family == AF_INET6) {
34078c2654abSrjs inp->inp_vflag |= INP_IPV6;
34088c2654abSrjs } else if (laddr->ifa->ifa_addr->sa_family == AF_INET) {
34098c2654abSrjs inp->inp_vflag |= INP_IPV4;
34108c2654abSrjs }
34118c2654abSrjs }
34128c2654abSrjs }
34138c2654abSrjs
34148c2654abSrjs /*
34158c2654abSrjs * Add the address to the endpoint local address list
34168c2654abSrjs * There is nothing to be done if we are bound to all addresses
34178c2654abSrjs */
34188c2654abSrjs int
sctp_add_local_addr_ep(struct sctp_inpcb * inp,struct ifaddr * ifa)34198c2654abSrjs sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct ifaddr *ifa)
34208c2654abSrjs {
34218c2654abSrjs struct sctp_laddr *laddr;
34228c2654abSrjs int fnd, error;
34238c2654abSrjs fnd = 0;
34248c2654abSrjs
34258c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
34268c2654abSrjs /* You are already bound to all. You have it already */
34278c2654abSrjs return (0);
34288c2654abSrjs }
34298c2654abSrjs if (ifa->ifa_addr->sa_family == AF_INET6) {
34308c2654abSrjs struct in6_ifaddr *ifa6;
34318c2654abSrjs ifa6 = (struct in6_ifaddr *)ifa;
34328c2654abSrjs if (ifa6->ia6_flags & (IN6_IFF_DETACHED |
34338c2654abSrjs IN6_IFF_DEPRECATED | IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))
34348c2654abSrjs /* Can't bind a non-existent addr. */
34358c2654abSrjs return (-1);
34368c2654abSrjs }
34378c2654abSrjs /* first, is it already present? */
34388c2654abSrjs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
34398c2654abSrjs if (laddr->ifa == ifa) {
34408c2654abSrjs fnd = 1;
34418c2654abSrjs break;
34428c2654abSrjs }
34438c2654abSrjs }
34448c2654abSrjs
34458c2654abSrjs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) && (fnd == 0)) {
34468c2654abSrjs /* Not bound to all */
34478c2654abSrjs error = sctp_insert_laddr(&inp->sctp_addr_list, ifa);
34488c2654abSrjs if (error != 0)
34498c2654abSrjs return (error);
34508c2654abSrjs inp->laddr_count++;
34518c2654abSrjs /* update inp_vflag flags */
34528c2654abSrjs if (ifa->ifa_addr->sa_family == AF_INET6) {
34538c2654abSrjs inp->inp_vflag |= INP_IPV6;
34548c2654abSrjs } else if (ifa->ifa_addr->sa_family == AF_INET) {
34558c2654abSrjs inp->inp_vflag |= INP_IPV4;
34568c2654abSrjs }
34578c2654abSrjs }
34588c2654abSrjs return (0);
34598c2654abSrjs }
34608c2654abSrjs
34618c2654abSrjs
34628c2654abSrjs /*
34638c2654abSrjs * select a new (hopefully reachable) destination net
34648c2654abSrjs * (should only be used when we deleted an ep addr that is the
34658c2654abSrjs * only usable source address to reach the destination net)
34668c2654abSrjs */
34678c2654abSrjs static void
sctp_select_primary_destination(struct sctp_tcb * stcb)34688c2654abSrjs sctp_select_primary_destination(struct sctp_tcb *stcb)
34698c2654abSrjs {
34708c2654abSrjs struct sctp_nets *net;
34718c2654abSrjs
34728c2654abSrjs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
34738c2654abSrjs /* for now, we'll just pick the first reachable one we find */
34748c2654abSrjs if (net->dest_state & SCTP_ADDR_UNCONFIRMED)
34758c2654abSrjs continue;
34768c2654abSrjs if (sctp_destination_is_reachable(stcb,
34778c2654abSrjs rtcache_getdst(&net->ro))) {
34788c2654abSrjs /* found a reachable destination */
34798c2654abSrjs stcb->asoc.primary_destination = net;
34808c2654abSrjs }
34818c2654abSrjs }
34828c2654abSrjs /* I can't there from here! ...we're gonna die shortly... */
34838c2654abSrjs }
34848c2654abSrjs
34858c2654abSrjs
34868c2654abSrjs /*
34878c2654abSrjs * Delete the address from the endpoint local address list
34888c2654abSrjs * There is nothing to be done if we are bound to all addresses
34898c2654abSrjs */
34908c2654abSrjs int
sctp_del_local_addr_ep(struct sctp_inpcb * inp,struct ifaddr * ifa)34918c2654abSrjs sctp_del_local_addr_ep(struct sctp_inpcb *inp, struct ifaddr *ifa)
34928c2654abSrjs {
34938c2654abSrjs struct sctp_laddr *laddr;
34948c2654abSrjs int fnd;
34958c2654abSrjs fnd = 0;
34968c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
34978c2654abSrjs /* You are already bound to all. You have it already */
34988c2654abSrjs return (EINVAL);
34998c2654abSrjs }
35008c2654abSrjs
35018c2654abSrjs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
35028c2654abSrjs if (laddr->ifa == ifa) {
35038c2654abSrjs fnd = 1;
35048c2654abSrjs break;
35058c2654abSrjs }
35068c2654abSrjs }
35078c2654abSrjs if (fnd && (inp->laddr_count < 2)) {
35088c2654abSrjs /* can't delete unless there are at LEAST 2 addresses */
35098c2654abSrjs return (-1);
35108c2654abSrjs }
35118c2654abSrjs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) && (fnd)) {
35128c2654abSrjs /*
35138c2654abSrjs * clean up any use of this address
35148c2654abSrjs * go through our associations and clear any
35158c2654abSrjs * last_used_address that match this one
35168c2654abSrjs * for each assoc, see if a new primary_destination is needed
35178c2654abSrjs */
35188c2654abSrjs struct sctp_tcb *stcb;
35198c2654abSrjs
35208c2654abSrjs /* clean up "next_addr_touse" */
35218c2654abSrjs if (inp->next_addr_touse == laddr)
35228c2654abSrjs /* delete this address */
35238c2654abSrjs inp->next_addr_touse = NULL;
35248c2654abSrjs
35258c2654abSrjs /* clean up "last_used_address" */
35268c2654abSrjs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
35278c2654abSrjs if (stcb->asoc.last_used_address == laddr)
35288c2654abSrjs /* delete this address */
35298c2654abSrjs stcb->asoc.last_used_address = NULL;
35308c2654abSrjs } /* for each tcb */
35318c2654abSrjs
35328c2654abSrjs /* remove it from the ep list */
35338c2654abSrjs sctp_remove_laddr(laddr);
35348c2654abSrjs inp->laddr_count--;
35358c2654abSrjs /* update inp_vflag flags */
35368c2654abSrjs sctp_update_ep_vflag(inp);
35378c2654abSrjs /* select a new primary destination if needed */
35388c2654abSrjs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
35398c2654abSrjs /* presume caller (sctp_asconf.c) already owns INP lock */
35408c2654abSrjs SCTP_TCB_LOCK(stcb);
35418c2654abSrjs if (sctp_destination_is_reachable(stcb,
35428c2654abSrjs rtcache_getdst(&stcb->asoc.primary_destination->ro)) == 0) {
35438c2654abSrjs sctp_select_primary_destination(stcb);
35448c2654abSrjs }
35458c2654abSrjs SCTP_TCB_UNLOCK(stcb);
35468c2654abSrjs } /* for each tcb */
35478c2654abSrjs }
35488c2654abSrjs return (0);
35498c2654abSrjs }
35508c2654abSrjs
35518c2654abSrjs /*
35528c2654abSrjs * Add the addr to the TCB local address list
35538c2654abSrjs * For the BOUNDALL or dynamic case, this is a "pending" address list
35548c2654abSrjs * (eg. addresses waiting for an ASCONF-ACK response)
35558c2654abSrjs * For the subset binding, static case, this is a "valid" address list
35568c2654abSrjs */
35578c2654abSrjs int
sctp_add_local_addr_assoc(struct sctp_tcb * stcb,struct ifaddr * ifa)35588c2654abSrjs sctp_add_local_addr_assoc(struct sctp_tcb *stcb, struct ifaddr *ifa)
35598c2654abSrjs {
35608c2654abSrjs struct sctp_laddr *laddr;
35618c2654abSrjs int error;
35628c2654abSrjs
35638c2654abSrjs /* Assumes TCP is locked.. and possiblye
35648c2654abSrjs * the INP. May need to confirm/fix that if
35658c2654abSrjs * we need it and is not the case.
35668c2654abSrjs */
35678c2654abSrjs if (ifa->ifa_addr->sa_family == AF_INET6) {
35688c2654abSrjs struct in6_ifaddr *ifa6;
35698c2654abSrjs ifa6 = (struct in6_ifaddr *)ifa;
35708c2654abSrjs if (ifa6->ia6_flags & (IN6_IFF_DETACHED |
35718c2654abSrjs /* IN6_IFF_DEPRECATED | */
35728c2654abSrjs IN6_IFF_ANYCAST |
35738c2654abSrjs IN6_IFF_NOTREADY))
35748c2654abSrjs /* Can't bind a non-existent addr. */
35758c2654abSrjs return (-1);
35768c2654abSrjs }
35778c2654abSrjs /* does the address already exist? */
35788c2654abSrjs LIST_FOREACH(laddr, &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr) {
35798c2654abSrjs if (laddr->ifa == ifa) {
35808c2654abSrjs return (-1);
35818c2654abSrjs }
35828c2654abSrjs }
35838c2654abSrjs
35848c2654abSrjs /* add to the list */
35858c2654abSrjs error = sctp_insert_laddr(&stcb->asoc.sctp_local_addr_list, ifa);
35868c2654abSrjs if (error != 0)
35878c2654abSrjs return (error);
35888c2654abSrjs return (0);
35898c2654abSrjs }
35908c2654abSrjs
35918c2654abSrjs /*
35928c2654abSrjs * insert an laddr entry with the given ifa for the desired list
35938c2654abSrjs */
35948c2654abSrjs int
sctp_insert_laddr(struct sctpladdr * list,struct ifaddr * ifa)35958c2654abSrjs sctp_insert_laddr(struct sctpladdr *list, struct ifaddr *ifa) {
35968c2654abSrjs struct sctp_laddr *laddr;
35978c2654abSrjs int s;
35988c2654abSrjs
35998c2654abSrjs s = splsoftnet();
36008c2654abSrjs
36018c2654abSrjs laddr = (struct sctp_laddr *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr);
36028c2654abSrjs if (laddr == NULL) {
36038c2654abSrjs /* out of memory? */
36048c2654abSrjs splx(s);
36058c2654abSrjs return (EINVAL);
36068c2654abSrjs }
36078c2654abSrjs sctppcbinfo.ipi_count_laddr++;
36088c2654abSrjs sctppcbinfo.ipi_gencnt_laddr++;
36098c2654abSrjs memset(laddr, 0, sizeof(*laddr));
36108c2654abSrjs laddr->ifa = ifa;
36118c2654abSrjs /* insert it */
36128c2654abSrjs LIST_INSERT_HEAD(list, laddr, sctp_nxt_addr);
36138c2654abSrjs
36148c2654abSrjs splx(s);
36158c2654abSrjs return (0);
36168c2654abSrjs }
36178c2654abSrjs
36188c2654abSrjs /*
36198c2654abSrjs * Remove an laddr entry from the local address list (on an assoc)
36208c2654abSrjs */
36218c2654abSrjs void
sctp_remove_laddr(struct sctp_laddr * laddr)36228c2654abSrjs sctp_remove_laddr(struct sctp_laddr *laddr)
36238c2654abSrjs {
36248c2654abSrjs int s;
36258c2654abSrjs s = splsoftnet();
36268c2654abSrjs /* remove from the list */
36278c2654abSrjs LIST_REMOVE(laddr, sctp_nxt_addr);
36288c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_laddr, laddr);
36298c2654abSrjs sctppcbinfo.ipi_count_laddr--;
36308c2654abSrjs sctppcbinfo.ipi_gencnt_laddr++;
36318c2654abSrjs
36328c2654abSrjs splx(s);
36338c2654abSrjs }
36348c2654abSrjs
36358c2654abSrjs /*
36368c2654abSrjs * Remove an address from the TCB local address list
36378c2654abSrjs */
36388c2654abSrjs int
sctp_del_local_addr_assoc(struct sctp_tcb * stcb,struct ifaddr * ifa)36398c2654abSrjs sctp_del_local_addr_assoc(struct sctp_tcb *stcb, struct ifaddr *ifa)
36408c2654abSrjs {
36418c2654abSrjs struct sctp_inpcb *inp;
36428c2654abSrjs struct sctp_laddr *laddr;
36438c2654abSrjs
36448c2654abSrjs /* This is called by asconf work. It is assumed that
36458c2654abSrjs * a) The TCB is locked
36468c2654abSrjs * and
36478c2654abSrjs * b) The INP is locked.
36488c2654abSrjs * This is true in as much as I can trace through
36498c2654abSrjs * the entry asconf code where I did these locks.
36508c2654abSrjs * Again, the ASCONF code is a bit different in
36518c2654abSrjs * that it does lock the INP during its work often
36528c2654abSrjs * times. This must be since we don't want other
36538c2654abSrjs * proc's looking up things while what they are
36548c2654abSrjs * looking up is changing :-D
36558c2654abSrjs */
36568c2654abSrjs
36578c2654abSrjs inp = stcb->sctp_ep;
36588c2654abSrjs /* if subset bound and don't allow ASCONF's, can't delete last */
36598c2654abSrjs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) &&
36608c2654abSrjs ((inp->sctp_flags & SCTP_PCB_FLAGS_DO_ASCONF) == 0)) {
36618c2654abSrjs if (stcb->asoc.numnets < 2) {
36628c2654abSrjs /* can't delete last address */
36638c2654abSrjs return (-1);
36648c2654abSrjs }
36658c2654abSrjs }
36668c2654abSrjs
36678c2654abSrjs LIST_FOREACH(laddr, &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr) {
36688c2654abSrjs /* remove the address if it exists */
36698c2654abSrjs if (laddr->ifa == NULL)
36708c2654abSrjs continue;
36718c2654abSrjs if (laddr->ifa == ifa) {
36728c2654abSrjs sctp_remove_laddr(laddr);
36738c2654abSrjs return (0);
36748c2654abSrjs }
36758c2654abSrjs }
36768c2654abSrjs
36778c2654abSrjs /* address not found! */
36788c2654abSrjs return (-1);
36798c2654abSrjs }
36808c2654abSrjs
36818c2654abSrjs /*
36828c2654abSrjs * Remove an address from the TCB local address list
36838c2654abSrjs * lookup using a sockaddr addr
36848c2654abSrjs */
36858c2654abSrjs int
sctp_del_local_addr_assoc_sa(struct sctp_tcb * stcb,struct sockaddr * sa)36868c2654abSrjs sctp_del_local_addr_assoc_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
36878c2654abSrjs {
36888c2654abSrjs struct sctp_inpcb *inp;
36898c2654abSrjs struct sctp_laddr *laddr;
36908c2654abSrjs struct sockaddr *l_sa;
36918c2654abSrjs
36928c2654abSrjs /*
36938c2654abSrjs * This function I find does not seem to have a caller.
36948c2654abSrjs * As such we NEED TO DELETE this code. If we do
36958c2654abSrjs * find a caller, the caller MUST have locked the TCB
36968c2654abSrjs * at the least and probably the INP as well.
36978c2654abSrjs */
36988c2654abSrjs inp = stcb->sctp_ep;
36998c2654abSrjs /* if subset bound and don't allow ASCONF's, can't delete last */
37008c2654abSrjs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) &&
37018c2654abSrjs ((inp->sctp_flags & SCTP_PCB_FLAGS_DO_ASCONF) == 0)) {
37028c2654abSrjs if (stcb->asoc.numnets < 2) {
37038c2654abSrjs /* can't delete last address */
37048c2654abSrjs return (-1);
37058c2654abSrjs }
37068c2654abSrjs }
37078c2654abSrjs
37088c2654abSrjs LIST_FOREACH(laddr, &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr) {
37098c2654abSrjs /* make sure the address exists */
37108c2654abSrjs if (laddr->ifa == NULL)
37118c2654abSrjs continue;
37128c2654abSrjs if (laddr->ifa->ifa_addr == NULL)
37138c2654abSrjs continue;
37148c2654abSrjs
37158c2654abSrjs l_sa = laddr->ifa->ifa_addr;
37168c2654abSrjs if (l_sa->sa_family == AF_INET6) {
37178c2654abSrjs /* IPv6 address */
37188c2654abSrjs struct sockaddr_in6 *sin1, *sin2;
37198c2654abSrjs sin1 = (struct sockaddr_in6 *)l_sa;
37208c2654abSrjs sin2 = (struct sockaddr_in6 *)sa;
37218c2654abSrjs if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
37228c2654abSrjs sizeof(struct in6_addr)) == 0) {
37238c2654abSrjs /* matched */
37248c2654abSrjs sctp_remove_laddr(laddr);
37258c2654abSrjs return (0);
37268c2654abSrjs }
37278c2654abSrjs } else if (l_sa->sa_family == AF_INET) {
37288c2654abSrjs /* IPv4 address */
37298c2654abSrjs struct sockaddr_in *sin1, *sin2;
37308c2654abSrjs sin1 = (struct sockaddr_in *)l_sa;
37318c2654abSrjs sin2 = (struct sockaddr_in *)sa;
37328c2654abSrjs if (sin1->sin_addr.s_addr == sin2->sin_addr.s_addr) {
37338c2654abSrjs /* matched */
37348c2654abSrjs sctp_remove_laddr(laddr);
37358c2654abSrjs return (0);
37368c2654abSrjs }
37378c2654abSrjs } else {
37388c2654abSrjs /* invalid family */
37398c2654abSrjs return (-1);
37408c2654abSrjs }
37418c2654abSrjs } /* end foreach */
37428c2654abSrjs /* address not found! */
37438c2654abSrjs return (-1);
37448c2654abSrjs }
37458c2654abSrjs
37468c2654abSrjs static char sctp_pcb_initialized = 0;
37478c2654abSrjs
37488c2654abSrjs #if defined(__FreeBSD__) || defined(__APPLE__)
37498c2654abSrjs /* sysctl */
37508c2654abSrjs static int sctp_max_number_of_assoc = SCTP_MAX_NUM_OF_ASOC;
37518c2654abSrjs static int sctp_scale_up_for_address = SCTP_SCALE_FOR_ADDR;
37528c2654abSrjs
37538c2654abSrjs #endif /* FreeBSD || APPLE */
37548c2654abSrjs
37558c2654abSrjs #ifndef SCTP_TCBHASHSIZE
37568c2654abSrjs #define SCTP_TCBHASHSIZE 1024
37578c2654abSrjs #endif
37588c2654abSrjs
37598c2654abSrjs #ifndef SCTP_CHUNKQUEUE_SCALE
37608c2654abSrjs #define SCTP_CHUNKQUEUE_SCALE 10
37618c2654abSrjs #endif
37628c2654abSrjs
37638c2654abSrjs void
sctp_pcb_init(void)37648c2654abSrjs sctp_pcb_init(void)
37658c2654abSrjs {
37668c2654abSrjs /*
37678c2654abSrjs * SCTP initialization for the PCB structures
3768c3ad0bddSandvar * should be called by the sctp_init() function.
37698c2654abSrjs */
37708c2654abSrjs int i;
37718c2654abSrjs int hashtblsize = SCTP_TCBHASHSIZE;
37728c2654abSrjs
37738c2654abSrjs #if defined(__FreeBSD__) || defined(__APPLE__)
37748c2654abSrjs int sctp_chunkscale = SCTP_CHUNKQUEUE_SCALE;
37758c2654abSrjs #endif
37768c2654abSrjs
37778c2654abSrjs if (sctp_pcb_initialized != 0) {
37788c2654abSrjs /* error I was called twice */
37798c2654abSrjs return;
37808c2654abSrjs }
37818c2654abSrjs sctp_pcb_initialized = 1;
37828c2654abSrjs
37838c2654abSrjs /* Init all peg counts */
37848c2654abSrjs for (i = 0; i < SCTP_NUMBER_OF_PEGS; i++) {
37858c2654abSrjs sctp_pegs[i] = 0;
37868c2654abSrjs }
37878c2654abSrjs
37888c2654abSrjs /* init the empty list of (All) Endpoints */
37898c2654abSrjs LIST_INIT(&sctppcbinfo.listhead);
37908c2654abSrjs
37918c2654abSrjs /* init the iterator head */
37928c2654abSrjs LIST_INIT(&sctppcbinfo.iteratorhead);
37938c2654abSrjs
37948c2654abSrjs /* init the hash table of endpoints */
37958c2654abSrjs #if defined(__FreeBSD__)
37968c2654abSrjs #if defined(__FreeBSD_cc_version) && __FreeBSD_cc_version >= 440000
37978c2654abSrjs TUNABLE_INT_FETCH("net.inet.sctp.tcbhashsize", &hashtblsize);
37988c2654abSrjs TUNABLE_INT_FETCH("net.inet.sctp.pcbhashsize", &sctp_pcbtblsize);
37998c2654abSrjs TUNABLE_INT_FETCH("net.inet.sctp.chunkscale", &sctp_chunkscale);
38008c2654abSrjs #else
38018c2654abSrjs TUNABLE_INT_FETCH("net.inet.sctp.tcbhashsize", SCTP_TCBHASHSIZE,
38028c2654abSrjs hashtblsize);
38038c2654abSrjs TUNABLE_INT_FETCH("net.inet.sctp.pcbhashsize", SCTP_PCBHASHSIZE,
38048c2654abSrjs sctp_pcbtblsize);
38058c2654abSrjs TUNABLE_INT_FETCH("net.inet.sctp.chunkscale", SCTP_CHUNKQUEUE_SCALE,
38068c2654abSrjs sctp_chunkscale);
38078c2654abSrjs #endif
38088c2654abSrjs #endif
38098c2654abSrjs
38108c2654abSrjs sctppcbinfo.sctp_asochash = hashinit((hashtblsize * 31), HASH_LIST,
38118c2654abSrjs M_WAITOK, &sctppcbinfo.hashasocmark);
38128c2654abSrjs
38138c2654abSrjs sctppcbinfo.sctp_ephash = hashinit(hashtblsize, HASH_LIST,
38148c2654abSrjs M_WAITOK, &sctppcbinfo.hashmark);
38158c2654abSrjs
38168c2654abSrjs sctppcbinfo.sctp_tcpephash = hashinit(hashtblsize, HASH_LIST,
38178c2654abSrjs M_WAITOK, &sctppcbinfo.hashtcpmark);
38188c2654abSrjs
38198c2654abSrjs sctppcbinfo.hashtblsize = hashtblsize;
38208c2654abSrjs
38218c2654abSrjs /* init the zones */
38228c2654abSrjs /*
38238c2654abSrjs * FIX ME: Should check for NULL returns, but if it does fail we
38248c2654abSrjs * are doomed to panic anyways... add later maybe.
38258c2654abSrjs */
38268c2654abSrjs SCTP_ZONE_INIT(sctppcbinfo.ipi_zone_ep, "sctp_ep",
38278c2654abSrjs sizeof(struct sctp_inpcb), maxsockets);
38288c2654abSrjs
38298c2654abSrjs SCTP_ZONE_INIT(sctppcbinfo.ipi_zone_asoc, "sctp_asoc",
38308c2654abSrjs sizeof(struct sctp_tcb), sctp_max_number_of_assoc);
38318c2654abSrjs
38328c2654abSrjs SCTP_ZONE_INIT(sctppcbinfo.ipi_zone_laddr, "sctp_laddr",
38338c2654abSrjs sizeof(struct sctp_laddr),
38348c2654abSrjs (sctp_max_number_of_assoc * sctp_scale_up_for_address));
38358c2654abSrjs
38368c2654abSrjs SCTP_ZONE_INIT(sctppcbinfo.ipi_zone_net, "sctp_raddr",
38378c2654abSrjs sizeof(struct sctp_nets),
38388c2654abSrjs (sctp_max_number_of_assoc * sctp_scale_up_for_address));
38398c2654abSrjs
38408c2654abSrjs SCTP_ZONE_INIT(sctppcbinfo.ipi_zone_chunk, "sctp_chunk",
38418c2654abSrjs sizeof(struct sctp_tmit_chunk),
38428c2654abSrjs (sctp_max_number_of_assoc * sctp_scale_up_for_address *
38438c2654abSrjs sctp_chunkscale));
38448c2654abSrjs
38458c2654abSrjs SCTP_ZONE_INIT(sctppcbinfo.ipi_zone_sockq, "sctp_sockq",
38468c2654abSrjs sizeof(struct sctp_socket_q_list),
38478c2654abSrjs (sctp_max_number_of_assoc * sctp_scale_up_for_address *
38488c2654abSrjs sctp_chunkscale));
38498c2654abSrjs
38508c2654abSrjs SCTP_ZONE_INIT(sctppcbinfo.ipi_zone_hash, "sctp_hash",
38518c2654abSrjs sizeof(void *) * sctp_pcbtblsize, maxsockets);
38528c2654abSrjs
38538c2654abSrjs /* Master Lock INIT for info structure */
38548c2654abSrjs SCTP_INP_INFO_LOCK_INIT();
38558c2654abSrjs SCTP_ITERATOR_LOCK_INIT();
38568c2654abSrjs /* not sure if we need all the counts */
38578c2654abSrjs sctppcbinfo.ipi_count_ep = 0;
38588c2654abSrjs sctppcbinfo.ipi_gencnt_ep = 0;
38598c2654abSrjs /* assoc/tcb zone info */
38608c2654abSrjs sctppcbinfo.ipi_count_asoc = 0;
38618c2654abSrjs sctppcbinfo.ipi_gencnt_asoc = 0;
38628c2654abSrjs /* local addrlist zone info */
38638c2654abSrjs sctppcbinfo.ipi_count_laddr = 0;
38648c2654abSrjs sctppcbinfo.ipi_gencnt_laddr = 0;
38658c2654abSrjs /* remote addrlist zone info */
38668c2654abSrjs sctppcbinfo.ipi_count_raddr = 0;
38678c2654abSrjs sctppcbinfo.ipi_gencnt_raddr = 0;
38688c2654abSrjs /* chunk info */
38698c2654abSrjs sctppcbinfo.ipi_count_chunk = 0;
38708c2654abSrjs sctppcbinfo.ipi_gencnt_chunk = 0;
38718c2654abSrjs
38728c2654abSrjs /* socket queue zone info */
38738c2654abSrjs sctppcbinfo.ipi_count_sockq = 0;
38748c2654abSrjs sctppcbinfo.ipi_gencnt_sockq = 0;
38758c2654abSrjs
38768c2654abSrjs /* mbuf tracker */
38778c2654abSrjs sctppcbinfo.mbuf_track = 0;
38788c2654abSrjs /* port stuff */
38798c2654abSrjs sctppcbinfo.lastlow = anonportmin;
38803fb74706Srjs
38818c2654abSrjs /* Init the TIMEWAIT list */
38828c2654abSrjs for (i = 0; i < SCTP_STACK_VTAG_HASH_SIZE; i++) {
38838c2654abSrjs LIST_INIT(&sctppcbinfo.vtag_timewait[i]);
38848c2654abSrjs }
38858c2654abSrjs
38868c2654abSrjs #if defined(_SCTP_NEEDS_CALLOUT_) && !defined(__APPLE__)
38878c2654abSrjs TAILQ_INIT(&sctppcbinfo.callqueue);
38888c2654abSrjs #endif
38898c2654abSrjs
38908c2654abSrjs }
38918c2654abSrjs
38928c2654abSrjs int
sctp_load_addresses_from_init(struct sctp_tcb * stcb,struct mbuf * m,int iphlen,int offset,int limit,struct sctphdr * sh,struct sockaddr * altsa)38938c2654abSrjs sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
38948c2654abSrjs int iphlen, int offset, int limit, struct sctphdr *sh,
38958c2654abSrjs struct sockaddr *altsa)
38968c2654abSrjs {
38978c2654abSrjs /*
38988c2654abSrjs * grub through the INIT pulling addresses and
38998c2654abSrjs * loading them to the nets structure in the asoc.
39008c2654abSrjs * The from address in the mbuf should also be loaded
39018c2654abSrjs * (if it is not already). This routine can be called
39028c2654abSrjs * with either INIT or INIT-ACK's as long as the
39038c2654abSrjs * m points to the IP packet and the offset points
39048c2654abSrjs * to the beginning of the parameters.
39058c2654abSrjs */
39068c2654abSrjs struct sctp_inpcb *inp, *l_inp;
39078c2654abSrjs struct sctp_nets *net, *net_tmp;
39088c2654abSrjs struct ip *iph;
39098c2654abSrjs struct sctp_paramhdr *phdr, parm_buf;
39108c2654abSrjs struct sctp_tcb *stcb_tmp;
39118c2654abSrjs u_int16_t ptype, plen;
39128c2654abSrjs struct sockaddr *sa;
39138c2654abSrjs struct sockaddr_storage dest_store;
39148c2654abSrjs struct sockaddr *local_sa = (struct sockaddr *)&dest_store;
39158c2654abSrjs struct sockaddr_in sin;
39168c2654abSrjs struct sockaddr_in6 sin6;
39178c2654abSrjs
39188c2654abSrjs /* First get the destination address setup too. */
39198c2654abSrjs memset(&sin, 0, sizeof(sin));
39208c2654abSrjs memset(&sin6, 0, sizeof(sin6));
39218c2654abSrjs
39228c2654abSrjs sin.sin_family = AF_INET;
39238c2654abSrjs sin.sin_len = sizeof(sin);
39248c2654abSrjs sin.sin_port = stcb->rport;
39258c2654abSrjs
39268c2654abSrjs sin6.sin6_family = AF_INET6;
39278c2654abSrjs sin6.sin6_len = sizeof(struct sockaddr_in6);
39288c2654abSrjs sin6.sin6_port = stcb->rport;
39298c2654abSrjs if (altsa == NULL) {
39308c2654abSrjs iph = mtod(m, struct ip *);
39318c2654abSrjs if (iph->ip_v == IPVERSION) {
39328c2654abSrjs /* its IPv4 */
39338c2654abSrjs struct sockaddr_in *sin_2;
39348c2654abSrjs sin_2 = (struct sockaddr_in *)(local_sa);
39358c2654abSrjs memset(sin_2, 0, sizeof(sin));
39368c2654abSrjs sin_2->sin_family = AF_INET;
39378c2654abSrjs sin_2->sin_len = sizeof(sin);
39388c2654abSrjs sin_2->sin_port = sh->dest_port;
39398c2654abSrjs sin_2->sin_addr.s_addr = iph->ip_dst.s_addr ;
39408c2654abSrjs sin.sin_addr = iph->ip_src;
39418c2654abSrjs sa = (struct sockaddr *)&sin;
39428c2654abSrjs } else if (iph->ip_v == (IPV6_VERSION >> 4)) {
39438c2654abSrjs /* its IPv6 */
39448c2654abSrjs struct ip6_hdr *ip6;
39458c2654abSrjs struct sockaddr_in6 *sin6_2;
39468c2654abSrjs
39478c2654abSrjs ip6 = mtod(m, struct ip6_hdr *);
39488c2654abSrjs sin6_2 = (struct sockaddr_in6 *)(local_sa);
39498c2654abSrjs memset(sin6_2, 0, sizeof(sin6));
39508c2654abSrjs sin6_2->sin6_family = AF_INET6;
39518c2654abSrjs sin6_2->sin6_len = sizeof(struct sockaddr_in6);
39528c2654abSrjs sin6_2->sin6_port = sh->dest_port;
39538c2654abSrjs sin6.sin6_addr = ip6->ip6_src;
39548c2654abSrjs sa = (struct sockaddr *)&sin6;
39558c2654abSrjs } else {
39568c2654abSrjs sa = NULL;
39578c2654abSrjs }
39588c2654abSrjs } else {
39598c2654abSrjs /*
39608c2654abSrjs * For cookies we use the src address NOT from the packet
39618c2654abSrjs * but from the original INIT
39628c2654abSrjs */
39638c2654abSrjs sa = altsa;
39648c2654abSrjs }
39658c2654abSrjs /* Turn off ECN until we get through all params */
39668c2654abSrjs stcb->asoc.ecn_allowed = 0;
39678c2654abSrjs
39688c2654abSrjs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
39698c2654abSrjs /* mark all addresses that we have currently on the list */
39708c2654abSrjs net->dest_state |= SCTP_ADDR_NOT_IN_ASSOC;
39718c2654abSrjs }
39728c2654abSrjs /* does the source address already exist? if so skip it */
39738c2654abSrjs l_inp = inp = stcb->sctp_ep;
39748c2654abSrjs stcb_tmp = sctp_findassociation_ep_addr(&inp, sa, &net_tmp, local_sa, stcb);
39758c2654abSrjs if ((stcb_tmp == NULL && inp == stcb->sctp_ep) || inp == NULL) {
39768c2654abSrjs /* we must add the source address */
39778c2654abSrjs /* no scope set here since we have a tcb already. */
39788c2654abSrjs if ((sa->sa_family == AF_INET) &&
39798c2654abSrjs (stcb->asoc.ipv4_addr_legal)) {
39808c2654abSrjs if (sctp_add_remote_addr(stcb, sa, 0, 2)) {
39818c2654abSrjs return (-1);
39828c2654abSrjs }
39838c2654abSrjs } else if ((sa->sa_family == AF_INET6) &&
39848c2654abSrjs (stcb->asoc.ipv6_addr_legal)) {
39858c2654abSrjs if (sctp_add_remote_addr(stcb, sa, 0, 3)) {
39868c2654abSrjs return (-1);
39878c2654abSrjs }
39888c2654abSrjs }
39898c2654abSrjs } else {
39908c2654abSrjs if (net_tmp != NULL && stcb_tmp == stcb) {
39918c2654abSrjs net_tmp->dest_state &= ~SCTP_ADDR_NOT_IN_ASSOC;
39928c2654abSrjs } else if (stcb_tmp != stcb) {
39938c2654abSrjs /* It belongs to another association? */
39948c2654abSrjs return (-1);
39958c2654abSrjs }
39968c2654abSrjs }
3997cbf5c65aSandvar /* since a unlock occurred we must check the
39988c2654abSrjs * TCB's state and the pcb's gone flags.
39998c2654abSrjs */
40008c2654abSrjs if (l_inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE|SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
40018c2654abSrjs /* the user freed the ep */
40028c2654abSrjs return (-1);
40038c2654abSrjs }
40048c2654abSrjs if (stcb->asoc.state == 0) {
40058c2654abSrjs /* the assoc was freed? */
40068c2654abSrjs return (-1);
40078c2654abSrjs }
40088c2654abSrjs
40098c2654abSrjs /* now we must go through each of the params. */
40108c2654abSrjs phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf));
40118c2654abSrjs while (phdr) {
40128c2654abSrjs ptype = ntohs(phdr->param_type);
40138c2654abSrjs plen = ntohs(phdr->param_length);
40148c2654abSrjs /*printf("ptype => %d, plen => %d\n", ptype, plen);*/
40158c2654abSrjs if (offset + plen > limit) {
40168c2654abSrjs break;
40178c2654abSrjs }
40188c2654abSrjs if (plen == 0) {
40198c2654abSrjs break;
40208c2654abSrjs }
40218c2654abSrjs if ((ptype == SCTP_IPV4_ADDRESS) &&
40228c2654abSrjs (stcb->asoc.ipv4_addr_legal)) {
40238c2654abSrjs struct sctp_ipv4addr_param *p4, p4_buf;
40248c2654abSrjs /* ok get the v4 address and check/add */
40258c2654abSrjs phdr = sctp_get_next_param(m, offset,
40268c2654abSrjs (struct sctp_paramhdr *)&p4_buf, sizeof(p4_buf));
40278c2654abSrjs if (plen != sizeof(struct sctp_ipv4addr_param) ||
40288c2654abSrjs phdr == NULL) {
40298c2654abSrjs return (-1);
40308c2654abSrjs }
40318c2654abSrjs p4 = (struct sctp_ipv4addr_param *)phdr;
40328c2654abSrjs sin.sin_addr.s_addr = p4->addr;
40338c2654abSrjs sa = (struct sockaddr *)&sin;
40348c2654abSrjs inp = stcb->sctp_ep;
40358c2654abSrjs stcb_tmp = sctp_findassociation_ep_addr(&inp, sa, &net,
40368c2654abSrjs local_sa, stcb);
40378c2654abSrjs
40388c2654abSrjs if ((stcb_tmp== NULL && inp == stcb->sctp_ep) ||
40398c2654abSrjs inp == NULL) {
40408c2654abSrjs /* we must add the source address */
40418c2654abSrjs /* no scope set since we have a tcb already */
40428c2654abSrjs
40438c2654abSrjs /* we must validate the state again here */
40448c2654abSrjs if (l_inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE|SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
40458c2654abSrjs /* the user freed the ep */
40468c2654abSrjs return (-1);
40478c2654abSrjs }
40488c2654abSrjs if (stcb->asoc.state == 0) {
40498c2654abSrjs /* the assoc was freed? */
40508c2654abSrjs return (-1);
40518c2654abSrjs }
40528c2654abSrjs if (sctp_add_remote_addr(stcb, sa, 0, 4)) {
40538c2654abSrjs return (-1);
40548c2654abSrjs }
40558c2654abSrjs } else if (stcb_tmp == stcb) {
40568c2654abSrjs if (l_inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE|SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
40578c2654abSrjs /* the user freed the ep */
40588c2654abSrjs return (-1);
40598c2654abSrjs }
40608c2654abSrjs if (stcb->asoc.state == 0) {
40618c2654abSrjs /* the assoc was freed? */
40628c2654abSrjs return (-1);
40638c2654abSrjs }
40648c2654abSrjs if (net != NULL) {
40658c2654abSrjs /* clear flag */
40668c2654abSrjs net->dest_state &=
40678c2654abSrjs ~SCTP_ADDR_NOT_IN_ASSOC;
40688c2654abSrjs }
40698c2654abSrjs } else {
40708c2654abSrjs /* strange, address is in another assoc?
40718c2654abSrjs * straighten out locks.
40728c2654abSrjs */
40738c2654abSrjs SCTP_TCB_UNLOCK(stcb_tmp);
40748c2654abSrjs SCTP_INP_RLOCK(inp);
40758c2654abSrjs if (l_inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE|SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
40768c2654abSrjs /* the user freed the ep */
40778c2654abSrjs SCTP_INP_RUNLOCK(l_inp);
40788c2654abSrjs return (-1);
40798c2654abSrjs }
40808c2654abSrjs if (stcb->asoc.state == 0) {
40818c2654abSrjs /* the assoc was freed? */
40828c2654abSrjs SCTP_INP_RUNLOCK(l_inp);
40838c2654abSrjs return (-1);
40848c2654abSrjs }
40858c2654abSrjs SCTP_TCB_LOCK(stcb);
40868c2654abSrjs SCTP_INP_RUNLOCK(stcb->sctp_ep);
40878c2654abSrjs return (-1);
40888c2654abSrjs }
40898c2654abSrjs } else if ((ptype == SCTP_IPV6_ADDRESS) &&
40908c2654abSrjs (stcb->asoc.ipv6_addr_legal)) {
40918c2654abSrjs /* ok get the v6 address and check/add */
40928c2654abSrjs struct sctp_ipv6addr_param *p6, p6_buf;
40938c2654abSrjs phdr = sctp_get_next_param(m, offset,
40948c2654abSrjs (struct sctp_paramhdr *)&p6_buf, sizeof(p6_buf));
40958c2654abSrjs if (plen != sizeof(struct sctp_ipv6addr_param) ||
40968c2654abSrjs phdr == NULL) {
40978c2654abSrjs return (-1);
40988c2654abSrjs }
40998c2654abSrjs p6 = (struct sctp_ipv6addr_param *)phdr;
41008c2654abSrjs memcpy((void *)&sin6.sin6_addr, p6->addr,
41018c2654abSrjs sizeof(p6->addr));
41028c2654abSrjs sa = (struct sockaddr *)&sin6;
41038c2654abSrjs inp = stcb->sctp_ep;
41048c2654abSrjs stcb_tmp= sctp_findassociation_ep_addr(&inp, sa, &net,
41058c2654abSrjs local_sa, stcb);
41068c2654abSrjs if (stcb_tmp == NULL && (inp == stcb->sctp_ep ||
41078c2654abSrjs inp == NULL)) {
41088c2654abSrjs /* we must validate the state again here */
41098c2654abSrjs if (l_inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE|SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
41108c2654abSrjs /* the user freed the ep */
41118c2654abSrjs return (-1);
41128c2654abSrjs }
41138c2654abSrjs if (stcb->asoc.state == 0) {
41148c2654abSrjs /* the assoc was freed? */
41158c2654abSrjs return (-1);
41168c2654abSrjs }
41178c2654abSrjs /* we must add the address, no scope set */
41188c2654abSrjs if (sctp_add_remote_addr(stcb, sa, 0, 5)) {
41198c2654abSrjs return (-1);
41208c2654abSrjs }
41218c2654abSrjs } else if (stcb_tmp == stcb) {
41228c2654abSrjs /* we must validate the state again here */
41238c2654abSrjs if (l_inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE|SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
41248c2654abSrjs /* the user freed the ep */
41258c2654abSrjs return (-1);
41268c2654abSrjs }
41278c2654abSrjs if (stcb->asoc.state == 0) {
41288c2654abSrjs /* the assoc was freed? */
41298c2654abSrjs return (-1);
41308c2654abSrjs }
41318c2654abSrjs if (net != NULL) {
41328c2654abSrjs /* clear flag */
41338c2654abSrjs net->dest_state &=
41348c2654abSrjs ~SCTP_ADDR_NOT_IN_ASSOC;
41358c2654abSrjs }
41368c2654abSrjs } else {
41378c2654abSrjs /* strange, address is in another assoc?
41388c2654abSrjs * straighten out locks.
41398c2654abSrjs */
41408c2654abSrjs SCTP_TCB_UNLOCK(stcb_tmp);
41418c2654abSrjs SCTP_INP_RLOCK(l_inp);
41428c2654abSrjs /* we must validate the state again here */
41438c2654abSrjs if (l_inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE|SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
41448c2654abSrjs /* the user freed the ep */
41458c2654abSrjs SCTP_INP_RUNLOCK(l_inp);
41468c2654abSrjs return (-1);
41478c2654abSrjs }
41488c2654abSrjs if (stcb->asoc.state == 0) {
41498c2654abSrjs /* the assoc was freed? */
41508c2654abSrjs SCTP_INP_RUNLOCK(l_inp);
41518c2654abSrjs return (-1);
41528c2654abSrjs }
41538c2654abSrjs SCTP_TCB_LOCK(stcb);
41548c2654abSrjs SCTP_INP_RUNLOCK(l_inp);
41558c2654abSrjs return (-1);
41568c2654abSrjs }
41578c2654abSrjs } else if (ptype == SCTP_ECN_CAPABLE) {
41588c2654abSrjs stcb->asoc.ecn_allowed = 1;
41598c2654abSrjs } else if (ptype == SCTP_ULP_ADAPTION) {
41608c2654abSrjs if (stcb->asoc.state != SCTP_STATE_OPEN) {
41618c2654abSrjs struct sctp_adaption_layer_indication ai, *aip;
41628c2654abSrjs
41638c2654abSrjs phdr = sctp_get_next_param(m, offset,
41648c2654abSrjs (struct sctp_paramhdr *)&ai, sizeof(ai));
41658c2654abSrjs aip = (struct sctp_adaption_layer_indication *)phdr;
41668c2654abSrjs sctp_ulp_notify(SCTP_NOTIFY_ADAPTION_INDICATION,
41678c2654abSrjs stcb, ntohl(aip->indication), NULL);
41688c2654abSrjs }
41698c2654abSrjs } else if (ptype == SCTP_SET_PRIM_ADDR) {
41708c2654abSrjs struct sctp_asconf_addr_param lstore, *fee;
41718c2654abSrjs struct sctp_asconf_addrv4_param *fii;
41728c2654abSrjs int lptype;
41738c2654abSrjs struct sockaddr *lsa = NULL;
41748c2654abSrjs
41758c2654abSrjs stcb->asoc.peer_supports_asconf = 1;
41768c2654abSrjs stcb->asoc.peer_supports_asconf_setprim = 1;
41778c2654abSrjs if (plen > sizeof(lstore)) {
41788c2654abSrjs return (-1);
41798c2654abSrjs }
41808c2654abSrjs phdr = sctp_get_next_param(m, offset,
41818c2654abSrjs (struct sctp_paramhdr *)&lstore, plen);
41828c2654abSrjs if (phdr == NULL) {
41838c2654abSrjs return (-1);
41848c2654abSrjs }
41858c2654abSrjs
41868c2654abSrjs fee = (struct sctp_asconf_addr_param *)phdr;
41878c2654abSrjs lptype = ntohs(fee->addrp.ph.param_type);
41888c2654abSrjs if (lptype == SCTP_IPV4_ADDRESS) {
41898c2654abSrjs if (plen !=
41908c2654abSrjs sizeof(struct sctp_asconf_addrv4_param)) {
41918c2654abSrjs printf("Sizeof setprim in init/init ack not %d but %d - ignored\n",
41928c2654abSrjs (int)sizeof(struct sctp_asconf_addrv4_param),
41938c2654abSrjs plen);
41948c2654abSrjs } else {
41958c2654abSrjs fii = (struct sctp_asconf_addrv4_param *)fee;
41968c2654abSrjs sin.sin_addr.s_addr = fii->addrp.addr;
41978c2654abSrjs lsa = (struct sockaddr *)&sin;
41988c2654abSrjs }
41998c2654abSrjs } else if (lptype == SCTP_IPV6_ADDRESS) {
42008c2654abSrjs if (plen !=
42018c2654abSrjs sizeof(struct sctp_asconf_addr_param)) {
42028c2654abSrjs printf("Sizeof setprim (v6) in init/init ack not %d but %d - ignored\n",
42038c2654abSrjs (int)sizeof(struct sctp_asconf_addr_param),
42048c2654abSrjs plen);
42058c2654abSrjs } else {
42068c2654abSrjs memcpy(sin6.sin6_addr.s6_addr,
42078c2654abSrjs fee->addrp.addr,
42088c2654abSrjs sizeof(fee->addrp.addr));
42098c2654abSrjs lsa = (struct sockaddr *)&sin6;
42108c2654abSrjs }
42118c2654abSrjs }
42128c2654abSrjs if (lsa) {
42138c2654abSrjs sctp_set_primary_addr(stcb, sa, NULL);
42148c2654abSrjs }
42158c2654abSrjs
42168c2654abSrjs } else if (ptype == SCTP_PRSCTP_SUPPORTED) {
42178c2654abSrjs /* Peer supports pr-sctp */
42188c2654abSrjs stcb->asoc.peer_supports_prsctp = 1;
42198c2654abSrjs } else if (ptype == SCTP_SUPPORTED_CHUNK_EXT) {
42208c2654abSrjs /* A supported extension chunk */
42218c2654abSrjs struct sctp_supported_chunk_types_param *pr_supported;
42228c2654abSrjs uint8_t local_store[128];
42238c2654abSrjs int num_ent, i;
42248c2654abSrjs
42258c2654abSrjs phdr = sctp_get_next_param(m, offset,
42268c2654abSrjs (struct sctp_paramhdr *)&local_store, plen);
42278c2654abSrjs if (phdr == NULL) {
42288c2654abSrjs return (-1);
42298c2654abSrjs }
42308c2654abSrjs stcb->asoc.peer_supports_asconf = 0;
42318c2654abSrjs stcb->asoc.peer_supports_asconf_setprim = 0;
42328c2654abSrjs stcb->asoc.peer_supports_prsctp = 0;
42338c2654abSrjs stcb->asoc.peer_supports_pktdrop = 0;
42348c2654abSrjs stcb->asoc.peer_supports_strreset = 0;
42358c2654abSrjs pr_supported = (struct sctp_supported_chunk_types_param *)phdr;
42368c2654abSrjs num_ent = plen - sizeof(struct sctp_paramhdr);
42378c2654abSrjs for (i=0; i<num_ent; i++) {
42388c2654abSrjs switch (pr_supported->chunk_types[i]) {
42398c2654abSrjs case SCTP_ASCONF:
42408c2654abSrjs stcb->asoc.peer_supports_asconf = 1;
42418c2654abSrjs stcb->asoc.peer_supports_asconf_setprim = 1;
42428c2654abSrjs break;
42438c2654abSrjs case SCTP_ASCONF_ACK:
42448c2654abSrjs stcb->asoc.peer_supports_asconf = 1;
42458c2654abSrjs stcb->asoc.peer_supports_asconf_setprim = 1;
42468c2654abSrjs break;
42478c2654abSrjs case SCTP_FORWARD_CUM_TSN:
42488c2654abSrjs stcb->asoc.peer_supports_prsctp = 1;
42498c2654abSrjs break;
42508c2654abSrjs case SCTP_PACKET_DROPPED:
42518c2654abSrjs stcb->asoc.peer_supports_pktdrop = 1;
42528c2654abSrjs break;
42538c2654abSrjs case SCTP_STREAM_RESET:
42548c2654abSrjs stcb->asoc.peer_supports_strreset = 1;
42558c2654abSrjs break;
42568c2654abSrjs default:
42578c2654abSrjs /* one I have not learned yet */
42588c2654abSrjs break;
42598c2654abSrjs
42608c2654abSrjs }
42618c2654abSrjs }
42628c2654abSrjs } else if (ptype == SCTP_ECN_NONCE_SUPPORTED) {
42638c2654abSrjs /* Peer supports ECN-nonce */
42648c2654abSrjs stcb->asoc.peer_supports_ecn_nonce = 1;
42658c2654abSrjs stcb->asoc.ecn_nonce_allowed = 1;
42668c2654abSrjs } else if ((ptype == SCTP_HEARTBEAT_INFO) ||
42678c2654abSrjs (ptype == SCTP_STATE_COOKIE) ||
42688c2654abSrjs (ptype == SCTP_UNRECOG_PARAM) ||
42698c2654abSrjs (ptype == SCTP_COOKIE_PRESERVE) ||
42708c2654abSrjs (ptype == SCTP_SUPPORTED_ADDRTYPE) ||
42718c2654abSrjs (ptype == SCTP_ADD_IP_ADDRESS) ||
42728c2654abSrjs (ptype == SCTP_DEL_IP_ADDRESS) ||
42738c2654abSrjs (ptype == SCTP_ERROR_CAUSE_IND) ||
42748c2654abSrjs (ptype == SCTP_SUCCESS_REPORT)) {
42758c2654abSrjs /* don't care */;
42768c2654abSrjs } else {
42778c2654abSrjs if ((ptype & 0x8000) == 0x0000) {
42788c2654abSrjs /* must stop processing the rest of
42798c2654abSrjs * the param's. Any report bits were
42808c2654abSrjs * handled with the call to sctp_arethere_unrecognized_parameters()
42818c2654abSrjs * when the INIT or INIT-ACK was first seen.
42828c2654abSrjs */
42838c2654abSrjs break;
42848c2654abSrjs }
42858c2654abSrjs }
42868c2654abSrjs offset += SCTP_SIZE32(plen);
42878c2654abSrjs if (offset >= limit) {
42888c2654abSrjs break;
42898c2654abSrjs }
42908c2654abSrjs phdr = sctp_get_next_param(m, offset, &parm_buf,
42918c2654abSrjs sizeof(parm_buf));
42928c2654abSrjs }
42938c2654abSrjs /* Now check to see if we need to purge any addresses */
42948c2654abSrjs for (net = TAILQ_FIRST(&stcb->asoc.nets); net != NULL; net = net_tmp) {
42958c2654abSrjs net_tmp = TAILQ_NEXT(net, sctp_next);
42968c2654abSrjs if ((net->dest_state & SCTP_ADDR_NOT_IN_ASSOC) ==
42978c2654abSrjs SCTP_ADDR_NOT_IN_ASSOC) {
42988c2654abSrjs /* This address has been removed from the asoc */
42998c2654abSrjs /* remove and free it */
43008c2654abSrjs stcb->asoc.numnets--;
43018c2654abSrjs TAILQ_REMOVE(&stcb->asoc.nets, net, sctp_next);
43028c2654abSrjs sctp_free_remote_addr(net);
43038c2654abSrjs if (net == stcb->asoc.primary_destination) {
43048c2654abSrjs stcb->asoc.primary_destination = NULL;
43058c2654abSrjs sctp_select_primary_destination(stcb);
43068c2654abSrjs }
43078c2654abSrjs }
43088c2654abSrjs }
43098c2654abSrjs return (0);
43108c2654abSrjs }
43118c2654abSrjs
43128c2654abSrjs int
sctp_set_primary_addr(struct sctp_tcb * stcb,struct sockaddr * sa,struct sctp_nets * net)43138c2654abSrjs sctp_set_primary_addr(struct sctp_tcb *stcb, struct sockaddr *sa,
43148c2654abSrjs struct sctp_nets *net)
43158c2654abSrjs {
43168c2654abSrjs /* make sure the requested primary address exists in the assoc */
43178c2654abSrjs if (net == NULL && sa)
43188c2654abSrjs net = sctp_findnet(stcb, sa);
43198c2654abSrjs
43208c2654abSrjs if (net == NULL) {
43218c2654abSrjs /* didn't find the requested primary address! */
43228c2654abSrjs return (-1);
43238c2654abSrjs } else {
43248c2654abSrjs /* set the primary address */
43258c2654abSrjs if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
43268c2654abSrjs /* Must be confirmed */
43278c2654abSrjs return (-1);
43288c2654abSrjs }
43298c2654abSrjs stcb->asoc.primary_destination = net;
43308c2654abSrjs net->dest_state &= ~SCTP_ADDR_WAS_PRIMARY;
43318c2654abSrjs return (0);
43328c2654abSrjs }
43338c2654abSrjs }
43348c2654abSrjs
43358c2654abSrjs
43368c2654abSrjs int
sctp_is_vtag_good(struct sctp_inpcb * inp,u_int32_t tag,struct timeval * now)43378c2654abSrjs sctp_is_vtag_good(struct sctp_inpcb *inp, u_int32_t tag, struct timeval *now)
43388c2654abSrjs {
43398c2654abSrjs /*
43408c2654abSrjs * This function serves two purposes. It will see if a TAG can be
43418c2654abSrjs * re-used and return 1 for yes it is ok and 0 for don't use that
43428c2654abSrjs * tag.
43438c2654abSrjs * A secondary function it will do is purge out old tags that can
43448c2654abSrjs * be removed.
43458c2654abSrjs */
43468c2654abSrjs struct sctpasochead *head;
43478c2654abSrjs struct sctpvtaghead *chain;
43488c2654abSrjs struct sctp_tagblock *twait_block;
43498c2654abSrjs struct sctp_tcb *stcb;
43508c2654abSrjs
43518c2654abSrjs int i;
43528c2654abSrjs SCTP_INP_INFO_WLOCK();
43538c2654abSrjs chain = &sctppcbinfo.vtag_timewait[(tag % SCTP_STACK_VTAG_HASH_SIZE)];
43548c2654abSrjs /* First is the vtag in use ? */
43558c2654abSrjs
43568c2654abSrjs head = &sctppcbinfo.sctp_asochash[SCTP_PCBHASH_ASOC(tag,
43578c2654abSrjs sctppcbinfo.hashasocmark)];
43588c2654abSrjs if (head == NULL) {
43598c2654abSrjs SCTP_INP_INFO_WUNLOCK();
43608c2654abSrjs return (0);
43618c2654abSrjs }
43628c2654abSrjs LIST_FOREACH(stcb, head, sctp_asocs) {
43638c2654abSrjs if (stcb->asoc.my_vtag == tag) {
43648c2654abSrjs /* We should remove this if and
43658c2654abSrjs * return 0 always if we want vtags
43668c2654abSrjs * unique across all endpoints. For
43678c2654abSrjs * now within a endpoint is ok.
43688c2654abSrjs */
43698c2654abSrjs if (inp == stcb->sctp_ep) {
43708c2654abSrjs /* bad tag, in use */
43718c2654abSrjs SCTP_INP_INFO_WUNLOCK();
43728c2654abSrjs return (0);
43738c2654abSrjs }
43748c2654abSrjs }
43758c2654abSrjs }
43768c2654abSrjs if (!LIST_EMPTY(chain)) {
43778c2654abSrjs /*
43788c2654abSrjs * Block(s) are present, lets see if we have this tag in
43798c2654abSrjs * the list
43808c2654abSrjs */
43818c2654abSrjs LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) {
43828c2654abSrjs for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) {
43838c2654abSrjs if (twait_block->vtag_block[i].v_tag == 0) {
43848c2654abSrjs /* not used */
43858c2654abSrjs continue;
43868c2654abSrjs } else if ((long)twait_block->vtag_block[i].tv_sec_at_expire >
43878c2654abSrjs now->tv_sec) {
43888c2654abSrjs /* Audit expires this guy */
43898c2654abSrjs twait_block->vtag_block[i].tv_sec_at_expire = 0;
43908c2654abSrjs twait_block->vtag_block[i].v_tag = 0;
43918c2654abSrjs } else if (twait_block->vtag_block[i].v_tag ==
43928c2654abSrjs tag) {
43938c2654abSrjs /* Bad tag, sorry :< */
43948c2654abSrjs SCTP_INP_INFO_WUNLOCK();
43958c2654abSrjs return (0);
43968c2654abSrjs }
43978c2654abSrjs }
43988c2654abSrjs }
43998c2654abSrjs }
44008c2654abSrjs /* Not found, ok to use the tag */
44018c2654abSrjs SCTP_INP_INFO_WUNLOCK();
44028c2654abSrjs return (1);
44038c2654abSrjs }
44048c2654abSrjs
44058c2654abSrjs
44068c2654abSrjs /*
44078c2654abSrjs * Delete the address from the endpoint local address list
44088c2654abSrjs * Lookup using a sockaddr address (ie. not an ifaddr)
44098c2654abSrjs */
44108c2654abSrjs int
sctp_del_local_addr_ep_sa(struct sctp_inpcb * inp,struct sockaddr * sa)44118c2654abSrjs sctp_del_local_addr_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa)
44128c2654abSrjs {
44138c2654abSrjs struct sctp_laddr *laddr;
44148c2654abSrjs struct sockaddr *l_sa;
44158c2654abSrjs int found = 0;
44168c2654abSrjs /* Here is another function I cannot find a
44178c2654abSrjs * caller for. As such we SHOULD delete it
44188c2654abSrjs * if we have no users. If we find a user that
44198c2654abSrjs * user MUST have the INP locked.
44208c2654abSrjs *
44218c2654abSrjs */
44228c2654abSrjs
44238c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
44248c2654abSrjs /* You are already bound to all. You have it already */
44258c2654abSrjs return (EINVAL);
44268c2654abSrjs }
44278c2654abSrjs
44288c2654abSrjs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
44298c2654abSrjs /* make sure the address exists */
44308c2654abSrjs if (laddr->ifa == NULL)
44318c2654abSrjs continue;
44328c2654abSrjs if (laddr->ifa->ifa_addr == NULL)
44338c2654abSrjs continue;
44348c2654abSrjs
44358c2654abSrjs l_sa = laddr->ifa->ifa_addr;
44368c2654abSrjs if (l_sa->sa_family == AF_INET6) {
44378c2654abSrjs /* IPv6 address */
44388c2654abSrjs struct sockaddr_in6 *sin1, *sin2;
44398c2654abSrjs sin1 = (struct sockaddr_in6 *)l_sa;
44408c2654abSrjs sin2 = (struct sockaddr_in6 *)sa;
44418c2654abSrjs if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
44428c2654abSrjs sizeof(struct in6_addr)) == 0) {
44438c2654abSrjs /* matched */
44448c2654abSrjs found = 1;
44458c2654abSrjs break;
44468c2654abSrjs }
44478c2654abSrjs } else if (l_sa->sa_family == AF_INET) {
44488c2654abSrjs /* IPv4 address */
44498c2654abSrjs struct sockaddr_in *sin1, *sin2;
44508c2654abSrjs sin1 = (struct sockaddr_in *)l_sa;
44518c2654abSrjs sin2 = (struct sockaddr_in *)sa;
44528c2654abSrjs if (sin1->sin_addr.s_addr == sin2->sin_addr.s_addr) {
44538c2654abSrjs /* matched */
44548c2654abSrjs found = 1;
44558c2654abSrjs break;
44568c2654abSrjs }
44578c2654abSrjs } else {
44588c2654abSrjs /* invalid family */
44598c2654abSrjs return (-1);
44608c2654abSrjs }
44618c2654abSrjs }
44628c2654abSrjs
44638c2654abSrjs if (found && inp->laddr_count < 2) {
44648c2654abSrjs /* can't delete unless there are at LEAST 2 addresses */
44658c2654abSrjs return (-1);
44668c2654abSrjs }
44678c2654abSrjs
44688c2654abSrjs if (found && (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
44698c2654abSrjs /*
44708c2654abSrjs * remove it from the ep list, this should NOT be
44718c2654abSrjs * done until its really gone from the interface list and
44728c2654abSrjs * we won't be receiving more of these. Probably right
44738c2654abSrjs * away. If we do allow a removal of an address from
44748c2654abSrjs * an association (sub-set bind) than this should NOT
44758c2654abSrjs * be called until the all ASCONF come back from this
44768c2654abSrjs * association.
44778c2654abSrjs */
44788c2654abSrjs sctp_remove_laddr(laddr);
44798c2654abSrjs return (0);
44808c2654abSrjs } else {
44818c2654abSrjs return (-1);
44828c2654abSrjs }
44838c2654abSrjs }
44848c2654abSrjs
44858c2654abSrjs static void
sctp_drain_mbufs(struct sctp_inpcb * inp,struct sctp_tcb * stcb)44868c2654abSrjs sctp_drain_mbufs(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
44878c2654abSrjs {
44888c2654abSrjs /*
44898c2654abSrjs * We must hunt this association for MBUF's past the cumack
44908c2654abSrjs * (i.e. out of order data that we can renege on).
44918c2654abSrjs */
44928c2654abSrjs struct sctp_association *asoc;
44938c2654abSrjs struct sctp_tmit_chunk *chk, *nchk;
44948c2654abSrjs u_int32_t cumulative_tsn_p1, tsn;
44958c2654abSrjs int cnt, strmat, gap;
44968c2654abSrjs /* We look for anything larger than the cum-ack + 1 */
44978c2654abSrjs
44988c2654abSrjs asoc = &stcb->asoc;
44998c2654abSrjs cumulative_tsn_p1 = asoc->cumulative_tsn + 1;
45008c2654abSrjs cnt = 0;
45018c2654abSrjs /* First look in the re-assembly queue */
45028c2654abSrjs chk = TAILQ_FIRST(&asoc->reasmqueue);
45038c2654abSrjs while (chk) {
45048c2654abSrjs /* Get the next one */
45058c2654abSrjs nchk = TAILQ_NEXT(chk, sctp_next);
45068c2654abSrjs if (compare_with_wrap(chk->rec.data.TSN_seq,
45078c2654abSrjs cumulative_tsn_p1, MAX_TSN)) {
45088c2654abSrjs /* Yep it is above cum-ack */
45098c2654abSrjs cnt++;
45108c2654abSrjs tsn = chk->rec.data.TSN_seq;
45118c2654abSrjs if (tsn >= asoc->mapping_array_base_tsn) {
45128c2654abSrjs gap = tsn - asoc->mapping_array_base_tsn;
45138c2654abSrjs } else {
45148c2654abSrjs gap = (MAX_TSN - asoc->mapping_array_base_tsn) +
45158c2654abSrjs tsn + 1;
45168c2654abSrjs }
45178c2654abSrjs asoc->size_on_reasm_queue -= chk->send_size;
45188c2654abSrjs asoc->cnt_on_reasm_queue--;
45198c2654abSrjs SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
45208c2654abSrjs TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
45218c2654abSrjs sctp_m_freem(chk->data);
45228c2654abSrjs chk->data = NULL;
45238c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
45248c2654abSrjs sctppcbinfo.ipi_count_chunk--;
45258c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) {
45268c2654abSrjs panic("Chunk count is negative");
45278c2654abSrjs }
45288c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++;
45298c2654abSrjs }
45308c2654abSrjs chk = nchk;
45318c2654abSrjs }
45328c2654abSrjs /* Ok that was fun, now we will drain all the inbound streams? */
45338c2654abSrjs for (strmat = 0; strmat < asoc->streamincnt; strmat++) {
45348c2654abSrjs chk = TAILQ_FIRST(&asoc->strmin[strmat].inqueue);
45358c2654abSrjs while (chk) {
45368c2654abSrjs nchk = TAILQ_NEXT(chk, sctp_next);
45378c2654abSrjs if (compare_with_wrap(chk->rec.data.TSN_seq,
45388c2654abSrjs cumulative_tsn_p1, MAX_TSN)) {
45398c2654abSrjs /* Yep it is above cum-ack */
45408c2654abSrjs cnt++;
45418c2654abSrjs tsn = chk->rec.data.TSN_seq;
45428c2654abSrjs if (tsn >= asoc->mapping_array_base_tsn) {
45438c2654abSrjs gap = tsn -
45448c2654abSrjs asoc->mapping_array_base_tsn;
45458c2654abSrjs } else {
45468c2654abSrjs gap = (MAX_TSN -
45478c2654abSrjs asoc->mapping_array_base_tsn) +
45488c2654abSrjs tsn + 1;
45498c2654abSrjs }
45508c2654abSrjs asoc->size_on_all_streams -= chk->send_size;
45518c2654abSrjs asoc->cnt_on_all_streams--;
45528c2654abSrjs
45538c2654abSrjs SCTP_UNSET_TSN_PRESENT(asoc->mapping_array,
45548c2654abSrjs gap);
45558c2654abSrjs TAILQ_REMOVE(&asoc->strmin[strmat].inqueue,
45568c2654abSrjs chk, sctp_next);
45578c2654abSrjs sctp_m_freem(chk->data);
45588c2654abSrjs chk->data = NULL;
45598c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
45608c2654abSrjs sctppcbinfo.ipi_count_chunk--;
45618c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) {
45628c2654abSrjs panic("Chunk count is negative");
45638c2654abSrjs }
45648c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++;
45658c2654abSrjs }
45668c2654abSrjs chk = nchk;
45678c2654abSrjs }
45688c2654abSrjs }
45698c2654abSrjs /*
45708c2654abSrjs * Question, should we go through the delivery queue?
45718c2654abSrjs * The only reason things are on here is the app not reading OR a
45728c2654abSrjs * p-d-api up. An attacker COULD send enough in to initiate the
45738c2654abSrjs * PD-API and then send a bunch of stuff to other streams... these
45748c2654abSrjs * would wind up on the delivery queue.. and then we would not get
45758c2654abSrjs * to them. But in order to do this I then have to back-track and
45768c2654abSrjs * un-deliver sequence numbers in streams.. el-yucko. I think for
45778c2654abSrjs * now we will NOT look at the delivery queue and leave it to be
45788c2654abSrjs * something to consider later. An alternative would be to abort
45798c2654abSrjs * the P-D-API with a notification and then deliver the data....
45808c2654abSrjs * Or another method might be to keep track of how many times the
45818c2654abSrjs * situation occurs and if we see a possible attack underway just
45828c2654abSrjs * abort the association.
45838c2654abSrjs */
45848c2654abSrjs #ifdef SCTP_DEBUG
45858c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_PCB1) {
45868c2654abSrjs if (cnt) {
45878c2654abSrjs printf("Freed %d chunks from reneg harvest\n", cnt);
45888c2654abSrjs }
45898c2654abSrjs }
45908c2654abSrjs #endif /* SCTP_DEBUG */
45918c2654abSrjs
45928c2654abSrjs /*
45938c2654abSrjs * Another issue, in un-setting the TSN's in the mapping array we
4594114b0226Sandvar * DID NOT adjust the highest_tsn marker. This will cause one of
45958c2654abSrjs * two things to occur. It may cause us to do extra work in checking
45968c2654abSrjs * for our mapping array movement. More importantly it may cause us
45978c2654abSrjs * to SACK every datagram. This may not be a bad thing though since
45988c2654abSrjs * we will recover once we get our cum-ack above and all this stuff
45998c2654abSrjs * we dumped recovered.
46008c2654abSrjs */
46018c2654abSrjs }
46028c2654abSrjs
46038c2654abSrjs void
sctp_drain(void)46048c2654abSrjs sctp_drain(void)
46058c2654abSrjs {
46068c2654abSrjs /*
46078c2654abSrjs * We must walk the PCB lists for ALL associations here. The system
46088c2654abSrjs * is LOW on MBUF's and needs help. This is where reneging will
46098c2654abSrjs * occur. We really hope this does NOT happen!
46108c2654abSrjs */
46118c2654abSrjs struct sctp_inpcb *inp;
46128c2654abSrjs struct sctp_tcb *stcb;
46138c2654abSrjs
46148c2654abSrjs SCTP_INP_INFO_RLOCK();
46158c2654abSrjs LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) {
46168c2654abSrjs /* For each endpoint */
46178c2654abSrjs SCTP_INP_RLOCK(inp);
46188c2654abSrjs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
46198c2654abSrjs /* For each association */
46208c2654abSrjs SCTP_TCB_LOCK(stcb);
46218c2654abSrjs sctp_drain_mbufs(inp, stcb);
46228c2654abSrjs SCTP_TCB_UNLOCK(stcb);
46238c2654abSrjs }
46248c2654abSrjs SCTP_INP_RUNLOCK(inp);
46258c2654abSrjs }
46268c2654abSrjs SCTP_INP_INFO_RUNLOCK();
46278c2654abSrjs }
46288c2654abSrjs
46298c2654abSrjs int
sctp_add_to_socket_q(struct sctp_inpcb * inp,struct sctp_tcb * stcb)46308c2654abSrjs sctp_add_to_socket_q(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
46318c2654abSrjs {
46328c2654abSrjs struct sctp_socket_q_list *sq;
46338c2654abSrjs
46348c2654abSrjs /* write lock on INP assumed */
46358c2654abSrjs if ((inp == NULL) || (stcb == NULL)) {
46368c2654abSrjs /* I am paranoid */
46378c2654abSrjs return (0);
46388c2654abSrjs }
46398c2654abSrjs sq = (struct sctp_socket_q_list *)SCTP_ZONE_GET(
46408c2654abSrjs sctppcbinfo.ipi_zone_sockq);
46418c2654abSrjs if (sq == NULL) {
46428c2654abSrjs /* out of sq structs */
46438c2654abSrjs return (0);
46448c2654abSrjs }
46458c2654abSrjs sctppcbinfo.ipi_count_sockq++;
46468c2654abSrjs sctppcbinfo.ipi_gencnt_sockq++;
46478c2654abSrjs if (stcb)
46488c2654abSrjs stcb->asoc.cnt_msg_on_sb++;
46498c2654abSrjs sq->tcb = stcb;
46508c2654abSrjs TAILQ_INSERT_TAIL(&inp->sctp_queue_list, sq, next_sq);
46518c2654abSrjs return (1);
46528c2654abSrjs }
46538c2654abSrjs
46548c2654abSrjs
46558c2654abSrjs struct sctp_tcb *
sctp_remove_from_socket_q(struct sctp_inpcb * inp)46568c2654abSrjs sctp_remove_from_socket_q(struct sctp_inpcb *inp)
46578c2654abSrjs {
46588c2654abSrjs struct sctp_tcb *stcb = NULL;
46598c2654abSrjs struct sctp_socket_q_list *sq;
46608c2654abSrjs
46618c2654abSrjs /* W-Lock on INP assumed held */
46628c2654abSrjs sq = TAILQ_FIRST(&inp->sctp_queue_list);
46638c2654abSrjs if (sq == NULL)
46648c2654abSrjs return (NULL);
46658c2654abSrjs
46668c2654abSrjs stcb = sq->tcb;
46678c2654abSrjs TAILQ_REMOVE(&inp->sctp_queue_list, sq, next_sq);
46688c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_sockq, sq);
46698c2654abSrjs sctppcbinfo.ipi_count_sockq--;
46708c2654abSrjs sctppcbinfo.ipi_gencnt_sockq++;
46718c2654abSrjs if (stcb) {
46728c2654abSrjs stcb->asoc.cnt_msg_on_sb--;
46738c2654abSrjs }
46748c2654abSrjs return (stcb);
46758c2654abSrjs }
46768c2654abSrjs
46778c2654abSrjs int
sctp_initiate_iterator(asoc_func af,uint32_t pcb_state,uint32_t asoc_state,void * argp,uint32_t argi,end_func ef,struct sctp_inpcb * s_inp)46788c2654abSrjs sctp_initiate_iterator(asoc_func af, uint32_t pcb_state, uint32_t asoc_state,
46798c2654abSrjs void *argp, uint32_t argi, end_func ef,
46808c2654abSrjs struct sctp_inpcb *s_inp)
46818c2654abSrjs {
46828c2654abSrjs struct sctp_iterator *it=NULL;
46838c2654abSrjs int s;
46848c2654abSrjs if (af == NULL) {
46858c2654abSrjs return (-1);
46868c2654abSrjs }
46878c2654abSrjs it = malloc(sizeof(struct sctp_iterator), M_PCB, M_WAITOK);
46888c2654abSrjs if (it == NULL) {
46898c2654abSrjs return (ENOMEM);
46908c2654abSrjs }
46918c2654abSrjs memset(it, 0, sizeof(*it));
46928c2654abSrjs it->function_toapply = af;
46938c2654abSrjs it->function_atend = ef;
46948c2654abSrjs it->pointer = argp;
46958c2654abSrjs it->val = argi;
46968c2654abSrjs it->pcb_flags = pcb_state;
46978c2654abSrjs it->asoc_state = asoc_state;
46988c2654abSrjs if (s_inp) {
46998c2654abSrjs it->inp = s_inp;
47008c2654abSrjs it->iterator_flags = SCTP_ITERATOR_DO_SINGLE_INP;
47018c2654abSrjs } else {
47028c2654abSrjs SCTP_INP_INFO_RLOCK();
47038c2654abSrjs it->inp = LIST_FIRST(&sctppcbinfo.listhead);
47048c2654abSrjs SCTP_INP_INFO_RUNLOCK();
47058c2654abSrjs it->iterator_flags = SCTP_ITERATOR_DO_ALL_INP;
47068c2654abSrjs
47078c2654abSrjs }
47088c2654abSrjs /* Init the timer */
47098c2654abSrjs callout_init(&it->tmr.timer, 0);
47108c2654abSrjs /* add to the list of all iterators */
47118c2654abSrjs SCTP_INP_INFO_WLOCK();
47128c2654abSrjs LIST_INSERT_HEAD(&sctppcbinfo.iteratorhead, it, sctp_nxt_itr);
47138c2654abSrjs SCTP_INP_INFO_WUNLOCK();
47148c2654abSrjs s = splsoftnet();
47158c2654abSrjs sctp_iterator_timer(it);
47168c2654abSrjs splx(s);
47178c2654abSrjs return (0);
47188c2654abSrjs }
47198c2654abSrjs
47208c2654abSrjs
4721