18c2654abSrjs /* $KAME: sctputil.c,v 1.39 2005/06/16 20:54:06 jinmei Exp $ */
2*481d3881Srin /* $NetBSD: sctputil.c,v 1.20 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
368c2654abSrjs #include <sys/cdefs.h>
37*481d3881Srin __KERNEL_RCSID(0, "$NetBSD: sctputil.c,v 1.20 2024/07/05 04:31:54 rin Exp $");
388c2654abSrjs
398c2654abSrjs #ifdef _KERNEL_OPT
408c2654abSrjs #include "opt_inet.h"
418c2654abSrjs #include "opt_ipsec.h"
428c2654abSrjs #include "opt_sctp.h"
438c2654abSrjs #endif /* _KERNEL_OPT */
448c2654abSrjs
458c2654abSrjs #include <sys/param.h>
468c2654abSrjs #include <sys/systm.h>
478c2654abSrjs #include <sys/malloc.h>
488c2654abSrjs #include <sys/mbuf.h>
498c2654abSrjs #include <sys/domain.h>
508c2654abSrjs #include <sys/protosw.h>
518c2654abSrjs #include <sys/socket.h>
528c2654abSrjs #include <sys/socketvar.h>
538c2654abSrjs #include <sys/mutex.h>
548c2654abSrjs #include <sys/proc.h>
558c2654abSrjs #include <sys/kernel.h>
568c2654abSrjs #include <sys/sysctl.h>
57a2f9ec55Sriastradh #include <sys/cprng.h>
588c2654abSrjs
598c2654abSrjs #include <sys/callout.h>
608c2654abSrjs
618c2654abSrjs #include <net/route.h>
628c2654abSrjs
638c2654abSrjs #ifdef INET6
648c2654abSrjs #include <sys/domain.h>
658c2654abSrjs #endif
668c2654abSrjs
678c2654abSrjs #include <machine/limits.h>
688c2654abSrjs
698c2654abSrjs #include <net/if.h>
708c2654abSrjs #include <net/if_types.h>
718c2654abSrjs #include <net/route.h>
728c2654abSrjs
738c2654abSrjs #include <netinet/in.h>
748c2654abSrjs #include <netinet/in_systm.h>
758c2654abSrjs #include <netinet/ip.h>
768c2654abSrjs #include <netinet/in_pcb.h>
778c2654abSrjs #include <netinet/in_var.h>
788c2654abSrjs #include <netinet/ip_var.h>
798c2654abSrjs
808c2654abSrjs #ifdef INET6
818c2654abSrjs #include <netinet/ip6.h>
828c2654abSrjs #include <netinet6/ip6_var.h>
838c2654abSrjs #include <netinet6/scope6_var.h>
848c2654abSrjs #include <netinet6/in6_pcb.h>
858c2654abSrjs
868c2654abSrjs #endif /* INET6 */
878c2654abSrjs
888c2654abSrjs #include <netinet/sctp_pcb.h>
898c2654abSrjs
908c2654abSrjs #ifdef IPSEC
91991b8746Srjs #include <netipsec/ipsec.h>
92991b8746Srjs #include <netipsec/key.h>
938c2654abSrjs #endif /* IPSEC */
948c2654abSrjs
958c2654abSrjs #include <netinet/sctputil.h>
968c2654abSrjs #include <netinet/sctp_var.h>
978c2654abSrjs #ifdef INET6
988c2654abSrjs #include <netinet6/sctp6_var.h>
998c2654abSrjs #endif
1008c2654abSrjs #include <netinet/sctp_header.h>
1018c2654abSrjs #include <netinet/sctp_output.h>
1028c2654abSrjs #include <netinet/sctp_hashdriver.h>
1038c2654abSrjs #include <netinet/sctp_uio.h>
1048c2654abSrjs #include <netinet/sctp_timer.h>
1058c2654abSrjs #include <netinet/sctp_crc32.h>
1068c2654abSrjs #include <netinet/sctp_indata.h> /* for sctp_deliver_data() */
1078c2654abSrjs #define NUMBER_OF_MTU_SIZES 18
1088c2654abSrjs
1098c2654abSrjs #ifdef SCTP_DEBUG
1108c2654abSrjs extern u_int32_t sctp_debug_on;
1118c2654abSrjs #endif
1128c2654abSrjs
1138c2654abSrjs #ifdef SCTP_STAT_LOGGING
1148c2654abSrjs int sctp_cwnd_log_at=0;
1158c2654abSrjs int sctp_cwnd_log_rolled=0;
1168c2654abSrjs struct sctp_cwnd_log sctp_clog[SCTP_STAT_LOG_SIZE];
1178c2654abSrjs
sctp_clr_stat_log(void)1188c2654abSrjs void sctp_clr_stat_log(void)
1198c2654abSrjs {
1208c2654abSrjs sctp_cwnd_log_at=0;
1218c2654abSrjs sctp_cwnd_log_rolled=0;
1228c2654abSrjs }
1238c2654abSrjs
1248c2654abSrjs void
sctp_log_strm_del_alt(u_int32_t tsn,u_int16_t sseq,int from)1258c2654abSrjs sctp_log_strm_del_alt(u_int32_t tsn, u_int16_t sseq, int from)
1268c2654abSrjs {
1278c2654abSrjs
1288c2654abSrjs sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
1298c2654abSrjs sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_STRM;
1308c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.strlog.n_tsn = tsn;
1318c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.strlog.n_sseq = sseq;
1328c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.strlog.e_tsn = 0;
1338c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.strlog.e_sseq = 0;
1348c2654abSrjs sctp_cwnd_log_at++;
1358c2654abSrjs if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
1368c2654abSrjs sctp_cwnd_log_at = 0;
1378c2654abSrjs sctp_cwnd_log_rolled = 1;
1388c2654abSrjs }
1398c2654abSrjs
1408c2654abSrjs }
1418c2654abSrjs
1428c2654abSrjs void
sctp_log_map(uint32_t map,uint32_t cum,uint32_t high,int from)1438c2654abSrjs sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from)
1448c2654abSrjs {
1458c2654abSrjs
1468c2654abSrjs sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
1478c2654abSrjs sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_MAP;
1488c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.map.base = map;
1498c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.map.cum = cum;
1508c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.map.high = high;
1518c2654abSrjs sctp_cwnd_log_at++;
1528c2654abSrjs if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
1538c2654abSrjs sctp_cwnd_log_at = 0;
1548c2654abSrjs sctp_cwnd_log_rolled = 1;
1558c2654abSrjs }
1568c2654abSrjs }
1578c2654abSrjs
1588c2654abSrjs void
sctp_log_fr(uint32_t biggest_tsn,uint32_t biggest_new_tsn,uint32_t tsn,int from)1598c2654abSrjs sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn,
1608c2654abSrjs int from)
1618c2654abSrjs {
1628c2654abSrjs
1638c2654abSrjs sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
1648c2654abSrjs sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_FR;
1658c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.fr.largest_tsn = biggest_tsn;
1668c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.fr.largest_new_tsn = biggest_new_tsn;
1678c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.fr.tsn = tsn;
1688c2654abSrjs sctp_cwnd_log_at++;
1698c2654abSrjs if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
1708c2654abSrjs sctp_cwnd_log_at = 0;
1718c2654abSrjs sctp_cwnd_log_rolled = 1;
1728c2654abSrjs }
1738c2654abSrjs }
1748c2654abSrjs
1758c2654abSrjs void
sctp_log_strm_del(struct sctp_tmit_chunk * chk,struct sctp_tmit_chunk * poschk,int from)1768c2654abSrjs sctp_log_strm_del(struct sctp_tmit_chunk *chk, struct sctp_tmit_chunk *poschk,
1778c2654abSrjs int from)
1788c2654abSrjs {
1798c2654abSrjs
1808c2654abSrjs if (chk == NULL) {
1818c2654abSrjs printf("Gak log of NULL?\n");
1828c2654abSrjs return;
1838c2654abSrjs }
1848c2654abSrjs sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
1858c2654abSrjs sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_STRM;
1868c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.strlog.n_tsn = chk->rec.data.TSN_seq;
1878c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.strlog.n_sseq = chk->rec.data.stream_seq;
1888c2654abSrjs if (poschk != NULL) {
1898c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.strlog.e_tsn =
1908c2654abSrjs poschk->rec.data.TSN_seq;
1918c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.strlog.e_sseq =
1928c2654abSrjs poschk->rec.data.stream_seq;
1938c2654abSrjs } else {
1948c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.strlog.e_tsn = 0;
1958c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.strlog.e_sseq = 0;
1968c2654abSrjs }
1978c2654abSrjs sctp_cwnd_log_at++;
1988c2654abSrjs if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
1998c2654abSrjs sctp_cwnd_log_at = 0;
2008c2654abSrjs sctp_cwnd_log_rolled = 1;
2018c2654abSrjs }
2028c2654abSrjs }
2038c2654abSrjs
2048c2654abSrjs void
sctp_log_cwnd(struct sctp_nets * net,int augment,uint8_t from)2058c2654abSrjs sctp_log_cwnd(struct sctp_nets *net, int augment, uint8_t from)
2068c2654abSrjs {
2078c2654abSrjs
2088c2654abSrjs sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
2098c2654abSrjs sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_CWND;
2108c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.cwnd.net = net;
2118c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.cwnd.cwnd_new_value = net->cwnd;
2128c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.cwnd.inflight = net->flight_size;
2138c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.cwnd.cwnd_augment = augment;
2148c2654abSrjs sctp_cwnd_log_at++;
2158c2654abSrjs if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
2168c2654abSrjs sctp_cwnd_log_at = 0;
2178c2654abSrjs sctp_cwnd_log_rolled = 1;
2188c2654abSrjs }
2198c2654abSrjs }
2208c2654abSrjs
2218c2654abSrjs void
sctp_log_maxburst(struct sctp_nets * net,int error,int burst,uint8_t from)2228c2654abSrjs sctp_log_maxburst(struct sctp_nets *net, int error, int burst, uint8_t from)
2238c2654abSrjs {
2248c2654abSrjs sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
2258c2654abSrjs sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_MAXBURST;
2268c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.cwnd.net = net;
2278c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.cwnd.cwnd_new_value = error;
2288c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.cwnd.inflight = net->flight_size;
2298c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.cwnd.cwnd_augment = burst;
2308c2654abSrjs sctp_cwnd_log_at++;
2318c2654abSrjs if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
2328c2654abSrjs sctp_cwnd_log_at = 0;
2338c2654abSrjs sctp_cwnd_log_rolled = 1;
2348c2654abSrjs }
2358c2654abSrjs }
2368c2654abSrjs
2378c2654abSrjs void
sctp_log_rwnd(uint8_t from,u_int32_t peers_rwnd,u_int32_t snd_size,u_int32_t overhead)2388c2654abSrjs sctp_log_rwnd(uint8_t from, u_int32_t peers_rwnd , u_int32_t snd_size, u_int32_t overhead)
2398c2654abSrjs {
2408c2654abSrjs sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
2418c2654abSrjs sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_RWND;
2428c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.rwnd.rwnd = peers_rwnd;
2438c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.rwnd.send_size = snd_size;
2448c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.rwnd.overhead = overhead;
2458c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.rwnd.new_rwnd = 0;
2468c2654abSrjs sctp_cwnd_log_at++;
2478c2654abSrjs if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
2488c2654abSrjs sctp_cwnd_log_at = 0;
2498c2654abSrjs sctp_cwnd_log_rolled = 1;
2508c2654abSrjs }
2518c2654abSrjs }
2528c2654abSrjs
2538c2654abSrjs void
sctp_log_rwnd_set(uint8_t from,u_int32_t peers_rwnd,u_int32_t flight_size,u_int32_t overhead,u_int32_t a_rwndval)2548c2654abSrjs sctp_log_rwnd_set(uint8_t from, u_int32_t peers_rwnd , u_int32_t flight_size, u_int32_t overhead, u_int32_t a_rwndval)
2558c2654abSrjs {
2568c2654abSrjs sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
2578c2654abSrjs sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_RWND;
2588c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.rwnd.rwnd = peers_rwnd;
2598c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.rwnd.send_size = flight_size;
2608c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.rwnd.overhead = overhead;
2618c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.rwnd.new_rwnd = a_rwndval;
2628c2654abSrjs sctp_cwnd_log_at++;
2638c2654abSrjs if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
2648c2654abSrjs sctp_cwnd_log_at = 0;
2658c2654abSrjs sctp_cwnd_log_rolled = 1;
2668c2654abSrjs }
2678c2654abSrjs }
2688c2654abSrjs
2698c2654abSrjs void
sctp_log_mbcnt(uint8_t from,u_int32_t total_oq,u_int32_t book,u_int32_t total_mbcnt_q,u_int32_t mbcnt)2708c2654abSrjs sctp_log_mbcnt(uint8_t from, u_int32_t total_oq , u_int32_t book, u_int32_t total_mbcnt_q, u_int32_t mbcnt)
2718c2654abSrjs {
2728c2654abSrjs sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
2738c2654abSrjs sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_MBCNT;
2748c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.mbcnt.total_queue_size = total_oq;
2758c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.mbcnt.size_change = book;
2768c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.mbcnt.total_queue_mb_size = total_mbcnt_q;
2778c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.mbcnt.mbcnt_change = mbcnt;
2788c2654abSrjs sctp_cwnd_log_at++;
2798c2654abSrjs if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
2808c2654abSrjs sctp_cwnd_log_at = 0;
2818c2654abSrjs sctp_cwnd_log_rolled = 1;
2828c2654abSrjs }
2838c2654abSrjs }
2848c2654abSrjs
2858c2654abSrjs void
sctp_log_block(uint8_t from,struct socket * so,struct sctp_association * asoc)2868c2654abSrjs sctp_log_block(uint8_t from, struct socket *so, struct sctp_association *asoc)
2878c2654abSrjs {
2888c2654abSrjs
2898c2654abSrjs sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
2908c2654abSrjs sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_BLOCK;
2918c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.blk.maxmb = (u_int16_t)(so->so_snd.sb_mbmax/1024);
2928c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.blk.onmb = asoc->total_output_mbuf_queue_size;
2938c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.blk.maxsb = (u_int16_t)(so->so_snd.sb_hiwat/1024);
2948c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.blk.onsb = asoc->total_output_queue_size;
2958c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.blk.send_sent_qcnt = (u_int16_t)(asoc->send_queue_cnt + asoc->sent_queue_cnt);
2968c2654abSrjs sctp_clog[sctp_cwnd_log_at].x.blk.stream_qcnt = (u_int16_t)asoc->stream_queue_cnt;
2978c2654abSrjs sctp_cwnd_log_at++;
2988c2654abSrjs if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
2998c2654abSrjs sctp_cwnd_log_at = 0;
3008c2654abSrjs sctp_cwnd_log_rolled = 1;
3018c2654abSrjs }
3028c2654abSrjs }
3038c2654abSrjs
3048c2654abSrjs int
sctp_fill_stat_log(struct mbuf * m)3058c2654abSrjs sctp_fill_stat_log(struct mbuf *m)
3068c2654abSrjs {
3078c2654abSrjs struct sctp_cwnd_log_req *req;
3088c2654abSrjs int size_limit, num, i, at, cnt_out=0;
3098c2654abSrjs
3108c2654abSrjs if (m == NULL)
3118c2654abSrjs return (EINVAL);
3128c2654abSrjs
3138c2654abSrjs size_limit = (m->m_len - sizeof(struct sctp_cwnd_log_req));
3148c2654abSrjs if (size_limit < sizeof(struct sctp_cwnd_log)) {
3158c2654abSrjs return (EINVAL);
3168c2654abSrjs }
3178c2654abSrjs req = mtod(m, struct sctp_cwnd_log_req *);
3188c2654abSrjs num = size_limit/sizeof(struct sctp_cwnd_log);
3198c2654abSrjs if (sctp_cwnd_log_rolled) {
3208c2654abSrjs req->num_in_log = SCTP_STAT_LOG_SIZE;
3218c2654abSrjs } else {
3228c2654abSrjs req->num_in_log = sctp_cwnd_log_at;
3238c2654abSrjs /* if the log has not rolled, we don't
3248c2654abSrjs * let you have old data.
3258c2654abSrjs */
3268c2654abSrjs if (req->end_at > sctp_cwnd_log_at) {
3278c2654abSrjs req->end_at = sctp_cwnd_log_at;
3288c2654abSrjs }
3298c2654abSrjs }
3308c2654abSrjs if ((num < SCTP_STAT_LOG_SIZE) &&
3318c2654abSrjs ((sctp_cwnd_log_rolled) || (sctp_cwnd_log_at > num))) {
3328c2654abSrjs /* we can't return all of it */
3338c2654abSrjs if (((req->start_at == 0) && (req->end_at == 0)) ||
3348c2654abSrjs (req->start_at >= SCTP_STAT_LOG_SIZE) ||
3358c2654abSrjs (req->end_at >= SCTP_STAT_LOG_SIZE)) {
3368c2654abSrjs /* No user request or user is wacked. */
3378c2654abSrjs req->num_ret = num;
3388c2654abSrjs req->end_at = sctp_cwnd_log_at - 1;
3398c2654abSrjs if ((sctp_cwnd_log_at - num) < 0) {
3408c2654abSrjs int cc;
3418c2654abSrjs cc = num - sctp_cwnd_log_at;
3428c2654abSrjs req->start_at = SCTP_STAT_LOG_SIZE - cc;
3438c2654abSrjs } else {
3448c2654abSrjs req->start_at = sctp_cwnd_log_at - num;
3458c2654abSrjs }
3468c2654abSrjs } else {
3478c2654abSrjs /* a user request */
3488c2654abSrjs int cc;
3498c2654abSrjs if (req->start_at > req->end_at) {
3508c2654abSrjs cc = (SCTP_STAT_LOG_SIZE - req->start_at) +
3518c2654abSrjs (req->end_at + 1);
3528c2654abSrjs } else {
3538c2654abSrjs
3548c2654abSrjs cc = req->end_at - req->start_at;
3558c2654abSrjs }
3568c2654abSrjs if (cc < num) {
3578c2654abSrjs num = cc;
3588c2654abSrjs }
3598c2654abSrjs req->num_ret = num;
3608c2654abSrjs }
3618c2654abSrjs } else {
3628c2654abSrjs /* We can return all of it */
3638c2654abSrjs req->start_at = 0;
3648c2654abSrjs req->end_at = sctp_cwnd_log_at - 1;
3658c2654abSrjs req->num_ret = sctp_cwnd_log_at;
3668c2654abSrjs }
3678c2654abSrjs for (i = 0, at = req->start_at; i < req->num_ret; i++) {
3688c2654abSrjs req->log[i] = sctp_clog[at];
3698c2654abSrjs cnt_out++;
3708c2654abSrjs at++;
3718c2654abSrjs if (at >= SCTP_STAT_LOG_SIZE)
3728c2654abSrjs at = 0;
3738c2654abSrjs }
3748c2654abSrjs m->m_len = (cnt_out * sizeof(struct sctp_cwnd_log_req)) + sizeof(struct sctp_cwnd_log_req);
3758c2654abSrjs return (0);
3768c2654abSrjs }
3778c2654abSrjs
3788c2654abSrjs #endif
3798c2654abSrjs
3808c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
3818c2654abSrjs u_int8_t sctp_audit_data[SCTP_AUDIT_SIZE][2];
3828c2654abSrjs static int sctp_audit_indx = 0;
3838c2654abSrjs
3848c2654abSrjs static
sctp_print_audit_report(void)3858c2654abSrjs void sctp_print_audit_report(void)
3868c2654abSrjs {
3878c2654abSrjs int i;
3888c2654abSrjs int cnt;
3898c2654abSrjs cnt = 0;
3908c2654abSrjs for (i=sctp_audit_indx;i<SCTP_AUDIT_SIZE;i++) {
3918c2654abSrjs if ((sctp_audit_data[i][0] == 0xe0) &&
3928c2654abSrjs (sctp_audit_data[i][1] == 0x01)) {
3938c2654abSrjs cnt = 0;
3948c2654abSrjs printf("\n");
3958c2654abSrjs } else if (sctp_audit_data[i][0] == 0xf0) {
3968c2654abSrjs cnt = 0;
3978c2654abSrjs printf("\n");
3988c2654abSrjs } else if ((sctp_audit_data[i][0] == 0xc0) &&
3998c2654abSrjs (sctp_audit_data[i][1] == 0x01)) {
4008c2654abSrjs printf("\n");
4018c2654abSrjs cnt = 0;
4028c2654abSrjs }
4038c2654abSrjs printf("%2.2x%2.2x ", (uint32_t)sctp_audit_data[i][0],
4048c2654abSrjs (uint32_t)sctp_audit_data[i][1]);
4058c2654abSrjs cnt++;
4068c2654abSrjs if ((cnt % 14) == 0)
4078c2654abSrjs printf("\n");
4088c2654abSrjs }
4098c2654abSrjs for (i=0;i<sctp_audit_indx;i++) {
4108c2654abSrjs if ((sctp_audit_data[i][0] == 0xe0) &&
4118c2654abSrjs (sctp_audit_data[i][1] == 0x01)) {
4128c2654abSrjs cnt = 0;
4138c2654abSrjs printf("\n");
4148c2654abSrjs } else if (sctp_audit_data[i][0] == 0xf0) {
4158c2654abSrjs cnt = 0;
4168c2654abSrjs printf("\n");
4178c2654abSrjs } else if ((sctp_audit_data[i][0] == 0xc0) &&
4188c2654abSrjs (sctp_audit_data[i][1] == 0x01)) {
4198c2654abSrjs printf("\n");
4208c2654abSrjs cnt = 0;
4218c2654abSrjs }
4228c2654abSrjs printf("%2.2x%2.2x ", (uint32_t)sctp_audit_data[i][0],
4238c2654abSrjs (uint32_t)sctp_audit_data[i][1]);
4248c2654abSrjs cnt++;
4258c2654abSrjs if ((cnt % 14) == 0)
4268c2654abSrjs printf("\n");
4278c2654abSrjs }
4288c2654abSrjs printf("\n");
4298c2654abSrjs }
4308c2654abSrjs
sctp_auditing(int from,struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)4318c2654abSrjs void sctp_auditing(int from, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
4328c2654abSrjs struct sctp_nets *net)
4338c2654abSrjs {
4348c2654abSrjs int resend_cnt, tot_out, rep, tot_book_cnt;
4358c2654abSrjs struct sctp_nets *lnet;
4368c2654abSrjs struct sctp_tmit_chunk *chk;
4378c2654abSrjs
4388c2654abSrjs sctp_audit_data[sctp_audit_indx][0] = 0xAA;
4398c2654abSrjs sctp_audit_data[sctp_audit_indx][1] = 0x000000ff & from;
4408c2654abSrjs sctp_audit_indx++;
4418c2654abSrjs if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
4428c2654abSrjs sctp_audit_indx = 0;
4438c2654abSrjs }
4448c2654abSrjs if (inp == NULL) {
4458c2654abSrjs sctp_audit_data[sctp_audit_indx][0] = 0xAF;
4468c2654abSrjs sctp_audit_data[sctp_audit_indx][1] = 0x01;
4478c2654abSrjs sctp_audit_indx++;
4488c2654abSrjs if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
4498c2654abSrjs sctp_audit_indx = 0;
4508c2654abSrjs }
4518c2654abSrjs return;
4528c2654abSrjs }
4538c2654abSrjs if (stcb == NULL) {
4548c2654abSrjs sctp_audit_data[sctp_audit_indx][0] = 0xAF;
4558c2654abSrjs sctp_audit_data[sctp_audit_indx][1] = 0x02;
4568c2654abSrjs sctp_audit_indx++;
4578c2654abSrjs if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
4588c2654abSrjs sctp_audit_indx = 0;
4598c2654abSrjs }
4608c2654abSrjs return;
4618c2654abSrjs }
4628c2654abSrjs sctp_audit_data[sctp_audit_indx][0] = 0xA1;
4638c2654abSrjs sctp_audit_data[sctp_audit_indx][1] =
4648c2654abSrjs (0x000000ff & stcb->asoc.sent_queue_retran_cnt);
4658c2654abSrjs sctp_audit_indx++;
4668c2654abSrjs if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
4678c2654abSrjs sctp_audit_indx = 0;
4688c2654abSrjs }
4698c2654abSrjs rep = 0;
4708c2654abSrjs tot_book_cnt = 0;
4718c2654abSrjs resend_cnt = tot_out = 0;
4728c2654abSrjs TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
4738c2654abSrjs if (chk->sent == SCTP_DATAGRAM_RESEND) {
4748c2654abSrjs resend_cnt++;
4758c2654abSrjs } else if (chk->sent < SCTP_DATAGRAM_RESEND) {
4768c2654abSrjs tot_out += chk->book_size;
4778c2654abSrjs tot_book_cnt++;
4788c2654abSrjs }
4798c2654abSrjs }
4808c2654abSrjs if (resend_cnt != stcb->asoc.sent_queue_retran_cnt) {
4818c2654abSrjs sctp_audit_data[sctp_audit_indx][0] = 0xAF;
4828c2654abSrjs sctp_audit_data[sctp_audit_indx][1] = 0xA1;
4838c2654abSrjs sctp_audit_indx++;
4848c2654abSrjs if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
4858c2654abSrjs sctp_audit_indx = 0;
4868c2654abSrjs }
4878c2654abSrjs printf("resend_cnt:%d asoc-tot:%d\n",
4888c2654abSrjs resend_cnt, stcb->asoc.sent_queue_retran_cnt);
4898c2654abSrjs rep = 1;
4908c2654abSrjs stcb->asoc.sent_queue_retran_cnt = resend_cnt;
4918c2654abSrjs sctp_audit_data[sctp_audit_indx][0] = 0xA2;
4928c2654abSrjs sctp_audit_data[sctp_audit_indx][1] =
4938c2654abSrjs (0x000000ff & stcb->asoc.sent_queue_retran_cnt);
4948c2654abSrjs sctp_audit_indx++;
4958c2654abSrjs if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
4968c2654abSrjs sctp_audit_indx = 0;
4978c2654abSrjs }
4988c2654abSrjs }
4998c2654abSrjs if (tot_out != stcb->asoc.total_flight) {
5008c2654abSrjs sctp_audit_data[sctp_audit_indx][0] = 0xAF;
5018c2654abSrjs sctp_audit_data[sctp_audit_indx][1] = 0xA2;
5028c2654abSrjs sctp_audit_indx++;
5038c2654abSrjs if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
5048c2654abSrjs sctp_audit_indx = 0;
5058c2654abSrjs }
5068c2654abSrjs rep = 1;
5078c2654abSrjs printf("tot_flt:%d asoc_tot:%d\n", tot_out,
5088c2654abSrjs (int)stcb->asoc.total_flight);
5098c2654abSrjs stcb->asoc.total_flight = tot_out;
5108c2654abSrjs }
5118c2654abSrjs if (tot_book_cnt != stcb->asoc.total_flight_count) {
5128c2654abSrjs sctp_audit_data[sctp_audit_indx][0] = 0xAF;
5138c2654abSrjs sctp_audit_data[sctp_audit_indx][1] = 0xA5;
5148c2654abSrjs sctp_audit_indx++;
5158c2654abSrjs if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
5168c2654abSrjs sctp_audit_indx = 0;
5178c2654abSrjs }
5188c2654abSrjs rep = 1;
5198c2654abSrjs printf("tot_flt_book:%d\n", tot_book);
5208c2654abSrjs
5218c2654abSrjs stcb->asoc.total_flight_count = tot_book_cnt;
5228c2654abSrjs }
5238c2654abSrjs tot_out = 0;
5248c2654abSrjs TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
5258c2654abSrjs tot_out += lnet->flight_size;
5268c2654abSrjs }
5278c2654abSrjs if (tot_out != stcb->asoc.total_flight) {
5288c2654abSrjs sctp_audit_data[sctp_audit_indx][0] = 0xAF;
5298c2654abSrjs sctp_audit_data[sctp_audit_indx][1] = 0xA3;
5308c2654abSrjs sctp_audit_indx++;
5318c2654abSrjs if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
5328c2654abSrjs sctp_audit_indx = 0;
5338c2654abSrjs }
5348c2654abSrjs rep = 1;
5358c2654abSrjs printf("real flight:%d net total was %d\n",
5368c2654abSrjs stcb->asoc.total_flight, tot_out);
5378c2654abSrjs /* now corrective action */
5388c2654abSrjs TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
5398c2654abSrjs tot_out = 0;
5408c2654abSrjs TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
5418c2654abSrjs if ((chk->whoTo == lnet) &&
5428c2654abSrjs (chk->sent < SCTP_DATAGRAM_RESEND)) {
5438c2654abSrjs tot_out += chk->book_size;
5448c2654abSrjs }
5458c2654abSrjs }
5468c2654abSrjs if (lnet->flight_size != tot_out) {
5478c2654abSrjs printf("net:%x flight was %d corrected to %d\n",
5488c2654abSrjs (uint32_t)lnet, lnet->flight_size, tot_out);
5498c2654abSrjs lnet->flight_size = tot_out;
5508c2654abSrjs }
5518c2654abSrjs
5528c2654abSrjs }
5538c2654abSrjs }
5548c2654abSrjs
5558c2654abSrjs if (rep) {
5568c2654abSrjs sctp_print_audit_report();
5578c2654abSrjs }
5588c2654abSrjs }
5598c2654abSrjs
5608c2654abSrjs void
sctp_audit_log(u_int8_t ev,u_int8_t fd)5618c2654abSrjs sctp_audit_log(u_int8_t ev, u_int8_t fd)
5628c2654abSrjs {
5638c2654abSrjs sctp_audit_data[sctp_audit_indx][0] = ev;
5648c2654abSrjs sctp_audit_data[sctp_audit_indx][1] = fd;
5658c2654abSrjs sctp_audit_indx++;
5668c2654abSrjs if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
5678c2654abSrjs sctp_audit_indx = 0;
5688c2654abSrjs }
5698c2654abSrjs }
5708c2654abSrjs
5718c2654abSrjs #endif
5728c2654abSrjs
5738c2654abSrjs /*
5748c2654abSrjs * a list of sizes based on typical mtu's, used only if next hop
5758c2654abSrjs * size not returned.
5768c2654abSrjs */
5778c2654abSrjs static int sctp_mtu_sizes[] = {
5788c2654abSrjs 68,
5798c2654abSrjs 296,
5808c2654abSrjs 508,
5818c2654abSrjs 512,
5828c2654abSrjs 544,
5838c2654abSrjs 576,
5848c2654abSrjs 1006,
5858c2654abSrjs 1492,
5868c2654abSrjs 1500,
5878c2654abSrjs 1536,
5888c2654abSrjs 2002,
5898c2654abSrjs 2048,
5908c2654abSrjs 4352,
5918c2654abSrjs 4464,
5928c2654abSrjs 8166,
5938c2654abSrjs 17914,
5948c2654abSrjs 32000,
5958c2654abSrjs 65535
5968c2654abSrjs };
5978c2654abSrjs
5988c2654abSrjs int
find_next_best_mtu(int totsz)5998c2654abSrjs find_next_best_mtu(int totsz)
6008c2654abSrjs {
6018c2654abSrjs int i, perfer;
6028c2654abSrjs /*
6038c2654abSrjs * if we are in here we must find the next best fit based on the
6048c2654abSrjs * size of the dg that failed to be sent.
6058c2654abSrjs */
6068c2654abSrjs perfer = 0;
6078c2654abSrjs for (i = 0; i < NUMBER_OF_MTU_SIZES; i++) {
6088c2654abSrjs if (totsz < sctp_mtu_sizes[i]) {
6098c2654abSrjs perfer = i - 1;
6108c2654abSrjs if (perfer < 0)
6118c2654abSrjs perfer = 0;
6128c2654abSrjs break;
6138c2654abSrjs }
6148c2654abSrjs }
6158c2654abSrjs return (sctp_mtu_sizes[perfer]);
6168c2654abSrjs }
6178c2654abSrjs
6188c2654abSrjs uint32_t
sctp_select_initial_TSN(struct sctp_pcb * m)6198c2654abSrjs sctp_select_initial_TSN(struct sctp_pcb *m)
6208c2654abSrjs {
621a2f9ec55Sriastradh return cprng_strong32();
6228c2654abSrjs }
6238c2654abSrjs
sctp_select_a_tag(struct sctp_inpcb * m)6248c2654abSrjs u_int32_t sctp_select_a_tag(struct sctp_inpcb *m)
6258c2654abSrjs {
6268c2654abSrjs u_long x, not_done;
6278c2654abSrjs struct timeval now;
6288c2654abSrjs
6298c2654abSrjs SCTP_GETTIME_TIMEVAL(&now);
6308c2654abSrjs not_done = 1;
6318c2654abSrjs while (not_done) {
6328c2654abSrjs x = sctp_select_initial_TSN(&m->sctp_ep);
6338c2654abSrjs if (x == 0) {
6348c2654abSrjs /* we never use 0 */
6358c2654abSrjs continue;
6368c2654abSrjs }
6378c2654abSrjs if (sctp_is_vtag_good(m, x, &now)) {
6388c2654abSrjs not_done = 0;
6398c2654abSrjs }
6408c2654abSrjs }
6418c2654abSrjs return (x);
6428c2654abSrjs }
6438c2654abSrjs
6448c2654abSrjs
6458c2654abSrjs int
sctp_init_asoc(struct sctp_inpcb * m,struct sctp_association * asoc,int for_a_init,uint32_t override_tag)6468c2654abSrjs sctp_init_asoc(struct sctp_inpcb *m, struct sctp_association *asoc,
6478c2654abSrjs int for_a_init, uint32_t override_tag )
6488c2654abSrjs {
6498c2654abSrjs /*
6508c2654abSrjs * Anything set to zero is taken care of by the allocation
6518c2654abSrjs * routine's bzero
6528c2654abSrjs */
6538c2654abSrjs
6548c2654abSrjs /*
6558c2654abSrjs * Up front select what scoping to apply on addresses I tell my peer
6568c2654abSrjs * Not sure what to do with these right now, we will need to come up
6578c2654abSrjs * with a way to set them. We may need to pass them through from the
6588c2654abSrjs * caller in the sctp_aloc_assoc() function.
6598c2654abSrjs */
6608c2654abSrjs int i;
6618c2654abSrjs /* init all variables to a known value.*/
6628c2654abSrjs asoc->state = SCTP_STATE_INUSE;
6638c2654abSrjs asoc->max_burst = m->sctp_ep.max_burst;
6648c2654abSrjs asoc->heart_beat_delay = m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT];
6658c2654abSrjs asoc->cookie_life = m->sctp_ep.def_cookie_life;
6668c2654abSrjs
6678c2654abSrjs if (override_tag) {
6688c2654abSrjs asoc->my_vtag = override_tag;
6698c2654abSrjs } else {
6708c2654abSrjs asoc->my_vtag = sctp_select_a_tag(m);
6718c2654abSrjs }
6728c2654abSrjs asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number = asoc->sending_seq =
6738c2654abSrjs sctp_select_initial_TSN(&m->sctp_ep);
6748c2654abSrjs asoc->t3timeout_highest_marked = asoc->asconf_seq_out;
6758c2654abSrjs /* we are opptimisitic here */
6768c2654abSrjs asoc->peer_supports_asconf = 1;
6778c2654abSrjs asoc->peer_supports_asconf_setprim = 1;
6788c2654abSrjs asoc->peer_supports_pktdrop = 1;
6798c2654abSrjs
6808c2654abSrjs asoc->sent_queue_retran_cnt = 0;
6818c2654abSrjs /* This will need to be adjusted */
6828c2654abSrjs asoc->last_cwr_tsn = asoc->init_seq_number - 1;
6838c2654abSrjs asoc->last_acked_seq = asoc->init_seq_number - 1;
6848c2654abSrjs asoc->advanced_peer_ack_point = asoc->last_acked_seq;
6858c2654abSrjs asoc->asconf_seq_in = asoc->last_acked_seq;
6868c2654abSrjs
6878c2654abSrjs /* here we are different, we hold the next one we expect */
6888c2654abSrjs asoc->str_reset_seq_in = asoc->last_acked_seq + 1;
6898c2654abSrjs
6908c2654abSrjs asoc->initial_init_rto_max = m->sctp_ep.initial_init_rto_max;
6918c2654abSrjs asoc->initial_rto = m->sctp_ep.initial_rto;
6928c2654abSrjs
6938c2654abSrjs asoc->max_init_times = m->sctp_ep.max_init_times;
6948c2654abSrjs asoc->max_send_times = m->sctp_ep.max_send_times;
6958c2654abSrjs asoc->def_net_failure = m->sctp_ep.def_net_failure;
6968c2654abSrjs
6978c2654abSrjs /* ECN Nonce initialization */
6988c2654abSrjs asoc->ecn_nonce_allowed = 0;
6998c2654abSrjs asoc->receiver_nonce_sum = 1;
7008c2654abSrjs asoc->nonce_sum_expect_base = 1;
7018c2654abSrjs asoc->nonce_sum_check = 1;
7028c2654abSrjs asoc->nonce_resync_tsn = 0;
7038c2654abSrjs asoc->nonce_wait_for_ecne = 0;
7048c2654abSrjs asoc->nonce_wait_tsn = 0;
7058c2654abSrjs
7068c2654abSrjs if (m->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
7078c2654abSrjs struct in6pcb *inp6;
7088c2654abSrjs
7098c2654abSrjs
7108c2654abSrjs /* Its a V6 socket */
7118c2654abSrjs inp6 = (struct in6pcb *)m;
7128c2654abSrjs asoc->ipv6_addr_legal = 1;
7138c2654abSrjs /* Now look at the binding flag to see if V4 will be legal */
7148c2654abSrjs if (
7158c2654abSrjs #if defined(__OpenBSD__)
7168c2654abSrjs (0) /* we always do dual bind */
7178c2654abSrjs #elif defined (__NetBSD__)
7188c2654abSrjs (inp6->in6p_flags & IN6P_IPV6_V6ONLY)
7198c2654abSrjs #else
7208c2654abSrjs (inp6->inp_flags & IN6P_IPV6_V6ONLY)
7218c2654abSrjs #endif
7228c2654abSrjs == 0) {
7238c2654abSrjs asoc->ipv4_addr_legal = 1;
7248c2654abSrjs } else {
7258c2654abSrjs /* V4 addresses are NOT legal on the association */
7268c2654abSrjs asoc->ipv4_addr_legal = 0;
7278c2654abSrjs }
7288c2654abSrjs } else {
7298c2654abSrjs /* Its a V4 socket, no - V6 */
7308c2654abSrjs asoc->ipv4_addr_legal = 1;
7318c2654abSrjs asoc->ipv6_addr_legal = 0;
7328c2654abSrjs }
7338c2654abSrjs
7348c2654abSrjs
735d1579b2dSriastradh asoc->my_rwnd = uimax(m->sctp_socket->so_rcv.sb_hiwat, SCTP_MINIMAL_RWND);
7368c2654abSrjs asoc->peers_rwnd = m->sctp_socket->so_rcv.sb_hiwat;
7378c2654abSrjs
7388c2654abSrjs asoc->smallest_mtu = m->sctp_frag_point;
7398c2654abSrjs asoc->minrto = m->sctp_ep.sctp_minrto;
7408c2654abSrjs asoc->maxrto = m->sctp_ep.sctp_maxrto;
7418c2654abSrjs
7428c2654abSrjs LIST_INIT(&asoc->sctp_local_addr_list);
7438c2654abSrjs TAILQ_INIT(&asoc->nets);
7448c2654abSrjs TAILQ_INIT(&asoc->pending_reply_queue);
7458c2654abSrjs asoc->last_asconf_ack_sent = NULL;
7468c2654abSrjs /* Setup to fill the hb random cache at first HB */
7478c2654abSrjs asoc->hb_random_idx = 4;
7488c2654abSrjs
7498c2654abSrjs asoc->sctp_autoclose_ticks = m->sctp_ep.auto_close_time;
7508c2654abSrjs
7518c2654abSrjs /*
7528c2654abSrjs * Now the stream parameters, here we allocate space for all
7538c2654abSrjs * streams that we request by default.
7548c2654abSrjs */
7558c2654abSrjs asoc->streamoutcnt = asoc->pre_open_streams =
7568c2654abSrjs m->sctp_ep.pre_open_stream_count;
7578c2654abSrjs asoc->strmout = malloc(asoc->streamoutcnt *
7588c2654abSrjs sizeof(struct sctp_stream_out), M_PCB, M_NOWAIT);
7598c2654abSrjs if (asoc->strmout == NULL) {
7608c2654abSrjs /* big trouble no memory */
7618c2654abSrjs return (ENOMEM);
7628c2654abSrjs }
7638c2654abSrjs for (i = 0; i < asoc->streamoutcnt; i++) {
7648c2654abSrjs /*
7658c2654abSrjs * inbound side must be set to 0xffff,
7668c2654abSrjs * also NOTE when we get the INIT-ACK back (for INIT sender)
7678c2654abSrjs * we MUST reduce the count (streamoutcnt) but first check
7688c2654abSrjs * if we sent to any of the upper streams that were dropped
7698c2654abSrjs * (if some were). Those that were dropped must be notified
7708c2654abSrjs * to the upper layer as failed to send.
7718c2654abSrjs */
7728c2654abSrjs asoc->strmout[i].next_sequence_sent = 0x0;
7738c2654abSrjs TAILQ_INIT(&asoc->strmout[i].outqueue);
7748c2654abSrjs asoc->strmout[i].stream_no = i;
7758c2654abSrjs asoc->strmout[i].next_spoke.tqe_next = 0;
7768c2654abSrjs asoc->strmout[i].next_spoke.tqe_prev = 0;
7778c2654abSrjs }
7788c2654abSrjs /* Now the mapping array */
7798c2654abSrjs asoc->mapping_array_size = SCTP_INITIAL_MAPPING_ARRAY;
7808c2654abSrjs asoc->mapping_array = malloc(asoc->mapping_array_size,
7818c2654abSrjs M_PCB, M_NOWAIT);
7828c2654abSrjs if (asoc->mapping_array == NULL) {
7838c2654abSrjs free(asoc->strmout, M_PCB);
7848c2654abSrjs return (ENOMEM);
7858c2654abSrjs }
7868c2654abSrjs memset(asoc->mapping_array, 0, asoc->mapping_array_size);
7878c2654abSrjs /* Now the init of the other outqueues */
7888c2654abSrjs TAILQ_INIT(&asoc->out_wheel);
7898c2654abSrjs TAILQ_INIT(&asoc->control_send_queue);
7908c2654abSrjs TAILQ_INIT(&asoc->send_queue);
7918c2654abSrjs TAILQ_INIT(&asoc->sent_queue);
7928c2654abSrjs TAILQ_INIT(&asoc->reasmqueue);
7938c2654abSrjs TAILQ_INIT(&asoc->delivery_queue);
7948c2654abSrjs asoc->max_inbound_streams = m->sctp_ep.max_open_streams_intome;
7958c2654abSrjs
7968c2654abSrjs TAILQ_INIT(&asoc->asconf_queue);
7978c2654abSrjs return (0);
7988c2654abSrjs }
7998c2654abSrjs
8008c2654abSrjs int
sctp_expand_mapping_array(struct sctp_association * asoc)8018c2654abSrjs sctp_expand_mapping_array(struct sctp_association *asoc)
8028c2654abSrjs {
8038c2654abSrjs /* mapping array needs to grow */
8048c2654abSrjs u_int8_t *new_array;
8056228dc51Schristos uint16_t new_size, old_size;
8068c2654abSrjs
8076228dc51Schristos old_size = asoc->mapping_array_size;
8086228dc51Schristos new_size = old_size + SCTP_MAPPING_ARRAY_INCR;
8098c2654abSrjs new_array = malloc(new_size, M_PCB, M_NOWAIT);
8108c2654abSrjs if (new_array == NULL) {
8118c2654abSrjs /* can't get more, forget it */
8128c2654abSrjs printf("No memory for expansion of SCTP mapping array %d\n",
8138c2654abSrjs new_size);
8148c2654abSrjs return (-1);
8158c2654abSrjs }
8166228dc51Schristos memcpy(new_array, asoc->mapping_array, old_size);
8176228dc51Schristos memset(new_array + old_size, 0, SCTP_MAPPING_ARRAY_INCR);
8188c2654abSrjs free(asoc->mapping_array, M_PCB);
8198c2654abSrjs asoc->mapping_array = new_array;
8208c2654abSrjs asoc->mapping_array_size = new_size;
8218c2654abSrjs return (0);
8228c2654abSrjs }
8238c2654abSrjs
8248c2654abSrjs static void
sctp_timeout_handler(void * t)8258c2654abSrjs sctp_timeout_handler(void *t)
8268c2654abSrjs {
8278c2654abSrjs struct sctp_inpcb *inp;
8288c2654abSrjs struct sctp_tcb *stcb;
8298c2654abSrjs struct sctp_nets *net;
8308c2654abSrjs struct sctp_timer *tmr;
8318c2654abSrjs int did_output;
8328c2654abSrjs
8338c2654abSrjs mutex_enter(softnet_lock);
8348c2654abSrjs tmr = (struct sctp_timer *)t;
8358c2654abSrjs inp = (struct sctp_inpcb *)tmr->ep;
8368c2654abSrjs stcb = (struct sctp_tcb *)tmr->tcb;
8378c2654abSrjs net = (struct sctp_nets *)tmr->net;
8388c2654abSrjs did_output = 1;
8398c2654abSrjs
8408c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
8418c2654abSrjs sctp_audit_log(0xF0, (u_int8_t)tmr->type);
8428c2654abSrjs sctp_auditing(3, inp, stcb, net);
8438c2654abSrjs #endif
8448c2654abSrjs sctp_pegs[SCTP_TIMERS_EXP]++;
8458c2654abSrjs
8468c2654abSrjs if (inp == NULL) {
8478c2654abSrjs return;
8488c2654abSrjs }
8498c2654abSrjs
8508c2654abSrjs SCTP_INP_WLOCK(inp);
8518c2654abSrjs if (inp->sctp_socket == 0) {
8528c2654abSrjs mutex_exit(softnet_lock);
8538c2654abSrjs SCTP_INP_WUNLOCK(inp);
8548c2654abSrjs return;
8558c2654abSrjs }
8568c2654abSrjs if (stcb) {
8578c2654abSrjs if (stcb->asoc.state == 0) {
8588c2654abSrjs mutex_exit(softnet_lock);
8598c2654abSrjs SCTP_INP_WUNLOCK(inp);
8608c2654abSrjs return;
8618c2654abSrjs }
8628c2654abSrjs }
8638c2654abSrjs #ifdef SCTP_DEBUG
8648c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
8658c2654abSrjs printf("Timer type %d goes off\n", tmr->type);
8668c2654abSrjs }
8678c2654abSrjs #endif /* SCTP_DEBUG */
8688c2654abSrjs #ifndef __NetBSD__
8698c2654abSrjs if (!callout_active(&tmr->timer)) {
8708c2654abSrjs SCTP_INP_WUNLOCK(inp);
8718c2654abSrjs return;
8728c2654abSrjs }
8738c2654abSrjs #endif
8748c2654abSrjs if (stcb) {
8758c2654abSrjs SCTP_TCB_LOCK(stcb);
8768c2654abSrjs }
8778c2654abSrjs SCTP_INP_INCR_REF(inp);
8788c2654abSrjs SCTP_INP_WUNLOCK(inp);
8798c2654abSrjs
8808c2654abSrjs switch (tmr->type) {
8818c2654abSrjs case SCTP_TIMER_TYPE_ITERATOR:
8828c2654abSrjs {
8838c2654abSrjs struct sctp_iterator *it;
8848c2654abSrjs it = (struct sctp_iterator *)inp;
8858c2654abSrjs sctp_iterator_timer(it);
8868c2654abSrjs }
8878c2654abSrjs break;
8888c2654abSrjs /* call the handler for the appropriate timer type */
8898c2654abSrjs case SCTP_TIMER_TYPE_SEND:
8908c2654abSrjs sctp_pegs[SCTP_TMIT_TIMER]++;
8918c2654abSrjs stcb->asoc.num_send_timers_up--;
8928c2654abSrjs if (stcb->asoc.num_send_timers_up < 0) {
8938c2654abSrjs stcb->asoc.num_send_timers_up = 0;
8948c2654abSrjs }
8958c2654abSrjs if (sctp_t3rxt_timer(inp, stcb, net)) {
8968c2654abSrjs /* no need to unlock on tcb its gone */
8978c2654abSrjs
8988c2654abSrjs goto out_decr;
8998c2654abSrjs }
9008c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
9018c2654abSrjs sctp_auditing(4, inp, stcb, net);
9028c2654abSrjs #endif
9038c2654abSrjs sctp_chunk_output(inp, stcb, 1);
9048c2654abSrjs if ((stcb->asoc.num_send_timers_up == 0) &&
9058c2654abSrjs (stcb->asoc.sent_queue_cnt > 0)
9068c2654abSrjs ) {
9078c2654abSrjs struct sctp_tmit_chunk *chk;
9088c2654abSrjs /*
9098c2654abSrjs * safeguard. If there on some on the sent queue
9108c2654abSrjs * somewhere but no timers running something is
9118c2654abSrjs * wrong... so we start a timer on the first chunk
9128c2654abSrjs * on the send queue on whatever net it is sent to.
9138c2654abSrjs */
9148c2654abSrjs sctp_pegs[SCTP_T3_SAFEGRD]++;
9158c2654abSrjs chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
9168c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb,
9178c2654abSrjs chk->whoTo);
9188c2654abSrjs }
9198c2654abSrjs break;
9208c2654abSrjs case SCTP_TIMER_TYPE_INIT:
9218c2654abSrjs if (sctp_t1init_timer(inp, stcb, net)) {
9228c2654abSrjs /* no need to unlock on tcb its gone */
9238c2654abSrjs goto out_decr;
9248c2654abSrjs }
9258c2654abSrjs /* We do output but not here */
9268c2654abSrjs did_output = 0;
9278c2654abSrjs break;
9288c2654abSrjs case SCTP_TIMER_TYPE_RECV:
9298c2654abSrjs sctp_pegs[SCTP_RECV_TIMER]++;
9308c2654abSrjs sctp_send_sack(stcb);
9318c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
9328c2654abSrjs sctp_auditing(4, inp, stcb, net);
9338c2654abSrjs #endif
9348c2654abSrjs sctp_chunk_output(inp, stcb, 4);
9358c2654abSrjs break;
9368c2654abSrjs case SCTP_TIMER_TYPE_SHUTDOWN:
9378c2654abSrjs if (sctp_shutdown_timer(inp, stcb, net) ) {
9388c2654abSrjs /* no need to unlock on tcb its gone */
9398c2654abSrjs goto out_decr;
9408c2654abSrjs }
9418c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
9428c2654abSrjs sctp_auditing(4, inp, stcb, net);
9438c2654abSrjs #endif
9448c2654abSrjs sctp_chunk_output(inp, stcb, 5);
9458c2654abSrjs break;
9468c2654abSrjs case SCTP_TIMER_TYPE_HEARTBEAT:
9478c2654abSrjs if (sctp_heartbeat_timer(inp, stcb, net)) {
9488c2654abSrjs /* no need to unlock on tcb its gone */
9498c2654abSrjs goto out_decr;
9508c2654abSrjs }
9518c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
9528c2654abSrjs sctp_auditing(4, inp, stcb, net);
9538c2654abSrjs #endif
9548c2654abSrjs sctp_chunk_output(inp, stcb, 6);
9558c2654abSrjs break;
9568c2654abSrjs case SCTP_TIMER_TYPE_COOKIE:
9578c2654abSrjs if (sctp_cookie_timer(inp, stcb, net)) {
9588c2654abSrjs /* no need to unlock on tcb its gone */
9598c2654abSrjs goto out_decr;
9608c2654abSrjs }
9618c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
9628c2654abSrjs sctp_auditing(4, inp, stcb, net);
9638c2654abSrjs #endif
9648c2654abSrjs sctp_chunk_output(inp, stcb, 1);
9658c2654abSrjs break;
9668c2654abSrjs case SCTP_TIMER_TYPE_NEWCOOKIE:
9678c2654abSrjs {
9688c2654abSrjs struct timeval tv;
9698c2654abSrjs int i, secret;
9708c2654abSrjs SCTP_GETTIME_TIMEVAL(&tv);
9718c2654abSrjs SCTP_INP_WLOCK(inp);
9728c2654abSrjs inp->sctp_ep.time_of_secret_change = tv.tv_sec;
9738c2654abSrjs inp->sctp_ep.last_secret_number =
9748c2654abSrjs inp->sctp_ep.current_secret_number;
9758c2654abSrjs inp->sctp_ep.current_secret_number++;
9768c2654abSrjs if (inp->sctp_ep.current_secret_number >=
9778c2654abSrjs SCTP_HOW_MANY_SECRETS) {
9788c2654abSrjs inp->sctp_ep.current_secret_number = 0;
9798c2654abSrjs }
9808c2654abSrjs secret = (int)inp->sctp_ep.current_secret_number;
9818c2654abSrjs for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) {
9828c2654abSrjs inp->sctp_ep.secret_key[secret][i] =
9838c2654abSrjs sctp_select_initial_TSN(&inp->sctp_ep);
9848c2654abSrjs }
9858c2654abSrjs SCTP_INP_WUNLOCK(inp);
9868c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, stcb, net);
9878c2654abSrjs }
9888c2654abSrjs did_output = 0;
9898c2654abSrjs break;
9908c2654abSrjs case SCTP_TIMER_TYPE_PATHMTURAISE:
9918c2654abSrjs sctp_pathmtu_timer(inp, stcb, net);
9928c2654abSrjs did_output = 0;
9938c2654abSrjs break;
9948c2654abSrjs case SCTP_TIMER_TYPE_SHUTDOWNACK:
9958c2654abSrjs if (sctp_shutdownack_timer(inp, stcb, net)) {
9968c2654abSrjs /* no need to unlock on tcb its gone */
9978c2654abSrjs goto out_decr;
9988c2654abSrjs }
9998c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
10008c2654abSrjs sctp_auditing(4, inp, stcb, net);
10018c2654abSrjs #endif
10028c2654abSrjs sctp_chunk_output(inp, stcb, 7);
10038c2654abSrjs break;
10048c2654abSrjs case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
10058c2654abSrjs sctp_abort_an_association(inp, stcb,
10068c2654abSrjs SCTP_SHUTDOWN_GUARD_EXPIRES, NULL);
10078c2654abSrjs /* no need to unlock on tcb its gone */
10088c2654abSrjs goto out_decr;
10098c2654abSrjs break;
10108c2654abSrjs
10118c2654abSrjs case SCTP_TIMER_TYPE_STRRESET:
10128c2654abSrjs if (sctp_strreset_timer(inp, stcb, net)) {
10138c2654abSrjs /* no need to unlock on tcb its gone */
10148c2654abSrjs goto out_decr;
10158c2654abSrjs }
10168c2654abSrjs sctp_chunk_output(inp, stcb, 9);
10178c2654abSrjs break;
10188c2654abSrjs
10198c2654abSrjs case SCTP_TIMER_TYPE_ASCONF:
10208c2654abSrjs if (sctp_asconf_timer(inp, stcb, net)) {
10218c2654abSrjs /* no need to unlock on tcb its gone */
10228c2654abSrjs goto out_decr;
10238c2654abSrjs }
10248c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
10258c2654abSrjs sctp_auditing(4, inp, stcb, net);
10268c2654abSrjs #endif
10278c2654abSrjs sctp_chunk_output(inp, stcb, 8);
10288c2654abSrjs break;
10298c2654abSrjs
10308c2654abSrjs case SCTP_TIMER_TYPE_AUTOCLOSE:
10318c2654abSrjs sctp_autoclose_timer(inp, stcb, net);
10328c2654abSrjs sctp_chunk_output(inp, stcb, 10);
10338c2654abSrjs did_output = 0;
10348c2654abSrjs break;
10358c2654abSrjs case SCTP_TIMER_TYPE_INPKILL:
10368c2654abSrjs /* special case, take away our
10378c2654abSrjs * increment since WE are the killer
10388c2654abSrjs */
10398c2654abSrjs SCTP_INP_WLOCK(inp);
10408c2654abSrjs SCTP_INP_DECR_REF(inp);
10418c2654abSrjs SCTP_INP_WUNLOCK(inp);
10428c2654abSrjs sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL);
10438c2654abSrjs sctp_inpcb_free(inp, 1);
10448c2654abSrjs goto out_no_decr;
10458c2654abSrjs break;
10468c2654abSrjs default:
10478c2654abSrjs #ifdef SCTP_DEBUG
10488c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
10498c2654abSrjs printf("sctp_timeout_handler:unknown timer %d\n",
10508c2654abSrjs tmr->type);
10518c2654abSrjs }
10528c2654abSrjs #endif /* SCTP_DEBUG */
10538c2654abSrjs break;
10548c2654abSrjs };
10558c2654abSrjs #ifdef SCTP_AUDITING_ENABLED
10568c2654abSrjs sctp_audit_log(0xF1, (u_int8_t)tmr->type);
10578c2654abSrjs sctp_auditing(5, inp, stcb, net);
10588c2654abSrjs #endif
10598c2654abSrjs if (did_output) {
10608c2654abSrjs /*
10618c2654abSrjs * Now we need to clean up the control chunk chain if an
10628c2654abSrjs * ECNE is on it. It must be marked as UNSENT again so next
10638c2654abSrjs * call will continue to send it until such time that we get
10648c2654abSrjs * a CWR, to remove it. It is, however, less likely that we
10658c2654abSrjs * will find a ecn echo on the chain though.
10668c2654abSrjs */
10678c2654abSrjs sctp_fix_ecn_echo(&stcb->asoc);
10688c2654abSrjs }
10698c2654abSrjs if (stcb) {
10708c2654abSrjs SCTP_TCB_UNLOCK(stcb);
10718c2654abSrjs }
10728c2654abSrjs out_decr:
10738c2654abSrjs SCTP_INP_WLOCK(inp);
10748c2654abSrjs SCTP_INP_DECR_REF(inp);
10758c2654abSrjs SCTP_INP_WUNLOCK(inp);
10768c2654abSrjs
10778c2654abSrjs out_no_decr:
10788c2654abSrjs
10798c2654abSrjs mutex_exit(softnet_lock);
10808c2654abSrjs }
10818c2654abSrjs
10828c2654abSrjs int
sctp_timer_start(int t_type,struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)10838c2654abSrjs sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
10848c2654abSrjs struct sctp_nets *net)
10858c2654abSrjs {
10868c2654abSrjs int to_ticks;
10878c2654abSrjs struct sctp_timer *tmr;
10888c2654abSrjs
10898c2654abSrjs if (inp == NULL)
10908c2654abSrjs return (EFAULT);
10918c2654abSrjs
10928c2654abSrjs to_ticks = 0;
10938c2654abSrjs
10948c2654abSrjs tmr = NULL;
10958c2654abSrjs switch (t_type) {
10968c2654abSrjs case SCTP_TIMER_TYPE_ITERATOR:
10978c2654abSrjs {
10988c2654abSrjs struct sctp_iterator *it;
10998c2654abSrjs it = (struct sctp_iterator *)inp;
11008c2654abSrjs tmr = &it->tmr;
11018c2654abSrjs to_ticks = SCTP_ITERATOR_TICKS;
11028c2654abSrjs }
11038c2654abSrjs break;
11048c2654abSrjs case SCTP_TIMER_TYPE_SEND:
11058c2654abSrjs /* Here we use the RTO timer */
11068c2654abSrjs {
11078c2654abSrjs int rto_val;
11088c2654abSrjs if ((stcb == NULL) || (net == NULL)) {
11098c2654abSrjs return (EFAULT);
11108c2654abSrjs }
11118c2654abSrjs tmr = &net->rxt_timer;
11128c2654abSrjs if (net->RTO == 0) {
11138c2654abSrjs rto_val = stcb->asoc.initial_rto;
11148c2654abSrjs } else {
11158c2654abSrjs rto_val = net->RTO;
11168c2654abSrjs }
11178c2654abSrjs to_ticks = MSEC_TO_TICKS(rto_val);
11188c2654abSrjs }
11198c2654abSrjs break;
11208c2654abSrjs case SCTP_TIMER_TYPE_INIT:
11218c2654abSrjs /*
11228c2654abSrjs * Here we use the INIT timer default
11238c2654abSrjs * usually about 1 minute.
11248c2654abSrjs */
11258c2654abSrjs if ((stcb == NULL) || (net == NULL)) {
11268c2654abSrjs return (EFAULT);
11278c2654abSrjs }
11288c2654abSrjs tmr = &net->rxt_timer;
11298c2654abSrjs if (net->RTO == 0) {
11308c2654abSrjs to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
11318c2654abSrjs } else {
11328c2654abSrjs to_ticks = MSEC_TO_TICKS(net->RTO);
11338c2654abSrjs }
11348c2654abSrjs break;
11358c2654abSrjs case SCTP_TIMER_TYPE_RECV:
11368c2654abSrjs /*
11378c2654abSrjs * Here we use the Delayed-Ack timer value from the inp
11388c2654abSrjs * ususually about 200ms.
11398c2654abSrjs */
11408c2654abSrjs if (stcb == NULL) {
11418c2654abSrjs return (EFAULT);
11428c2654abSrjs }
11438c2654abSrjs tmr = &stcb->asoc.dack_timer;
11448c2654abSrjs to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV];
11458c2654abSrjs break;
11468c2654abSrjs case SCTP_TIMER_TYPE_SHUTDOWN:
11478c2654abSrjs /* Here we use the RTO of the destination. */
11488c2654abSrjs if ((stcb == NULL) || (net == NULL)) {
11498c2654abSrjs return (EFAULT);
11508c2654abSrjs }
11518c2654abSrjs
11528c2654abSrjs if (net->RTO == 0) {
11538c2654abSrjs to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
11548c2654abSrjs } else {
11558c2654abSrjs to_ticks = MSEC_TO_TICKS(net->RTO);
11568c2654abSrjs }
11578c2654abSrjs tmr = &net->rxt_timer;
11588c2654abSrjs break;
11598c2654abSrjs case SCTP_TIMER_TYPE_HEARTBEAT:
11608c2654abSrjs /*
11618c2654abSrjs * the net is used here so that we can add in the RTO.
11628c2654abSrjs * Even though we use a different timer. We also add the
11638c2654abSrjs * HB timer PLUS a random jitter.
11648c2654abSrjs */
11658c2654abSrjs if (stcb == NULL) {
11668c2654abSrjs return (EFAULT);
11678c2654abSrjs }
11688c2654abSrjs {
11698c2654abSrjs uint32_t rndval;
11708c2654abSrjs uint8_t this_random;
11718c2654abSrjs int cnt_of_unconf=0;
11728c2654abSrjs struct sctp_nets *lnet;
11738c2654abSrjs
11748c2654abSrjs TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
11758c2654abSrjs if (lnet->dest_state & SCTP_ADDR_UNCONFIRMED) {
11768c2654abSrjs cnt_of_unconf++;
11778c2654abSrjs }
11788c2654abSrjs }
11798c2654abSrjs #ifdef SCTP_DEBUG
11808c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
11818c2654abSrjs printf("HB timer to start unconfirmed:%d hb_delay:%d\n",
11828c2654abSrjs cnt_of_unconf, stcb->asoc.heart_beat_delay);
11838c2654abSrjs }
11848c2654abSrjs #endif
11858c2654abSrjs if (stcb->asoc.hb_random_idx > 3) {
11868c2654abSrjs rndval = sctp_select_initial_TSN(&inp->sctp_ep);
11878c2654abSrjs memcpy(stcb->asoc.hb_random_values, &rndval,
11888c2654abSrjs sizeof(stcb->asoc.hb_random_values));
11898c2654abSrjs this_random = stcb->asoc.hb_random_values[0];
11908c2654abSrjs stcb->asoc.hb_random_idx = 0;
11918c2654abSrjs stcb->asoc.hb_ect_randombit = 0;
11928c2654abSrjs } else {
11938c2654abSrjs this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx];
11948c2654abSrjs stcb->asoc.hb_random_idx++;
11958c2654abSrjs stcb->asoc.hb_ect_randombit = 0;
11968c2654abSrjs }
11978c2654abSrjs /*
11988c2654abSrjs * this_random will be 0 - 256 ms
11998c2654abSrjs * RTO is in ms.
12008c2654abSrjs */
12018c2654abSrjs if ((stcb->asoc.heart_beat_delay == 0) &&
12028c2654abSrjs (cnt_of_unconf == 0)) {
12038c2654abSrjs /* no HB on this inp after confirmations */
12048c2654abSrjs return (0);
12058c2654abSrjs }
12068c2654abSrjs if (net) {
12078c2654abSrjs int delay;
12088c2654abSrjs delay = stcb->asoc.heart_beat_delay;
12098c2654abSrjs TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
12108c2654abSrjs if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) &&
12118c2654abSrjs ((lnet->dest_state & SCTP_ADDR_OUT_OF_SCOPE) == 0) &&
12128c2654abSrjs (lnet->dest_state & SCTP_ADDR_REACHABLE)) {
12138c2654abSrjs delay = 0;
12148c2654abSrjs }
12158c2654abSrjs }
12168c2654abSrjs if (net->RTO == 0) {
12178c2654abSrjs /* Never been checked */
12188c2654abSrjs to_ticks = this_random + stcb->asoc.initial_rto + delay;
12198c2654abSrjs } else {
12208c2654abSrjs /* set rto_val to the ms */
12218c2654abSrjs to_ticks = delay + net->RTO + this_random;
12228c2654abSrjs }
12238c2654abSrjs } else {
12248c2654abSrjs if (cnt_of_unconf) {
12258c2654abSrjs to_ticks = this_random + stcb->asoc.initial_rto;
12268c2654abSrjs } else {
12278c2654abSrjs to_ticks = stcb->asoc.heart_beat_delay + this_random + stcb->asoc.initial_rto;
12288c2654abSrjs }
12298c2654abSrjs }
12308c2654abSrjs /*
12318c2654abSrjs * Now we must convert the to_ticks that are now in
12328c2654abSrjs * ms to ticks.
12338c2654abSrjs */
12348c2654abSrjs to_ticks *= hz;
12358c2654abSrjs to_ticks /= 1000;
12368c2654abSrjs #ifdef SCTP_DEBUG
12378c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
12388c2654abSrjs printf("Timer to expire in %d ticks\n", to_ticks);
12398c2654abSrjs }
12408c2654abSrjs #endif
12418c2654abSrjs tmr = &stcb->asoc.hb_timer;
12428c2654abSrjs }
12438c2654abSrjs break;
12448c2654abSrjs case SCTP_TIMER_TYPE_COOKIE:
12458c2654abSrjs /*
12468c2654abSrjs * Here we can use the RTO timer from the network since
12478c2654abSrjs * one RTT was compelete. If a retran happened then we will
12488c2654abSrjs * be using the RTO initial value.
12498c2654abSrjs */
12508c2654abSrjs if ((stcb == NULL) || (net == NULL)) {
12518c2654abSrjs return (EFAULT);
12528c2654abSrjs }
12538c2654abSrjs if (net->RTO == 0) {
12548c2654abSrjs to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
12558c2654abSrjs } else {
12568c2654abSrjs to_ticks = MSEC_TO_TICKS(net->RTO);
12578c2654abSrjs }
12588c2654abSrjs tmr = &net->rxt_timer;
12598c2654abSrjs break;
12608c2654abSrjs case SCTP_TIMER_TYPE_NEWCOOKIE:
12618c2654abSrjs /*
12628c2654abSrjs * nothing needed but the endpoint here
12638c2654abSrjs * ususually about 60 minutes.
12648c2654abSrjs */
12658c2654abSrjs tmr = &inp->sctp_ep.signature_change;
12668c2654abSrjs to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_SIGNATURE];
12678c2654abSrjs break;
12688c2654abSrjs case SCTP_TIMER_TYPE_INPKILL:
12698c2654abSrjs /*
12708c2654abSrjs * The inp is setup to die. We re-use the
12717991f5a7Sandvar * signature_change timer since that has
12728c2654abSrjs * stopped and we are in the GONE state.
12738c2654abSrjs */
12748c2654abSrjs tmr = &inp->sctp_ep.signature_change;
12758c2654abSrjs to_ticks = (SCTP_INP_KILL_TIMEOUT * hz) / 1000;
12768c2654abSrjs break;
12778c2654abSrjs case SCTP_TIMER_TYPE_PATHMTURAISE:
12788c2654abSrjs /*
12798c2654abSrjs * Here we use the value found in the EP for PMTU
12808c2654abSrjs * ususually about 10 minutes.
12818c2654abSrjs */
12828c2654abSrjs if (stcb == NULL) {
12838c2654abSrjs return (EFAULT);
12848c2654abSrjs }
12858c2654abSrjs if (net == NULL) {
12868c2654abSrjs return (EFAULT);
12878c2654abSrjs }
12888c2654abSrjs to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_PMTU];
12898c2654abSrjs tmr = &net->pmtu_timer;
12908c2654abSrjs break;
12918c2654abSrjs case SCTP_TIMER_TYPE_SHUTDOWNACK:
12928c2654abSrjs /* Here we use the RTO of the destination */
12938c2654abSrjs if ((stcb == NULL) || (net == NULL)) {
12948c2654abSrjs return (EFAULT);
12958c2654abSrjs }
12968c2654abSrjs if (net->RTO == 0) {
12978c2654abSrjs to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
12988c2654abSrjs } else {
12998c2654abSrjs to_ticks = MSEC_TO_TICKS(net->RTO);
13008c2654abSrjs }
13018c2654abSrjs tmr = &net->rxt_timer;
13028c2654abSrjs break;
13038c2654abSrjs case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
13048c2654abSrjs /*
13058c2654abSrjs * Here we use the endpoints shutdown guard timer
13068c2654abSrjs * usually about 3 minutes.
13078c2654abSrjs */
13088c2654abSrjs if (stcb == NULL) {
13098c2654abSrjs return (EFAULT);
13108c2654abSrjs }
13118c2654abSrjs to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN];
13128c2654abSrjs tmr = &stcb->asoc.shut_guard_timer;
13138c2654abSrjs break;
13148c2654abSrjs case SCTP_TIMER_TYPE_STRRESET:
13158c2654abSrjs /*
13168c2654abSrjs * Here the timer comes from the inp
13178c2654abSrjs * but its value is from the RTO.
13188c2654abSrjs */
13198c2654abSrjs if ((stcb == NULL) || (net == NULL)) {
13208c2654abSrjs return (EFAULT);
13218c2654abSrjs }
13228c2654abSrjs if (net->RTO == 0) {
13238c2654abSrjs to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
13248c2654abSrjs } else {
13258c2654abSrjs to_ticks = MSEC_TO_TICKS(net->RTO);
13268c2654abSrjs }
13278c2654abSrjs tmr = &stcb->asoc.strreset_timer;
13288c2654abSrjs break;
13298c2654abSrjs
13308c2654abSrjs case SCTP_TIMER_TYPE_ASCONF:
13318c2654abSrjs /*
13328c2654abSrjs * Here the timer comes from the inp
13338c2654abSrjs * but its value is from the RTO.
13348c2654abSrjs */
13358c2654abSrjs if ((stcb == NULL) || (net == NULL)) {
13368c2654abSrjs return (EFAULT);
13378c2654abSrjs }
13388c2654abSrjs if (net->RTO == 0) {
13398c2654abSrjs to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
13408c2654abSrjs } else {
13418c2654abSrjs to_ticks = MSEC_TO_TICKS(net->RTO);
13428c2654abSrjs }
13438c2654abSrjs tmr = &stcb->asoc.asconf_timer;
13448c2654abSrjs break;
13458c2654abSrjs case SCTP_TIMER_TYPE_AUTOCLOSE:
13468c2654abSrjs if (stcb == NULL) {
13478c2654abSrjs return (EFAULT);
13488c2654abSrjs }
13498c2654abSrjs if (stcb->asoc.sctp_autoclose_ticks == 0) {
13508c2654abSrjs /* Really an error since stcb is NOT set to autoclose */
13518c2654abSrjs return (0);
13528c2654abSrjs }
13538c2654abSrjs to_ticks = stcb->asoc.sctp_autoclose_ticks;
13548c2654abSrjs tmr = &stcb->asoc.autoclose_timer;
13558c2654abSrjs break;
13568c2654abSrjs default:
13578c2654abSrjs #ifdef SCTP_DEBUG
13588c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
13598c2654abSrjs printf("sctp_timer_start:Unknown timer type %d\n",
13608c2654abSrjs t_type);
13618c2654abSrjs }
13628c2654abSrjs #endif /* SCTP_DEBUG */
13638c2654abSrjs return (EFAULT);
13648c2654abSrjs break;
13658c2654abSrjs };
13668c2654abSrjs if ((to_ticks <= 0) || (tmr == NULL)) {
13678c2654abSrjs #ifdef SCTP_DEBUG
13688c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
13698c2654abSrjs printf("sctp_timer_start:%d:software error to_ticks:%d tmr:%p not set ??\n",
13708c2654abSrjs t_type, to_ticks, tmr);
13718c2654abSrjs }
13728c2654abSrjs #endif /* SCTP_DEBUG */
13738c2654abSrjs return (EFAULT);
13748c2654abSrjs }
13758c2654abSrjs if (callout_pending(&tmr->timer)) {
13768c2654abSrjs /*
13778c2654abSrjs * we do NOT allow you to have it already running.
13788c2654abSrjs * if it is we leave the current one up unchanged
13798c2654abSrjs */
13808c2654abSrjs return (EALREADY);
13818c2654abSrjs }
13828c2654abSrjs /* At this point we can proceed */
13838c2654abSrjs if (t_type == SCTP_TIMER_TYPE_SEND) {
13848c2654abSrjs stcb->asoc.num_send_timers_up++;
13858c2654abSrjs }
13868c2654abSrjs tmr->type = t_type;
13878c2654abSrjs tmr->ep = (void *)inp;
13888c2654abSrjs tmr->tcb = (void *)stcb;
13898c2654abSrjs tmr->net = (void *)net;
13908c2654abSrjs callout_reset(&tmr->timer, to_ticks, sctp_timeout_handler, tmr);
13918c2654abSrjs return (0);
13928c2654abSrjs }
13938c2654abSrjs
13948c2654abSrjs int
sctp_timer_stop(int t_type,struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)13958c2654abSrjs sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
13968c2654abSrjs struct sctp_nets *net)
13978c2654abSrjs {
13988c2654abSrjs struct sctp_timer *tmr;
13998c2654abSrjs
14008c2654abSrjs if (inp == NULL)
14018c2654abSrjs return (EFAULT);
14028c2654abSrjs
14038c2654abSrjs tmr = NULL;
14048c2654abSrjs switch (t_type) {
14058c2654abSrjs case SCTP_TIMER_TYPE_ITERATOR:
14068c2654abSrjs {
14078c2654abSrjs struct sctp_iterator *it;
14088c2654abSrjs it = (struct sctp_iterator *)inp;
14098c2654abSrjs tmr = &it->tmr;
14108c2654abSrjs }
14118c2654abSrjs break;
14128c2654abSrjs case SCTP_TIMER_TYPE_SEND:
14138c2654abSrjs if ((stcb == NULL) || (net == NULL)) {
14148c2654abSrjs return (EFAULT);
14158c2654abSrjs }
14168c2654abSrjs tmr = &net->rxt_timer;
14178c2654abSrjs break;
14188c2654abSrjs case SCTP_TIMER_TYPE_INIT:
14198c2654abSrjs if ((stcb == NULL) || (net == NULL)) {
14208c2654abSrjs return (EFAULT);
14218c2654abSrjs }
14228c2654abSrjs tmr = &net->rxt_timer;
14238c2654abSrjs break;
14248c2654abSrjs case SCTP_TIMER_TYPE_RECV:
14258c2654abSrjs if (stcb == NULL) {
14268c2654abSrjs return (EFAULT);
14278c2654abSrjs }
14288c2654abSrjs tmr = &stcb->asoc.dack_timer;
14298c2654abSrjs break;
14308c2654abSrjs case SCTP_TIMER_TYPE_SHUTDOWN:
14318c2654abSrjs if ((stcb == NULL) || (net == NULL)) {
14328c2654abSrjs return (EFAULT);
14338c2654abSrjs }
14348c2654abSrjs tmr = &net->rxt_timer;
14358c2654abSrjs break;
14368c2654abSrjs case SCTP_TIMER_TYPE_HEARTBEAT:
14378c2654abSrjs if (stcb == NULL) {
14388c2654abSrjs return (EFAULT);
14398c2654abSrjs }
14408c2654abSrjs tmr = &stcb->asoc.hb_timer;
14418c2654abSrjs break;
14428c2654abSrjs case SCTP_TIMER_TYPE_COOKIE:
14438c2654abSrjs if ((stcb == NULL) || (net == NULL)) {
14448c2654abSrjs return (EFAULT);
14458c2654abSrjs }
14468c2654abSrjs tmr = &net->rxt_timer;
14478c2654abSrjs break;
14488c2654abSrjs case SCTP_TIMER_TYPE_NEWCOOKIE:
14498c2654abSrjs /* nothing needed but the endpoint here */
14508c2654abSrjs tmr = &inp->sctp_ep.signature_change;
14518c2654abSrjs /* We re-use the newcookie timer for
14528c2654abSrjs * the INP kill timer. We must assure
14538c2654abSrjs * that we do not kill it by accident.
14548c2654abSrjs */
14558c2654abSrjs break;
14568c2654abSrjs case SCTP_TIMER_TYPE_INPKILL:
14578c2654abSrjs /*
14588c2654abSrjs * The inp is setup to die. We re-use the
14597991f5a7Sandvar * signature_change timer since that has
14608c2654abSrjs * stopped and we are in the GONE state.
14618c2654abSrjs */
14628c2654abSrjs tmr = &inp->sctp_ep.signature_change;
14638c2654abSrjs break;
14648c2654abSrjs case SCTP_TIMER_TYPE_PATHMTURAISE:
14658c2654abSrjs if (stcb == NULL) {
14668c2654abSrjs return (EFAULT);
14678c2654abSrjs }
14688c2654abSrjs if (net == NULL) {
14698c2654abSrjs return (EFAULT);
14708c2654abSrjs }
14718c2654abSrjs tmr = &net->pmtu_timer;
14728c2654abSrjs break;
14738c2654abSrjs case SCTP_TIMER_TYPE_SHUTDOWNACK:
14748c2654abSrjs if ((stcb == NULL) || (net == NULL)) {
14758c2654abSrjs return (EFAULT);
14768c2654abSrjs }
14778c2654abSrjs tmr = &net->rxt_timer;
14788c2654abSrjs break;
14798c2654abSrjs case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
14808c2654abSrjs if (stcb == NULL) {
14818c2654abSrjs return (EFAULT);
14828c2654abSrjs }
14838c2654abSrjs tmr = &stcb->asoc.shut_guard_timer;
14848c2654abSrjs break;
14858c2654abSrjs case SCTP_TIMER_TYPE_STRRESET:
14868c2654abSrjs if (stcb == NULL) {
14878c2654abSrjs return (EFAULT);
14888c2654abSrjs }
14898c2654abSrjs tmr = &stcb->asoc.strreset_timer;
14908c2654abSrjs break;
14918c2654abSrjs case SCTP_TIMER_TYPE_ASCONF:
14928c2654abSrjs if (stcb == NULL) {
14938c2654abSrjs return (EFAULT);
14948c2654abSrjs }
14958c2654abSrjs tmr = &stcb->asoc.asconf_timer;
14968c2654abSrjs break;
14978c2654abSrjs case SCTP_TIMER_TYPE_AUTOCLOSE:
14988c2654abSrjs if (stcb == NULL) {
14998c2654abSrjs return (EFAULT);
15008c2654abSrjs }
15018c2654abSrjs tmr = &stcb->asoc.autoclose_timer;
15028c2654abSrjs break;
15038c2654abSrjs default:
15048c2654abSrjs #ifdef SCTP_DEBUG
15058c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
15068c2654abSrjs printf("sctp_timer_stop:Unknown timer type %d\n",
15078c2654abSrjs t_type);
15088c2654abSrjs }
15098c2654abSrjs #endif /* SCTP_DEBUG */
15108c2654abSrjs break;
15118c2654abSrjs };
15128c2654abSrjs if (tmr == NULL)
15138c2654abSrjs return (EFAULT);
15148c2654abSrjs
15158c2654abSrjs if ((tmr->type != t_type) && tmr->type) {
15168c2654abSrjs /*
15178c2654abSrjs * Ok we have a timer that is under joint use. Cookie timer
15188c2654abSrjs * per chance with the SEND timer. We therefore are NOT
15198c2654abSrjs * running the timer that the caller wants stopped. So just
15208c2654abSrjs * return.
15218c2654abSrjs */
15228c2654abSrjs return (0);
15238c2654abSrjs }
15248c2654abSrjs if (t_type == SCTP_TIMER_TYPE_SEND) {
15258c2654abSrjs stcb->asoc.num_send_timers_up--;
15268c2654abSrjs if (stcb->asoc.num_send_timers_up < 0) {
15278c2654abSrjs stcb->asoc.num_send_timers_up = 0;
15288c2654abSrjs }
15298c2654abSrjs }
15308c2654abSrjs callout_stop(&tmr->timer);
15318c2654abSrjs return (0);
15328c2654abSrjs }
15338c2654abSrjs
15348c2654abSrjs u_int32_t
sctp_calculate_len(struct mbuf * m)15358c2654abSrjs sctp_calculate_len(struct mbuf *m)
15368c2654abSrjs {
15378c2654abSrjs u_int32_t tlen=0;
15388c2654abSrjs struct mbuf *at;
15398c2654abSrjs at = m;
15408c2654abSrjs while (at) {
15418c2654abSrjs tlen += at->m_len;
15428c2654abSrjs at = at->m_next;
15438c2654abSrjs }
15448c2654abSrjs return (tlen);
15458c2654abSrjs }
15468c2654abSrjs
15478c2654abSrjs uint32_t
sctp_calculate_sum(struct mbuf * m,int32_t * pktlen,uint32_t offset)15488c2654abSrjs sctp_calculate_sum(struct mbuf *m, int32_t *pktlen, uint32_t offset)
15498c2654abSrjs {
15508c2654abSrjs /*
15518c2654abSrjs * given a mbuf chain with a packetheader offset by 'offset'
15528c2654abSrjs * pointing at a sctphdr (with csum set to 0) go through
15538c2654abSrjs * the chain of m_next's and calculate the SCTP checksum.
155412b0ad45Srjs * This is CRC32c.
155512b0ad45Srjs * Also has a side bonus calculate the total length
15568c2654abSrjs * of the mbuf chain.
15578c2654abSrjs * Note: if offset is greater than the total mbuf length,
15588c2654abSrjs * checksum=1, pktlen=0 is returned (ie. no real error code)
15598c2654abSrjs */
15608c2654abSrjs int32_t tlen=0;
15618c2654abSrjs uint32_t base = 0xffffffff;
15628c2654abSrjs struct mbuf *at;
15638c2654abSrjs at = m;
15648c2654abSrjs /* find the correct mbuf and offset into mbuf */
15658c2654abSrjs while ((at != NULL) && (offset > (uint32_t)at->m_len)) {
15668c2654abSrjs offset -= at->m_len; /* update remaining offset left */
15678c2654abSrjs at = at->m_next;
15688c2654abSrjs }
15698c2654abSrjs
15708c2654abSrjs while (at != NULL) {
15718c2654abSrjs base = update_crc32(base, at->m_data + offset,
15728c2654abSrjs at->m_len - offset);
15738c2654abSrjs tlen += at->m_len - offset;
15748c2654abSrjs /* we only offset once into the first mbuf */
15758c2654abSrjs if (offset) {
15768c2654abSrjs offset = 0;
15778c2654abSrjs }
15788c2654abSrjs at = at->m_next;
15798c2654abSrjs }
15808c2654abSrjs if (pktlen != NULL) {
15818c2654abSrjs *pktlen = tlen;
15828c2654abSrjs }
15838c2654abSrjs /* CRC-32c */
15848c2654abSrjs base = sctp_csum_finalize(base);
15858c2654abSrjs return (base);
15868c2654abSrjs }
15878c2654abSrjs
15888c2654abSrjs void
sctp_mtu_size_reset(struct sctp_inpcb * inp,struct sctp_association * asoc,u_long mtu)15898c2654abSrjs sctp_mtu_size_reset(struct sctp_inpcb *inp,
15908c2654abSrjs struct sctp_association *asoc, u_long mtu)
15918c2654abSrjs {
15928c2654abSrjs /*
15938c2654abSrjs * Reset the P-MTU size on this association, this involves changing
15948c2654abSrjs * the asoc MTU, going through ANY chunk+overhead larger than mtu
15958c2654abSrjs * to allow the DF flag to be cleared.
15968c2654abSrjs */
15978c2654abSrjs struct sctp_tmit_chunk *chk;
15988c2654abSrjs struct sctp_stream_out *strm;
15998c2654abSrjs unsigned int eff_mtu, ovh;
16008c2654abSrjs asoc->smallest_mtu = mtu;
16018c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
16028c2654abSrjs ovh = SCTP_MIN_OVERHEAD;
16038c2654abSrjs } else {
16048c2654abSrjs ovh = SCTP_MIN_V4_OVERHEAD;
16058c2654abSrjs }
16068c2654abSrjs eff_mtu = mtu - ovh;
16078c2654abSrjs /* Now mark any chunks that need to let IP fragment */
16088c2654abSrjs TAILQ_FOREACH(strm, &asoc->out_wheel, next_spoke) {
16098c2654abSrjs TAILQ_FOREACH(chk, &strm->outqueue, sctp_next) {
16108c2654abSrjs if (chk->send_size > eff_mtu) {
16118c2654abSrjs chk->flags &= SCTP_DONT_FRAGMENT;
16128c2654abSrjs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
16138c2654abSrjs }
16148c2654abSrjs }
16158c2654abSrjs }
16168c2654abSrjs TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
16178c2654abSrjs if (chk->send_size > eff_mtu) {
16188c2654abSrjs chk->flags &= SCTP_DONT_FRAGMENT;
16198c2654abSrjs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
16208c2654abSrjs }
16218c2654abSrjs }
16228c2654abSrjs TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
16238c2654abSrjs if (chk->send_size > eff_mtu) {
16248c2654abSrjs chk->flags &= SCTP_DONT_FRAGMENT;
16258c2654abSrjs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
16268c2654abSrjs }
16278c2654abSrjs }
16288c2654abSrjs }
16298c2654abSrjs
16308c2654abSrjs
16318c2654abSrjs /*
16328c2654abSrjs * given an association and starting time of the current RTT period
16338c2654abSrjs * return RTO in number of usecs
16348c2654abSrjs * net should point to the current network
16358c2654abSrjs */
16368c2654abSrjs u_int32_t
sctp_calculate_rto(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_nets * net,struct timeval * old)16378c2654abSrjs sctp_calculate_rto(struct sctp_tcb *stcb,
16388c2654abSrjs struct sctp_association *asoc,
16398c2654abSrjs struct sctp_nets *net,
16408c2654abSrjs struct timeval *old)
16418c2654abSrjs {
16428c2654abSrjs /*
16438c2654abSrjs * given an association and the starting time of the current RTT
16448c2654abSrjs * period (in value1/value2) return RTO in number of usecs.
16458c2654abSrjs */
16468c2654abSrjs int calc_time = 0;
16478c2654abSrjs unsigned int new_rto = 0;
16488c2654abSrjs int first_measure = 0;
16498c2654abSrjs struct timeval now;
16508c2654abSrjs
16518c2654abSrjs /************************/
16528c2654abSrjs /* 1. calculate new RTT */
16538c2654abSrjs /************************/
16548c2654abSrjs /* get the current time */
16558c2654abSrjs SCTP_GETTIME_TIMEVAL(&now);
16568c2654abSrjs /* compute the RTT value */
16578c2654abSrjs if ((u_long)now.tv_sec > (u_long)old->tv_sec) {
16588c2654abSrjs calc_time = ((u_long)now.tv_sec - (u_long)old->tv_sec) * 1000;
16598c2654abSrjs if ((u_long)now.tv_usec > (u_long)old->tv_usec) {
16608c2654abSrjs calc_time += (((u_long)now.tv_usec -
16618c2654abSrjs (u_long)old->tv_usec)/1000);
16628c2654abSrjs } else if ((u_long)now.tv_usec < (u_long)old->tv_usec) {
16638c2654abSrjs /* Borrow 1,000ms from current calculation */
16648c2654abSrjs calc_time -= 1000;
16658c2654abSrjs /* Add in the slop over */
16668c2654abSrjs calc_time += ((int)now.tv_usec/1000);
16678c2654abSrjs /* Add in the pre-second ms's */
16688c2654abSrjs calc_time += (((int)1000000 - (int)old->tv_usec)/1000);
16698c2654abSrjs }
16708c2654abSrjs } else if ((u_long)now.tv_sec == (u_long)old->tv_sec) {
16718c2654abSrjs if ((u_long)now.tv_usec > (u_long)old->tv_usec) {
16728c2654abSrjs calc_time = ((u_long)now.tv_usec -
16738c2654abSrjs (u_long)old->tv_usec)/1000;
16748c2654abSrjs } else if ((u_long)now.tv_usec < (u_long)old->tv_usec) {
16758c2654abSrjs /* impossible .. garbage in nothing out */
16768c2654abSrjs return (((net->lastsa >> 2) + net->lastsv) >> 1);
16778c2654abSrjs } else {
16788c2654abSrjs /* impossible .. garbage in nothing out */
16798c2654abSrjs return (((net->lastsa >> 2) + net->lastsv) >> 1);
16808c2654abSrjs }
16818c2654abSrjs } else {
16828c2654abSrjs /* Clock wrapped? */
16838c2654abSrjs return (((net->lastsa >> 2) + net->lastsv) >> 1);
16848c2654abSrjs }
16858c2654abSrjs /***************************/
16868c2654abSrjs /* 2. update RTTVAR & SRTT */
16878c2654abSrjs /***************************/
16888c2654abSrjs #if 0
16898c2654abSrjs /* if (net->lastsv || net->lastsa) {*/
16908c2654abSrjs /* per Section 5.3.1 C3 in SCTP */
16918c2654abSrjs /* net->lastsv = (int) *//* RTTVAR */
16928c2654abSrjs /* (((double)(1.0 - 0.25) * (double)net->lastsv) +
16938c2654abSrjs (double)(0.25 * (double)abs(net->lastsa - calc_time)));
16948c2654abSrjs net->lastsa = (int) */ /* SRTT */
16958c2654abSrjs /*(((double)(1.0 - 0.125) * (double)net->lastsa) +
16968c2654abSrjs (double)(0.125 * (double)calc_time));
16978c2654abSrjs } else {
16988c2654abSrjs *//* the first RTT calculation, per C2 Section 5.3.1 */
16998c2654abSrjs /* net->lastsa = calc_time; *//* SRTT */
17008c2654abSrjs /* net->lastsv = calc_time / 2; *//* RTTVAR */
17018c2654abSrjs /* }*/
17028c2654abSrjs /* if RTTVAR goes to 0 you set to clock grainularity */
17038c2654abSrjs /* if (net->lastsv == 0) {
17048c2654abSrjs net->lastsv = SCTP_CLOCK_GRANULARITY;
17058c2654abSrjs }
17068c2654abSrjs new_rto = net->lastsa + 4 * net->lastsv;
17078c2654abSrjs */
17088c2654abSrjs #endif
17098c2654abSrjs /* this is Van Jacobson's integer version */
17108c2654abSrjs if (net->RTO) {
17118c2654abSrjs calc_time -= (net->lastsa >> 3);
17128c2654abSrjs net->lastsa += calc_time;
17138c2654abSrjs if (calc_time < 0) {
17148c2654abSrjs calc_time = -calc_time;
17158c2654abSrjs }
17168c2654abSrjs calc_time -= (net->lastsv >> 2);
17178c2654abSrjs net->lastsv += calc_time;
17188c2654abSrjs if (net->lastsv == 0) {
17198c2654abSrjs net->lastsv = SCTP_CLOCK_GRANULARITY;
17208c2654abSrjs }
17218c2654abSrjs } else {
1722213f8d89Smsaitoh /* First RTO measurement */
17238c2654abSrjs net->lastsa = calc_time;
17248c2654abSrjs net->lastsv = calc_time >> 1;
17258c2654abSrjs first_measure = 1;
17268c2654abSrjs }
17278c2654abSrjs new_rto = ((net->lastsa >> 2) + net->lastsv) >> 1;
17288c2654abSrjs if ((new_rto > SCTP_SAT_NETWORK_MIN) &&
17298c2654abSrjs (stcb->asoc.sat_network_lockout == 0)) {
17308c2654abSrjs stcb->asoc.sat_network = 1;
17318c2654abSrjs } else if ((!first_measure) && stcb->asoc.sat_network) {
17328c2654abSrjs stcb->asoc.sat_network = 0;
17338c2654abSrjs stcb->asoc.sat_network_lockout = 1;
17348c2654abSrjs }
17358c2654abSrjs /* bound it, per C6/C7 in Section 5.3.1 */
17368c2654abSrjs if (new_rto < stcb->asoc.minrto) {
17378c2654abSrjs new_rto = stcb->asoc.minrto;
17388c2654abSrjs }
17398c2654abSrjs if (new_rto > stcb->asoc.maxrto) {
17408c2654abSrjs new_rto = stcb->asoc.maxrto;
17418c2654abSrjs }
17428c2654abSrjs /* we are now returning the RTT Smoothed */
17438c2654abSrjs return ((u_int32_t)new_rto);
17448c2654abSrjs }
17458c2654abSrjs
17468c2654abSrjs
17478c2654abSrjs /*
17488c2654abSrjs * return a pointer to a contiguous piece of data from the given
17498c2654abSrjs * mbuf chain starting at 'off' for 'len' bytes. If the desired
17508c2654abSrjs * piece spans more than one mbuf, a copy is made at 'ptr'.
17518c2654abSrjs * caller must ensure that the buffer size is >= 'len'
17528c2654abSrjs * returns NULL if there there isn't 'len' bytes in the chain.
17538c2654abSrjs */
17548c2654abSrjs void *
sctp_m_getptr(struct mbuf * m,int off,int len,u_int8_t * in_ptr)17558c2654abSrjs sctp_m_getptr(struct mbuf *m, int off, int len, u_int8_t *in_ptr)
17568c2654abSrjs {
17578c2654abSrjs uint32_t count;
17588c2654abSrjs uint8_t *ptr;
17598c2654abSrjs ptr = in_ptr;
17608c2654abSrjs if ((off < 0) || (len <= 0))
17618c2654abSrjs return (NULL);
17628c2654abSrjs
17638c2654abSrjs /* find the desired start location */
17648c2654abSrjs while ((m != NULL) && (off > 0)) {
17658c2654abSrjs if (off < m->m_len)
17668c2654abSrjs break;
17678c2654abSrjs off -= m->m_len;
17688c2654abSrjs m = m->m_next;
17698c2654abSrjs }
17708c2654abSrjs if (m == NULL)
17718c2654abSrjs return (NULL);
17728c2654abSrjs
17738c2654abSrjs /* is the current mbuf large enough (eg. contiguous)? */
17748c2654abSrjs if ((m->m_len - off) >= len) {
17758c2654abSrjs return ((void *)(mtod(m, vaddr_t) + off));
17768c2654abSrjs } else {
17778c2654abSrjs /* else, it spans more than one mbuf, so save a temp copy... */
17788c2654abSrjs while ((m != NULL) && (len > 0)) {
1779d1579b2dSriastradh count = uimin(m->m_len - off, len);
17808c2654abSrjs memcpy(ptr, (void *)(mtod(m, vaddr_t) + off), count);
17818c2654abSrjs len -= count;
17828c2654abSrjs ptr += count;
17838c2654abSrjs off = 0;
17848c2654abSrjs m = m->m_next;
17858c2654abSrjs }
17868c2654abSrjs if ((m == NULL) && (len > 0))
17878c2654abSrjs return (NULL);
17888c2654abSrjs else
17898c2654abSrjs return ((void *)in_ptr);
17908c2654abSrjs }
17918c2654abSrjs }
17928c2654abSrjs
17938c2654abSrjs
17948c2654abSrjs struct sctp_paramhdr *
sctp_get_next_param(struct mbuf * m,int offset,struct sctp_paramhdr * pull,int pull_limit)17958c2654abSrjs sctp_get_next_param(struct mbuf *m,
17968c2654abSrjs int offset,
17978c2654abSrjs struct sctp_paramhdr *pull,
17988c2654abSrjs int pull_limit)
17998c2654abSrjs {
18008c2654abSrjs /* This just provides a typed signature to Peter's Pull routine */
18018c2654abSrjs return ((struct sctp_paramhdr *)sctp_m_getptr(m, offset, pull_limit,
18028c2654abSrjs (u_int8_t *)pull));
18038c2654abSrjs }
18048c2654abSrjs
18058c2654abSrjs
18068c2654abSrjs int
sctp_add_pad_tombuf(struct mbuf * m,int padlen)18078c2654abSrjs sctp_add_pad_tombuf(struct mbuf *m, int padlen)
18088c2654abSrjs {
18098c2654abSrjs /*
18108c2654abSrjs * add padlen bytes of 0 filled padding to the end of the mbuf.
18118c2654abSrjs * If padlen is > 3 this routine will fail.
18128c2654abSrjs */
18138c2654abSrjs u_int8_t *dp;
18148c2654abSrjs int i;
18158c2654abSrjs if (padlen > 3) {
18168c2654abSrjs return (ENOBUFS);
18178c2654abSrjs }
18188c2654abSrjs if (M_TRAILINGSPACE(m)) {
18198c2654abSrjs /*
18208c2654abSrjs * The easy way.
18218c2654abSrjs * We hope the majority of the time we hit here :)
18228c2654abSrjs */
18238c2654abSrjs dp = (u_int8_t *)(mtod(m, vaddr_t) + m->m_len);
18248c2654abSrjs m->m_len += padlen;
18258c2654abSrjs } else {
18268c2654abSrjs /* Hard way we must grow the mbuf */
18278c2654abSrjs struct mbuf *tmp;
18288c2654abSrjs MGET(tmp, M_DONTWAIT, MT_DATA);
18298c2654abSrjs if (tmp == NULL) {
18308c2654abSrjs /* Out of space GAK! we are in big trouble. */
18318c2654abSrjs return (ENOSPC);
18328c2654abSrjs }
18338c2654abSrjs /* setup and insert in middle */
18348c2654abSrjs tmp->m_next = m->m_next;
18358c2654abSrjs tmp->m_len = padlen;
18368c2654abSrjs m->m_next = tmp;
18378c2654abSrjs dp = mtod(tmp, u_int8_t *);
18388c2654abSrjs }
18398c2654abSrjs /* zero out the pad */
18408c2654abSrjs for (i= 0; i < padlen; i++) {
18418c2654abSrjs *dp = 0;
18428c2654abSrjs dp++;
18438c2654abSrjs }
18448c2654abSrjs return (0);
18458c2654abSrjs }
18468c2654abSrjs
18478c2654abSrjs int
sctp_pad_lastmbuf(struct mbuf * m,int padval)18488c2654abSrjs sctp_pad_lastmbuf(struct mbuf *m, int padval)
18498c2654abSrjs {
18508c2654abSrjs /* find the last mbuf in chain and pad it */
18518c2654abSrjs struct mbuf *m_at;
18528c2654abSrjs m_at = m;
18538c2654abSrjs while (m_at) {
18548c2654abSrjs if (m_at->m_next == NULL) {
18558c2654abSrjs return (sctp_add_pad_tombuf(m_at, padval));
18568c2654abSrjs }
18578c2654abSrjs m_at = m_at->m_next;
18588c2654abSrjs }
18598c2654abSrjs return (EFAULT);
18608c2654abSrjs }
18618c2654abSrjs
18628c2654abSrjs static void
sctp_notify_assoc_change(u_int32_t event,struct sctp_tcb * stcb,u_int32_t error)18638c2654abSrjs sctp_notify_assoc_change(u_int32_t event, struct sctp_tcb *stcb,
18648c2654abSrjs u_int32_t error)
18658c2654abSrjs {
18668c2654abSrjs struct mbuf *m_notify;
18678c2654abSrjs struct sctp_assoc_change *sac;
18688c2654abSrjs const struct sockaddr *to;
18698c2654abSrjs struct sockaddr_in6 sin6, lsa6;
18708c2654abSrjs
18718c2654abSrjs #ifdef SCTP_DEBUG
18728c2654abSrjs printf("notify: %d\n", event);
18738c2654abSrjs #endif
18748c2654abSrjs /*
187554c9821eSmsaitoh * First if we are going down dump everything we
18768c2654abSrjs * can to the socket rcv queue.
18778c2654abSrjs */
18788c2654abSrjs if ((event == SCTP_SHUTDOWN_COMP) || (event == SCTP_COMM_LOST)) {
18798c2654abSrjs sctp_deliver_data(stcb, &stcb->asoc, NULL, 0);
18808c2654abSrjs }
18818c2654abSrjs
18828c2654abSrjs /*
18838c2654abSrjs * For TCP model AND UDP connected sockets we will send
18848c2654abSrjs * an error up when an ABORT comes in.
18858c2654abSrjs */
18868c2654abSrjs if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
18878c2654abSrjs (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
18888c2654abSrjs (event == SCTP_COMM_LOST)) {
18898c2654abSrjs stcb->sctp_socket->so_error = ECONNRESET;
18908c2654abSrjs /* Wake ANY sleepers */
18918c2654abSrjs sowwakeup(stcb->sctp_socket);
18928c2654abSrjs sorwakeup(stcb->sctp_socket);
18938c2654abSrjs }
18948c2654abSrjs #if 0
18958c2654abSrjs if ((event == SCTP_COMM_UP) &&
18968c2654abSrjs (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
18978c2654abSrjs (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
18988c2654abSrjs soisconnected(stcb->sctp_socket);
18998c2654abSrjs }
19008c2654abSrjs #endif
19018c2654abSrjs if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
19028c2654abSrjs /* event not enabled */
19038c2654abSrjs return;
19048c2654abSrjs }
19058c2654abSrjs MGETHDR(m_notify, M_DONTWAIT, MT_DATA);
19068c2654abSrjs if (m_notify == NULL)
19078c2654abSrjs /* no space left */
19088c2654abSrjs return;
19098c2654abSrjs m_notify->m_len = 0;
19108c2654abSrjs
19118c2654abSrjs sac = mtod(m_notify, struct sctp_assoc_change *);
19128c2654abSrjs sac->sac_type = SCTP_ASSOC_CHANGE;
19138c2654abSrjs sac->sac_flags = 0;
19148c2654abSrjs sac->sac_length = sizeof(struct sctp_assoc_change);
19158c2654abSrjs sac->sac_state = event;
19168c2654abSrjs sac->sac_error = error;
19178c2654abSrjs /* XXX verify these stream counts */
19188c2654abSrjs sac->sac_outbound_streams = stcb->asoc.streamoutcnt;
19198c2654abSrjs sac->sac_inbound_streams = stcb->asoc.streamincnt;
19208c2654abSrjs sac->sac_assoc_id = sctp_get_associd(stcb);
19218c2654abSrjs
19228c2654abSrjs m_notify->m_flags |= M_EOR | M_NOTIFICATION;
19238c2654abSrjs m_notify->m_pkthdr.len = sizeof(struct sctp_assoc_change);
1924d938d837Sozaki-r m_reset_rcvif(m_notify);
19258c2654abSrjs m_notify->m_len = sizeof(struct sctp_assoc_change);
19268c2654abSrjs m_notify->m_next = NULL;
19278c2654abSrjs
19288c2654abSrjs /* append to socket */
19298c2654abSrjs to = rtcache_getdst(&stcb->asoc.primary_destination->ro);
19308c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
19318c2654abSrjs to->sa_family == AF_INET) {
19328c2654abSrjs const struct sockaddr_in *sin;
19338c2654abSrjs
19348c2654abSrjs sin = (const struct sockaddr_in *)to;
19350a0528fdSrtr in6_sin_2_v4mapsin6(sin, &sin6);
19368c2654abSrjs to = (struct sockaddr *)&sin6;
19378c2654abSrjs }
19388c2654abSrjs /* check and strip embedded scope junk */
19398c2654abSrjs to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to,
19408c2654abSrjs &lsa6);
19418c2654abSrjs /*
19428c2654abSrjs * We need to always notify comm changes.
19438c2654abSrjs * if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
19448c2654abSrjs * sctp_m_freem(m_notify);
19458c2654abSrjs * return;
19468c2654abSrjs * }
19478c2654abSrjs */
19488c2654abSrjs SCTP_TCB_UNLOCK(stcb);
19498c2654abSrjs SCTP_INP_WLOCK(stcb->sctp_ep);
19508c2654abSrjs SCTP_TCB_LOCK(stcb);
19518c2654abSrjs if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv,
19528c2654abSrjs to, m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
19538c2654abSrjs /* not enough room */
19548c2654abSrjs sctp_m_freem(m_notify);
19558c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep);
19568c2654abSrjs return;
19578c2654abSrjs }
19588c2654abSrjs if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
19598c2654abSrjs ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
19608c2654abSrjs if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
19618c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
19628c2654abSrjs }
19638c2654abSrjs } else {
19648c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
19658c2654abSrjs }
19668c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep);
19678c2654abSrjs /* Wake up any sleeper */
19688c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
19698c2654abSrjs sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
19708c2654abSrjs }
19718c2654abSrjs
19728c2654abSrjs static void
sctp_notify_peer_addr_change(struct sctp_tcb * stcb,uint32_t state,const struct sockaddr * sa,uint32_t error)19738c2654abSrjs sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
19748c2654abSrjs const struct sockaddr *sa, uint32_t error)
19758c2654abSrjs {
19768c2654abSrjs struct mbuf *m_notify;
19778c2654abSrjs struct sctp_paddr_change *spc;
19788c2654abSrjs const struct sockaddr *to;
19798c2654abSrjs struct sockaddr_in6 sin6, lsa6;
19808c2654abSrjs
19818c2654abSrjs if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVPADDREVNT))
19828c2654abSrjs /* event not enabled */
19838c2654abSrjs return;
19848c2654abSrjs
19858c2654abSrjs MGETHDR(m_notify, M_DONTWAIT, MT_DATA);
19868c2654abSrjs if (m_notify == NULL)
19878c2654abSrjs return;
19888c2654abSrjs m_notify->m_len = 0;
19898c2654abSrjs
19908c2654abSrjs MCLGET(m_notify, M_DONTWAIT);
19918c2654abSrjs if ((m_notify->m_flags & M_EXT) != M_EXT) {
19928c2654abSrjs sctp_m_freem(m_notify);
19938c2654abSrjs return;
19948c2654abSrjs }
19958c2654abSrjs
19968c2654abSrjs spc = mtod(m_notify, struct sctp_paddr_change *);
19978c2654abSrjs spc->spc_type = SCTP_PEER_ADDR_CHANGE;
19988c2654abSrjs spc->spc_flags = 0;
19998c2654abSrjs spc->spc_length = sizeof(struct sctp_paddr_change);
20008c2654abSrjs if (sa->sa_family == AF_INET) {
20018c2654abSrjs memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in));
20028c2654abSrjs } else {
20038c2654abSrjs memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in6));
20048c2654abSrjs }
20058c2654abSrjs spc->spc_state = state;
20068c2654abSrjs spc->spc_error = error;
20078c2654abSrjs spc->spc_assoc_id = sctp_get_associd(stcb);
20088c2654abSrjs
20098c2654abSrjs m_notify->m_flags |= M_EOR | M_NOTIFICATION;
20108c2654abSrjs m_notify->m_pkthdr.len = sizeof(struct sctp_paddr_change);
2011d938d837Sozaki-r m_reset_rcvif(m_notify);
20128c2654abSrjs m_notify->m_len = sizeof(struct sctp_paddr_change);
20138c2654abSrjs m_notify->m_next = NULL;
20148c2654abSrjs
20158c2654abSrjs to = rtcache_getdst(&stcb->asoc.primary_destination->ro);
20168c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
20178c2654abSrjs to->sa_family == AF_INET) {
20188c2654abSrjs const struct sockaddr_in *sin;
20198c2654abSrjs
20208c2654abSrjs sin = (const struct sockaddr_in *)to;
20210a0528fdSrtr in6_sin_2_v4mapsin6(sin, &sin6);
20228c2654abSrjs to = (struct sockaddr *)&sin6;
20238c2654abSrjs }
20248c2654abSrjs /* check and strip embedded scope junk */
20258c2654abSrjs to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to,
20268c2654abSrjs &lsa6);
20278c2654abSrjs
20288c2654abSrjs if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
20298c2654abSrjs sctp_m_freem(m_notify);
20308c2654abSrjs return;
20318c2654abSrjs }
20328c2654abSrjs /* append to socket */
20338c2654abSrjs SCTP_TCB_UNLOCK(stcb);
20348c2654abSrjs SCTP_INP_WLOCK(stcb->sctp_ep);
20358c2654abSrjs SCTP_TCB_LOCK(stcb);
20368c2654abSrjs if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
20378c2654abSrjs m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
20388c2654abSrjs /* not enough room */
20398c2654abSrjs sctp_m_freem(m_notify);
20408c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep);
20418c2654abSrjs return;
20428c2654abSrjs }
20438c2654abSrjs if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
20448c2654abSrjs ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
20458c2654abSrjs if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
20468c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
20478c2654abSrjs }
20488c2654abSrjs } else {
20498c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
20508c2654abSrjs }
20518c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep);
20528c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
20538c2654abSrjs }
20548c2654abSrjs
20558c2654abSrjs
20568c2654abSrjs static void
sctp_notify_send_failed(struct sctp_tcb * stcb,u_int32_t error,struct sctp_tmit_chunk * chk)20578c2654abSrjs sctp_notify_send_failed(struct sctp_tcb *stcb, u_int32_t error,
20588c2654abSrjs struct sctp_tmit_chunk *chk)
20598c2654abSrjs {
20608c2654abSrjs struct mbuf *m_notify;
20618c2654abSrjs struct sctp_send_failed *ssf;
20628c2654abSrjs struct sockaddr_in6 sin6, lsa6;
20638c2654abSrjs const struct sockaddr *to;
20648c2654abSrjs int length;
20658c2654abSrjs
20668c2654abSrjs if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVSENDFAILEVNT))
20678c2654abSrjs /* event not enabled */
20688c2654abSrjs return;
20698c2654abSrjs
20708c2654abSrjs length = sizeof(struct sctp_send_failed) + chk->send_size;
20718c2654abSrjs MGETHDR(m_notify, M_DONTWAIT, MT_DATA);
20728c2654abSrjs if (m_notify == NULL)
20738c2654abSrjs /* no space left */
20748c2654abSrjs return;
20758c2654abSrjs m_notify->m_len = 0;
20768c2654abSrjs ssf = mtod(m_notify, struct sctp_send_failed *);
20778c2654abSrjs ssf->ssf_type = SCTP_SEND_FAILED;
20788c2654abSrjs if (error == SCTP_NOTIFY_DATAGRAM_UNSENT)
20798c2654abSrjs ssf->ssf_flags = SCTP_DATA_UNSENT;
20808c2654abSrjs else
20818c2654abSrjs ssf->ssf_flags = SCTP_DATA_SENT;
20828c2654abSrjs ssf->ssf_length = length;
20838c2654abSrjs ssf->ssf_error = error;
20848c2654abSrjs /* not exactly what the user sent in, but should be close :) */
20858c2654abSrjs ssf->ssf_info.sinfo_stream = chk->rec.data.stream_number;
20868c2654abSrjs ssf->ssf_info.sinfo_ssn = chk->rec.data.stream_seq;
20878c2654abSrjs ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags;
20888c2654abSrjs ssf->ssf_info.sinfo_ppid = chk->rec.data.payloadtype;
20898c2654abSrjs ssf->ssf_info.sinfo_context = chk->rec.data.context;
20908c2654abSrjs ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
20918c2654abSrjs ssf->ssf_assoc_id = sctp_get_associd(stcb);
20928c2654abSrjs m_notify->m_next = chk->data;
20938c2654abSrjs if (m_notify->m_next == NULL)
20948c2654abSrjs m_notify->m_flags |= M_EOR | M_NOTIFICATION;
20958c2654abSrjs else {
20968c2654abSrjs struct mbuf *m;
20978c2654abSrjs m_notify->m_flags |= M_NOTIFICATION;
20988c2654abSrjs m = m_notify;
20998c2654abSrjs while (m->m_next != NULL)
21008c2654abSrjs m = m->m_next;
21018c2654abSrjs m->m_flags |= M_EOR;
21028c2654abSrjs }
21038c2654abSrjs m_notify->m_pkthdr.len = length;
2104d938d837Sozaki-r m_reset_rcvif(m_notify);
21058c2654abSrjs m_notify->m_len = sizeof(struct sctp_send_failed);
21068c2654abSrjs
21078c2654abSrjs /* Steal off the mbuf */
21088c2654abSrjs chk->data = NULL;
21098c2654abSrjs to = rtcache_getdst(&stcb->asoc.primary_destination->ro);
21108c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
21118c2654abSrjs to->sa_family == AF_INET) {
21128c2654abSrjs const struct sockaddr_in *sin;
21138c2654abSrjs
21148c2654abSrjs sin = satocsin(to);
21150a0528fdSrtr in6_sin_2_v4mapsin6(sin, &sin6);
21168c2654abSrjs to = (struct sockaddr *)&sin6;
21178c2654abSrjs }
21188c2654abSrjs /* check and strip embedded scope junk */
21198c2654abSrjs to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to,
21208c2654abSrjs &lsa6);
21218c2654abSrjs
21228c2654abSrjs if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
21238c2654abSrjs sctp_m_freem(m_notify);
21248c2654abSrjs return;
21258c2654abSrjs }
21268c2654abSrjs
21278c2654abSrjs /* append to socket */
21288c2654abSrjs SCTP_TCB_UNLOCK(stcb);
21298c2654abSrjs SCTP_INP_WLOCK(stcb->sctp_ep);
21308c2654abSrjs SCTP_TCB_LOCK(stcb);
21318c2654abSrjs if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
21328c2654abSrjs m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
21338c2654abSrjs /* not enough room */
21348c2654abSrjs sctp_m_freem(m_notify);
21358c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep);
21368c2654abSrjs return;
21378c2654abSrjs }
21388c2654abSrjs if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
21398c2654abSrjs ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
21408c2654abSrjs if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
21418c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
21428c2654abSrjs }
21438c2654abSrjs } else {
21448c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
21458c2654abSrjs }
21468c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep);
21478c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
21488c2654abSrjs }
21498c2654abSrjs
21508c2654abSrjs static void
sctp_notify_adaption_layer(struct sctp_tcb * stcb,u_int32_t error)21518c2654abSrjs sctp_notify_adaption_layer(struct sctp_tcb *stcb,
21528c2654abSrjs u_int32_t error)
21538c2654abSrjs {
21548c2654abSrjs struct mbuf *m_notify;
21558c2654abSrjs struct sctp_adaption_event *sai;
21568c2654abSrjs struct sockaddr_in6 sin6, lsa6;
21578c2654abSrjs const struct sockaddr *to;
21588c2654abSrjs
21598c2654abSrjs if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_ADAPTIONEVNT))
21608c2654abSrjs /* event not enabled */
21618c2654abSrjs return;
21628c2654abSrjs
21638c2654abSrjs MGETHDR(m_notify, M_DONTWAIT, MT_DATA);
21648c2654abSrjs if (m_notify == NULL)
21658c2654abSrjs /* no space left */
21668c2654abSrjs return;
21678c2654abSrjs m_notify->m_len = 0;
21688c2654abSrjs sai = mtod(m_notify, struct sctp_adaption_event *);
21698c2654abSrjs sai->sai_type = SCTP_ADAPTION_INDICATION;
21708c2654abSrjs sai->sai_flags = 0;
21718c2654abSrjs sai->sai_length = sizeof(struct sctp_adaption_event);
21728c2654abSrjs sai->sai_adaption_ind = error;
21738c2654abSrjs sai->sai_assoc_id = sctp_get_associd(stcb);
21748c2654abSrjs
21758c2654abSrjs m_notify->m_flags |= M_EOR | M_NOTIFICATION;
21768c2654abSrjs m_notify->m_pkthdr.len = sizeof(struct sctp_adaption_event);
2177d938d837Sozaki-r m_reset_rcvif(m_notify);
21788c2654abSrjs m_notify->m_len = sizeof(struct sctp_adaption_event);
21798c2654abSrjs m_notify->m_next = NULL;
21808c2654abSrjs
21818c2654abSrjs to = rtcache_getdst(&stcb->asoc.primary_destination->ro);
21828c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
21838c2654abSrjs (to->sa_family == AF_INET)) {
21848c2654abSrjs const struct sockaddr_in *sin;
21858c2654abSrjs
21868c2654abSrjs sin = satocsin(to);
21870a0528fdSrtr in6_sin_2_v4mapsin6(sin, &sin6);
21888c2654abSrjs to = (struct sockaddr *)&sin6;
21898c2654abSrjs }
21908c2654abSrjs /* check and strip embedded scope junk */
21918c2654abSrjs to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to,
21928c2654abSrjs &lsa6);
21938c2654abSrjs if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
21948c2654abSrjs sctp_m_freem(m_notify);
21958c2654abSrjs return;
21968c2654abSrjs }
21978c2654abSrjs /* append to socket */
21988c2654abSrjs SCTP_TCB_UNLOCK(stcb);
21998c2654abSrjs SCTP_INP_WLOCK(stcb->sctp_ep);
22008c2654abSrjs SCTP_TCB_LOCK(stcb);
22018c2654abSrjs if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
22028c2654abSrjs m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
22038c2654abSrjs /* not enough room */
22048c2654abSrjs sctp_m_freem(m_notify);
22058c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep);
22068c2654abSrjs return;
22078c2654abSrjs }
22088c2654abSrjs if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
22098c2654abSrjs ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
22108c2654abSrjs if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
22118c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
22128c2654abSrjs }
22138c2654abSrjs } else {
22148c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
22158c2654abSrjs }
22168c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep);
22178c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
22188c2654abSrjs }
22198c2654abSrjs
22208c2654abSrjs static void
sctp_notify_partial_delivery_indication(struct sctp_tcb * stcb,u_int32_t error)22218c2654abSrjs sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb,
22228c2654abSrjs u_int32_t error)
22238c2654abSrjs {
22248c2654abSrjs struct mbuf *m_notify;
22258c2654abSrjs struct sctp_pdapi_event *pdapi;
22268c2654abSrjs struct sockaddr_in6 sin6, lsa6;
22278c2654abSrjs const struct sockaddr *to;
22288c2654abSrjs
22298c2654abSrjs if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_PDAPIEVNT))
22308c2654abSrjs /* event not enabled */
22318c2654abSrjs return;
22328c2654abSrjs
22338c2654abSrjs MGETHDR(m_notify, M_DONTWAIT, MT_DATA);
22348c2654abSrjs if (m_notify == NULL)
22358c2654abSrjs /* no space left */
22368c2654abSrjs return;
22378c2654abSrjs m_notify->m_len = 0;
22388c2654abSrjs pdapi = mtod(m_notify, struct sctp_pdapi_event *);
22398c2654abSrjs pdapi->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT;
22408c2654abSrjs pdapi->pdapi_flags = 0;
22418c2654abSrjs pdapi->pdapi_length = sizeof(struct sctp_pdapi_event);
22428c2654abSrjs pdapi->pdapi_indication = error;
22438c2654abSrjs pdapi->pdapi_assoc_id = sctp_get_associd(stcb);
22448c2654abSrjs
22458c2654abSrjs m_notify->m_flags |= M_EOR | M_NOTIFICATION;
22468c2654abSrjs m_notify->m_pkthdr.len = sizeof(struct sctp_pdapi_event);
2247d938d837Sozaki-r m_reset_rcvif(m_notify);
22488c2654abSrjs m_notify->m_len = sizeof(struct sctp_pdapi_event);
22498c2654abSrjs m_notify->m_next = NULL;
22508c2654abSrjs
22518c2654abSrjs to = rtcache_getdst(&stcb->asoc.primary_destination->ro);
22528c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
22538c2654abSrjs (to->sa_family == AF_INET)) {
22548c2654abSrjs const struct sockaddr_in *sin;
22558c2654abSrjs
22568c2654abSrjs sin = satocsin(to);
22570a0528fdSrtr in6_sin_2_v4mapsin6(sin, &sin6);
22588c2654abSrjs to = (struct sockaddr *)&sin6;
22598c2654abSrjs }
22608c2654abSrjs /* check and strip embedded scope junk */
22618c2654abSrjs to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to,
22628c2654abSrjs &lsa6);
22638c2654abSrjs if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
22648c2654abSrjs sctp_m_freem(m_notify);
22658c2654abSrjs return;
22668c2654abSrjs }
22678c2654abSrjs /* append to socket */
22688c2654abSrjs SCTP_TCB_UNLOCK(stcb);
22698c2654abSrjs SCTP_INP_WLOCK(stcb->sctp_ep);
22708c2654abSrjs SCTP_TCB_LOCK(stcb);
22718c2654abSrjs if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
22728c2654abSrjs m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
22738c2654abSrjs /* not enough room */
22748c2654abSrjs sctp_m_freem(m_notify);
22758c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep);
22768c2654abSrjs return;
22778c2654abSrjs }
22788c2654abSrjs if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
22798c2654abSrjs ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
22808c2654abSrjs if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
22818c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
22828c2654abSrjs }
22838c2654abSrjs } else {
22848c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
22858c2654abSrjs }
22868c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep);
22878c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
22888c2654abSrjs }
22898c2654abSrjs
22908c2654abSrjs static void
sctp_notify_shutdown_event(struct sctp_tcb * stcb)22918c2654abSrjs sctp_notify_shutdown_event(struct sctp_tcb *stcb)
22928c2654abSrjs {
22938c2654abSrjs struct mbuf *m_notify;
22948c2654abSrjs struct sctp_shutdown_event *sse;
22958c2654abSrjs struct sockaddr_in6 sin6, lsa6;
22968c2654abSrjs const struct sockaddr *to;
22978c2654abSrjs
22988c2654abSrjs /*
22998c2654abSrjs * For TCP model AND UDP connected sockets we will send
23008c2654abSrjs * an error up when an SHUTDOWN completes
23018c2654abSrjs */
23028c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
23038c2654abSrjs (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
23048c2654abSrjs /* mark socket closed for read/write and wakeup! */
23058c2654abSrjs socantrcvmore(stcb->sctp_socket);
23068c2654abSrjs socantsendmore(stcb->sctp_socket);
23078c2654abSrjs }
23088c2654abSrjs
23098c2654abSrjs if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
23108c2654abSrjs /* event not enabled */
23118c2654abSrjs return;
23128c2654abSrjs
23138c2654abSrjs MGETHDR(m_notify, M_DONTWAIT, MT_DATA);
23148c2654abSrjs if (m_notify == NULL)
23158c2654abSrjs /* no space left */
23168c2654abSrjs return;
23178c2654abSrjs m_notify->m_len = 0;
23188c2654abSrjs sse = mtod(m_notify, struct sctp_shutdown_event *);
23198c2654abSrjs sse->sse_type = SCTP_SHUTDOWN_EVENT;
23208c2654abSrjs sse->sse_flags = 0;
23218c2654abSrjs sse->sse_length = sizeof(struct sctp_shutdown_event);
23228c2654abSrjs sse->sse_assoc_id = sctp_get_associd(stcb);
23238c2654abSrjs
23248c2654abSrjs m_notify->m_flags |= M_EOR | M_NOTIFICATION;
23258c2654abSrjs m_notify->m_pkthdr.len = sizeof(struct sctp_shutdown_event);
2326d938d837Sozaki-r m_reset_rcvif(m_notify);
23278c2654abSrjs m_notify->m_len = sizeof(struct sctp_shutdown_event);
23288c2654abSrjs m_notify->m_next = NULL;
23298c2654abSrjs
23308c2654abSrjs to = rtcache_getdst(&stcb->asoc.primary_destination->ro);
23318c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
23328c2654abSrjs to->sa_family == AF_INET) {
23338c2654abSrjs const struct sockaddr_in *sin;
23348c2654abSrjs
23358c2654abSrjs sin = satocsin(to);
23360a0528fdSrtr in6_sin_2_v4mapsin6(sin, &sin6);
23378c2654abSrjs to = (struct sockaddr *)&sin6;
23388c2654abSrjs }
23398c2654abSrjs /* check and strip embedded scope junk */
23408c2654abSrjs to = (const struct sockaddr *)sctp_recover_scope((const struct sockaddr_in6 *)to,
23418c2654abSrjs &lsa6);
23428c2654abSrjs if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
23438c2654abSrjs sctp_m_freem(m_notify);
23448c2654abSrjs return;
23458c2654abSrjs }
23468c2654abSrjs /* append to socket */
23478c2654abSrjs SCTP_TCB_UNLOCK(stcb);
23488c2654abSrjs SCTP_INP_WLOCK(stcb->sctp_ep);
23498c2654abSrjs SCTP_TCB_LOCK(stcb);
23508c2654abSrjs if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
23518c2654abSrjs m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
23528c2654abSrjs /* not enough room */
23538c2654abSrjs sctp_m_freem(m_notify);
23548c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep);
23558c2654abSrjs return;
23568c2654abSrjs }
23578c2654abSrjs if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
23588c2654abSrjs ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
23598c2654abSrjs if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
23608c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
23618c2654abSrjs }
23628c2654abSrjs } else {
23638c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
23648c2654abSrjs }
23658c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep);
23668c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
23678c2654abSrjs }
23688c2654abSrjs
23698c2654abSrjs static void
sctp_notify_stream_reset(struct sctp_tcb * stcb,int number_entries,uint16_t * list,int flag)23708c2654abSrjs sctp_notify_stream_reset(struct sctp_tcb *stcb,
23718c2654abSrjs int number_entries, uint16_t *list, int flag)
23728c2654abSrjs {
23738c2654abSrjs struct mbuf *m_notify;
23748c2654abSrjs struct sctp_stream_reset_event *strreset;
23758c2654abSrjs struct sockaddr_in6 sin6, lsa6;
23768c2654abSrjs const struct sockaddr *to;
23778c2654abSrjs int len;
23788c2654abSrjs
23798c2654abSrjs if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_STREAM_RESETEVNT))
23808c2654abSrjs /* event not enabled */
23818c2654abSrjs return;
23828c2654abSrjs
23838c2654abSrjs MGETHDR(m_notify, M_DONTWAIT, MT_DATA);
23848c2654abSrjs if (m_notify == NULL)
23858c2654abSrjs /* no space left */
23868c2654abSrjs return;
23878c2654abSrjs m_notify->m_len = 0;
23888c2654abSrjs len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t));
23898c2654abSrjs if (len > M_TRAILINGSPACE(m_notify)) {
23908c2654abSrjs MCLGET(m_notify, M_WAIT);
23918c2654abSrjs }
23928c2654abSrjs if (m_notify == NULL)
23938c2654abSrjs /* no clusters */
23948c2654abSrjs return;
23958c2654abSrjs
23968c2654abSrjs if (len > M_TRAILINGSPACE(m_notify)) {
23978c2654abSrjs /* never enough room */
23988c2654abSrjs m_freem(m_notify);
23998c2654abSrjs return;
24008c2654abSrjs }
24018c2654abSrjs strreset = mtod(m_notify, struct sctp_stream_reset_event *);
24028c2654abSrjs strreset->strreset_type = SCTP_STREAM_RESET_EVENT;
24038c2654abSrjs if (number_entries == 0) {
24048c2654abSrjs strreset->strreset_flags = flag | SCTP_STRRESET_ALL_STREAMS;
24058c2654abSrjs } else {
24068c2654abSrjs strreset->strreset_flags = flag | SCTP_STRRESET_STREAM_LIST;
24078c2654abSrjs }
24088c2654abSrjs strreset->strreset_length = len;
24098c2654abSrjs strreset->strreset_assoc_id = sctp_get_associd(stcb);
24108c2654abSrjs if (number_entries) {
24118c2654abSrjs int i;
24128c2654abSrjs for (i=0; i<number_entries; i++) {
24138c2654abSrjs strreset->strreset_list[i] = list[i];
24148c2654abSrjs }
24158c2654abSrjs }
24168c2654abSrjs m_notify->m_flags |= M_EOR | M_NOTIFICATION;
24178c2654abSrjs m_notify->m_pkthdr.len = len;
2418d938d837Sozaki-r m_reset_rcvif(m_notify);
24198c2654abSrjs m_notify->m_len = len;
24208c2654abSrjs m_notify->m_next = NULL;
24218c2654abSrjs if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
24228c2654abSrjs /* no space */
24238c2654abSrjs sctp_m_freem(m_notify);
24248c2654abSrjs return;
24258c2654abSrjs }
24268c2654abSrjs to = rtcache_getdst(&stcb->asoc.primary_destination->ro);
24278c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
24288c2654abSrjs to->sa_family == AF_INET) {
24298c2654abSrjs const struct sockaddr_in *sin;
24308c2654abSrjs
24318c2654abSrjs sin = satocsin(to);
24320a0528fdSrtr in6_sin_2_v4mapsin6(sin, &sin6);
24338c2654abSrjs to = (struct sockaddr *)&sin6;
24348c2654abSrjs }
24358c2654abSrjs /* check and strip embedded scope junk */
24368c2654abSrjs to = (const struct sockaddr *) sctp_recover_scope((const struct sockaddr_in6 *)to,
24378c2654abSrjs &lsa6);
24388c2654abSrjs /* append to socket */
24398c2654abSrjs SCTP_TCB_UNLOCK(stcb);
24408c2654abSrjs SCTP_INP_WLOCK(stcb->sctp_ep);
24418c2654abSrjs SCTP_TCB_LOCK(stcb);
24428c2654abSrjs if (!sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
24438c2654abSrjs m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
24448c2654abSrjs /* not enough room */
24458c2654abSrjs sctp_m_freem(m_notify);
24468c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep);
24478c2654abSrjs return;
24488c2654abSrjs }
24498c2654abSrjs if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
24508c2654abSrjs ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
24518c2654abSrjs if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
24528c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
24538c2654abSrjs }
24548c2654abSrjs } else {
24558c2654abSrjs stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
24568c2654abSrjs }
24578c2654abSrjs SCTP_INP_WUNLOCK(stcb->sctp_ep);
24588c2654abSrjs sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
24598c2654abSrjs }
24608c2654abSrjs
24618c2654abSrjs
24628c2654abSrjs void
sctp_ulp_notify(u_int32_t notification,struct sctp_tcb * stcb,u_int32_t error,void * data)24638c2654abSrjs sctp_ulp_notify(u_int32_t notification, struct sctp_tcb *stcb,
24648c2654abSrjs u_int32_t error, void *data)
24658c2654abSrjs {
24668c2654abSrjs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
24678c2654abSrjs /* No notifications up when we are in a no socket state */
24688c2654abSrjs return;
24698c2654abSrjs }
24708c2654abSrjs if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
24718c2654abSrjs /* Can't send up to a closed socket any notifications */
24728c2654abSrjs return;
24738c2654abSrjs }
24748c2654abSrjs switch (notification) {
24758c2654abSrjs case SCTP_NOTIFY_ASSOC_UP:
24768c2654abSrjs sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error);
24778c2654abSrjs break;
24788c2654abSrjs case SCTP_NOTIFY_ASSOC_DOWN:
24798c2654abSrjs sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error);
24808c2654abSrjs break;
24818c2654abSrjs case SCTP_NOTIFY_INTERFACE_DOWN:
24828c2654abSrjs {
24838c2654abSrjs struct sctp_nets *net;
24848c2654abSrjs net = (struct sctp_nets *)data;
24858c2654abSrjs sctp_notify_peer_addr_change(stcb, SCTP_ADDR_UNREACHABLE,
24868c2654abSrjs rtcache_getdst(&net->ro), error);
24878c2654abSrjs break;
24888c2654abSrjs }
24898c2654abSrjs case SCTP_NOTIFY_INTERFACE_UP:
24908c2654abSrjs {
24918c2654abSrjs struct sctp_nets *net;
24928c2654abSrjs net = (struct sctp_nets *)data;
24938c2654abSrjs sctp_notify_peer_addr_change(stcb, SCTP_ADDR_AVAILABLE,
24948c2654abSrjs rtcache_getdst(&net->ro), error);
24958c2654abSrjs break;
24968c2654abSrjs }
24978c2654abSrjs case SCTP_NOTIFY_INTERFACE_CONFIRMED:
24988c2654abSrjs {
24998c2654abSrjs struct sctp_nets *net;
25008c2654abSrjs net = (struct sctp_nets *)data;
25018c2654abSrjs sctp_notify_peer_addr_change(stcb, SCTP_ADDR_CONFIRMED,
25028c2654abSrjs rtcache_getdst(&net->ro), error);
25038c2654abSrjs break;
25048c2654abSrjs }
25058c2654abSrjs case SCTP_NOTIFY_DG_FAIL:
25068c2654abSrjs sctp_notify_send_failed(stcb, error,
25078c2654abSrjs (struct sctp_tmit_chunk *)data);
25088c2654abSrjs break;
25098c2654abSrjs case SCTP_NOTIFY_ADAPTION_INDICATION:
25108c2654abSrjs /* Here the error is the adaption indication */
25118c2654abSrjs sctp_notify_adaption_layer(stcb, error);
25128c2654abSrjs break;
25138c2654abSrjs case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION:
25148c2654abSrjs sctp_notify_partial_delivery_indication(stcb, error);
25158c2654abSrjs break;
25168c2654abSrjs case SCTP_NOTIFY_STRDATA_ERR:
25178c2654abSrjs break;
25188c2654abSrjs case SCTP_NOTIFY_ASSOC_ABORTED:
25198c2654abSrjs sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error);
25208c2654abSrjs break;
25218c2654abSrjs case SCTP_NOTIFY_PEER_OPENED_STREAM:
25228c2654abSrjs break;
25238c2654abSrjs case SCTP_NOTIFY_STREAM_OPENED_OK:
25248c2654abSrjs break;
25258c2654abSrjs case SCTP_NOTIFY_ASSOC_RESTART:
25268c2654abSrjs sctp_notify_assoc_change(SCTP_RESTART, stcb, error);
25278c2654abSrjs break;
25288c2654abSrjs case SCTP_NOTIFY_HB_RESP:
25298c2654abSrjs break;
25308c2654abSrjs case SCTP_NOTIFY_STR_RESET_SEND:
25318c2654abSrjs sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STRRESET_OUTBOUND_STR);
25328c2654abSrjs break;
25338c2654abSrjs case SCTP_NOTIFY_STR_RESET_RECV:
25348c2654abSrjs sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STRRESET_INBOUND_STR);
25358c2654abSrjs break;
25368c2654abSrjs case SCTP_NOTIFY_ASCONF_ADD_IP:
25378c2654abSrjs sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data,
25388c2654abSrjs error);
25398c2654abSrjs break;
25408c2654abSrjs case SCTP_NOTIFY_ASCONF_DELETE_IP:
25418c2654abSrjs sctp_notify_peer_addr_change(stcb, SCTP_ADDR_REMOVED, data,
25428c2654abSrjs error);
25438c2654abSrjs break;
25448c2654abSrjs case SCTP_NOTIFY_ASCONF_SET_PRIMARY:
25458c2654abSrjs sctp_notify_peer_addr_change(stcb, SCTP_ADDR_MADE_PRIM, data,
25468c2654abSrjs error);
25478c2654abSrjs break;
25488c2654abSrjs case SCTP_NOTIFY_ASCONF_SUCCESS:
25498c2654abSrjs break;
25508c2654abSrjs case SCTP_NOTIFY_ASCONF_FAILED:
25518c2654abSrjs break;
25528c2654abSrjs case SCTP_NOTIFY_PEER_SHUTDOWN:
25538c2654abSrjs sctp_notify_shutdown_event(stcb);
25548c2654abSrjs break;
25558c2654abSrjs default:
25568c2654abSrjs #ifdef SCTP_DEBUG
25578c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_UTIL1) {
25588c2654abSrjs printf("NOTIFY: unknown notification %xh (%u)\n",
25598c2654abSrjs notification, notification);
25608c2654abSrjs }
25618c2654abSrjs #endif /* SCTP_DEBUG */
25628c2654abSrjs break;
25638c2654abSrjs } /* end switch */
25648c2654abSrjs }
25658c2654abSrjs
25668c2654abSrjs void
sctp_report_all_outbound(struct sctp_tcb * stcb)25678c2654abSrjs sctp_report_all_outbound(struct sctp_tcb *stcb)
25688c2654abSrjs {
25698c2654abSrjs struct sctp_association *asoc;
25708c2654abSrjs struct sctp_stream_out *outs;
25718c2654abSrjs struct sctp_tmit_chunk *chk;
25728c2654abSrjs
25738c2654abSrjs asoc = &stcb->asoc;
25748c2654abSrjs
25758c2654abSrjs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
25768c2654abSrjs return;
25778c2654abSrjs }
25788c2654abSrjs /* now through all the gunk freeing chunks */
25798c2654abSrjs TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) {
25808c2654abSrjs /* now clean up any chunks here */
25818c2654abSrjs chk = TAILQ_FIRST(&outs->outqueue);
25828c2654abSrjs while (chk) {
25838c2654abSrjs stcb->asoc.stream_queue_cnt--;
25848c2654abSrjs TAILQ_REMOVE(&outs->outqueue, chk, sctp_next);
25858c2654abSrjs sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
25868c2654abSrjs SCTP_NOTIFY_DATAGRAM_UNSENT, chk);
25878c2654abSrjs sctp_m_freem(chk->data);
25888c2654abSrjs chk->data = NULL;
25898c2654abSrjs if (chk->whoTo)
25908c2654abSrjs sctp_free_remote_addr(chk->whoTo);
25918c2654abSrjs chk->whoTo = NULL;
25928c2654abSrjs chk->asoc = NULL;
25938c2654abSrjs /* Free the chunk */
25948c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
25958c2654abSrjs sctppcbinfo.ipi_count_chunk--;
25968c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) {
25978c2654abSrjs panic("Chunk count is negative");
25988c2654abSrjs }
25998c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++;
26008c2654abSrjs chk = TAILQ_FIRST(&outs->outqueue);
26018c2654abSrjs }
26028c2654abSrjs }
26038c2654abSrjs /* pending send queue SHOULD be empty */
26048c2654abSrjs if (!TAILQ_EMPTY(&asoc->send_queue)) {
26058c2654abSrjs chk = TAILQ_FIRST(&asoc->send_queue);
26068c2654abSrjs while (chk) {
26078c2654abSrjs TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next);
26088c2654abSrjs sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, SCTP_NOTIFY_DATAGRAM_UNSENT, chk);
26098c2654abSrjs sctp_m_freem(chk->data);
26108c2654abSrjs chk->data = NULL;
26118c2654abSrjs if (chk->whoTo)
26128c2654abSrjs sctp_free_remote_addr(chk->whoTo);
26138c2654abSrjs chk->whoTo = NULL;
26148c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
26158c2654abSrjs sctppcbinfo.ipi_count_chunk--;
26168c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) {
26178c2654abSrjs panic("Chunk count is negative");
26188c2654abSrjs }
26198c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++;
26208c2654abSrjs chk = TAILQ_FIRST(&asoc->send_queue);
26218c2654abSrjs }
26228c2654abSrjs }
26238c2654abSrjs /* sent queue SHOULD be empty */
26248c2654abSrjs if (!TAILQ_EMPTY(&asoc->sent_queue)) {
26258c2654abSrjs chk = TAILQ_FIRST(&asoc->sent_queue);
26268c2654abSrjs while (chk) {
26278c2654abSrjs TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
26288c2654abSrjs sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
26298c2654abSrjs SCTP_NOTIFY_DATAGRAM_SENT, chk);
26308c2654abSrjs sctp_m_freem(chk->data);
26318c2654abSrjs chk->data = NULL;
26328c2654abSrjs if (chk->whoTo)
26338c2654abSrjs sctp_free_remote_addr(chk->whoTo);
26348c2654abSrjs chk->whoTo = NULL;
26358c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
26368c2654abSrjs sctppcbinfo.ipi_count_chunk--;
26378c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) {
26388c2654abSrjs panic("Chunk count is negative");
26398c2654abSrjs }
26408c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++;
26418c2654abSrjs chk = TAILQ_FIRST(&asoc->sent_queue);
26428c2654abSrjs }
26438c2654abSrjs }
26448c2654abSrjs }
26458c2654abSrjs
26468c2654abSrjs void
sctp_abort_notification(struct sctp_tcb * stcb,int error)26478c2654abSrjs sctp_abort_notification(struct sctp_tcb *stcb, int error)
26488c2654abSrjs {
26498c2654abSrjs
26508c2654abSrjs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
26518c2654abSrjs return;
26528c2654abSrjs }
26538c2654abSrjs /* Tell them we lost the asoc */
26548c2654abSrjs sctp_report_all_outbound(stcb);
26558c2654abSrjs sctp_ulp_notify(SCTP_NOTIFY_ASSOC_ABORTED, stcb, error, NULL);
26568c2654abSrjs }
26578c2654abSrjs
26588c2654abSrjs void
sctp_abort_association(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct mbuf * m,int iphlen,struct sctphdr * sh,struct mbuf * op_err)26598c2654abSrjs sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
26608c2654abSrjs struct mbuf *m, int iphlen, struct sctphdr *sh, struct mbuf *op_err)
26618c2654abSrjs {
26628c2654abSrjs u_int32_t vtag;
26638c2654abSrjs
26648c2654abSrjs vtag = 0;
26658c2654abSrjs if (stcb != NULL) {
26668c2654abSrjs /* We have a TCB to abort, send notification too */
26678c2654abSrjs vtag = stcb->asoc.peer_vtag;
26688c2654abSrjs sctp_abort_notification(stcb, 0);
26698c2654abSrjs }
26708c2654abSrjs sctp_send_abort(m, iphlen, sh, vtag, op_err);
26718c2654abSrjs if (stcb != NULL) {
26728c2654abSrjs /* Ok, now lets free it */
26738c2654abSrjs sctp_free_assoc(inp, stcb);
26748c2654abSrjs } else {
26758c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
26768c2654abSrjs if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) {
26778c2654abSrjs sctp_inpcb_free(inp, 1);
26788c2654abSrjs }
26798c2654abSrjs }
26808c2654abSrjs }
26818c2654abSrjs }
26828c2654abSrjs
26838c2654abSrjs void
sctp_abort_an_association(struct sctp_inpcb * inp,struct sctp_tcb * stcb,int error,struct mbuf * op_err)26848c2654abSrjs sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
26858c2654abSrjs int error, struct mbuf *op_err)
26868c2654abSrjs {
26878c2654abSrjs
26888c2654abSrjs if (stcb == NULL) {
26898c2654abSrjs /* Got to have a TCB */
26908c2654abSrjs if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
26918c2654abSrjs if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) {
26928c2654abSrjs sctp_inpcb_free(inp, 1);
26938c2654abSrjs }
26948c2654abSrjs }
26958c2654abSrjs return;
26968c2654abSrjs }
26978c2654abSrjs /* notify the ulp */
26988c2654abSrjs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0)
26998c2654abSrjs sctp_abort_notification(stcb, error);
27008c2654abSrjs /* notify the peer */
27018c2654abSrjs sctp_send_abort_tcb(stcb, op_err);
27028c2654abSrjs /* now free the asoc */
27038c2654abSrjs sctp_free_assoc(inp, stcb);
27048c2654abSrjs }
27058c2654abSrjs
27068c2654abSrjs void
sctp_handle_ootb(struct mbuf * m,int iphlen,int offset,struct sctphdr * sh,struct sctp_inpcb * inp,struct mbuf * op_err)27078c2654abSrjs sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
27088c2654abSrjs struct sctp_inpcb *inp, struct mbuf *op_err)
27098c2654abSrjs {
27108c2654abSrjs struct sctp_chunkhdr *ch, chunk_buf;
27118c2654abSrjs unsigned int chk_length;
27128c2654abSrjs
27138c2654abSrjs /* Generate a TO address for future reference */
27148c2654abSrjs if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
27158c2654abSrjs if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) {
27168c2654abSrjs sctp_inpcb_free(inp, 1);
27178c2654abSrjs }
27188c2654abSrjs }
27198c2654abSrjs ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
27208c2654abSrjs sizeof(*ch), (u_int8_t *)&chunk_buf);
27218c2654abSrjs while (ch != NULL) {
27228c2654abSrjs chk_length = ntohs(ch->chunk_length);
27238c2654abSrjs if (chk_length < sizeof(*ch)) {
27248c2654abSrjs /* break to abort land */
27258c2654abSrjs break;
27268c2654abSrjs }
27278c2654abSrjs switch (ch->chunk_type) {
27288c2654abSrjs case SCTP_PACKET_DROPPED:
27298c2654abSrjs /* we don't respond to pkt-dropped */
27308c2654abSrjs return;
27318c2654abSrjs case SCTP_ABORT_ASSOCIATION:
27328c2654abSrjs /* we don't respond with an ABORT to an ABORT */
27338c2654abSrjs return;
27348c2654abSrjs case SCTP_SHUTDOWN_COMPLETE:
27358c2654abSrjs /*
27368c2654abSrjs * we ignore it since we are not waiting for it
27378c2654abSrjs * and peer is gone
27388c2654abSrjs */
27398c2654abSrjs return;
27408c2654abSrjs case SCTP_SHUTDOWN_ACK:
27418c2654abSrjs sctp_send_shutdown_complete2(m, iphlen, sh);
27428c2654abSrjs return;
27438c2654abSrjs default:
27448c2654abSrjs break;
27458c2654abSrjs }
27468c2654abSrjs offset += SCTP_SIZE32(chk_length);
27478c2654abSrjs ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
27488c2654abSrjs sizeof(*ch), (u_int8_t *)&chunk_buf);
27498c2654abSrjs }
27508c2654abSrjs sctp_send_abort(m, iphlen, sh, 0, op_err);
27518c2654abSrjs }
27528c2654abSrjs
27538c2654abSrjs /*
27548c2654abSrjs * check the inbound datagram to make sure there is not an abort
27558c2654abSrjs * inside it, if there is return 1, else return 0.
27568c2654abSrjs */
27578c2654abSrjs int
sctp_is_there_an_abort_here(struct mbuf * m,int iphlen,int * vtagfill)27588c2654abSrjs sctp_is_there_an_abort_here(struct mbuf *m, int iphlen, int *vtagfill)
27598c2654abSrjs {
27608c2654abSrjs struct sctp_chunkhdr *ch;
27618c2654abSrjs struct sctp_init_chunk *init_chk, chunk_buf;
27628c2654abSrjs int offset;
27638c2654abSrjs unsigned int chk_length;
27648c2654abSrjs
27658c2654abSrjs offset = iphlen + sizeof(struct sctphdr);
27668c2654abSrjs ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, sizeof(*ch),
27678c2654abSrjs (u_int8_t *)&chunk_buf);
27688c2654abSrjs while (ch != NULL) {
27698c2654abSrjs chk_length = ntohs(ch->chunk_length);
27708c2654abSrjs if (chk_length < sizeof(*ch)) {
27718c2654abSrjs /* packet is probably corrupt */
27728c2654abSrjs break;
27738c2654abSrjs }
27748c2654abSrjs /* we seem to be ok, is it an abort? */
27758c2654abSrjs if (ch->chunk_type == SCTP_ABORT_ASSOCIATION) {
27768c2654abSrjs /* yep, tell them */
27778c2654abSrjs return (1);
27788c2654abSrjs }
27798c2654abSrjs if (ch->chunk_type == SCTP_INITIATION) {
27808c2654abSrjs /* need to update the Vtag */
27818c2654abSrjs init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m,
27828c2654abSrjs offset, sizeof(*init_chk), (u_int8_t *)&chunk_buf);
27838c2654abSrjs if (init_chk != NULL) {
27848c2654abSrjs *vtagfill = ntohl(init_chk->init.initiate_tag);
27858c2654abSrjs }
27868c2654abSrjs }
27878c2654abSrjs /* Nope, move to the next chunk */
27888c2654abSrjs offset += SCTP_SIZE32(chk_length);
27898c2654abSrjs ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
27908c2654abSrjs sizeof(*ch), (u_int8_t *)&chunk_buf);
27918c2654abSrjs }
27928c2654abSrjs return (0);
27938c2654abSrjs }
27948c2654abSrjs
27958c2654abSrjs /*
27968c2654abSrjs * currently (2/02), ifa_addr embeds scope_id's and don't
27978c2654abSrjs * have sin6_scope_id set (i.e. it's 0)
27988c2654abSrjs * so, create this function to compare link local scopes
27998c2654abSrjs */
28008c2654abSrjs uint32_t
sctp_is_same_scope(const struct sockaddr_in6 * addr1,const struct sockaddr_in6 * addr2)2801afd52931Srjs sctp_is_same_scope(const struct sockaddr_in6 *addr1, const struct sockaddr_in6 *addr2)
28028c2654abSrjs {
28038c2654abSrjs struct sockaddr_in6 a, b;
28048c2654abSrjs
28058c2654abSrjs /* save copies */
28068c2654abSrjs a = *addr1;
28078c2654abSrjs b = *addr2;
28088c2654abSrjs
28098c2654abSrjs if (a.sin6_scope_id == 0)
28108c2654abSrjs if (sa6_recoverscope(&a)) {
28118c2654abSrjs /* can't get scope, so can't match */
28128c2654abSrjs return (0);
28138c2654abSrjs }
28148c2654abSrjs if (b.sin6_scope_id == 0)
28158c2654abSrjs if (sa6_recoverscope(&b)) {
28168c2654abSrjs /* can't get scope, so can't match */
28178c2654abSrjs return (0);
28188c2654abSrjs }
28198c2654abSrjs if (a.sin6_scope_id != b.sin6_scope_id)
28208c2654abSrjs return (0);
28218c2654abSrjs
28228c2654abSrjs return (1);
28238c2654abSrjs }
28248c2654abSrjs
28258c2654abSrjs /*
28268c2654abSrjs * returns a sockaddr_in6 with embedded scope recovered and removed
28278c2654abSrjs */
28288c2654abSrjs const struct sockaddr_in6 *
sctp_recover_scope(const struct sockaddr_in6 * addr,struct sockaddr_in6 * store)28298c2654abSrjs sctp_recover_scope(const struct sockaddr_in6 *addr, struct sockaddr_in6 *store)
28308c2654abSrjs {
28318c2654abSrjs const struct sockaddr_in6 *newaddr;
28328c2654abSrjs
28338c2654abSrjs newaddr = addr;
28348c2654abSrjs /* check and strip embedded scope junk */
28358c2654abSrjs if (addr->sin6_family == AF_INET6) {
28368c2654abSrjs if (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr)) {
28378c2654abSrjs if (addr->sin6_scope_id == 0) {
28388c2654abSrjs *store = *addr;
28398c2654abSrjs if (sa6_recoverscope(store) == 0) {
28408c2654abSrjs /* use the recovered scope */
28418c2654abSrjs newaddr = store;
28428c2654abSrjs }
28438c2654abSrjs /* else, return the original "to" addr */
28448c2654abSrjs }
28458c2654abSrjs }
28468c2654abSrjs }
28478c2654abSrjs return (newaddr);
28488c2654abSrjs }
28498c2654abSrjs
28508c2654abSrjs /*
28518c2654abSrjs * are the two addresses the same? currently a "scopeless" check
28528c2654abSrjs * returns: 1 if same, 0 if not
28538c2654abSrjs */
28548c2654abSrjs int
sctp_cmpaddr(const struct sockaddr * sa1,const struct sockaddr * sa2)28558c2654abSrjs sctp_cmpaddr(const struct sockaddr *sa1, const struct sockaddr *sa2)
28568c2654abSrjs {
28578c2654abSrjs
28588c2654abSrjs /* must be valid */
28598c2654abSrjs if (sa1 == NULL || sa2 == NULL)
28608c2654abSrjs return (0);
28618c2654abSrjs
28628c2654abSrjs /* must be the same family */
28638c2654abSrjs if (sa1->sa_family != sa2->sa_family)
28648c2654abSrjs return (0);
28658c2654abSrjs
28668c2654abSrjs if (sa1->sa_family == AF_INET6) {
28678c2654abSrjs /* IPv6 addresses */
28688c2654abSrjs const struct sockaddr_in6 *sin6_1, *sin6_2;
28698c2654abSrjs
28708c2654abSrjs sin6_1 = (const struct sockaddr_in6 *)sa1;
28718c2654abSrjs sin6_2 = (const struct sockaddr_in6 *)sa2;
28728c2654abSrjs return (SCTP6_ARE_ADDR_EQUAL(&sin6_1->sin6_addr,
28738c2654abSrjs &sin6_2->sin6_addr));
28748c2654abSrjs } else if (sa1->sa_family == AF_INET) {
28758c2654abSrjs /* IPv4 addresses */
28768c2654abSrjs const struct sockaddr_in *sin_1, *sin_2;
28778c2654abSrjs
28788c2654abSrjs sin_1 = (const struct sockaddr_in *)sa1;
28798c2654abSrjs sin_2 = (const struct sockaddr_in *)sa2;
28808c2654abSrjs return (sin_1->sin_addr.s_addr == sin_2->sin_addr.s_addr);
28818c2654abSrjs } else {
28828c2654abSrjs /* we don't do these... */
28838c2654abSrjs return (0);
28848c2654abSrjs }
28858c2654abSrjs }
28868c2654abSrjs
28878c2654abSrjs void
sctp_print_address(const struct sockaddr * sa)28888c2654abSrjs sctp_print_address(const struct sockaddr *sa)
28898c2654abSrjs {
289028f4c24cSryo char ip6buf[INET6_ADDRSTRLEN];
28918c2654abSrjs
28928c2654abSrjs if (sa->sa_family == AF_INET6) {
28938c2654abSrjs const struct sockaddr_in6 *sin6;
28948c2654abSrjs sin6 = (const struct sockaddr_in6 *)sa;
28958c2654abSrjs printf("IPv6 address: %s:%d scope:%u\n",
289635561f6bSchristos IN6_PRINT(ip6buf, &sin6->sin6_addr), ntohs(sin6->sin6_port),
28978c2654abSrjs sin6->sin6_scope_id);
28988c2654abSrjs } else if (sa->sa_family == AF_INET) {
28998c2654abSrjs const struct sockaddr_in *sin;
29008c2654abSrjs sin = (const struct sockaddr_in *)sa;
29018c2654abSrjs printf("IPv4 address: %s:%d\n", inet_ntoa(sin->sin_addr),
29028c2654abSrjs ntohs(sin->sin_port));
29038c2654abSrjs } else {
29048c2654abSrjs printf("?\n");
29058c2654abSrjs }
29068c2654abSrjs }
29078c2654abSrjs
29088c2654abSrjs void
sctp_print_address_pkt(struct ip * iph,struct sctphdr * sh)29098c2654abSrjs sctp_print_address_pkt(struct ip *iph, struct sctphdr *sh)
29108c2654abSrjs {
29118c2654abSrjs if (iph->ip_v == IPVERSION) {
29128c2654abSrjs struct sockaddr_in lsa, fsa;
29138c2654abSrjs
29148c2654abSrjs memset(&lsa, 0, sizeof(lsa));
29158c2654abSrjs lsa.sin_len = sizeof(lsa);
29168c2654abSrjs lsa.sin_family = AF_INET;
29178c2654abSrjs lsa.sin_addr = iph->ip_src;
29188c2654abSrjs lsa.sin_port = sh->src_port;
29198c2654abSrjs memset(&fsa, 0, sizeof(fsa));
29208c2654abSrjs fsa.sin_len = sizeof(fsa);
29218c2654abSrjs fsa.sin_family = AF_INET;
29228c2654abSrjs fsa.sin_addr = iph->ip_dst;
29238c2654abSrjs fsa.sin_port = sh->dest_port;
29248c2654abSrjs printf("src: ");
29258c2654abSrjs sctp_print_address((struct sockaddr *)&lsa);
29268c2654abSrjs printf("dest: ");
29278c2654abSrjs sctp_print_address((struct sockaddr *)&fsa);
29288c2654abSrjs } else if (iph->ip_v == (IPV6_VERSION >> 4)) {
29298c2654abSrjs struct ip6_hdr *ip6;
29308c2654abSrjs struct sockaddr_in6 lsa6, fsa6;
29318c2654abSrjs
29328c2654abSrjs ip6 = (struct ip6_hdr *)iph;
29338c2654abSrjs memset(&lsa6, 0, sizeof(lsa6));
29348c2654abSrjs lsa6.sin6_len = sizeof(lsa6);
29358c2654abSrjs lsa6.sin6_family = AF_INET6;
29368c2654abSrjs lsa6.sin6_addr = ip6->ip6_src;
29378c2654abSrjs lsa6.sin6_port = sh->src_port;
29388c2654abSrjs memset(&fsa6, 0, sizeof(fsa6));
29398c2654abSrjs fsa6.sin6_len = sizeof(fsa6);
29408c2654abSrjs fsa6.sin6_family = AF_INET6;
29418c2654abSrjs fsa6.sin6_addr = ip6->ip6_dst;
29428c2654abSrjs fsa6.sin6_port = sh->dest_port;
29438c2654abSrjs printf("src: ");
29448c2654abSrjs sctp_print_address((struct sockaddr *)&lsa6);
29458c2654abSrjs printf("dest: ");
29468c2654abSrjs sctp_print_address((struct sockaddr *)&fsa6);
29478c2654abSrjs }
29488c2654abSrjs }
29498c2654abSrjs
29508c2654abSrjs #if defined(__FreeBSD__) || defined(__APPLE__)
29518c2654abSrjs
29528c2654abSrjs /* cloned from uipc_socket.c */
29538c2654abSrjs
29548c2654abSrjs #define SCTP_SBLINKRECORD(sb, m0) do { \
29558c2654abSrjs if ((sb)->sb_lastrecord != NULL) \
29568c2654abSrjs (sb)->sb_lastrecord->m_nextpkt = (m0); \
29578c2654abSrjs else \
29588c2654abSrjs (sb)->sb_mb = (m0); \
29598c2654abSrjs (sb)->sb_lastrecord = (m0); \
29608c2654abSrjs } while (/*CONSTCOND*/0)
29618c2654abSrjs #endif
29628c2654abSrjs
29638c2654abSrjs
29648c2654abSrjs int
sbappendaddr_nocheck(struct sockbuf * sb,const struct sockaddr * asa,struct mbuf * m0,struct mbuf * control,u_int32_t tag,struct sctp_inpcb * inp)29658c2654abSrjs sbappendaddr_nocheck(struct sockbuf *sb, const struct sockaddr *asa,
29668c2654abSrjs struct mbuf *m0, struct mbuf *control,
29678c2654abSrjs u_int32_t tag, struct sctp_inpcb *inp)
29688c2654abSrjs {
29698c2654abSrjs #ifdef __NetBSD__
29708c2654abSrjs struct mbuf *m, *n;
29718c2654abSrjs
29728c2654abSrjs if (m0 && (m0->m_flags & M_PKTHDR) == 0)
29738c2654abSrjs panic("sbappendaddr_nocheck");
29748c2654abSrjs
29758c2654abSrjs m0->m_pkthdr.csum_data = (int)tag;
29768c2654abSrjs
29778c2654abSrjs for (n = control; n; n = n->m_next) {
29788c2654abSrjs if (n->m_next == 0) /* keep pointer to last control buf */
29798c2654abSrjs break;
29808c2654abSrjs }
29818c2654abSrjs if (((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) ||
29828c2654abSrjs ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)== 0)) {
29838c2654abSrjs MGETHDR(m, M_DONTWAIT, MT_SONAME);
29848c2654abSrjs if (m == 0)
29858c2654abSrjs return (0);
29868c2654abSrjs
29878c2654abSrjs m->m_len = asa->sa_len;
29888c2654abSrjs memcpy(mtod(m, void *), (const void *)asa, asa->sa_len);
29898c2654abSrjs } else {
29908c2654abSrjs m = NULL;
29918c2654abSrjs }
29928c2654abSrjs if (n) {
29938c2654abSrjs n->m_next = m0; /* concatenate data to control */
29948c2654abSrjs }else {
29958c2654abSrjs control = m0;
29968c2654abSrjs }
29978c2654abSrjs if (m)
29988c2654abSrjs m->m_next = control;
29998c2654abSrjs else
30008c2654abSrjs m = control;
30018c2654abSrjs m->m_pkthdr.csum_data = tag;
30028c2654abSrjs
30038c2654abSrjs for (n = m; n; n = n->m_next)
30048c2654abSrjs sballoc(sb, n);
30058c2654abSrjs if ((n = sb->sb_mb) != NULL) {
30068c2654abSrjs if ((n->m_nextpkt != inp->sb_last_mpkt) && (n->m_nextpkt == NULL)) {
30078c2654abSrjs inp->sb_last_mpkt = NULL;
30088c2654abSrjs }
30098c2654abSrjs if (inp->sb_last_mpkt)
30108c2654abSrjs inp->sb_last_mpkt->m_nextpkt = m;
30118c2654abSrjs else {
30128c2654abSrjs while (n->m_nextpkt) {
30138c2654abSrjs n = n->m_nextpkt;
30148c2654abSrjs }
30158c2654abSrjs n->m_nextpkt = m;
30168c2654abSrjs }
30178c2654abSrjs inp->sb_last_mpkt = m;
30188c2654abSrjs } else {
30198c2654abSrjs inp->sb_last_mpkt = sb->sb_mb = m;
30208c2654abSrjs inp->sctp_vtag_first = tag;
30218c2654abSrjs }
30228c2654abSrjs return (1);
30238c2654abSrjs #endif
30248c2654abSrjs #if defined(__FreeBSD__) || defined(__APPLE__)
30258c2654abSrjs struct mbuf *m, *n, *nlast;
30268c2654abSrjs int cnt=0;
30278c2654abSrjs
30288c2654abSrjs if (m0 && (m0->m_flags & M_PKTHDR) == 0)
30298c2654abSrjs panic("sbappendaddr_nocheck");
30308c2654abSrjs
30318c2654abSrjs for (n = control; n; n = n->m_next) {
30328c2654abSrjs if (n->m_next == 0) /* get pointer to last control buf */
30338c2654abSrjs break;
30348c2654abSrjs }
30358c2654abSrjs if (((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) ||
30368c2654abSrjs ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)== 0)) {
30378c2654abSrjs if (asa->sa_len > MHLEN)
30388c2654abSrjs return (0);
30398c2654abSrjs try_again:
30408c2654abSrjs MGETHDR(m, M_DONTWAIT, MT_SONAME);
30418c2654abSrjs if (m == 0)
30428c2654abSrjs return (0);
30438c2654abSrjs m->m_len = 0;
30448c2654abSrjs /* safety */
30458c2654abSrjs if (m == m0) {
30468c2654abSrjs printf("Duplicate mbuf allocated %p in and mget returned %p?\n",
30478c2654abSrjs m0, m);
30488c2654abSrjs if (cnt) {
30498c2654abSrjs panic("more than once");
30508c2654abSrjs }
30518c2654abSrjs cnt++;
30528c2654abSrjs goto try_again;
30538c2654abSrjs }
30548c2654abSrjs m->m_len = asa->sa_len;
30558c2654abSrjs bcopy((void *)asa, mtod(m, void *), asa->sa_len);
30568c2654abSrjs }
30578c2654abSrjs else {
30588c2654abSrjs m = NULL;
30598c2654abSrjs }
30608c2654abSrjs if (n)
30618c2654abSrjs n->m_next = m0; /* concatenate data to control */
30628c2654abSrjs else
30638c2654abSrjs control = m0;
30648c2654abSrjs if (m)
30658c2654abSrjs m->m_next = control;
30668c2654abSrjs else
30678c2654abSrjs m = control;
30688c2654abSrjs m->m_pkthdr.csum_data = (int)tag;
30698c2654abSrjs
30708c2654abSrjs for (n = m; n; n = n->m_next)
30718c2654abSrjs sballoc(sb, n);
30728c2654abSrjs nlast = n;
30738c2654abSrjs if (sb->sb_mb == NULL) {
30748c2654abSrjs inp->sctp_vtag_first = tag;
30758c2654abSrjs }
30768c2654abSrjs
30778c2654abSrjs #ifdef __FREEBSD__
30788c2654abSrjs if (sb->sb_mb == NULL)
30798c2654abSrjs inp->sctp_vtag_first = tag;
30808c2654abSrjs SCTP_SBLINKRECORD(sb, m);
30818c2654abSrjs sb->sb_mbtail = nlast;
30828c2654abSrjs #else
30838c2654abSrjs if ((n = sb->sb_mb) != NULL) {
30848c2654abSrjs if ((n->m_nextpkt != inp->sb_last_mpkt) && (n->m_nextpkt == NULL)) {
30858c2654abSrjs inp->sb_last_mpkt = NULL;
30868c2654abSrjs }
30878c2654abSrjs if (inp->sb_last_mpkt)
30888c2654abSrjs inp->sb_last_mpkt->m_nextpkt = m;
30898c2654abSrjs else {
30908c2654abSrjs while (n->m_nextpkt) {
30918c2654abSrjs n = n->m_nextpkt;
30928c2654abSrjs }
30938c2654abSrjs n->m_nextpkt = m;
30948c2654abSrjs }
30958c2654abSrjs inp->sb_last_mpkt = m;
30968c2654abSrjs } else {
30978c2654abSrjs inp->sb_last_mpkt = sb->sb_mb = m;
30988c2654abSrjs inp->sctp_vtag_first = tag;
30998c2654abSrjs }
31008c2654abSrjs #endif
31018c2654abSrjs return (1);
31028c2654abSrjs #endif
31038c2654abSrjs #ifdef __OpenBSD__
31048c2654abSrjs struct mbuf *m, *n;
31058c2654abSrjs
31068c2654abSrjs if (m0 && (m0->m_flags & M_PKTHDR) == 0)
31078c2654abSrjs panic("sbappendaddr_nocheck");
31088c2654abSrjs m0->m_pkthdr.csum = (int)tag;
31098c2654abSrjs for (n = control; n; n = n->m_next) {
31108c2654abSrjs if (n->m_next == 0) /* keep pointer to last control buf */
31118c2654abSrjs break;
31128c2654abSrjs }
31138c2654abSrjs if (((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) ||
31148c2654abSrjs ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)== 0)) {
31158c2654abSrjs if (asa->sa_len > MHLEN)
31168c2654abSrjs return (0);
31178c2654abSrjs MGETHDR(m, M_DONTWAIT, MT_SONAME);
31188c2654abSrjs if (m == 0)
31198c2654abSrjs return (0);
31208c2654abSrjs m->m_len = asa->sa_len;
31218c2654abSrjs bcopy((void *)asa, mtod(m, void *), asa->sa_len);
31228c2654abSrjs } else {
31238c2654abSrjs m = NULL;
31248c2654abSrjs }
31258c2654abSrjs if (n)
31268c2654abSrjs n->m_next = m0; /* concatenate data to control */
31278c2654abSrjs else
31288c2654abSrjs control = m0;
31298c2654abSrjs
31308c2654abSrjs m->m_pkthdr.csum = (int)tag;
31318c2654abSrjs m->m_next = control;
31328c2654abSrjs for (n = m; n; n = n->m_next)
31338c2654abSrjs sballoc(sb, n);
31348c2654abSrjs if ((n = sb->sb_mb) != NULL) {
31358c2654abSrjs if ((n->m_nextpkt != inp->sb_last_mpkt) && (n->m_nextpkt == NULL)) {
31368c2654abSrjs inp->sb_last_mpkt = NULL;
31378c2654abSrjs }
31388c2654abSrjs if (inp->sb_last_mpkt)
31398c2654abSrjs inp->sb_last_mpkt->m_nextpkt = m;
31408c2654abSrjs else {
31418c2654abSrjs while (n->m_nextpkt) {
31428c2654abSrjs n = n->m_nextpkt;
31438c2654abSrjs }
31448c2654abSrjs n->m_nextpkt = m;
31458c2654abSrjs }
31468c2654abSrjs inp->sb_last_mpkt = m;
31478c2654abSrjs } else {
31488c2654abSrjs inp->sb_last_mpkt = sb->sb_mb = m;
31498c2654abSrjs inp->sctp_vtag_first = tag;
31508c2654abSrjs }
31518c2654abSrjs return (1);
31528c2654abSrjs #endif
31538c2654abSrjs }
31548c2654abSrjs
31558c2654abSrjs /*************HOLD THIS COMMENT FOR PATCH FILE OF
31568c2654abSrjs *************ALTERNATE ROUTING CODE
31578c2654abSrjs */
31588c2654abSrjs
31598c2654abSrjs /*************HOLD THIS COMMENT FOR END OF PATCH FILE OF
31608c2654abSrjs *************ALTERNATE ROUTING CODE
31618c2654abSrjs */
31628c2654abSrjs
31638c2654abSrjs struct mbuf *
sctp_generate_invmanparam(int err)31648c2654abSrjs sctp_generate_invmanparam(int err)
31658c2654abSrjs {
31668c2654abSrjs /* Return a MBUF with a invalid mandatory parameter */
31678c2654abSrjs struct mbuf *m;
31688c2654abSrjs
31698c2654abSrjs MGET(m, M_DONTWAIT, MT_DATA);
31708c2654abSrjs if (m) {
31718c2654abSrjs struct sctp_paramhdr *ph;
31728c2654abSrjs m->m_len = sizeof(struct sctp_paramhdr);
31738c2654abSrjs ph = mtod(m, struct sctp_paramhdr *);
31748c2654abSrjs ph->param_length = htons(sizeof(struct sctp_paramhdr));
31758c2654abSrjs ph->param_type = htons(err);
31768c2654abSrjs }
31778c2654abSrjs return (m);
31788c2654abSrjs }
31798c2654abSrjs
31808c2654abSrjs static int
sctp_should_be_moved(struct mbuf * this,struct sctp_association * asoc)31818c2654abSrjs sctp_should_be_moved(struct mbuf *this, struct sctp_association *asoc)
31828c2654abSrjs {
31838c2654abSrjs struct mbuf *m;
31848c2654abSrjs /*
31858c2654abSrjs * given a mbuf chain, look through it finding
31868c2654abSrjs * the M_PKTHDR and return 1 if it belongs to
31878c2654abSrjs * the association given. We tell this by
31888c2654abSrjs * a kludge where we stuff the my_vtag of the asoc
31898c2654abSrjs * into the m->m_pkthdr.csum_data/csum field.
31908c2654abSrjs */
31918c2654abSrjs m = this;
31928c2654abSrjs while (m) {
31938c2654abSrjs if (m->m_flags & M_PKTHDR) {
31948c2654abSrjs /* check it */
31958c2654abSrjs #if defined(__OpenBSD__)
31968c2654abSrjs if ((u_int32_t)m->m_pkthdr.csum == asoc->my_vtag)
31978c2654abSrjs #else
31988c2654abSrjs if ((u_int32_t)m->m_pkthdr.csum_data == asoc->my_vtag)
31998c2654abSrjs #endif
32008c2654abSrjs {
32018c2654abSrjs /* Yep */
32028c2654abSrjs return (1);
32038c2654abSrjs }
32048c2654abSrjs }
32058c2654abSrjs m = m->m_next;
32068c2654abSrjs }
32078c2654abSrjs return (0);
32088c2654abSrjs }
32098c2654abSrjs
32108c2654abSrjs u_int32_t
sctp_get_first_vtag_from_sb(struct socket * so)32118c2654abSrjs sctp_get_first_vtag_from_sb(struct socket *so)
32128c2654abSrjs {
32138c2654abSrjs struct mbuf *this, *at;
32148c2654abSrjs u_int32_t retval;
32158c2654abSrjs
32168c2654abSrjs retval = 0;
32178c2654abSrjs if (so->so_rcv.sb_mb) {
32188c2654abSrjs /* grubbing time */
32198c2654abSrjs this = so->so_rcv.sb_mb;
32208c2654abSrjs while (this) {
32218c2654abSrjs at = this;
32228c2654abSrjs /* get to the m_pkthdr */
32238c2654abSrjs while (at) {
32248c2654abSrjs if (at->m_flags & M_PKTHDR)
32258c2654abSrjs break;
32268c2654abSrjs else {
32278c2654abSrjs at = at->m_next;
32288c2654abSrjs }
32298c2654abSrjs }
32308c2654abSrjs /* now do we have a m_pkthdr */
32318c2654abSrjs if (at && (at->m_flags & M_PKTHDR)) {
32328c2654abSrjs /* check it */
32338c2654abSrjs #if defined(__OpenBSD__)
32348c2654abSrjs if ((u_int32_t)at->m_pkthdr.csum != 0)
32358c2654abSrjs #else
32368c2654abSrjs if ((u_int32_t)at->m_pkthdr.csum_data != 0)
32378c2654abSrjs #endif
32388c2654abSrjs {
32398c2654abSrjs /* its the one */
32408c2654abSrjs #if defined(__OpenBSD__)
32418c2654abSrjs retval = (u_int32_t)at->m_pkthdr.csum;
32428c2654abSrjs #else
32438c2654abSrjs retval =
32448c2654abSrjs (u_int32_t)at->m_pkthdr.csum_data;
32458c2654abSrjs #endif
32468c2654abSrjs break;
32478c2654abSrjs }
32488c2654abSrjs }
32498c2654abSrjs this = this->m_nextpkt;
32508c2654abSrjs }
32518c2654abSrjs
32528c2654abSrjs }
32538c2654abSrjs return (retval);
32548c2654abSrjs
32558c2654abSrjs }
32568c2654abSrjs void
sctp_grub_through_socket_buffer(struct sctp_inpcb * inp,struct socket * old,struct socket * new,struct sctp_tcb * stcb)32578c2654abSrjs sctp_grub_through_socket_buffer(struct sctp_inpcb *inp, struct socket *old,
32588c2654abSrjs struct socket *new, struct sctp_tcb *stcb)
32598c2654abSrjs {
32608c2654abSrjs struct mbuf **put, **take, *next, *this;
32618c2654abSrjs struct sockbuf *old_sb, *new_sb;
32628c2654abSrjs struct sctp_association *asoc;
32638c2654abSrjs int moved_top = 0;
32648c2654abSrjs
32658c2654abSrjs asoc = &stcb->asoc;
32668c2654abSrjs old_sb = &old->so_rcv;
32678c2654abSrjs new_sb = &new->so_rcv;
32688c2654abSrjs if (old_sb->sb_mb == NULL) {
32698c2654abSrjs /* Nothing to move */
32708c2654abSrjs return;
32718c2654abSrjs }
32728c2654abSrjs
32738c2654abSrjs if (inp->sctp_vtag_first == asoc->my_vtag) {
32748c2654abSrjs /* First one must be moved */
32758c2654abSrjs struct mbuf *mm;
32768c2654abSrjs for (mm = old_sb->sb_mb; mm; mm = mm->m_next) {
32778c2654abSrjs /*
32788c2654abSrjs * Go down the chain and fix
32798c2654abSrjs * the space allocation of the
32808c2654abSrjs * two sockets.
32818c2654abSrjs */
32828c2654abSrjs sbfree(old_sb, mm);
32838c2654abSrjs sballoc(new_sb, mm);
32848c2654abSrjs }
32858c2654abSrjs new_sb->sb_mb = old_sb->sb_mb;
32868c2654abSrjs old_sb->sb_mb = new_sb->sb_mb->m_nextpkt;
32878c2654abSrjs new_sb->sb_mb->m_nextpkt = NULL;
32888c2654abSrjs put = &new_sb->sb_mb->m_nextpkt;
32898c2654abSrjs moved_top = 1;
32908c2654abSrjs } else {
32918c2654abSrjs put = &new_sb->sb_mb;
32928c2654abSrjs }
32938c2654abSrjs
32948c2654abSrjs take = &old_sb->sb_mb;
32958c2654abSrjs next = old_sb->sb_mb;
32968c2654abSrjs while (next) {
32978c2654abSrjs this = next;
3298146d03e6Sandvar /* position for next one */
32998c2654abSrjs next = this->m_nextpkt;
33008c2654abSrjs /* check the tag of this packet */
33018c2654abSrjs if (sctp_should_be_moved(this, asoc)) {
33028c2654abSrjs /* yes this needs to be moved */
33038c2654abSrjs struct mbuf *mm;
33048c2654abSrjs *take = this->m_nextpkt;
33058c2654abSrjs this->m_nextpkt = NULL;
33068c2654abSrjs *put = this;
33078c2654abSrjs for (mm = this; mm; mm = mm->m_next) {
33088c2654abSrjs /*
33098c2654abSrjs * Go down the chain and fix
33108c2654abSrjs * the space allocation of the
33118c2654abSrjs * two sockets.
33128c2654abSrjs */
33138c2654abSrjs sbfree(old_sb, mm);
33148c2654abSrjs sballoc(new_sb, mm);
33158c2654abSrjs }
33168c2654abSrjs put = &this->m_nextpkt;
33178c2654abSrjs
33188c2654abSrjs } else {
33198c2654abSrjs /* no advance our take point. */
33208c2654abSrjs take = &this->m_nextpkt;
33218c2654abSrjs }
33228c2654abSrjs }
33238c2654abSrjs if (moved_top) {
33248c2654abSrjs /*
3325146d03e6Sandvar * Ok so now we must re-position vtag_first to
33268c2654abSrjs * match the new first one since we moved the
33278c2654abSrjs * mbuf at the top.
33288c2654abSrjs */
33298c2654abSrjs inp->sctp_vtag_first = sctp_get_first_vtag_from_sb(old);
33308c2654abSrjs }
33318c2654abSrjs }
33328c2654abSrjs
33338c2654abSrjs void
sctp_free_bufspace(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_tmit_chunk * tp1)33348c2654abSrjs sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc,
33358c2654abSrjs struct sctp_tmit_chunk *tp1)
33368c2654abSrjs {
33378c2654abSrjs if (tp1->data == NULL) {
33388c2654abSrjs return;
33398c2654abSrjs }
33408c2654abSrjs #ifdef SCTP_MBCNT_LOGGING
33418c2654abSrjs sctp_log_mbcnt(SCTP_LOG_MBCNT_DECREASE,
33428c2654abSrjs asoc->total_output_queue_size,
33438c2654abSrjs tp1->book_size,
33448c2654abSrjs asoc->total_output_mbuf_queue_size,
33458c2654abSrjs tp1->mbcnt);
33468c2654abSrjs #endif
33478c2654abSrjs if (asoc->total_output_queue_size >= tp1->book_size) {
33488c2654abSrjs asoc->total_output_queue_size -= tp1->book_size;
33498c2654abSrjs } else {
33508c2654abSrjs asoc->total_output_queue_size = 0;
33518c2654abSrjs }
33528c2654abSrjs
33538c2654abSrjs /* Now free the mbuf */
33548c2654abSrjs if (asoc->total_output_mbuf_queue_size >= tp1->mbcnt) {
33558c2654abSrjs asoc->total_output_mbuf_queue_size -= tp1->mbcnt;
33568c2654abSrjs } else {
33578c2654abSrjs asoc->total_output_mbuf_queue_size = 0;
33588c2654abSrjs }
33598c2654abSrjs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
33608c2654abSrjs (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
33618c2654abSrjs if (stcb->sctp_socket->so_snd.sb_cc >= tp1->book_size) {
33628c2654abSrjs stcb->sctp_socket->so_snd.sb_cc -= tp1->book_size;
33638c2654abSrjs } else {
33648c2654abSrjs stcb->sctp_socket->so_snd.sb_cc = 0;
33658c2654abSrjs
33668c2654abSrjs }
33678c2654abSrjs if (stcb->sctp_socket->so_snd.sb_mbcnt >= tp1->mbcnt) {
33688c2654abSrjs stcb->sctp_socket->so_snd.sb_mbcnt -= tp1->mbcnt;
33698c2654abSrjs } else {
33708c2654abSrjs stcb->sctp_socket->so_snd.sb_mbcnt = 0;
33718c2654abSrjs }
33728c2654abSrjs }
33738c2654abSrjs }
33748c2654abSrjs
33758c2654abSrjs int
sctp_release_pr_sctp_chunk(struct sctp_tcb * stcb,struct sctp_tmit_chunk * tp1,int reason,struct sctpchunk_listhead * queue)33768c2654abSrjs sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
33778c2654abSrjs int reason, struct sctpchunk_listhead *queue)
33788c2654abSrjs {
33798c2654abSrjs int ret_sz = 0;
33808c2654abSrjs int notdone;
33818c2654abSrjs uint8_t foundeom = 0;
33828c2654abSrjs
33838c2654abSrjs do {
33848c2654abSrjs ret_sz += tp1->book_size;
33858c2654abSrjs tp1->sent = SCTP_FORWARD_TSN_SKIP;
33868c2654abSrjs if (tp1->data) {
33878c2654abSrjs sctp_free_bufspace(stcb, &stcb->asoc, tp1);
33888c2654abSrjs sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1);
33898c2654abSrjs sctp_m_freem(tp1->data);
33908c2654abSrjs tp1->data = NULL;
33918c2654abSrjs sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
33928c2654abSrjs }
33938c2654abSrjs if (tp1->flags & SCTP_PR_SCTP_BUFFER) {
33948c2654abSrjs stcb->asoc.sent_queue_cnt_removeable--;
33958c2654abSrjs }
33968c2654abSrjs if (queue == &stcb->asoc.send_queue) {
33978c2654abSrjs TAILQ_REMOVE(&stcb->asoc.send_queue, tp1, sctp_next);
33988c2654abSrjs /* on to the sent queue */
33998c2654abSrjs TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, tp1,
34008c2654abSrjs sctp_next);
34018c2654abSrjs stcb->asoc.sent_queue_cnt++;
34028c2654abSrjs }
34038c2654abSrjs if ((tp1->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) ==
34048c2654abSrjs SCTP_DATA_NOT_FRAG) {
34058c2654abSrjs /* not frag'ed we ae done */
34068c2654abSrjs notdone = 0;
34078c2654abSrjs foundeom = 1;
34088c2654abSrjs } else if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
34098c2654abSrjs /* end of frag, we are done */
34108c2654abSrjs notdone = 0;
34118c2654abSrjs foundeom = 1;
34128c2654abSrjs } else {
34138c2654abSrjs /* Its a begin or middle piece, we must mark all of it */
34148c2654abSrjs notdone = 1;
34158c2654abSrjs tp1 = TAILQ_NEXT(tp1, sctp_next);
34168c2654abSrjs }
34178c2654abSrjs } while (tp1 && notdone);
34188c2654abSrjs if ((foundeom == 0) && (queue == &stcb->asoc.sent_queue)) {
34198c2654abSrjs /*
34208c2654abSrjs * The multi-part message was scattered
34218c2654abSrjs * across the send and sent queue.
34228c2654abSrjs */
34238c2654abSrjs tp1 = TAILQ_FIRST(&stcb->asoc.send_queue);
34248c2654abSrjs /*
34258c2654abSrjs * recurse throught the send_queue too, starting at the
34268c2654abSrjs * beginning.
34278c2654abSrjs */
34288c2654abSrjs if (tp1) {
34298c2654abSrjs ret_sz += sctp_release_pr_sctp_chunk(stcb, tp1, reason,
34308c2654abSrjs &stcb->asoc.send_queue);
34318c2654abSrjs } else {
34328c2654abSrjs printf("hmm, nothing on the send queue and no EOM?\n");
34338c2654abSrjs }
34348c2654abSrjs }
34358c2654abSrjs return (ret_sz);
34368c2654abSrjs }
34378c2654abSrjs
34388c2654abSrjs /*
34398c2654abSrjs * checks to see if the given address, sa, is one that is currently
34408c2654abSrjs * known by the kernel
34418c2654abSrjs * note: can't distinguish the same address on multiple interfaces and
34428c2654abSrjs * doesn't handle multiple addresses with different zone/scope id's
34438c2654abSrjs * note: ifa_ifwithaddr() compares the entire sockaddr struct
34448c2654abSrjs */
34458c2654abSrjs struct ifaddr *
sctp_find_ifa_by_addr(struct sockaddr * sa)34468c2654abSrjs sctp_find_ifa_by_addr(struct sockaddr *sa)
34478c2654abSrjs {
34488c2654abSrjs struct ifnet *ifn;
34498c2654abSrjs struct ifaddr *ifa;
3450040205aeSozaki-r int s;
34518c2654abSrjs
34528c2654abSrjs /* go through all our known interfaces */
3453040205aeSozaki-r s = pserialize_read_enter();
3454040205aeSozaki-r IFNET_READER_FOREACH(ifn) {
34558c2654abSrjs /* go through each interface addresses */
34569e4c2bdaSozaki-r IFADDR_READER_FOREACH(ifa, ifn) {
34578c2654abSrjs /* correct family? */
34588c2654abSrjs if (ifa->ifa_addr->sa_family != sa->sa_family)
34598c2654abSrjs continue;
34608c2654abSrjs
34618c2654abSrjs #ifdef INET6
34628c2654abSrjs if (ifa->ifa_addr->sa_family == AF_INET6) {
34638c2654abSrjs /* IPv6 address */
34648c2654abSrjs struct sockaddr_in6 *sin1, *sin2, sin6_tmp;
34658c2654abSrjs sin1 = (struct sockaddr_in6 *)ifa->ifa_addr;
34668c2654abSrjs if (IN6_IS_SCOPE_LINKLOCAL(&sin1->sin6_addr)) {
34678c2654abSrjs /* create a copy and clear scope */
34688c2654abSrjs memcpy(&sin6_tmp, sin1,
34698c2654abSrjs sizeof(struct sockaddr_in6));
34708c2654abSrjs sin1 = &sin6_tmp;
34718c2654abSrjs in6_clearscope(&sin1->sin6_addr);
34728c2654abSrjs }
34738c2654abSrjs sin2 = (struct sockaddr_in6 *)sa;
34748c2654abSrjs if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
34758c2654abSrjs sizeof(struct in6_addr)) == 0) {
34768c2654abSrjs /* found it */
3477040205aeSozaki-r pserialize_read_exit(s);
34788c2654abSrjs return (ifa);
34798c2654abSrjs }
34808c2654abSrjs } else
34818c2654abSrjs #endif
34828c2654abSrjs if (ifa->ifa_addr->sa_family == AF_INET) {
34838c2654abSrjs /* IPv4 address */
34848c2654abSrjs struct sockaddr_in *sin1, *sin2;
34858c2654abSrjs sin1 = (struct sockaddr_in *)ifa->ifa_addr;
34868c2654abSrjs sin2 = (struct sockaddr_in *)sa;
34878c2654abSrjs if (sin1->sin_addr.s_addr ==
34888c2654abSrjs sin2->sin_addr.s_addr) {
34898c2654abSrjs /* found it */
3490040205aeSozaki-r pserialize_read_exit(s);
34918c2654abSrjs return (ifa);
34928c2654abSrjs }
34938c2654abSrjs }
34948c2654abSrjs /* else, not AF_INET or AF_INET6, so skip */
34958c2654abSrjs } /* end foreach ifa */
34968c2654abSrjs } /* end foreach ifn */
3497040205aeSozaki-r pserialize_read_exit(s);
3498040205aeSozaki-r
34998c2654abSrjs /* not found! */
35008c2654abSrjs return (NULL);
35018c2654abSrjs }
35028c2654abSrjs
35038c2654abSrjs
35048c2654abSrjs #ifdef __APPLE__
35058c2654abSrjs /*
35068c2654abSrjs * here we hack in a fix for Apple's m_copym for the case where the first mbuf
35078c2654abSrjs * in the chain is a M_PKTHDR and the length is zero
35088c2654abSrjs */
35098c2654abSrjs static void
sctp_pkthdr_fix(struct mbuf * m)35108c2654abSrjs sctp_pkthdr_fix(struct mbuf *m)
35118c2654abSrjs {
35128c2654abSrjs struct mbuf *m_nxt;
35138c2654abSrjs
35148c2654abSrjs if ((m->m_flags & M_PKTHDR) == 0) {
35158c2654abSrjs /* not a PKTHDR */
35168c2654abSrjs return;
35178c2654abSrjs }
35188c2654abSrjs
35198c2654abSrjs if (m->m_len != 0) {
35208c2654abSrjs /* not a zero length PKTHDR mbuf */
35218c2654abSrjs return;
35228c2654abSrjs }
35238c2654abSrjs
35248c2654abSrjs /* let's move in a word into the first mbuf... yes, ugly! */
35258c2654abSrjs m_nxt = m->m_next;
35268c2654abSrjs if (m_nxt == NULL) {
35278c2654abSrjs /* umm... not a very useful mbuf chain... */
35288c2654abSrjs return;
35298c2654abSrjs }
35308c2654abSrjs if ((size_t)m_nxt->m_len > sizeof(long)) {
35318c2654abSrjs /* move over a long */
35328c2654abSrjs bcopy(mtod(m_nxt, void *), mtod(m, void *), sizeof(long));
35338c2654abSrjs /* update mbuf data pointers and lengths */
35348c2654abSrjs m->m_len += sizeof(long);
35358c2654abSrjs m_nxt->m_data += sizeof(long);
35368c2654abSrjs m_nxt->m_len -= sizeof(long);
35378c2654abSrjs }
35388c2654abSrjs }
35398c2654abSrjs
35408c2654abSrjs inline struct mbuf *
sctp_m_copym(struct mbuf * m,int off,int len,int wait)35418c2654abSrjs sctp_m_copym(struct mbuf *m, int off, int len, int wait)
35428c2654abSrjs {
35438c2654abSrjs sctp_pkthdr_fix(m);
35448c2654abSrjs return (m_copym(m, off, len, wait));
35458c2654abSrjs }
35468c2654abSrjs #endif /* __APPLE__ */
3547