summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet/sctputil.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet/sctputil.c')
-rw-r--r--freebsd/sys/netinet/sctputil.c2214
1 files changed, 1089 insertions, 1125 deletions
diff --git a/freebsd/sys/netinet/sctputil.c b/freebsd/sys/netinet/sctputil.c
index e9a279c9..60888bef 100644
--- a/freebsd/sys/netinet/sctputil.c
+++ b/freebsd/sys/netinet/sctputil.c
@@ -2,16 +2,18 @@
/*-
* Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
+ * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* a) Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
+ * this list of conditions and the following disclaimer.
*
* b) Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the distribution.
+ * the documentation and/or other materials provided with the distribution.
*
* c) Neither the name of Cisco Systems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
@@ -30,8 +32,6 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-/* $KAME: sctputil.c,v 1.37 2005/03/07 23:26:09 itojun Exp $ */
-
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_var.h>
#include <netinet/sctp_sysctl.h>
#ifdef INET6
+#include <netinet6/sctp6_var.h>
#endif
#include <netinet/sctp_header.h>
#include <netinet/sctp_output.h>
@@ -49,17 +50,21 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_indata.h>/* for sctp_deliver_data() */
#include <netinet/sctp_auth.h>
#include <netinet/sctp_asconf.h>
-#include <netinet/sctp_cc_functions.h>
#include <netinet/sctp_bsd_addr.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <sys/proc.h>
#ifndef KTR_SCTP
#define KTR_SCTP KTR_SUBSYS
#endif
+extern struct sctp_cc_functions sctp_cc_functions[];
+extern struct sctp_ss_functions sctp_ss_functions[];
+
void
-sctp_sblog(struct sockbuf *sb,
- struct sctp_tcb *stcb, int from, int incr)
+sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr)
{
struct sctp_cwnd_log sctp_clog;
@@ -103,7 +108,6 @@ sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc)
sctp_clog.x.misc.log4);
}
-
void
rto_logging(struct sctp_nets *net, int from)
{
@@ -111,7 +115,7 @@ rto_logging(struct sctp_nets *net, int from)
memset(&sctp_clog, 0, sizeof(sctp_clog));
sctp_clog.x.rto.net = (void *)net;
- sctp_clog.x.rto.rtt = net->prev_rtt;
+ sctp_clog.x.rto.rtt = net->rtt / 1000;
SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_RTT,
from,
@@ -119,7 +123,6 @@ rto_logging(struct sctp_nets *net, int from)
sctp_clog.x.misc.log2,
sctp_clog.x.misc.log3,
sctp_clog.x.misc.log4);
-
}
void
@@ -140,7 +143,6 @@ sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16
sctp_clog.x.misc.log2,
sctp_clog.x.misc.log3,
sctp_clog.x.misc.log4);
-
}
void
@@ -162,7 +164,6 @@ sctp_log_nagle_event(struct sctp_tcb *stcb, int action)
sctp_clog.x.misc.log4);
}
-
void
sctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps, uint16_t dups, int from)
{
@@ -201,8 +202,7 @@ sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from)
}
void
-sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn,
- int from)
+sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn, int from)
{
struct sctp_cwnd_log sctp_clog;
@@ -217,10 +217,8 @@ sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn,
sctp_clog.x.misc.log2,
sctp_clog.x.misc.log3,
sctp_clog.x.misc.log4);
-
}
-
void
sctp_log_mb(struct mbuf *m, int from)
{
@@ -246,10 +244,8 @@ sctp_log_mb(struct mbuf *m, int from)
sctp_clog.x.misc.log4);
}
-
void
-sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_read *poschk,
- int from)
+sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_read *poschk, int from)
{
struct sctp_cwnd_log sctp_clog;
@@ -275,7 +271,6 @@ sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_rea
sctp_clog.x.misc.log2,
sctp_clog.x.misc.log3,
sctp_clog.x.misc.log4);
-
}
void
@@ -311,7 +306,6 @@ sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t
sctp_clog.x.misc.log2,
sctp_clog.x.misc.log3,
sctp_clog.x.misc.log4);
-
}
void
@@ -356,7 +350,6 @@ sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from)
sctp_clog.x.misc.log2,
sctp_clog.x.misc.log3,
sctp_clog.x.misc.log4);
-
}
void
@@ -384,7 +377,6 @@ sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int b
sctp_clog.x.misc.log2,
sctp_clog.x.misc.log3,
sctp_clog.x.misc.log4);
-
}
void
@@ -439,7 +431,6 @@ sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mb
sctp_clog.x.misc.log2,
sctp_clog.x.misc.log3,
sctp_clog.x.misc.log4);
-
}
void
@@ -452,7 +443,7 @@ sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
}
void
-sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t cumtsn, uint32_t wake_cnt, int from)
+sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from)
{
struct sctp_cwnd_log sctp_clog;
@@ -495,11 +486,10 @@ sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t cumtsn, uint32_t wake_cnt, int f
sctp_clog.x.misc.log2,
sctp_clog.x.misc.log3,
sctp_clog.x.misc.log4);
-
}
void
-sctp_log_block(uint8_t from, struct socket *so, struct sctp_association *asoc, int sendlen)
+sctp_log_block(uint8_t from, struct sctp_association *asoc, int sendlen)
{
struct sctp_cwnd_log sctp_clog;
@@ -517,11 +507,10 @@ sctp_log_block(uint8_t from, struct socket *so, struct sctp_association *asoc, i
sctp_clog.x.misc.log2,
sctp_clog.x.misc.log3,
sctp_clog.x.misc.log4);
-
}
int
-sctp_fill_stat_log(void *optval, size_t *optsize)
+sctp_fill_stat_log(void *optval SCTP_UNUSED, size_t *optsize SCTP_UNUSED)
{
/* May need to fix this if ktrdump does not work */
return (0);
@@ -699,7 +688,7 @@ sctp_auditing(int from, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
}
if (lnet->flight_size != tot_out) {
SCTP_PRINTF("net:%p flight was %d corrected to %d\n",
- lnet, lnet->flight_size,
+ (void *)lnet, lnet->flight_size,
tot_out);
lnet->flight_size = tot_out;
}
@@ -737,15 +726,14 @@ sctp_stop_timers_for_shutdown(struct sctp_tcb *stcb)
asoc = &stcb->asoc;
- (void)SCTP_OS_TIMER_STOP(&asoc->hb_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer);
(void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer);
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
- (void)SCTP_OS_TIMER_STOP(&net->fr_timer.timer);
(void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer);
+ (void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer);
}
}
@@ -799,7 +787,7 @@ sctp_get_prev_mtu(uint32_t val)
* entry, just return val.
*/
uint32_t
-sctp_get_next_mtu(struct sctp_inpcb *inp, uint32_t val)
+sctp_get_next_mtu(uint32_t val)
{
/* select another MTU that is just bigger than this one */
uint32_t i;
@@ -870,28 +858,29 @@ retry:
}
uint32_t
-sctp_select_a_tag(struct sctp_inpcb *inp, uint16_t lport, uint16_t rport, int save_in_twait)
+sctp_select_a_tag(struct sctp_inpcb *inp, uint16_t lport, uint16_t rport, int check)
{
- uint32_t x, not_done;
+ uint32_t x;
struct timeval now;
- (void)SCTP_GETTIME_TIMEVAL(&now);
- not_done = 1;
- while (not_done) {
+ if (check) {
+ (void)SCTP_GETTIME_TIMEVAL(&now);
+ }
+ for (;;) {
x = sctp_select_initial_TSN(&inp->sctp_ep);
if (x == 0) {
/* we never use 0 */
continue;
}
- if (sctp_is_vtag_good(inp, x, lport, rport, &now, save_in_twait)) {
- not_done = 0;
+ if (!check || sctp_is_vtag_good(x, lport, rport, &now)) {
+ break;
}
}
return (x);
}
int
-sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
+sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
uint32_t override_tag, uint32_t vrf_id)
{
struct sctp_association *asoc;
@@ -912,40 +901,41 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
asoc = &stcb->asoc;
/* init all variables to a known value. */
SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_INUSE);
- asoc->max_burst = m->sctp_ep.max_burst;
- asoc->heart_beat_delay = TICKS_TO_MSEC(m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
- asoc->cookie_life = m->sctp_ep.def_cookie_life;
- asoc->sctp_cmt_on_off = m->sctp_cmt_on_off;
+ asoc->max_burst = inp->sctp_ep.max_burst;
+ asoc->fr_max_burst = inp->sctp_ep.fr_max_burst;
+ asoc->heart_beat_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
+ asoc->cookie_life = inp->sctp_ep.def_cookie_life;
+ asoc->sctp_cmt_on_off = inp->sctp_cmt_on_off;
+ asoc->ecn_allowed = inp->sctp_ecn_enable;
asoc->sctp_nr_sack_on_off = (uint8_t) SCTP_BASE_SYSCTL(sctp_nr_sack_on_off);
- asoc->sctp_cmt_pf = (uint8_t) SCTP_BASE_SYSCTL(sctp_cmt_pf);
- asoc->sctp_frag_point = m->sctp_frag_point;
-#ifdef INET
- asoc->default_tos = m->ip_inp.inp.inp_ip_tos;
-#else
- asoc->default_tos = 0;
-#endif
-
+ asoc->sctp_cmt_pf = (uint8_t) 0;
+ asoc->sctp_frag_point = inp->sctp_frag_point;
+ asoc->sctp_features = inp->sctp_features;
+ asoc->default_dscp = inp->sctp_ep.default_dscp;
#ifdef INET6
- asoc->default_flowlabel = ((struct in6pcb *)m)->in6p_flowinfo;
-#else
- asoc->default_flowlabel = 0;
+ if (inp->sctp_ep.default_flowlabel) {
+ asoc->default_flowlabel = inp->sctp_ep.default_flowlabel;
+ } else {
+ if (inp->ip_inp.inp.inp_flags & IN6P_AUTOFLOWLABEL) {
+ asoc->default_flowlabel = sctp_select_initial_TSN(&inp->sctp_ep);
+ asoc->default_flowlabel &= 0x000fffff;
+ asoc->default_flowlabel |= 0x80000000;
+ } else {
+ asoc->default_flowlabel = 0;
+ }
+ }
#endif
asoc->sb_send_resv = 0;
if (override_tag) {
asoc->my_vtag = override_tag;
} else {
- asoc->my_vtag = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 1);
+ asoc->my_vtag = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 1);
}
/* Get the nonce tags */
- asoc->my_vtag_nonce = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
- asoc->peer_vtag_nonce = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
+ asoc->my_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
+ asoc->peer_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
asoc->vrf_id = vrf_id;
- if (sctp_is_feature_on(m, SCTP_PCB_FLAGS_DONOT_HEARTBEAT))
- asoc->hb_is_disabled = 1;
- else
- asoc->hb_is_disabled = 0;
-
#ifdef SCTP_ASOCLOG_OF_TSNS
asoc->tsn_in_at = 0;
asoc->tsn_out_at = 0;
@@ -960,7 +950,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
asoc->refcnt = 0;
asoc->assoc_up_sent = 0;
asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number = asoc->sending_seq =
- sctp_select_initial_TSN(&m->sctp_ep);
+ sctp_select_initial_TSN(&inp->sctp_ep);
asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1;
/* we are optimisitic here */
asoc->peer_supports_pktdrop = 1;
@@ -971,7 +961,6 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
asoc->last_net_cmt_send_started = NULL;
/* This will need to be adjusted */
- asoc->last_cwr_tsn = asoc->init_seq_number - 1;
asoc->last_acked_seq = asoc->init_seq_number - 1;
asoc->advanced_peer_ack_point = asoc->last_acked_seq;
asoc->asconf_seq_in = asoc->last_acked_seq;
@@ -979,55 +968,42 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
/* here we are different, we hold the next one we expect */
asoc->str_reset_seq_in = asoc->last_acked_seq + 1;
- asoc->initial_init_rto_max = m->sctp_ep.initial_init_rto_max;
- asoc->initial_rto = m->sctp_ep.initial_rto;
+ asoc->initial_init_rto_max = inp->sctp_ep.initial_init_rto_max;
+ asoc->initial_rto = inp->sctp_ep.initial_rto;
- asoc->max_init_times = m->sctp_ep.max_init_times;
- asoc->max_send_times = m->sctp_ep.max_send_times;
- asoc->def_net_failure = m->sctp_ep.def_net_failure;
+ asoc->max_init_times = inp->sctp_ep.max_init_times;
+ asoc->max_send_times = inp->sctp_ep.max_send_times;
+ asoc->def_net_failure = inp->sctp_ep.def_net_failure;
+ asoc->def_net_pf_threshold = inp->sctp_ep.def_net_pf_threshold;
asoc->free_chunk_cnt = 0;
asoc->iam_blocking = 0;
- /* ECN Nonce initialization */
- asoc->context = m->sctp_context;
- asoc->def_send = m->def_send;
- asoc->ecn_nonce_allowed = 0;
- asoc->receiver_nonce_sum = 1;
- asoc->nonce_sum_expect_base = 1;
- asoc->nonce_sum_check = 1;
- asoc->nonce_resync_tsn = 0;
- asoc->nonce_wait_for_ecne = 0;
- asoc->nonce_wait_tsn = 0;
- asoc->delayed_ack = TICKS_TO_MSEC(m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
- asoc->sack_freq = m->sctp_ep.sctp_sack_freq;
+ asoc->context = inp->sctp_context;
+ asoc->local_strreset_support = inp->local_strreset_support;
+ asoc->def_send = inp->def_send;
+ asoc->delayed_ack = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
+ asoc->sack_freq = inp->sctp_ep.sctp_sack_freq;
asoc->pr_sctp_cnt = 0;
asoc->total_output_queue_size = 0;
- if (m->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- struct in6pcb *inp6;
-
- /* Its a V6 socket */
- inp6 = (struct in6pcb *)m;
- asoc->ipv6_addr_legal = 1;
- /* Now look at the binding flag to see if V4 will be legal */
- if (SCTP_IPV6_V6ONLY(inp6) == 0) {
- asoc->ipv4_addr_legal = 1;
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
+ asoc->scope.ipv6_addr_legal = 1;
+ if (SCTP_IPV6_V6ONLY(inp) == 0) {
+ asoc->scope.ipv4_addr_legal = 1;
} else {
- /* V4 addresses are NOT legal on the association */
- asoc->ipv4_addr_legal = 0;
+ asoc->scope.ipv4_addr_legal = 0;
}
} else {
- /* Its a V4 socket, no - V6 */
- asoc->ipv4_addr_legal = 1;
- asoc->ipv6_addr_legal = 0;
+ asoc->scope.ipv6_addr_legal = 0;
+ asoc->scope.ipv4_addr_legal = 1;
}
- asoc->my_rwnd = max(SCTP_SB_LIMIT_RCV(m->sctp_socket), SCTP_MINIMAL_RWND);
- asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(m->sctp_socket);
+ asoc->my_rwnd = max(SCTP_SB_LIMIT_RCV(inp->sctp_socket), SCTP_MINIMAL_RWND);
+ asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(inp->sctp_socket);
- asoc->smallest_mtu = m->sctp_frag_point;
- asoc->minrto = m->sctp_ep.sctp_minrto;
- asoc->maxrto = m->sctp_ep.sctp_maxrto;
+ asoc->smallest_mtu = inp->sctp_frag_point;
+ asoc->minrto = inp->sctp_ep.sctp_minrto;
+ asoc->maxrto = inp->sctp_ep.sctp_maxrto;
asoc->locked_on_sending = NULL;
asoc->stream_locked_on = 0;
@@ -1044,77 +1020,20 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
/* Setup to fill the hb random cache at first HB */
asoc->hb_random_idx = 4;
- asoc->sctp_autoclose_ticks = m->sctp_ep.auto_close_time;
+ asoc->sctp_autoclose_ticks = inp->sctp_ep.auto_close_time;
- /*
- * JRS - Pick the default congestion control module based on the
- * sysctl.
- */
- switch (m->sctp_ep.sctp_default_cc_module) {
- /* JRS - Standard TCP congestion control */
- case SCTP_CC_RFC2581:
- {
- stcb->asoc.congestion_control_module = SCTP_CC_RFC2581;
- stcb->asoc.cc_functions.sctp_set_initial_cc_param = &sctp_set_initial_cc_param;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_sack = &sctp_cwnd_update_after_sack;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_fr = &sctp_cwnd_update_after_fr;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout = &sctp_cwnd_update_after_timeout;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_ecn_echo = &sctp_cwnd_update_after_ecn_echo;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_packet_dropped = &sctp_cwnd_update_after_packet_dropped;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_output = &sctp_cwnd_update_after_output;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer = &sctp_cwnd_update_after_fr_timer;
- break;
- }
- /* JRS - High Speed TCP congestion control (Floyd) */
- case SCTP_CC_HSTCP:
- {
- stcb->asoc.congestion_control_module = SCTP_CC_HSTCP;
- stcb->asoc.cc_functions.sctp_set_initial_cc_param = &sctp_set_initial_cc_param;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_sack = &sctp_hs_cwnd_update_after_sack;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_fr = &sctp_hs_cwnd_update_after_fr;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout = &sctp_cwnd_update_after_timeout;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_ecn_echo = &sctp_cwnd_update_after_ecn_echo;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_packet_dropped = &sctp_cwnd_update_after_packet_dropped;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_output = &sctp_cwnd_update_after_output;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer = &sctp_cwnd_update_after_fr_timer;
- break;
- }
- /* JRS - HTCP congestion control */
- case SCTP_CC_HTCP:
- {
- stcb->asoc.congestion_control_module = SCTP_CC_HTCP;
- stcb->asoc.cc_functions.sctp_set_initial_cc_param = &sctp_htcp_set_initial_cc_param;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_sack = &sctp_htcp_cwnd_update_after_sack;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_fr = &sctp_htcp_cwnd_update_after_fr;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout = &sctp_htcp_cwnd_update_after_timeout;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_ecn_echo = &sctp_htcp_cwnd_update_after_ecn_echo;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_packet_dropped = &sctp_cwnd_update_after_packet_dropped;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_output = &sctp_cwnd_update_after_output;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer = &sctp_htcp_cwnd_update_after_fr_timer;
- break;
- }
- /* JRS - By default, use RFC2581 */
- default:
- {
- stcb->asoc.congestion_control_module = SCTP_CC_RFC2581;
- stcb->asoc.cc_functions.sctp_set_initial_cc_param = &sctp_set_initial_cc_param;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_sack = &sctp_cwnd_update_after_sack;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_fr = &sctp_cwnd_update_after_fr;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout = &sctp_cwnd_update_after_timeout;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_ecn_echo = &sctp_cwnd_update_after_ecn_echo;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_packet_dropped = &sctp_cwnd_update_after_packet_dropped;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_output = &sctp_cwnd_update_after_output;
- stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer = &sctp_cwnd_update_after_fr_timer;
- break;
- }
- }
+ stcb->asoc.congestion_control_module = inp->sctp_ep.sctp_default_cc_module;
+ stcb->asoc.cc_functions = sctp_cc_functions[inp->sctp_ep.sctp_default_cc_module];
+
+ stcb->asoc.stream_scheduling_module = inp->sctp_ep.sctp_default_ss_module;
+ stcb->asoc.ss_functions = sctp_ss_functions[inp->sctp_ep.sctp_default_ss_module];
/*
* Now the stream parameters, here we allocate space for all streams
* that we request by default.
*/
asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams =
- m->sctp_ep.pre_open_stream_count;
+ inp->sctp_ep.pre_open_stream_count;
SCTP_MALLOC(asoc->strmout, struct sctp_stream_out *,
asoc->streamoutcnt * sizeof(struct sctp_stream_out),
SCTP_M_STRMO);
@@ -1132,13 +1051,15 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
* that were dropped must be notified to the upper layer as
* failed to send.
*/
- asoc->strmout[i].next_sequence_sent = 0x0;
+ asoc->strmout[i].next_sequence_send = 0x0;
TAILQ_INIT(&asoc->strmout[i].outqueue);
+ asoc->strmout[i].chunks_on_queues = 0;
asoc->strmout[i].stream_no = i;
asoc->strmout[i].last_msg_incomplete = 0;
- asoc->strmout[i].next_spoke.tqe_next = 0;
- asoc->strmout[i].next_spoke.tqe_prev = 0;
+ asoc->ss_functions.sctp_ss_init_stream(&asoc->strmout[i], NULL);
}
+ asoc->ss_functions.sctp_ss_init(stcb, asoc, 0);
+
/* Now the mapping array */
asoc->mapping_array_size = SCTP_INITIAL_MAPPING_ARRAY;
SCTP_MALLOC(asoc->mapping_array, uint8_t *, asoc->mapping_array_size,
@@ -1161,14 +1082,13 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
/* Now the init of the other outqueues */
TAILQ_INIT(&asoc->free_chunks);
- TAILQ_INIT(&asoc->out_wheel);
TAILQ_INIT(&asoc->control_send_queue);
TAILQ_INIT(&asoc->asconf_send_queue);
TAILQ_INIT(&asoc->send_queue);
TAILQ_INIT(&asoc->sent_queue);
TAILQ_INIT(&asoc->reasmqueue);
TAILQ_INIT(&asoc->resetHead);
- asoc->max_inbound_streams = m->sctp_ep.max_open_streams_intome;
+ asoc->max_inbound_streams = inp->sctp_ep.max_open_streams_intome;
TAILQ_INIT(&asoc->asconf_queue);
/* authentication fields */
asoc->authinfo.random = NULL;
@@ -1179,6 +1099,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
asoc->authinfo.recv_keyid = 0;
LIST_INIT(&asoc->shared_keys);
asoc->marked_retrans = 0;
+ asoc->port = inp->sctp_ep.port;
asoc->timoinit = 0;
asoc->timodata = 0;
asoc->timosack = 0;
@@ -1200,34 +1121,34 @@ sctp_print_mapping_array(struct sctp_association *asoc)
{
unsigned int i, limit;
- printf("Mapping array size: %d, baseTSN: %8.8x, cumAck: %8.8x, highestTSN: (%8.8x, %8.8x).\n",
+ SCTP_PRINTF("Mapping array size: %d, baseTSN: %8.8x, cumAck: %8.8x, highestTSN: (%8.8x, %8.8x).\n",
asoc->mapping_array_size,
asoc->mapping_array_base_tsn,
asoc->cumulative_tsn,
asoc->highest_tsn_inside_map,
asoc->highest_tsn_inside_nr_map);
for (limit = asoc->mapping_array_size; limit > 1; limit--) {
- if (asoc->mapping_array[limit - 1]) {
+ if (asoc->mapping_array[limit - 1] != 0) {
break;
}
}
- printf("Renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit);
+ SCTP_PRINTF("Renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit);
for (i = 0; i < limit; i++) {
- printf("%2.2x%c", asoc->mapping_array[i], ((i + 1) % 16) ? ' ' : '\n');
+ SCTP_PRINTF("%2.2x%c", asoc->mapping_array[i], ((i + 1) % 16) ? ' ' : '\n');
}
if (limit % 16)
- printf("\n");
+ SCTP_PRINTF("\n");
for (limit = asoc->mapping_array_size; limit > 1; limit--) {
if (asoc->nr_mapping_array[limit - 1]) {
break;
}
}
- printf("Non renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit);
+ SCTP_PRINTF("Non renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit);
for (i = 0; i < limit; i++) {
- printf("%2.2x%c", asoc->nr_mapping_array[i], ((i + 1) % 16) ? ' ' : '\n');
+ SCTP_PRINTF("%2.2x%c", asoc->nr_mapping_array[i], ((i + 1) % 16) ? ' ' : '\n');
}
if (limit % 16)
- printf("\n");
+ SCTP_PRINTF("\n");
}
int
@@ -1355,10 +1276,6 @@ select_a_new_ep:
SCTP_INP_DECR_REF(it->inp);
atomic_add_int(&it->stcb->asoc.refcnt, -1);
if (sctp_it_ctl.iterator_flags &
- SCTP_ITERATOR_MUST_EXIT) {
- goto done_with_iterator;
- }
- if (sctp_it_ctl.iterator_flags &
SCTP_ITERATOR_STOP_CUR_IT) {
sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_IT;
goto done_with_iterator;
@@ -1369,7 +1286,7 @@ select_a_new_ep:
goto no_stcb;
}
/* If we reach here huh? */
- printf("Unknown it ctl flag %x\n",
+ SCTP_PRINTF("Unknown it ctl flag %x\n",
sctp_it_ctl.iterator_flags);
sctp_it_ctl.iterator_flags = 0;
}
@@ -1419,27 +1336,22 @@ no_stcb:
void
sctp_iterator_worker(void)
{
- struct sctp_iterator *it = NULL;
+ struct sctp_iterator *it, *nit;
/* This function is called with the WQ lock in place */
sctp_it_ctl.iterator_running = 1;
- sctp_it_ctl.cur_it = it = TAILQ_FIRST(&sctp_it_ctl.iteratorhead);
- while (it) {
+ TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) {
+ sctp_it_ctl.cur_it = it;
/* now lets work on this one */
TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr);
SCTP_IPI_ITERATOR_WQ_UNLOCK();
CURVNET_SET(it->vn);
sctp_iterator_work(it);
-
+ sctp_it_ctl.cur_it = NULL;
CURVNET_RESTORE();
SCTP_IPI_ITERATOR_WQ_LOCK();
- if (sctp_it_ctl.iterator_flags & SCTP_ITERATOR_MUST_EXIT) {
- sctp_it_ctl.cur_it = NULL;
- break;
- }
/* sa_ignore FREED_MEMORY */
- sctp_it_ctl.cur_it = it = TAILQ_FIRST(&sctp_it_ctl.iteratorhead);
}
sctp_it_ctl.iterator_running = 0;
return;
@@ -1450,7 +1362,7 @@ static void
sctp_handle_addr_wq(void)
{
/* deal with the ADDR wq from the rtsock calls */
- struct sctp_laddr *wi;
+ struct sctp_laddr *wi, *nwi;
struct sctp_asconf_iterator *asc;
SCTP_MALLOC(asc, struct sctp_asconf_iterator *,
@@ -1467,12 +1379,10 @@ sctp_handle_addr_wq(void)
asc->cnt = 0;
SCTP_WQ_ADDR_LOCK();
- wi = LIST_FIRST(&SCTP_BASE_INFO(addr_wq));
- while (wi != NULL) {
+ LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) {
LIST_REMOVE(wi, sctp_nxt_addr);
LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr);
asc->cnt++;
- wi = LIST_FIRST(&SCTP_BASE_INFO(addr_wq));
}
SCTP_WQ_ADDR_UNLOCK();
@@ -1490,9 +1400,6 @@ sctp_handle_addr_wq(void)
}
}
-int retcode = 0;
-int cur_oerr = 0;
-
void
sctp_timeout_handler(void *t)
{
@@ -1501,7 +1408,7 @@ sctp_timeout_handler(void *t)
struct sctp_nets *net;
struct sctp_timer *tmr;
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
struct socket *so;
#endif
@@ -1523,7 +1430,7 @@ sctp_timeout_handler(void *t)
if (tmr->self != (void *)tmr) {
/*
* SCTP_PRINTF("Stale SCTP timer fired (%p), ignoring...\n",
- * tmr);
+ * (void *)tmr);
*/
CURVNET_RESTORE();
return;
@@ -1547,7 +1454,7 @@ sctp_timeout_handler(void *t)
type = tmr->type;
if (inp) {
SCTP_INP_INCR_REF(inp);
- if ((inp->sctp_socket == 0) &&
+ if ((inp->sctp_socket == NULL) &&
((tmr->type != SCTP_TIMER_TYPE_INPKILL) &&
(tmr->type != SCTP_TIMER_TYPE_INIT) &&
(tmr->type != SCTP_TIMER_TYPE_SEND) &&
@@ -1653,9 +1560,7 @@ sctp_timeout_handler(void *t)
stcb->asoc.num_send_timers_up = 0;
}
SCTP_TCB_LOCK_ASSERT(stcb);
- cur_oerr = stcb->asoc.overall_error_count;
- retcode = sctp_t3rxt_timer(inp, stcb, net);
- if (retcode) {
+ if (sctp_t3rxt_timer(inp, stcb, net)) {
/* no need to unlock on tcb its gone */
goto out_decr;
@@ -1666,8 +1571,7 @@ sctp_timeout_handler(void *t)
#endif
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
if ((stcb->asoc.num_send_timers_up == 0) &&
- (stcb->asoc.sent_queue_cnt > 0)
- ) {
+ (stcb->asoc.sent_queue_cnt > 0)) {
struct sctp_tmit_chunk *chk;
/*
@@ -1697,11 +1601,10 @@ sctp_timeout_handler(void *t)
case SCTP_TIMER_TYPE_RECV:
if ((stcb == NULL) || (inp == NULL)) {
break;
- } {
- SCTP_STAT_INCR(sctps_timosack);
- stcb->asoc.timosack++;
- sctp_send_sack(stcb);
}
+ SCTP_STAT_INCR(sctps_timosack);
+ stcb->asoc.timosack++;
+ sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
@@ -1723,33 +1626,20 @@ sctp_timeout_handler(void *t)
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED);
break;
case SCTP_TIMER_TYPE_HEARTBEAT:
- {
- struct sctp_nets *lnet;
- int cnt_of_unconf = 0;
-
- if ((stcb == NULL) || (inp == NULL)) {
- break;
- }
- SCTP_STAT_INCR(sctps_timoheartbeat);
- stcb->asoc.timoheartbeat++;
- TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
- if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) &&
- (lnet->dest_state & SCTP_ADDR_REACHABLE)) {
- cnt_of_unconf++;
- }
- }
- if (cnt_of_unconf == 0) {
- if (sctp_heartbeat_timer(inp, stcb, lnet,
- cnt_of_unconf)) {
- /* no need to unlock on tcb its gone */
- goto out_decr;
- }
- }
+ if ((stcb == NULL) || (inp == NULL) || (net == NULL)) {
+ break;
+ }
+ SCTP_STAT_INCR(sctps_timoheartbeat);
+ stcb->asoc.timoheartbeat++;
+ if (sctp_heartbeat_timer(inp, stcb, net)) {
+ /* no need to unlock on tcb its gone */
+ goto out_decr;
+ }
#ifdef SCTP_AUDITING_ENABLED
- sctp_auditing(4, inp, stcb, lnet);
+ sctp_auditing(4, inp, stcb, net);
#endif
- sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT,
- stcb->sctp_ep, stcb, lnet);
+ if (!(net->dest_state & SCTP_ADDR_NOHB)) {
+ sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED);
}
break;
@@ -1829,8 +1719,7 @@ sctp_timeout_handler(void *t)
break;
}
SCTP_STAT_INCR(sctps_timoshutdownguard);
- sctp_abort_an_association(inp, stcb,
- SCTP_SHUTDOWN_GUARD_EXPIRES, NULL, SCTP_SO_NOT_LOCKED);
+ sctp_abort_an_association(inp, stcb, NULL, SCTP_SO_NOT_LOCKED);
/* no need to unlock on tcb its gone */
goto out_decr;
@@ -1845,14 +1734,6 @@ sctp_timeout_handler(void *t)
SCTP_STAT_INCR(sctps_timostrmrst);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED);
break;
- case SCTP_TIMER_TYPE_EARLYFR:
- /* Need to do FR of things for net */
- if ((stcb == NULL) || (inp == NULL)) {
- break;
- }
- SCTP_STAT_INCR(sctps_timoearlyfr);
- sctp_early_fr_timer(inp, stcb, net);
- break;
case SCTP_TIMER_TYPE_ASCONF:
if ((stcb == NULL) || (inp == NULL)) {
break;
@@ -1892,7 +1773,7 @@ sctp_timeout_handler(void *t)
/* Can we free it yet? */
SCTP_INP_DECR_REF(inp);
sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_1);
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
so = SCTP_INP_SO(inp);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -1901,7 +1782,7 @@ sctp_timeout_handler(void *t)
atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_2);
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
/*
@@ -1929,7 +1810,7 @@ sctp_timeout_handler(void *t)
SCTPDBG(SCTP_DEBUG_TIMER1, "sctp_timeout_handler:unknown timer %d\n",
tmr->type);
break;
- };
+ }
#ifdef SCTP_AUDITING_ENABLED
sctp_audit_log(0xF1, (uint8_t) tmr->type);
if (inp)
@@ -1963,14 +1844,12 @@ void
sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct sctp_nets *net)
{
- int to_ticks;
+ uint32_t to_ticks;
struct sctp_timer *tmr;
if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL))
return;
- to_ticks = 0;
-
tmr = NULL;
if (stcb) {
SCTP_TCB_LOCK_ASSERT(stcb);
@@ -2050,71 +1929,38 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
* though we use a different timer. We also add the HB timer
* PLUS a random jitter.
*/
- if ((inp == NULL) || (stcb == NULL)) {
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL)) {
return;
} else {
uint32_t rndval;
- uint8_t this_random;
- int cnt_of_unconf = 0;
- struct sctp_nets *lnet;
-
- TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
- if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) &&
- (lnet->dest_state & SCTP_ADDR_REACHABLE)) {
- cnt_of_unconf++;
- }
- }
- if (cnt_of_unconf) {
- net = lnet = NULL;
- (void)sctp_heartbeat_timer(inp, stcb, lnet, cnt_of_unconf);
- }
- if (stcb->asoc.hb_random_idx > 3) {
- rndval = sctp_select_initial_TSN(&inp->sctp_ep);
- memcpy(stcb->asoc.hb_random_values, &rndval,
- sizeof(stcb->asoc.hb_random_values));
- stcb->asoc.hb_random_idx = 0;
- }
- this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx];
- stcb->asoc.hb_random_idx++;
- stcb->asoc.hb_ect_randombit = 0;
- /*
- * this_random will be 0 - 256 ms RTO is in ms.
- */
- if ((stcb->asoc.hb_is_disabled) &&
- (cnt_of_unconf == 0)) {
+ uint32_t jitter;
+
+ if ((net->dest_state & SCTP_ADDR_NOHB) &&
+ !(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
return;
}
- if (net) {
- int delay;
-
- delay = stcb->asoc.heart_beat_delay;
- TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
- if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) &&
- ((lnet->dest_state & SCTP_ADDR_OUT_OF_SCOPE) == 0) &&
- (lnet->dest_state & SCTP_ADDR_REACHABLE)) {
- delay = 0;
- }
- }
- if (net->RTO == 0) {
- /* Never been checked */
- to_ticks = this_random + stcb->asoc.initial_rto + delay;
- } else {
- /* set rto_val to the ms */
- to_ticks = delay + net->RTO + this_random;
- }
+ if (net->RTO == 0) {
+ to_ticks = stcb->asoc.initial_rto;
} else {
- if (cnt_of_unconf) {
- to_ticks = this_random + stcb->asoc.initial_rto;
- } else {
- to_ticks = stcb->asoc.heart_beat_delay + this_random + stcb->asoc.initial_rto;
- }
+ to_ticks = net->RTO;
+ }
+ rndval = sctp_select_initial_TSN(&inp->sctp_ep);
+ jitter = rndval % to_ticks;
+ if (jitter >= (to_ticks >> 1)) {
+ to_ticks = to_ticks + (jitter - (to_ticks >> 1));
+ } else {
+ to_ticks = to_ticks - jitter;
+ }
+ if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
+ !(net->dest_state & SCTP_ADDR_PF)) {
+ to_ticks += net->heart_beat_delay;
}
/*
* Now we must convert the to_ticks that are now in
* ms to ticks.
*/
to_ticks = MSEC_TO_TICKS(to_ticks);
- tmr = &stcb->asoc.hb_timer;
+ tmr = &net->hb_timer;
}
break;
case SCTP_TIMER_TYPE_COOKIE:
@@ -2174,6 +2020,9 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
if (net == NULL) {
return;
}
+ if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
+ return;
+ }
to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_PMTU];
tmr = &net->pmtu_timer;
break;
@@ -2215,35 +2064,6 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
}
tmr = &stcb->asoc.strreset_timer;
break;
-
- case SCTP_TIMER_TYPE_EARLYFR:
- {
- unsigned int msec;
-
- if ((stcb == NULL) || (net == NULL)) {
- return;
- }
- if (net->flight_size > net->cwnd) {
- /* no need to start */
- return;
- }
- SCTP_STAT_INCR(sctps_earlyfrstart);
- if (net->lastsa == 0) {
- /* Hmm no rtt estimate yet? */
- msec = stcb->asoc.initial_rto >> 2;
- } else {
- msec = ((net->lastsa >> 2) + net->lastsv) >> 1;
- }
- if (msec < SCTP_BASE_SYSCTL(sctp_early_fr_msec)) {
- msec = SCTP_BASE_SYSCTL(sctp_early_fr_msec);
- if (msec < SCTP_MINFR_MSEC_FLOOR) {
- msec = SCTP_MINFR_MSEC_FLOOR;
- }
- }
- to_ticks = MSEC_TO_TICKS(msec);
- tmr = &net->fr_timer;
- }
- break;
case SCTP_TIMER_TYPE_ASCONF:
/*
* Here the timer comes from the stcb but its value is from
@@ -2285,10 +2105,10 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
__FUNCTION__, t_type);
return;
break;
- };
+ }
if ((to_ticks <= 0) || (tmr == NULL)) {
SCTPDBG(SCTP_DEBUG_TIMER1, "%s: %d:software error to_ticks:%d tmr:%p not set ??\n",
- __FUNCTION__, t_type, to_ticks, tmr);
+ __FUNCTION__, t_type, to_ticks, (void *)tmr);
return;
}
if (SCTP_OS_TIMER_PENDING(&tmr->timer)) {
@@ -2338,13 +2158,6 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
case SCTP_TIMER_TYPE_ADDR_WQ:
tmr = &SCTP_BASE_INFO(addr_wq_timer);
break;
- case SCTP_TIMER_TYPE_EARLYFR:
- if ((stcb == NULL) || (net == NULL)) {
- return;
- }
- tmr = &net->fr_timer;
- SCTP_STAT_INCR(sctps_earlyfrstop);
- break;
case SCTP_TIMER_TYPE_SEND:
if ((stcb == NULL) || (net == NULL)) {
return;
@@ -2370,10 +2183,10 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
tmr = &net->rxt_timer;
break;
case SCTP_TIMER_TYPE_HEARTBEAT:
- if (stcb == NULL) {
+ if ((stcb == NULL) || (net == NULL)) {
return;
}
- tmr = &stcb->asoc.hb_timer;
+ tmr = &net->hb_timer;
break;
case SCTP_TIMER_TYPE_COOKIE:
if ((stcb == NULL) || (net == NULL)) {
@@ -2453,7 +2266,7 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
SCTPDBG(SCTP_DEBUG_TIMER1, "%s: Unknown timer type %d\n",
__FUNCTION__, t_type);
break;
- };
+ }
if (tmr == NULL) {
return;
}
@@ -2528,20 +2341,20 @@ sctp_mtu_size_reset(struct sctp_inpcb *inp,
* given an association and starting time of the current RTT period return
* RTO in number of msecs net should point to the current network
*/
+
uint32_t
sctp_calculate_rto(struct sctp_tcb *stcb,
struct sctp_association *asoc,
struct sctp_nets *net,
struct timeval *told,
- int safe)
+ int safe, int rtt_from_sack)
{
/*-
* given an association and the starting time of the current RTT
* period (in value1/value2) return RTO in number of msecs.
*/
- int calc_time = 0;
- int o_calctime;
- uint32_t new_rto = 0;
+ int32_t rtt; /* RTT in ms */
+ uint32_t new_rto;
int first_measure = 0;
struct timeval now, then, *old;
@@ -2560,81 +2373,72 @@ sctp_calculate_rto(struct sctp_tcb *stcb,
/* 1. calculate new RTT */
/************************/
/* get the current time */
- (void)SCTP_GETTIME_TIMEVAL(&now);
- /* compute the RTT value */
- if ((u_long)now.tv_sec > (u_long)old->tv_sec) {
- calc_time = ((u_long)now.tv_sec - (u_long)old->tv_sec) * 1000;
- if ((u_long)now.tv_usec > (u_long)old->tv_usec) {
- calc_time += (((u_long)now.tv_usec -
- (u_long)old->tv_usec) / 1000);
- } else if ((u_long)now.tv_usec < (u_long)old->tv_usec) {
- /* Borrow 1,000ms from current calculation */
- calc_time -= 1000;
- /* Add in the slop over */
- calc_time += ((int)now.tv_usec / 1000);
- /* Add in the pre-second ms's */
- calc_time += (((int)1000000 - (int)old->tv_usec) / 1000);
- }
- } else if ((u_long)now.tv_sec == (u_long)old->tv_sec) {
- if ((u_long)now.tv_usec > (u_long)old->tv_usec) {
- calc_time = ((u_long)now.tv_usec -
- (u_long)old->tv_usec) / 1000;
- } else if ((u_long)now.tv_usec < (u_long)old->tv_usec) {
- /* impossible .. garbage in nothing out */
- goto calc_rto;
- } else if ((u_long)now.tv_usec == (u_long)old->tv_usec) {
- /*
- * We have to have 1 usec :-D this must be the
- * loopback.
- */
- calc_time = 1;
+ if (stcb->asoc.use_precise_time) {
+ (void)SCTP_GETPTIME_TIMEVAL(&now);
+ } else {
+ (void)SCTP_GETTIME_TIMEVAL(&now);
+ }
+ timevalsub(&now, old);
+ /* store the current RTT in us */
+ net->rtt = (uint64_t) 1000000 *(uint64_t) now.tv_sec +
+ (uint64_t) now.tv_usec;
+
+ /* computer rtt in ms */
+ rtt = net->rtt / 1000;
+ if ((asoc->cc_functions.sctp_rtt_calculated) && (rtt_from_sack == SCTP_RTT_FROM_DATA)) {
+ /*
+ * Tell the CC module that a new update has just occurred
+ * from a sack
+ */
+ (*asoc->cc_functions.sctp_rtt_calculated) (stcb, net, &now);
+ }
+ /*
+ * Do we need to determine the lan? We do this only on sacks i.e.
+ * RTT being determined from data not non-data (HB/INIT->INITACK).
+ */
+ if ((rtt_from_sack == SCTP_RTT_FROM_DATA) &&
+ (net->lan_type == SCTP_LAN_UNKNOWN)) {
+ if (net->rtt > SCTP_LOCAL_LAN_RTT) {
+ net->lan_type = SCTP_LAN_INTERNET;
} else {
- /* impossible .. garbage in nothing out */
- goto calc_rto;
+ net->lan_type = SCTP_LAN_LOCAL;
}
- } else {
- /* Clock wrapped? */
- goto calc_rto;
}
/***************************/
/* 2. update RTTVAR & SRTT */
/***************************/
- net->rtt = o_calctime = calc_time;
- /* this is Van Jacobson's integer version */
+ /*-
+ * Compute the scaled average lastsa and the
+ * scaled variance lastsv as described in van Jacobson
+ * Paper "Congestion Avoidance and Control", Annex A.
+ *
+ * (net->lastsa >> SCTP_RTT_SHIFT) is the srtt
+ * (net->lastsa >> SCTP_RTT_VAR_SHIFT) is the rttvar
+ */
if (net->RTO_measured) {
- calc_time -= (net->lastsa >> SCTP_RTT_SHIFT); /* take away 1/8th when
- * shift=3 */
+ rtt -= (net->lastsa >> SCTP_RTT_SHIFT);
+ net->lastsa += rtt;
+ if (rtt < 0) {
+ rtt = -rtt;
+ }
+ rtt -= (net->lastsv >> SCTP_RTT_VAR_SHIFT);
+ net->lastsv += rtt;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) {
rto_logging(net, SCTP_LOG_RTTVAR);
}
- net->prev_rtt = o_calctime;
- net->lastsa += calc_time; /* add 7/8th into sa when
- * shift=3 */
- if (calc_time < 0) {
- calc_time = -calc_time;
- }
- calc_time -= (net->lastsv >> SCTP_RTT_VAR_SHIFT); /* take away 1/4 when
- * VAR shift=2 */
- net->lastsv += calc_time;
- if (net->lastsv == 0) {
- net->lastsv = SCTP_CLOCK_GRANULARITY;
- }
} else {
/* First RTO measurment */
net->RTO_measured = 1;
- net->lastsa = calc_time << SCTP_RTT_SHIFT; /* Multiply by 8 when
- * shift=3 */
- net->lastsv = calc_time;
- if (net->lastsv == 0) {
- net->lastsv = SCTP_CLOCK_GRANULARITY;
- }
first_measure = 1;
- net->prev_rtt = o_calctime;
+ net->lastsa = rtt << SCTP_RTT_SHIFT;
+ net->lastsv = (rtt / 2) << SCTP_RTT_VAR_SHIFT;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) {
rto_logging(net, SCTP_LOG_INITIAL_RTT);
}
}
-calc_rto:
+ if (net->lastsv == 0) {
+ net->lastsv = SCTP_CLOCK_GRANULARITY;
+ }
new_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
if ((new_rto > SCTP_SAT_NETWORK_MIN) &&
(stcb->asoc.sat_network_lockout == 0)) {
@@ -2742,8 +2546,8 @@ sctp_add_pad_tombuf(struct mbuf *m, int padlen)
tmp = sctp_get_mbuf_for_msg(padlen, 0, M_DONTWAIT, 1, MT_DATA);
if (tmp == NULL) {
/* Out of space GAK! we are in big trouble. */
- SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
- return (ENOSPC);
+ SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
+ return (ENOBUFS);
}
/* setup and insert in middle */
SCTP_BUF_LEN(tmp) = padlen;
@@ -2765,15 +2569,13 @@ sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf)
/* find the last mbuf in chain and pad it */
struct mbuf *m_at;
- m_at = m;
if (last_mbuf) {
return (sctp_add_pad_tombuf(last_mbuf, padval));
} else {
- while (m_at) {
+ for (m_at = m; m_at; m_at = SCTP_BUF_NEXT(m_at)) {
if (SCTP_BUF_NEXT(m_at) == NULL) {
return (sctp_add_pad_tombuf(m_at, padval));
}
- m_at = SCTP_BUF_NEXT(m_at);
}
}
SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT);
@@ -2781,8 +2583,8 @@ sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf)
}
static void
-sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
- uint32_t error, void *data, int so_locked
+sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
+ uint16_t error, struct sctp_abort_chunk *abort, uint8_t from_peer, int so_locked
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
SCTP_UNUSED
#endif
@@ -2791,111 +2593,134 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
struct mbuf *m_notify;
struct sctp_assoc_change *sac;
struct sctp_queued_to_read *control;
+ size_t notif_len, abort_len;
+ unsigned int i;
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
struct socket *so;
#endif
- /*
- * For TCP model AND UDP connected sockets we will send an error up
- * when an ABORT comes in.
- */
- if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
- ((event == SCTP_COMM_LOST) || (event == SCTP_CANT_STR_ASSOC))) {
- if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) {
- SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED);
- stcb->sctp_socket->so_error = ECONNREFUSED;
+ if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
+ notif_len = sizeof(struct sctp_assoc_change);
+ if (abort != NULL) {
+ abort_len = htons(abort->ch.chunk_length);
} else {
- SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
- stcb->sctp_socket->so_error = ECONNRESET;
+ abort_len = 0;
+ }
+ if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) {
+ notif_len += SCTP_ASSOC_SUPPORTS_MAX;
+ } else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) {
+ notif_len += abort_len;
+ }
+ m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_DONTWAIT, 1, MT_DATA);
+ if (m_notify == NULL) {
+ /* Retry with smaller value. */
+ notif_len = sizeof(struct sctp_assoc_change);
+ m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_DONTWAIT, 1, MT_DATA);
+ if (m_notify == NULL) {
+ goto set_error;
+ }
}
- /* Wake ANY sleepers */
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
- so = SCTP_INP_SO(stcb->sctp_ep);
- if (!so_locked) {
- atomic_add_int(&stcb->asoc.refcnt, 1);
- SCTP_TCB_UNLOCK(stcb);
- SCTP_SOCKET_LOCK(so, 1);
- SCTP_TCB_LOCK(stcb);
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
- if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
- SCTP_SOCKET_UNLOCK(so, 1);
- return;
+ SCTP_BUF_NEXT(m_notify) = NULL;
+ sac = mtod(m_notify, struct sctp_assoc_change *);
+ sac->sac_type = SCTP_ASSOC_CHANGE;
+ sac->sac_flags = 0;
+ sac->sac_length = sizeof(struct sctp_assoc_change);
+ sac->sac_state = state;
+ sac->sac_error = error;
+ /* XXX verify these stream counts */
+ sac->sac_outbound_streams = stcb->asoc.streamoutcnt;
+ sac->sac_inbound_streams = stcb->asoc.streamincnt;
+ sac->sac_assoc_id = sctp_get_associd(stcb);
+ if (notif_len > sizeof(struct sctp_assoc_change)) {
+ if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) {
+ i = 0;
+ if (stcb->asoc.peer_supports_prsctp) {
+ sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_PR;
+ }
+ if (stcb->asoc.peer_supports_auth) {
+ sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_AUTH;
+ }
+ if (stcb->asoc.peer_supports_asconf) {
+ sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_ASCONF;
+ }
+ sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_MULTIBUF;
+ if (stcb->asoc.peer_supports_strreset) {
+ sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_RE_CONFIG;
+ }
+ sac->sac_length += i;
+ } else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) {
+ memcpy(sac->sac_info, abort, abort_len);
+ sac->sac_length += abort_len;
}
}
-#endif
- socantrcvmore(stcb->sctp_socket);
- sorwakeup(stcb->sctp_socket);
- sowwakeup(stcb->sctp_socket);
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
- if (!so_locked) {
- SCTP_SOCKET_UNLOCK(so, 1);
+ SCTP_BUF_LEN(m_notify) = sac->sac_length;
+ control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
+ 0, 0, stcb->asoc.context, 0, 0, 0,
+ m_notify);
+ if (control != NULL) {
+ control->length = SCTP_BUF_LEN(m_notify);
+ /* not that we need this */
+ control->tail_mbuf = m_notify;
+ control->spec_flags = M_NOTIFICATION;
+ sctp_add_to_readq(stcb->sctp_ep, stcb,
+ control,
+ &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD,
+ so_locked);
+ } else {
+ sctp_m_freem(m_notify);
}
-#endif
- }
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
- /* event not enabled */
- return;
- }
- m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_assoc_change), 0, M_DONTWAIT, 1, MT_DATA);
- if (m_notify == NULL)
- /* no space left */
- return;
- SCTP_BUF_LEN(m_notify) = 0;
-
- sac = mtod(m_notify, struct sctp_assoc_change *);
- sac->sac_type = SCTP_ASSOC_CHANGE;
- sac->sac_flags = 0;
- sac->sac_length = sizeof(struct sctp_assoc_change);
- sac->sac_state = event;
- sac->sac_error = error;
- /* XXX verify these stream counts */
- sac->sac_outbound_streams = stcb->asoc.streamoutcnt;
- sac->sac_inbound_streams = stcb->asoc.streamincnt;
- sac->sac_assoc_id = sctp_get_associd(stcb);
- SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_assoc_change);
- SCTP_BUF_NEXT(m_notify) = NULL;
- control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
- 0, 0, 0, 0, 0, 0,
- m_notify);
- if (control == NULL) {
- /* no memory */
- sctp_m_freem(m_notify);
- return;
}
- control->length = SCTP_BUF_LEN(m_notify);
- /* not that we need this */
- control->tail_mbuf = m_notify;
- control->spec_flags = M_NOTIFICATION;
- sctp_add_to_readq(stcb->sctp_ep, stcb,
- control,
- &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD,
- so_locked);
- if (event == SCTP_COMM_LOST) {
- /* Wake up any sleeper */
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
- so = SCTP_INP_SO(stcb->sctp_ep);
- if (!so_locked) {
- atomic_add_int(&stcb->asoc.refcnt, 1);
- SCTP_TCB_UNLOCK(stcb);
- SCTP_SOCKET_LOCK(so, 1);
- SCTP_TCB_LOCK(stcb);
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
- if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
- SCTP_SOCKET_UNLOCK(so, 1);
- return;
+ /*
+ * For 1-to-1 style sockets, we send up and error when an ABORT
+ * comes in.
+ */
+set_error:
+ if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
+ (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
+ ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) {
+ SOCK_LOCK(stcb->sctp_socket);
+ if (from_peer) {
+ if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED);
+ stcb->sctp_socket->so_error = ECONNREFUSED;
+ } else {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
+ stcb->sctp_socket->so_error = ECONNRESET;
}
+ } else {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNABORTED);
+ stcb->sctp_socket->so_error = ECONNABORTED;
}
-#endif
- sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
- if (!so_locked) {
+ }
+ /* Wake ANY sleepers */
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ if (!so_locked) {
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
SCTP_SOCKET_UNLOCK(so, 1);
+ return;
}
+ }
#endif
+ if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
+ (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
+ ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) {
+ socantrcvmore_locked(stcb->sctp_socket);
+ }
+ sorwakeup(stcb->sctp_socket);
+ sowwakeup(stcb->sctp_socket);
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (!so_locked) {
+ SCTP_SOCKET_UNLOCK(so, 1);
}
+#endif
}
static void
@@ -2906,7 +2731,8 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
struct sctp_paddr_change *spc;
struct sctp_queued_to_read *control;
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVPADDREVNT)) {
+ if ((stcb == NULL) ||
+ sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT)) {
/* event not enabled */
return;
}
@@ -2919,9 +2745,11 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
spc->spc_flags = 0;
spc->spc_length = sizeof(struct sctp_paddr_change);
switch (sa->sa_family) {
+#ifdef INET
case AF_INET:
memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in));
break;
+#endif
#ifdef INET6
case AF_INET6:
{
@@ -2955,7 +2783,7 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
/* append to socket */
control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
- 0, 0, 0, 0, 0, 0,
+ 0, 0, stcb->asoc.context, 0, 0, 0,
m_notify);
if (control == NULL) {
/* no memory */
@@ -2975,7 +2803,7 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
static void
-sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
+sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error,
struct sctp_tmit_chunk *chk, int so_locked
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
SCTP_UNUSED
@@ -2984,38 +2812,68 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
{
struct mbuf *m_notify;
struct sctp_send_failed *ssf;
+ struct sctp_send_failed_event *ssfe;
struct sctp_queued_to_read *control;
int length;
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) {
+ if ((stcb == NULL) ||
+ (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) &&
+ sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) {
/* event not enabled */
return;
}
- m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_send_failed), 0, M_DONTWAIT, 1, MT_DATA);
+ if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
+ length = sizeof(struct sctp_send_failed_event);
+ } else {
+ length = sizeof(struct sctp_send_failed);
+ }
+ m_notify = sctp_get_mbuf_for_msg(length, 0, M_DONTWAIT, 1, MT_DATA);
if (m_notify == NULL)
/* no space left */
return;
- length = sizeof(struct sctp_send_failed) + chk->send_size;
+ length += chk->send_size;
length -= sizeof(struct sctp_data_chunk);
SCTP_BUF_LEN(m_notify) = 0;
- ssf = mtod(m_notify, struct sctp_send_failed *);
- ssf->ssf_type = SCTP_SEND_FAILED;
- if (error == SCTP_NOTIFY_DATAGRAM_UNSENT)
- ssf->ssf_flags = SCTP_DATA_UNSENT;
- else
- ssf->ssf_flags = SCTP_DATA_SENT;
- ssf->ssf_length = length;
- ssf->ssf_error = error;
- /* not exactly what the user sent in, but should be close :) */
- bzero(&ssf->ssf_info, sizeof(ssf->ssf_info));
- ssf->ssf_info.sinfo_stream = chk->rec.data.stream_number;
- ssf->ssf_info.sinfo_ssn = chk->rec.data.stream_seq;
- ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags;
- ssf->ssf_info.sinfo_ppid = chk->rec.data.payloadtype;
- ssf->ssf_info.sinfo_context = chk->rec.data.context;
- ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
- ssf->ssf_assoc_id = sctp_get_associd(stcb);
-
+ if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
+ ssfe = mtod(m_notify, struct sctp_send_failed_event *);
+ ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT;
+ if (sent) {
+ ssfe->ssfe_flags = SCTP_DATA_SENT;
+ } else {
+ ssfe->ssfe_flags = SCTP_DATA_UNSENT;
+ }
+ ssfe->ssfe_length = length;
+ ssfe->ssfe_error = error;
+ /* not exactly what the user sent in, but should be close :) */
+ bzero(&ssfe->ssfe_info, sizeof(ssfe->ssfe_info));
+ ssfe->ssfe_info.snd_sid = chk->rec.data.stream_number;
+ ssfe->ssfe_info.snd_flags = chk->rec.data.rcv_flags;
+ ssfe->ssfe_info.snd_ppid = chk->rec.data.payloadtype;
+ ssfe->ssfe_info.snd_context = chk->rec.data.context;
+ ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb);
+ ssfe->ssfe_assoc_id = sctp_get_associd(stcb);
+ SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed_event);
+ } else {
+ ssf = mtod(m_notify, struct sctp_send_failed *);
+ ssf->ssf_type = SCTP_SEND_FAILED;
+ if (sent) {
+ ssf->ssf_flags = SCTP_DATA_SENT;
+ } else {
+ ssf->ssf_flags = SCTP_DATA_UNSENT;
+ }
+ ssf->ssf_length = length;
+ ssf->ssf_error = error;
+ /* not exactly what the user sent in, but should be close :) */
+ bzero(&ssf->ssf_info, sizeof(ssf->ssf_info));
+ ssf->ssf_info.sinfo_stream = chk->rec.data.stream_number;
+ ssf->ssf_info.sinfo_ssn = chk->rec.data.stream_seq;
+ ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags;
+ ssf->ssf_info.sinfo_ppid = chk->rec.data.payloadtype;
+ ssf->ssf_info.sinfo_context = chk->rec.data.context;
+ ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
+ ssf->ssf_assoc_id = sctp_get_associd(stcb);
+ SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed);
+ }
if (chk->data) {
/*
* trim off the sctp chunk header(it should be there)
@@ -3027,7 +2885,6 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
}
}
SCTP_BUF_NEXT(m_notify) = chk->data;
- SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed);
/* Steal off the mbuf */
chk->data = NULL;
/*
@@ -3041,7 +2898,7 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
}
/* append to socket */
control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
- 0, 0, 0, 0, 0, 0,
+ 0, 0, stcb->asoc.context, 0, 0, 0,
m_notify);
if (control == NULL) {
/* no memory */
@@ -3067,42 +2924,69 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
{
struct mbuf *m_notify;
struct sctp_send_failed *ssf;
+ struct sctp_send_failed_event *ssfe;
struct sctp_queued_to_read *control;
int length;
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) {
+ if ((stcb == NULL) ||
+ (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) &&
+ sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) {
/* event not enabled */
return;
}
- length = sizeof(struct sctp_send_failed) + sp->length;
- m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_send_failed), 0, M_DONTWAIT, 1, MT_DATA);
- if (m_notify == NULL)
+ if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
+ length = sizeof(struct sctp_send_failed_event);
+ } else {
+ length = sizeof(struct sctp_send_failed);
+ }
+ m_notify = sctp_get_mbuf_for_msg(length, 0, M_DONTWAIT, 1, MT_DATA);
+ if (m_notify == NULL) {
/* no space left */
return;
+ }
+ length += sp->length;
SCTP_BUF_LEN(m_notify) = 0;
- ssf = mtod(m_notify, struct sctp_send_failed *);
- ssf->ssf_type = SCTP_SEND_FAILED;
- if (error == SCTP_NOTIFY_DATAGRAM_UNSENT)
- ssf->ssf_flags = SCTP_DATA_UNSENT;
- else
- ssf->ssf_flags = SCTP_DATA_SENT;
- ssf->ssf_length = length;
- ssf->ssf_error = error;
- /* not exactly what the user sent in, but should be close :) */
- bzero(&ssf->ssf_info, sizeof(ssf->ssf_info));
- ssf->ssf_info.sinfo_stream = sp->stream;
- ssf->ssf_info.sinfo_ssn = sp->strseq;
- if (sp->some_taken) {
- ssf->ssf_info.sinfo_flags = SCTP_DATA_LAST_FRAG;
+ if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) {
+ ssfe = mtod(m_notify, struct sctp_send_failed_event *);
+ ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT;
+ ssfe->ssfe_flags = SCTP_DATA_UNSENT;
+ ssfe->ssfe_length = length;
+ ssfe->ssfe_error = error;
+ /* not exactly what the user sent in, but should be close :) */
+ bzero(&ssfe->ssfe_info, sizeof(ssfe->ssfe_info));
+ ssfe->ssfe_info.snd_sid = sp->stream;
+ if (sp->some_taken) {
+ ssfe->ssfe_info.snd_flags = SCTP_DATA_LAST_FRAG;
+ } else {
+ ssfe->ssfe_info.snd_flags = SCTP_DATA_NOT_FRAG;
+ }
+ ssfe->ssfe_info.snd_ppid = sp->ppid;
+ ssfe->ssfe_info.snd_context = sp->context;
+ ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb);
+ ssfe->ssfe_assoc_id = sctp_get_associd(stcb);
+ SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed_event);
} else {
- ssf->ssf_info.sinfo_flags = SCTP_DATA_NOT_FRAG;
+ ssf = mtod(m_notify, struct sctp_send_failed *);
+ ssf->ssf_type = SCTP_SEND_FAILED;
+ ssf->ssf_flags = SCTP_DATA_UNSENT;
+ ssf->ssf_length = length;
+ ssf->ssf_error = error;
+ /* not exactly what the user sent in, but should be close :) */
+ bzero(&ssf->ssf_info, sizeof(ssf->ssf_info));
+ ssf->ssf_info.sinfo_stream = sp->stream;
+ ssf->ssf_info.sinfo_ssn = 0;
+ if (sp->some_taken) {
+ ssf->ssf_info.sinfo_flags = SCTP_DATA_LAST_FRAG;
+ } else {
+ ssf->ssf_info.sinfo_flags = SCTP_DATA_NOT_FRAG;
+ }
+ ssf->ssf_info.sinfo_ppid = sp->ppid;
+ ssf->ssf_info.sinfo_context = sp->context;
+ ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
+ ssf->ssf_assoc_id = sctp_get_associd(stcb);
+ SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed);
}
- ssf->ssf_info.sinfo_ppid = sp->ppid;
- ssf->ssf_info.sinfo_context = sp->context;
- ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
- ssf->ssf_assoc_id = sctp_get_associd(stcb);
SCTP_BUF_NEXT(m_notify) = sp->data;
- SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed);
/* Steal off the mbuf */
sp->data = NULL;
@@ -3117,7 +3001,7 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
}
/* append to socket */
control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
- 0, 0, 0, 0, 0, 0,
+ 0, 0, stcb->asoc.context, 0, 0, 0,
m_notify);
if (control == NULL) {
/* no memory */
@@ -3133,14 +3017,14 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
static void
-sctp_notify_adaptation_layer(struct sctp_tcb *stcb,
- uint32_t error)
+sctp_notify_adaptation_layer(struct sctp_tcb *stcb)
{
struct mbuf *m_notify;
struct sctp_adaptation_event *sai;
struct sctp_queued_to_read *control;
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) {
+ if ((stcb == NULL) ||
+ sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) {
/* event not enabled */
return;
}
@@ -3161,7 +3045,7 @@ sctp_notify_adaptation_layer(struct sctp_tcb *stcb,
/* append to socket */
control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
- 0, 0, 0, 0, 0, 0,
+ 0, 0, stcb->asoc.context, 0, 0, 0,
m_notify);
if (control == NULL) {
/* no memory */
@@ -3191,7 +3075,8 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
struct sctp_queued_to_read *control;
struct sockbuf *sb;
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_PDAPIEVNT)) {
+ if ((stcb == NULL) ||
+ sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_PDAPIEVNT)) {
/* event not enabled */
return;
}
@@ -3215,7 +3100,7 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_pdapi_event);
SCTP_BUF_NEXT(m_notify) = NULL;
control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
- 0, 0, 0, 0, 0, 0,
+ 0, 0, stcb->asoc.context, 0, 0, 0,
m_notify);
if (control == NULL) {
/* no memory */
@@ -3246,7 +3131,7 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
}
if (stcb->sctp_ep && stcb->sctp_socket) {
/* This should always be the case */
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
struct socket *so;
so = SCTP_INP_SO(stcb->sctp_ep);
@@ -3263,7 +3148,7 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
}
#endif
sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
if (!so_locked) {
SCTP_SOCKET_UNLOCK(so, 1);
}
@@ -3285,7 +3170,7 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
/* mark socket closed for read/write and wakeup! */
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
struct socket *so;
so = SCTP_INP_SO(stcb->sctp_ep);
@@ -3300,11 +3185,11 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
}
#endif
socantsendmore(stcb->sctp_socket);
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
}
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) {
+ if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) {
/* event not enabled */
return;
}
@@ -3323,7 +3208,7 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
/* append to socket */
control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
- 0, 0, 0, 0, 0, 0,
+ 0, 0, stcb->asoc.context, 0, 0, 0,
m_notify);
if (control == NULL) {
/* no memory */
@@ -3351,7 +3236,8 @@ sctp_notify_sender_dry_event(struct sctp_tcb *stcb,
struct sctp_sender_dry_event *event;
struct sctp_queued_to_read *control;
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_DRYEVNT)) {
+ if ((stcb == NULL) ||
+ sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DRYEVNT)) {
/* event not enabled */
return;
}
@@ -3372,7 +3258,8 @@ sctp_notify_sender_dry_event(struct sctp_tcb *stcb,
/* append to socket */
control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
- 0, 0, 0, 0, 0, 0, m_notify);
+ 0, 0, stcb->asoc.context, 0, 0, 0,
+ m_notify);
if (control == NULL) {
/* no memory */
sctp_m_freem(m_notify);
@@ -3387,36 +3274,99 @@ sctp_notify_sender_dry_event(struct sctp_tcb *stcb,
}
-static void
-sctp_notify_stream_reset_add(struct sctp_tcb *stcb, int number_entries, int flag)
+void
+sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t numberout, int flag)
{
struct mbuf *m_notify;
struct sctp_queued_to_read *control;
- struct sctp_stream_reset_event *strreset;
+ struct sctp_stream_change_event *stradd;
int len;
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) {
+ if ((stcb == NULL) ||
+ (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_CHANGEEVNT))) {
/* event not enabled */
return;
}
+ if ((stcb->asoc.peer_req_out) && flag) {
+ /* Peer made the request, don't tell the local user */
+ stcb->asoc.peer_req_out = 0;
+ return;
+ }
+ stcb->asoc.peer_req_out = 0;
m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA);
if (m_notify == NULL)
/* no space left */
return;
SCTP_BUF_LEN(m_notify) = 0;
- len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t));
+ len = sizeof(struct sctp_stream_change_event);
if (len > M_TRAILINGSPACE(m_notify)) {
/* never enough room */
sctp_m_freem(m_notify);
return;
}
- strreset = mtod(m_notify, struct sctp_stream_reset_event *);
- strreset->strreset_type = SCTP_STREAM_RESET_EVENT;
- strreset->strreset_flags = SCTP_STRRESET_ADD_STREAM | flag;
- strreset->strreset_length = len;
- strreset->strreset_assoc_id = sctp_get_associd(stcb);
- strreset->strreset_list[0] = number_entries;
+ stradd = mtod(m_notify, struct sctp_stream_change_event *);
+ stradd->strchange_type = SCTP_STREAM_CHANGE_EVENT;
+ stradd->strchange_flags = flag;
+ stradd->strchange_length = len;
+ stradd->strchange_assoc_id = sctp_get_associd(stcb);
+ stradd->strchange_instrms = numberin;
+ stradd->strchange_outstrms = numberout;
+ SCTP_BUF_LEN(m_notify) = len;
+ SCTP_BUF_NEXT(m_notify) = NULL;
+ if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
+ /* no space */
+ sctp_m_freem(m_notify);
+ return;
+ }
+ /* append to socket */
+ control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
+ 0, 0, stcb->asoc.context, 0, 0, 0,
+ m_notify);
+ if (control == NULL) {
+ /* no memory */
+ sctp_m_freem(m_notify);
+ return;
+ }
+ control->spec_flags = M_NOTIFICATION;
+ control->length = SCTP_BUF_LEN(m_notify);
+ /* not that we need this */
+ control->tail_mbuf = m_notify;
+ sctp_add_to_readq(stcb->sctp_ep, stcb,
+ control,
+ &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
+}
+void
+sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32_t recv_tsn, int flag)
+{
+ struct mbuf *m_notify;
+ struct sctp_queued_to_read *control;
+ struct sctp_assoc_reset_event *strasoc;
+ int len;
+
+ if ((stcb == NULL) ||
+ (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ASSOC_RESETEVNT))) {
+ /* event not enabled */
+ return;
+ }
+ m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA);
+ if (m_notify == NULL)
+ /* no space left */
+ return;
+ SCTP_BUF_LEN(m_notify) = 0;
+ len = sizeof(struct sctp_assoc_reset_event);
+ if (len > M_TRAILINGSPACE(m_notify)) {
+ /* never enough room */
+ sctp_m_freem(m_notify);
+ return;
+ }
+ strasoc = mtod(m_notify, struct sctp_assoc_reset_event *);
+ strasoc->assocreset_type = SCTP_ASSOC_RESET_EVENT;
+ strasoc->assocreset_flags = flag;
+ strasoc->assocreset_length = len;
+ strasoc->assocreset_assoc_id = sctp_get_associd(stcb);
+ strasoc->assocreset_local_tsn = sending_tsn;
+ strasoc->assocreset_remote_tsn = recv_tsn;
SCTP_BUF_LEN(m_notify) = len;
SCTP_BUF_NEXT(m_notify) = NULL;
if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
@@ -3426,7 +3376,7 @@ sctp_notify_stream_reset_add(struct sctp_tcb *stcb, int number_entries, int flag
}
/* append to socket */
control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
- 0, 0, 0, 0, 0, 0,
+ 0, 0, stcb->asoc.context, 0, 0, 0,
m_notify);
if (control == NULL) {
/* no memory */
@@ -3443,6 +3393,7 @@ sctp_notify_stream_reset_add(struct sctp_tcb *stcb, int number_entries, int flag
}
+
static void
sctp_notify_stream_reset(struct sctp_tcb *stcb,
int number_entries, uint16_t * list, int flag)
@@ -3452,7 +3403,8 @@ sctp_notify_stream_reset(struct sctp_tcb *stcb,
struct sctp_stream_reset_event *strreset;
int len;
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) {
+ if ((stcb == NULL) ||
+ (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT))) {
/* event not enabled */
return;
}
@@ -3469,18 +3421,14 @@ sctp_notify_stream_reset(struct sctp_tcb *stcb,
}
strreset = mtod(m_notify, struct sctp_stream_reset_event *);
strreset->strreset_type = SCTP_STREAM_RESET_EVENT;
- if (number_entries == 0) {
- strreset->strreset_flags = flag | SCTP_STRRESET_ALL_STREAMS;
- } else {
- strreset->strreset_flags = flag | SCTP_STRRESET_STREAM_LIST;
- }
+ strreset->strreset_flags = flag;
strreset->strreset_length = len;
strreset->strreset_assoc_id = sctp_get_associd(stcb);
if (number_entries) {
int i;
for (i = 0; i < number_entries; i++) {
- strreset->strreset_list[i] = ntohs(list[i]);
+ strreset->strreset_stream_list[i] = ntohs(list[i]);
}
}
SCTP_BUF_LEN(m_notify) = len;
@@ -3492,7 +3440,7 @@ sctp_notify_stream_reset(struct sctp_tcb *stcb,
}
/* append to socket */
control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
- 0, 0, 0, 0, 0, 0,
+ 0, 0, stcb->asoc.context, 0, 0, 0,
m_notify);
if (control == NULL) {
/* no memory */
@@ -3509,6 +3457,63 @@ sctp_notify_stream_reset(struct sctp_tcb *stcb,
}
+static void
+sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_error_chunk *chunk)
+{
+ struct mbuf *m_notify;
+ struct sctp_remote_error *sre;
+ struct sctp_queued_to_read *control;
+ size_t notif_len, chunk_len;
+
+ if ((stcb == NULL) ||
+ sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) {
+ return;
+ }
+ if (chunk != NULL) {
+ chunk_len = htons(chunk->ch.chunk_length);
+ } else {
+ chunk_len = 0;
+ }
+ notif_len = sizeof(struct sctp_remote_error) + chunk_len;
+ m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_DONTWAIT, 1, MT_DATA);
+ if (m_notify == NULL) {
+ /* Retry with smaller value. */
+ notif_len = sizeof(struct sctp_remote_error);
+ m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_DONTWAIT, 1, MT_DATA);
+ if (m_notify == NULL) {
+ return;
+ }
+ }
+ SCTP_BUF_NEXT(m_notify) = NULL;
+ sre = mtod(m_notify, struct sctp_remote_error *);
+ sre->sre_type = SCTP_REMOTE_ERROR;
+ sre->sre_flags = 0;
+ sre->sre_length = sizeof(struct sctp_remote_error);
+ sre->sre_error = error;
+ sre->sre_assoc_id = sctp_get_associd(stcb);
+ if (notif_len > sizeof(struct sctp_remote_error)) {
+ memcpy(sre->sre_data, chunk, chunk_len);
+ sre->sre_length += chunk_len;
+ }
+ SCTP_BUF_LEN(m_notify) = sre->sre_length;
+ control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
+ 0, 0, stcb->asoc.context, 0, 0, 0,
+ m_notify);
+ if (control != NULL) {
+ control->length = SCTP_BUF_LEN(m_notify);
+ /* not that we need this */
+ control->tail_mbuf = m_notify;
+ control->spec_flags = M_NOTIFICATION;
+ sctp_add_to_readq(stcb->sctp_ep, stcb,
+ control,
+ &stcb->sctp_socket->so_rcv, 1,
+ SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
+ } else {
+ sctp_m_freem(m_notify);
+ }
+}
+
+
void
sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
uint32_t error, void *data, int so_locked
@@ -3539,11 +3544,11 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
switch (notification) {
case SCTP_NOTIFY_ASSOC_UP:
if (stcb->asoc.assoc_up_sent == 0) {
- sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL, so_locked);
+ sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL, 0, so_locked);
stcb->asoc.assoc_up_sent = 1;
}
if (stcb->asoc.adaptation_needed && (stcb->asoc.adaptation_sent == 0)) {
- sctp_notify_adaptation_layer(stcb, error);
+ sctp_notify_adaptation_layer(stcb);
}
if (stcb->asoc.peer_supports_auth == 0) {
sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0,
@@ -3551,7 +3556,7 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
}
break;
case SCTP_NOTIFY_ASSOC_DOWN:
- sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL, so_locked);
+ sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL, 0, so_locked);
break;
case SCTP_NOTIFY_INTERFACE_DOWN:
{
@@ -3584,8 +3589,12 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
sctp_notify_send_failed2(stcb, error,
(struct sctp_stream_queue_pending *)data, so_locked);
break;
- case SCTP_NOTIFY_DG_FAIL:
- sctp_notify_send_failed(stcb, error,
+ case SCTP_NOTIFY_SENT_DG_FAIL:
+ sctp_notify_send_failed(stcb, 1, error,
+ (struct sctp_tmit_chunk *)data, so_locked);
+ break;
+ case SCTP_NOTIFY_UNSENT_DG_FAIL:
+ sctp_notify_send_failed(stcb, 0, error,
(struct sctp_tmit_chunk *)data, so_locked);
break;
case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION:
@@ -3597,50 +3606,50 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
sctp_notify_partial_delivery_indication(stcb, error, val, so_locked);
break;
}
- case SCTP_NOTIFY_STRDATA_ERR:
- break;
- case SCTP_NOTIFY_ASSOC_ABORTED:
+ case SCTP_NOTIFY_ASSOC_LOC_ABORTED:
if ((stcb) && (((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_WAIT) ||
((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_ECHOED))) {
- sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, NULL, so_locked);
+ sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 0, so_locked);
} else {
- sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, NULL, so_locked);
+ sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 0, so_locked);
}
break;
- case SCTP_NOTIFY_PEER_OPENED_STREAM:
- break;
- case SCTP_NOTIFY_STREAM_OPENED_OK:
+ case SCTP_NOTIFY_ASSOC_REM_ABORTED:
+ if ((stcb) && (((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_WAIT) ||
+ ((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_ECHOED))) {
+ sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 1, so_locked);
+ } else {
+ sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 1, so_locked);
+ }
break;
case SCTP_NOTIFY_ASSOC_RESTART:
- sctp_notify_assoc_change(SCTP_RESTART, stcb, error, data, so_locked);
+ sctp_notify_assoc_change(SCTP_RESTART, stcb, error, NULL, 0, so_locked);
if (stcb->asoc.peer_supports_auth == 0) {
sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0,
NULL, so_locked);
}
break;
- case SCTP_NOTIFY_HB_RESP:
- break;
- case SCTP_NOTIFY_STR_RESET_INSTREAM_ADD_OK:
- sctp_notify_stream_reset_add(stcb, error, SCTP_STRRESET_INBOUND_STR);
- break;
- case SCTP_NOTIFY_STR_RESET_ADD_OK:
- sctp_notify_stream_reset_add(stcb, error, SCTP_STRRESET_OUTBOUND_STR);
- break;
- case SCTP_NOTIFY_STR_RESET_ADD_FAIL:
- sctp_notify_stream_reset_add(stcb, error, (SCTP_STRRESET_FAILED | SCTP_STRRESET_OUTBOUND_STR));
- break;
-
case SCTP_NOTIFY_STR_RESET_SEND:
- sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STRRESET_OUTBOUND_STR);
+ sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STREAM_RESET_OUTGOING_SSN);
break;
case SCTP_NOTIFY_STR_RESET_RECV:
- sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STRRESET_INBOUND_STR);
+ sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STREAM_RESET_INCOMING);
break;
case SCTP_NOTIFY_STR_RESET_FAILED_OUT:
- sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), (SCTP_STRRESET_OUTBOUND_STR | SCTP_STRRESET_FAILED));
+ sctp_notify_stream_reset(stcb, error, ((uint16_t *) data),
+ (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_FAILED));
+ break;
+ case SCTP_NOTIFY_STR_RESET_DENIED_OUT:
+ sctp_notify_stream_reset(stcb, error, ((uint16_t *) data),
+ (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_DENIED));
break;
case SCTP_NOTIFY_STR_RESET_FAILED_IN:
- sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), (SCTP_STRRESET_INBOUND_STR | SCTP_STRRESET_FAILED));
+ sctp_notify_stream_reset(stcb, error, ((uint16_t *) data),
+ (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_FAILED));
+ break;
+ case SCTP_NOTIFY_STR_RESET_DENIED_IN:
+ sctp_notify_stream_reset(stcb, error, ((uint16_t *) data),
+ (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_DENIED));
break;
case SCTP_NOTIFY_ASCONF_ADD_IP:
sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data,
@@ -3654,15 +3663,11 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
sctp_notify_peer_addr_change(stcb, SCTP_ADDR_MADE_PRIM, data,
error);
break;
- case SCTP_NOTIFY_ASCONF_SUCCESS:
- break;
- case SCTP_NOTIFY_ASCONF_FAILED:
- break;
case SCTP_NOTIFY_PEER_SHUTDOWN:
sctp_notify_shutdown_event(stcb);
break;
case SCTP_NOTIFY_AUTH_NEW_KEY:
- sctp_notify_authentication(stcb, SCTP_AUTH_NEWKEY, error,
+ sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY, error,
(uint16_t) (uintptr_t) data,
so_locked);
break;
@@ -3679,6 +3684,9 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
case SCTP_NOTIFY_SENDER_DRY:
sctp_notify_sender_dry_event(stcb, so_locked);
break;
+ case SCTP_NOTIFY_REMOTE_ERROR:
+ sctp_notify_remote_error(stcb, error, data);
+ break;
default:
SCTPDBG(SCTP_DEBUG_UTIL1, "%s: unknown notification %xh (%u)\n",
__FUNCTION__, notification, notification);
@@ -3687,7 +3695,7 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
}
void
-sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked
+sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock, int so_locked
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
SCTP_UNUSED
#endif
@@ -3695,22 +3703,21 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked
{
struct sctp_association *asoc;
struct sctp_stream_out *outs;
- struct sctp_tmit_chunk *chk;
- struct sctp_stream_queue_pending *sp;
+ struct sctp_tmit_chunk *chk, *nchk;
+ struct sctp_stream_queue_pending *sp, *nsp;
int i;
- asoc = &stcb->asoc;
-
if (stcb == NULL) {
return;
}
- if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ asoc = &stcb->asoc;
+ if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) {
/* already being freed */
return;
}
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
- (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) {
+ (asoc->state & SCTP_STATE_CLOSED_SOCKET)) {
return;
}
/* now through all the gunk freeing chunks */
@@ -3718,61 +3725,70 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked
SCTP_TCB_SEND_LOCK(stcb);
}
/* sent queue SHOULD be empty */
- if (!TAILQ_EMPTY(&asoc->sent_queue)) {
- chk = TAILQ_FIRST(&asoc->sent_queue);
- while (chk) {
- TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
- asoc->sent_queue_cnt--;
- if (chk->data != NULL) {
- sctp_free_bufspace(stcb, asoc, chk, 1);
- sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
- SCTP_NOTIFY_DATAGRAM_SENT, chk, so_locked);
- if (chk->data) {
- sctp_m_freem(chk->data);
- chk->data = NULL;
- }
+ TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) {
+ TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
+ asoc->sent_queue_cnt--;
+ if (chk->sent != SCTP_DATAGRAM_NR_ACKED) {
+ if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) {
+ asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--;
+#ifdef INVARIANTS
+ } else {
+ panic("No chunks on the queues for sid %u.", chk->rec.data.stream_number);
+#endif
+ }
+ }
+ if (chk->data != NULL) {
+ sctp_free_bufspace(stcb, asoc, chk, 1);
+ sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb,
+ error, chk, so_locked);
+ if (chk->data) {
+ sctp_m_freem(chk->data);
+ chk->data = NULL;
}
- sctp_free_a_chunk(stcb, chk);
- /* sa_ignore FREED_MEMORY */
- chk = TAILQ_FIRST(&asoc->sent_queue);
}
+ sctp_free_a_chunk(stcb, chk, so_locked);
+ /* sa_ignore FREED_MEMORY */
}
/* pending send queue SHOULD be empty */
- if (!TAILQ_EMPTY(&asoc->send_queue)) {
- chk = TAILQ_FIRST(&asoc->send_queue);
- while (chk) {
- TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next);
- asoc->send_queue_cnt--;
- if (chk->data != NULL) {
- sctp_free_bufspace(stcb, asoc, chk, 1);
- sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
- SCTP_NOTIFY_DATAGRAM_UNSENT, chk, so_locked);
- if (chk->data) {
- sctp_m_freem(chk->data);
- chk->data = NULL;
- }
+ TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) {
+ TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next);
+ asoc->send_queue_cnt--;
+ if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) {
+ asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--;
+#ifdef INVARIANTS
+ } else {
+ panic("No chunks on the queues for sid %u.", chk->rec.data.stream_number);
+#endif
+ }
+ if (chk->data != NULL) {
+ sctp_free_bufspace(stcb, asoc, chk, 1);
+ sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb,
+ error, chk, so_locked);
+ if (chk->data) {
+ sctp_m_freem(chk->data);
+ chk->data = NULL;
}
- sctp_free_a_chunk(stcb, chk);
- /* sa_ignore FREED_MEMORY */
- chk = TAILQ_FIRST(&asoc->send_queue);
}
+ sctp_free_a_chunk(stcb, chk, so_locked);
+ /* sa_ignore FREED_MEMORY */
}
- for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
+ for (i = 0; i < asoc->streamoutcnt; i++) {
/* For each stream */
- outs = &stcb->asoc.strmout[i];
+ outs = &asoc->strmout[i];
/* clean up any sends there */
- stcb->asoc.locked_on_sending = NULL;
- sp = TAILQ_FIRST(&outs->outqueue);
- while (sp) {
- stcb->asoc.stream_queue_cnt--;
+ asoc->locked_on_sending = NULL;
+ TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) {
+ asoc->stream_queue_cnt--;
TAILQ_REMOVE(&outs->outqueue, sp, next);
sctp_free_spbufspace(stcb, asoc, sp);
if (sp->data) {
sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb,
- SCTP_NOTIFY_DATAGRAM_UNSENT, (void *)sp, so_locked);
+ error, (void *)sp, so_locked);
if (sp->data) {
sctp_m_freem(sp->data);
sp->data = NULL;
+ sp->tail_mbuf = NULL;
+ sp->length = 0;
}
}
if (sp->net) {
@@ -3780,9 +3796,8 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked
sp->net = NULL;
}
/* Free the chunk */
- sctp_free_a_strmoq(stcb, sp);
+ sctp_free_a_strmoq(stcb, sp, so_locked);
/* sa_ignore FREED_MEMORY */
- sp = TAILQ_FIRST(&outs->outqueue);
}
}
@@ -3792,39 +3807,46 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked
}
void
-sctp_abort_notification(struct sctp_tcb *stcb, int error, int so_locked
+sctp_abort_notification(struct sctp_tcb *stcb, uint8_t from_peer, uint16_t error,
+ struct sctp_abort_chunk *abort, int so_locked
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
SCTP_UNUSED
#endif
)
{
-
if (stcb == NULL) {
return;
}
+ if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
+ ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
+ (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) {
+ stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_WAS_ABORTED;
+ }
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
(stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) {
return;
}
/* Tell them we lost the asoc */
- sctp_report_all_outbound(stcb, 1, so_locked);
- if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
- (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) {
- stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_WAS_ABORTED;
+ sctp_report_all_outbound(stcb, error, 1, so_locked);
+ if (from_peer) {
+ sctp_ulp_notify(SCTP_NOTIFY_ASSOC_REM_ABORTED, stcb, error, abort, so_locked);
+ } else {
+ sctp_ulp_notify(SCTP_NOTIFY_ASSOC_LOC_ABORTED, stcb, error, abort, so_locked);
}
- sctp_ulp_notify(SCTP_NOTIFY_ASSOC_ABORTED, stcb, error, NULL, so_locked);
}
void
sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
- struct mbuf *m, int iphlen, struct sctphdr *sh, struct mbuf *op_err,
+ struct mbuf *m, int iphlen,
+ struct sockaddr *src, struct sockaddr *dst,
+ struct sctphdr *sh, struct mbuf *op_err,
+ uint8_t use_mflowid, uint32_t mflowid,
uint32_t vrf_id, uint16_t port)
{
uint32_t vtag;
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
struct socket *so;
#endif
@@ -3833,15 +3855,17 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
if (stcb != NULL) {
/* We have a TCB to abort, send notification too */
vtag = stcb->asoc.peer_vtag;
- sctp_abort_notification(stcb, 0, SCTP_SO_NOT_LOCKED);
+ sctp_abort_notification(stcb, 0, 0, NULL, SCTP_SO_NOT_LOCKED);
/* get the assoc vrf id and table id */
vrf_id = stcb->asoc.vrf_id;
stcb->asoc.state |= SCTP_STATE_WAS_ABORTED;
}
- sctp_send_abort(m, iphlen, sh, vtag, op_err, vrf_id, port);
+ sctp_send_abort(m, iphlen, src, dst, sh, vtag, op_err,
+ use_mflowid, mflowid,
+ vrf_id, port);
if (stcb != NULL) {
/* Ok, now lets free it */
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
so = SCTP_INP_SO(inp);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -3855,7 +3879,7 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
}
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_4);
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
}
@@ -3927,21 +3951,19 @@ none_in:
void
sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
- int error, struct mbuf *op_err,
+ struct mbuf *op_err,
int so_locked
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
SCTP_UNUSED
#endif
)
{
- uint32_t vtag;
-
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
struct socket *so;
#endif
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
so = SCTP_INP_SO(inp);
#endif
if (stcb == NULL) {
@@ -3956,14 +3978,11 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
} else {
stcb->asoc.state |= SCTP_STATE_WAS_ABORTED;
}
- vtag = stcb->asoc.peer_vtag;
/* notify the ulp */
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0)
- sctp_abort_notification(stcb, error, so_locked);
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
+ sctp_abort_notification(stcb, 0, 0, NULL, so_locked);
+ }
/* notify the peer */
-#if defined(SCTP_PANIC_ON_ABORT)
- panic("aborting an association");
-#endif
sctp_send_abort_tcb(stcb, op_err, so_locked);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
@@ -3974,7 +3993,7 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
#ifdef SCTP_ASOCLOG_OF_TSNS
sctp_print_out_track_log(stcb);
#endif
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
if (!so_locked) {
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -3984,7 +4003,7 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
}
#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_5);
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
if (!so_locked) {
SCTP_SOCKET_UNLOCK(so, 1);
}
@@ -3992,11 +4011,15 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
}
void
-sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
- struct sctp_inpcb *inp, struct mbuf *op_err, uint32_t vrf_id, uint16_t port)
+sctp_handle_ootb(struct mbuf *m, int iphlen, int offset,
+ struct sockaddr *src, struct sockaddr *dst,
+ struct sctphdr *sh, struct sctp_inpcb *inp,
+ uint8_t use_mflowid, uint32_t mflowid,
+ uint32_t vrf_id, uint16_t port)
{
struct sctp_chunkhdr *ch, chunk_buf;
unsigned int chk_length;
+ int contains_init_chunk;
SCTP_STAT_INCR_COUNTER32(sctps_outoftheblue);
/* Generate a TO address for future reference */
@@ -4006,6 +4029,7 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
SCTP_CALLED_DIRECTLY_NOCMPSET);
}
}
+ contains_init_chunk = 0;
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
sizeof(*ch), (uint8_t *) & chunk_buf);
while (ch != NULL) {
@@ -4015,6 +4039,9 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
break;
}
switch (ch->chunk_type) {
+ case SCTP_INIT:
+ contains_init_chunk = 1;
+ break;
case SCTP_COOKIE_ECHO:
/* We hit here only if the assoc is being freed */
return;
@@ -4031,7 +4058,9 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
*/
return;
case SCTP_SHUTDOWN_ACK:
- sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id, port);
+ sctp_send_shutdown_complete2(src, dst, sh,
+ use_mflowid, mflowid,
+ vrf_id, port);
return;
default:
break;
@@ -4040,7 +4069,13 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
sizeof(*ch), (uint8_t *) & chunk_buf);
}
- sctp_send_abort(m, iphlen, sh, 0, op_err, vrf_id, port);
+ if ((SCTP_BASE_SYSCTL(sctp_blackhole) == 0) ||
+ ((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) &&
+ (contains_init_chunk == 0))) {
+ sctp_send_abort(m, iphlen, src, dst, sh, 0, NULL,
+ use_mflowid, mflowid,
+ vrf_id, port);
+ }
}
/*
@@ -4170,6 +4205,7 @@ sctp_cmpaddr(struct sockaddr *sa1, struct sockaddr *sa2)
sin6_2));
}
#endif
+#ifdef INET
case AF_INET:
{
/* IPv4 addresses */
@@ -4179,6 +4215,7 @@ sctp_cmpaddr(struct sockaddr *sa1, struct sockaddr *sa2)
sin_2 = (struct sockaddr_in *)sa2;
return (sin_1->sin_addr.s_addr == sin_2->sin_addr.s_addr);
}
+#endif
default:
/* we don't do these... */
return (0);
@@ -4191,7 +4228,6 @@ sctp_print_address(struct sockaddr *sa)
#ifdef INET6
char ip6buf[INET6_ADDRSTRLEN];
- ip6buf[0] = 0;
#endif
switch (sa->sa_family) {
@@ -4208,6 +4244,7 @@ sctp_print_address(struct sockaddr *sa)
break;
}
#endif
+#ifdef INET
case AF_INET:
{
struct sockaddr_in *sin;
@@ -4219,62 +4256,9 @@ sctp_print_address(struct sockaddr *sa)
p[0], p[1], p[2], p[3], ntohs(sin->sin_port));
break;
}
- default:
- SCTP_PRINTF("?\n");
- break;
- }
-}
-
-void
-sctp_print_address_pkt(struct ip *iph, struct sctphdr *sh)
-{
- switch (iph->ip_v) {
- case IPVERSION:
- {
- struct sockaddr_in lsa, fsa;
-
- bzero(&lsa, sizeof(lsa));
- lsa.sin_len = sizeof(lsa);
- lsa.sin_family = AF_INET;
- lsa.sin_addr = iph->ip_src;
- lsa.sin_port = sh->src_port;
- bzero(&fsa, sizeof(fsa));
- fsa.sin_len = sizeof(fsa);
- fsa.sin_family = AF_INET;
- fsa.sin_addr = iph->ip_dst;
- fsa.sin_port = sh->dest_port;
- SCTP_PRINTF("src: ");
- sctp_print_address((struct sockaddr *)&lsa);
- SCTP_PRINTF("dest: ");
- sctp_print_address((struct sockaddr *)&fsa);
- break;
- }
-#ifdef INET6
- case IPV6_VERSION >> 4:
- {
- struct ip6_hdr *ip6;
- struct sockaddr_in6 lsa6, fsa6;
-
- ip6 = (struct ip6_hdr *)iph;
- bzero(&lsa6, sizeof(lsa6));
- lsa6.sin6_len = sizeof(lsa6);
- lsa6.sin6_family = AF_INET6;
- lsa6.sin6_addr = ip6->ip6_src;
- lsa6.sin6_port = sh->src_port;
- bzero(&fsa6, sizeof(fsa6));
- fsa6.sin6_len = sizeof(fsa6);
- fsa6.sin6_family = AF_INET6;
- fsa6.sin6_addr = ip6->ip6_dst;
- fsa6.sin6_port = sh->dest_port;
- SCTP_PRINTF("src: ");
- sctp_print_address((struct sockaddr *)&lsa6);
- SCTP_PRINTF("dest: ");
- sctp_print_address((struct sockaddr *)&fsa6);
- break;
- }
#endif
default:
- /* TSNH */
+ SCTP_PRINTF("?\n");
break;
}
}
@@ -4313,10 +4297,8 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
}
/* lock the socket buffers */
SCTP_INP_READ_LOCK(old_inp);
- control = TAILQ_FIRST(&old_inp->read_queue);
- /* Pull off all for out target stcb */
- while (control) {
- nctl = TAILQ_NEXT(control, next);
+ TAILQ_FOREACH_SAFE(control, &old_inp->read_queue, next, nctl) {
+ /* Pull off all for out target stcb */
if (control->stcb == stcb) {
/* remove it we want it */
TAILQ_REMOVE(&old_inp->read_queue, control, next);
@@ -4333,17 +4315,14 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
m = SCTP_BUF_NEXT(m);
}
}
- control = nctl;
}
SCTP_INP_READ_UNLOCK(old_inp);
/* Remove the sb-lock on the old socket */
sbunlock(&old_so->so_rcv);
/* Now we move them over to the new socket buffer */
- control = TAILQ_FIRST(&tmp_queue);
SCTP_INP_READ_LOCK(new_inp);
- while (control) {
- nctl = TAILQ_NEXT(control, next);
+ TAILQ_FOREACH_SAFE(control, &tmp_queue, next, nctl) {
TAILQ_INSERT_TAIL(&new_inp->read_queue, control, next);
m = control->data;
while (m) {
@@ -4356,7 +4335,6 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
}
m = SCTP_BUF_NEXT(m);
}
- control = nctl;
}
SCTP_INP_READ_UNLOCK(new_inp);
}
@@ -4457,16 +4435,20 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
} else {
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
struct socket *so;
so = SCTP_INP_SO(inp);
if (!so_locked) {
- atomic_add_int(&stcb->asoc.refcnt, 1);
- SCTP_TCB_UNLOCK(stcb);
+ if (stcb) {
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ }
SCTP_SOCKET_LOCK(so, 1);
- SCTP_TCB_LOCK(stcb);
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ if (stcb) {
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ }
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
SCTP_SOCKET_UNLOCK(so, 1);
return;
@@ -4474,7 +4456,7 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
}
#endif
sctp_sorwakeup(inp, inp->sctp_socket);
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
if (!so_locked) {
SCTP_SOCKET_UNLOCK(so, 1);
}
@@ -4517,7 +4499,7 @@ get_out:
}
if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ)) {
SCTP_INP_READ_UNLOCK(inp);
- return 0;
+ return (0);
}
if (control->end_added) {
/* huh this one is complete? */
@@ -4607,22 +4589,26 @@ get_out:
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
} else {
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
struct socket *so;
so = SCTP_INP_SO(inp);
- atomic_add_int(&stcb->asoc.refcnt, 1);
- SCTP_TCB_UNLOCK(stcb);
+ if (stcb) {
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ }
SCTP_SOCKET_LOCK(so, 1);
- SCTP_TCB_LOCK(stcb);
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ if (stcb) {
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ }
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
SCTP_SOCKET_UNLOCK(so, 1);
return (0);
}
#endif
sctp_sorwakeup(inp, inp->sctp_socket);
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
}
@@ -4695,14 +4681,14 @@ sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc,
int
sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
- int reason, int so_locked
+ uint8_t sent, int so_locked
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
SCTP_UNUSED
#endif
)
{
struct sctp_stream_out *strq;
- struct sctp_tmit_chunk *chk = NULL;
+ struct sctp_tmit_chunk *chk = NULL, *tp2;
struct sctp_stream_queue_pending *sp;
uint16_t stream = 0, seq = 0;
uint8_t foundeom = 0;
@@ -4722,7 +4708,11 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
stcb->asoc.peers_rwnd += tp1->send_size;
stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh);
- sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1, so_locked);
+ if (sent) {
+ sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked);
+ } else {
+ sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked);
+ }
if (tp1->data) {
sctp_m_freem(tp1->data);
tp1->data = NULL;
@@ -4756,15 +4746,11 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
* The multi-part message was scattered across the send and
* sent queue.
*/
-next_on_sent:
- tp1 = TAILQ_FIRST(&stcb->asoc.send_queue);
- /*
- * recurse throught the send_queue too, starting at the
- * beginning.
- */
- if ((tp1) &&
- (tp1->rec.data.stream_number == stream) &&
- (tp1->rec.data.stream_seq == seq)) {
+ TAILQ_FOREACH_SAFE(tp1, &stcb->asoc.send_queue, sctp_next, tp2) {
+ if ((tp1->rec.data.stream_number != stream) ||
+ (tp1->rec.data.stream_seq != seq)) {
+ break;
+ }
/*
* save to chk in case we have some on stream out
* queue. If so and we have an un-transmitted one we
@@ -4773,7 +4759,11 @@ next_on_sent:
chk = tp1;
ret_sz += tp1->book_size;
sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
- sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1, so_locked);
+ if (sent) {
+ sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked);
+ } else {
+ sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked);
+ }
if (tp1->data) {
sctp_m_freem(tp1->data);
tp1->data = NULL;
@@ -4794,7 +4784,6 @@ next_on_sent:
sctp_next);
stcb->asoc.send_queue_cnt--;
stcb->asoc.sent_queue_cnt++;
- goto next_on_sent;
}
}
if (foundeom == 0) {
@@ -4802,81 +4791,73 @@ next_on_sent:
* Still no eom found. That means there is stuff left on the
* stream out queue.. yuck.
*/
- strq = &stcb->asoc.strmout[stream];
SCTP_TCB_SEND_LOCK(stcb);
+ strq = &stcb->asoc.strmout[stream];
sp = TAILQ_FIRST(&strq->outqueue);
- while (sp->strseq <= seq) {
- /* Check if its our SEQ */
- if (sp->strseq == seq) {
- sp->discard_rest = 1;
- /*
- * We may need to put a chunk on the queue
- * that holds the TSN that would have been
- * sent with the LAST bit.
- */
+ if (sp != NULL) {
+ sp->discard_rest = 1;
+ /*
+ * We may need to put a chunk on the queue that
+ * holds the TSN that would have been sent with the
+ * LAST bit.
+ */
+ if (chk == NULL) {
+ /* Yep, we have to */
+ sctp_alloc_a_chunk(stcb, chk);
if (chk == NULL) {
- /* Yep, we have to */
- sctp_alloc_a_chunk(stcb, chk);
- if (chk == NULL) {
- /*
- * we are hosed. All we can
- * do is nothing.. which
- * will cause an abort if
- * the peer is paying
- * attention.
- */
- goto oh_well;
- }
- memset(chk, 0, sizeof(*chk));
- chk->rec.data.rcv_flags = SCTP_DATA_LAST_FRAG;
- chk->sent = SCTP_FORWARD_TSN_SKIP;
- chk->asoc = &stcb->asoc;
- chk->rec.data.stream_seq = sp->strseq;
- chk->rec.data.stream_number = sp->stream;
- chk->rec.data.payloadtype = sp->ppid;
- chk->rec.data.context = sp->context;
- chk->flags = sp->act_flags;
- if (sp->net)
- chk->whoTo = sp->net;
- else
- chk->whoTo = stcb->asoc.primary_destination;
- atomic_add_int(&chk->whoTo->ref_count, 1);
- chk->rec.data.TSN_seq = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1);
- stcb->asoc.pr_sctp_cnt++;
- chk->pr_sctp_on = 1;
- TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, chk, sctp_next);
- stcb->asoc.sent_queue_cnt++;
- stcb->asoc.pr_sctp_cnt++;
- } else {
- chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG;
- }
- oh_well:
- if (sp->data) {
/*
- * Pull any data to free up the SB
- * and allow sender to "add more"
- * whilc we will throw away :-)
+ * we are hosed. All we can do is
+ * nothing.. which will cause an
+ * abort if the peer is paying
+ * attention.
*/
- sctp_free_spbufspace(stcb, &stcb->asoc,
- sp);
- ret_sz += sp->length;
- do_wakeup_routine = 1;
- sp->some_taken = 1;
- sctp_m_freem(sp->data);
- sp->length = 0;
- sp->data = NULL;
- sp->tail_mbuf = NULL;
+ goto oh_well;
}
- break;
+ memset(chk, 0, sizeof(*chk));
+ chk->rec.data.rcv_flags = SCTP_DATA_LAST_FRAG;
+ chk->sent = SCTP_FORWARD_TSN_SKIP;
+ chk->asoc = &stcb->asoc;
+ chk->rec.data.stream_seq = strq->next_sequence_send;
+ chk->rec.data.stream_number = sp->stream;
+ chk->rec.data.payloadtype = sp->ppid;
+ chk->rec.data.context = sp->context;
+ chk->flags = sp->act_flags;
+ if (sp->net)
+ chk->whoTo = sp->net;
+ else
+ chk->whoTo = stcb->asoc.primary_destination;
+ atomic_add_int(&chk->whoTo->ref_count, 1);
+ chk->rec.data.TSN_seq = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1);
+ stcb->asoc.pr_sctp_cnt++;
+ chk->pr_sctp_on = 1;
+ TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, chk, sctp_next);
+ stcb->asoc.sent_queue_cnt++;
+ stcb->asoc.pr_sctp_cnt++;
} else {
- /* Next one please */
- sp = TAILQ_NEXT(sp, next);
+ chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG;
+ }
+ strq->next_sequence_send++;
+ oh_well:
+ if (sp->data) {
+ /*
+ * Pull any data to free up the SB and allow
+ * sender to "add more" while we will throw
+ * away :-)
+ */
+ sctp_free_spbufspace(stcb, &stcb->asoc, sp);
+ ret_sz += sp->length;
+ do_wakeup_routine = 1;
+ sp->some_taken = 1;
+ sctp_m_freem(sp->data);
+ sp->data = NULL;
+ sp->tail_mbuf = NULL;
+ sp->length = 0;
}
- } /* End while */
+ }
SCTP_TCB_SEND_UNLOCK(stcb);
}
if (do_wakeup_routine) {
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
struct socket *so;
so = SCTP_INP_SO(stcb->sctp_ep);
@@ -4894,7 +4875,7 @@ next_on_sent:
}
#endif
sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
if (!so_locked) {
SCTP_SOCKET_UNLOCK(so, 1);
}
@@ -4923,6 +4904,7 @@ sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr,
continue;
if (addr->sa_family != laddr->ifa->address.sa.sa_family)
continue;
+#ifdef INET
if (addr->sa_family == AF_INET) {
if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
laddr->ifa->address.sin.sin_addr.s_addr) {
@@ -4934,6 +4916,7 @@ sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr,
break;
}
}
+#endif
#ifdef INET6
if (addr->sa_family == AF_INET6) {
if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr,
@@ -4957,22 +4940,33 @@ sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr,
uint32_t
sctp_get_ifa_hash_val(struct sockaddr *addr)
{
- if (addr->sa_family == AF_INET) {
- struct sockaddr_in *sin;
+ switch (addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ {
+ struct sockaddr_in *sin;
- sin = (struct sockaddr_in *)addr;
- return (sin->sin_addr.s_addr ^ (sin->sin_addr.s_addr >> 16));
- } else if (addr->sa_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- uint32_t hash_of_addr;
+ sin = (struct sockaddr_in *)addr;
+ return (sin->sin_addr.s_addr ^ (sin->sin_addr.s_addr >> 16));
+ }
+#endif
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6;
+ uint32_t hash_of_addr;
- sin6 = (struct sockaddr_in6 *)addr;
- hash_of_addr = (sin6->sin6_addr.s6_addr32[0] +
- sin6->sin6_addr.s6_addr32[1] +
- sin6->sin6_addr.s6_addr32[2] +
- sin6->sin6_addr.s6_addr32[3]);
- hash_of_addr = (hash_of_addr ^ (hash_of_addr >> 16));
- return (hash_of_addr);
+ sin6 = (struct sockaddr_in6 *)addr;
+ hash_of_addr = (sin6->sin6_addr.s6_addr32[0] +
+ sin6->sin6_addr.s6_addr32[1] +
+ sin6->sin6_addr.s6_addr32[2] +
+ sin6->sin6_addr.s6_addr32[3]);
+ hash_of_addr = (hash_of_addr ^ (hash_of_addr >> 16));
+ return (hash_of_addr);
+ }
+#endif
+ default:
+ break;
}
return (0);
}
@@ -5021,6 +5015,7 @@ stage_right:
}
if (addr->sa_family != sctp_ifap->address.sa.sa_family)
continue;
+#ifdef INET
if (addr->sa_family == AF_INET) {
if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
sctp_ifap->address.sin.sin_addr.s_addr) {
@@ -5031,6 +5026,7 @@ stage_right:
break;
}
}
+#endif
#ifdef INET6
if (addr->sa_family == AF_INET6) {
if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr,
@@ -5110,7 +5106,7 @@ sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t * freed_so_far, int hold_rlock,
goto out;
}
SCTP_STAT_INCR(sctps_wu_sacks_sent);
- sctp_send_sack(stcb);
+ sctp_send_sack(stcb, SCTP_SO_LOCKED);
sctp_chunk_output(stcb->sctp_ep, stcb,
SCTP_OUTPUT_FROM_USR_RCVD, SCTP_SO_LOCKED);
@@ -5218,10 +5214,10 @@ sctp_sorecvmsg(struct socket *so,
rwnd_req, block_allowed, so->so_rcv.sb_cc, uio->uio_resid);
}
error = sblock(&so->so_rcv, (block_allowed ? SBL_WAIT : 0));
- sockbuf_lock = 1;
if (error) {
goto release_unlocked;
}
+ sockbuf_lock = 1;
restart:
@@ -5234,7 +5230,7 @@ restart_nosblocks:
(inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
goto out;
}
- if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
+ if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && (so->so_rcv.sb_cc == 0)) {
if (so->so_error) {
error = so->so_error;
if ((in_flags & MSG_PEEK) == 0)
@@ -5242,7 +5238,6 @@ restart_nosblocks:
goto out;
} else {
if (so->so_rcv.sb_cc == 0) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN);
/* indicate EOF */
error = 0;
goto out;
@@ -5267,17 +5262,6 @@ restart_nosblocks:
*/
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
error = ECONNRESET;
- /*
- * You get this once if you are
- * active open side
- */
- if (!(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
- /*
- * Remove flag if on the
- * active open side
- */
- inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAS_ABORTED;
- }
}
so->so_state &= ~(SS_ISCONNECTING |
SS_ISDISCONNECTING |
@@ -5287,8 +5271,6 @@ restart_nosblocks:
if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN);
error = ENOTCONN;
- } else {
- inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAS_CONNECTED;
}
}
goto out;
@@ -5321,18 +5303,6 @@ restart_nosblocks:
*/
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
error = ECONNRESET;
- /*
- * You get this once if you
- * are active open side
- */
- if (!(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
- /*
- * Remove flag if on
- * the active open
- * side
- */
- inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAS_ABORTED;
- }
}
so->so_state &= ~(SS_ISCONNECTING |
SS_ISDISCONNECTING |
@@ -5342,8 +5312,6 @@ restart_nosblocks:
if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN);
error = ENOTCONN;
- } else {
- inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAS_CONNECTED;
}
}
goto out;
@@ -5369,7 +5337,6 @@ restart_nosblocks:
*/
if (hold_rlock == 0) {
SCTP_INP_READ_LOCK(inp);
- hold_rlock = 1;
}
control = TAILQ_FIRST(&inp->read_queue);
if ((control == NULL) && (so->so_rcv.sb_cc != 0)) {
@@ -5539,7 +5506,7 @@ found_one:
#ifdef INVARIANTS
panic("refcnt already incremented");
#else
- printf("refcnt already incremented?\n");
+ SCTP_PRINTF("refcnt already incremented?\n");
#endif
} else {
atomic_add_int(&stcb->asoc.refcnt, 1);
@@ -5567,7 +5534,8 @@ found_one:
if ((sinfo) && filling_sinfo) {
memcpy(sinfo, control, sizeof(struct sctp_nonpad_sndrcvinfo));
nxt = TAILQ_NEXT(control, next);
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO)) {
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) ||
+ sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) {
struct sctp_extrcvinfo *s_extra;
s_extra = (struct sctp_extrcvinfo *)sinfo;
@@ -5639,28 +5607,31 @@ found_one:
}
#endif
if (fromlen && from) {
- struct sockaddr *to;
-
+ cp_len = min((size_t)fromlen, (size_t)control->whoFrom->ro._l_addr.sa.sa_len);
+ switch (control->whoFrom->ro._l_addr.sa.sa_family) {
+#ifdef INET6
+ case AF_INET6:
+ ((struct sockaddr_in6 *)from)->sin6_port = control->port_from;
+ break;
+#endif
#ifdef INET
- cp_len = min((size_t)fromlen, (size_t)control->whoFrom->ro._l_addr.sin.sin_len);
- memcpy(from, &control->whoFrom->ro._l_addr, cp_len);
- ((struct sockaddr_in *)from)->sin_port = control->port_from;
-#else
- /* No AF_INET use AF_INET6 */
- cp_len = min((size_t)fromlen, (size_t)control->whoFrom->ro._l_addr.sin6.sin6_len);
- memcpy(from, &control->whoFrom->ro._l_addr, cp_len);
- ((struct sockaddr_in6 *)from)->sin6_port = control->port_from;
+ case AF_INET:
+ ((struct sockaddr_in *)from)->sin_port = control->port_from;
+ break;
#endif
+ default:
+ break;
+ }
+ memcpy(from, &control->whoFrom->ro._l_addr, cp_len);
- to = from;
#if defined(INET) && defined(INET6)
if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) &&
- (to->sa_family == AF_INET) &&
+ (from->sa_family == AF_INET) &&
((size_t)fromlen >= sizeof(struct sockaddr_in6))) {
struct sockaddr_in *sin;
struct sockaddr_in6 sin6;
- sin = (struct sockaddr_in *)to;
+ sin = (struct sockaddr_in *)from;
bzero(&sin6, sizeof(sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_len = sizeof(struct sockaddr_in6);
@@ -5669,15 +5640,15 @@ found_one:
&sin6.sin6_addr.s6_addr32[3],
sizeof(sin6.sin6_addr.s6_addr32[3]));
sin6.sin6_port = sin->sin_port;
- memcpy(from, (caddr_t)&sin6, sizeof(sin6));
+ memcpy(from, &sin6, sizeof(struct sockaddr_in6));
}
#endif
-#if defined(INET6)
+#ifdef INET6
{
- struct sockaddr_in6 lsa6, *to6;
+ struct sockaddr_in6 lsa6, *from6;
- to6 = (struct sockaddr_in6 *)to;
- sctp_recover_scope_mac(to6, (&lsa6));
+ from6 = (struct sockaddr_in6 *)from;
+ sctp_recover_scope_mac(from6, (&lsa6));
}
#endif
}
@@ -6014,7 +5985,9 @@ wait_some_more:
}
if (control->end_added) {
out_flags |= MSG_EOR;
- if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0))
+ if ((control->do_not_ref_stcb == 0) &&
+ (control->stcb != NULL) &&
+ ((control->spec_flags & M_NOTIFICATION) == 0))
control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
}
if (control->spec_flags & M_NOTIFICATION) {
@@ -6074,7 +6047,8 @@ out:
if (((out_flags & MSG_EOR) == 0) &&
((in_flags & MSG_PEEK) == 0) &&
(sinfo) &&
- (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO))) {
+ (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) ||
+ sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO))) {
struct sctp_extrcvinfo *s_extra;
s_extra = (struct sctp_extrcvinfo *)sinfo;
@@ -6082,11 +6056,9 @@ out:
}
if (hold_rlock == 1) {
SCTP_INP_READ_UNLOCK(inp);
- hold_rlock = 0;
}
if (hold_sblock) {
SOCKBUF_UNLOCK(&so->so_rcv);
- hold_sblock = 0;
}
if (sockbuf_lock) {
sbunlock(&so->so_rcv);
@@ -6107,7 +6079,6 @@ out:
#endif
}
atomic_add_int(&stcb->asoc.refcnt, -1);
- freecnt_applied = 0;
/* Save the value back for next time */
stcb->freed_by_sorcv_sincelast = freed_so_far;
}
@@ -6224,8 +6195,9 @@ sctp_soreceive(struct socket *so,
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
return (EINVAL);
}
- if ((sctp_is_feature_off(inp,
- SCTP_PCB_FLAGS_RECVDATAIOEVNT)) ||
+ if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) &&
+ sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) &&
+ sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) ||
(controlp == NULL)) {
/* user does not want the sndrcv ctl */
filling_sinfo = 0;
@@ -6261,71 +6233,6 @@ sctp_soreceive(struct socket *so,
}
-int
-sctp_l_soreceive(struct socket *so,
- struct sockaddr **name,
- struct uio *uio,
- char **controlp,
- int *controllen,
- int *flag)
-{
- int error, fromlen;
- uint8_t sockbuf[256];
- struct sockaddr *from;
- struct sctp_extrcvinfo sinfo;
- int filling_sinfo = 1;
- struct sctp_inpcb *inp;
-
- inp = (struct sctp_inpcb *)so->so_pcb;
- /* pickup the assoc we are reading from */
- if (inp == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
- return (EINVAL);
- }
- if ((sctp_is_feature_off(inp,
- SCTP_PCB_FLAGS_RECVDATAIOEVNT)) ||
- (controlp == NULL)) {
- /* user does not want the sndrcv ctl */
- filling_sinfo = 0;
- }
- if (name) {
- from = (struct sockaddr *)sockbuf;
- fromlen = sizeof(sockbuf);
- from->sa_len = 0;
- } else {
- from = NULL;
- fromlen = 0;
- }
-
- error = sctp_sorecvmsg(so, uio,
- (struct mbuf **)NULL,
- from, fromlen, flag,
- (struct sctp_sndrcvinfo *)&sinfo,
- filling_sinfo);
- if ((controlp) && (filling_sinfo)) {
- /*
- * copy back the sinfo in a CMSG format note that the caller
- * has reponsibility for freeing the memory.
- */
- if (filling_sinfo)
- *controlp = sctp_build_ctl_cchunk(inp,
- controllen,
- (struct sctp_sndrcvinfo *)&sinfo);
- }
- if (name) {
- /* copy back the address info */
- if (from && from->sa_len) {
- *name = sodupsockaddr(from, M_WAIT);
- } else {
- *name = NULL;
- }
- }
- return (error);
-}
-
-
-
-
@@ -6339,13 +6246,33 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
struct sockaddr *sa;
size_t incr = 0;
+#ifdef INET
+ struct sockaddr_in *sin;
+
+#endif
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+
+#endif
+
sa = addr;
inp = stcb->sctp_ep;
*error = 0;
for (i = 0; i < totaddr; i++) {
- if (sa->sa_family == AF_INET) {
+ switch (sa->sa_family) {
+#ifdef INET
+ case AF_INET:
incr = sizeof(struct sockaddr_in);
- if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
+ sin = (struct sockaddr_in *)sa;
+ if ((sin->sin_addr.s_addr == INADDR_ANY) ||
+ (sin->sin_addr.s_addr == INADDR_BROADCAST) ||
+ IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
+ *error = EINVAL;
+ goto out_now;
+ }
+ if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
/* assoc gone no un-lock */
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
@@ -6353,9 +6280,20 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
goto out_now;
}
added++;
- } else if (sa->sa_family == AF_INET6) {
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
incr = sizeof(struct sockaddr_in6);
- if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
+ sin6 = (struct sockaddr_in6 *)sa;
+ if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
+ IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);
+ *error = EINVAL;
+ goto out_now;
+ }
+ if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
/* assoc gone no un-lock */
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS);
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);
@@ -6363,6 +6301,10 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
goto out_now;
}
added++;
+ break;
+#endif
+ default:
+ break;
}
sa = (struct sockaddr *)((caddr_t)sa + incr);
}
@@ -6381,10 +6323,13 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
at = incr = 0;
sa = addr;
+
*error = *num_v6 = *num_v4 = 0;
/* account and validate addresses */
for (i = 0; i < (size_t)*totaddr; i++) {
- if (sa->sa_family == AF_INET) {
+ switch (sa->sa_family) {
+#ifdef INET
+ case AF_INET:
(*num_v4) += 1;
incr = sizeof(struct sockaddr_in);
if (sa->sa_len != incr) {
@@ -6393,30 +6338,40 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
*bad_addr = 1;
return (NULL);
}
- } else if (sa->sa_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
-
- sin6 = (struct sockaddr_in6 *)sa;
- if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
- /* Must be non-mapped for connectx */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
- *error = EINVAL;
- *bad_addr = 1;
- return (NULL);
- }
- (*num_v6) += 1;
- incr = sizeof(struct sockaddr_in6);
- if (sa->sa_len != incr) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
- *error = EINVAL;
- *bad_addr = 1;
- return (NULL);
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)sa;
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+ /* Must be non-mapped for connectx */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
+ *error = EINVAL;
+ *bad_addr = 1;
+ return (NULL);
+ }
+ (*num_v6) += 1;
+ incr = sizeof(struct sockaddr_in6);
+ if (sa->sa_len != incr) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
+ *error = EINVAL;
+ *bad_addr = 1;
+ return (NULL);
+ }
+ break;
}
- } else {
+#endif
+ default:
*totaddr = i;
/* we are done */
break;
}
+ if (i == (size_t)*totaddr) {
+ break;
+ }
SCTP_INP_INCR_REF(inp);
stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
if (stcb != NULL) {
@@ -6457,7 +6412,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
return;
}
addr_touse = sa;
-#if defined(INET6) && !defined(__Userspace__) /* TODO port in6_sin6_2_sin */
+#ifdef INET6
if (sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6;
@@ -6486,6 +6441,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
}
}
#endif
+#ifdef INET
if (sa->sa_family == AF_INET) {
if (sa->sa_len != sizeof(struct sockaddr_in)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
@@ -6500,6 +6456,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
return;
}
}
+#endif
if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
if (p == NULL) {
/* Can't get proc for Net/Open BSD */
@@ -6565,7 +6522,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
* assumes all arguments are valid/checked by caller.
*/
void
-sctp_bindx_delete_address(struct socket *so, struct sctp_inpcb *inp,
+sctp_bindx_delete_address(struct sctp_inpcb *inp,
struct sockaddr *sa, sctp_assoc_t assoc_id,
uint32_t vrf_id, int *error)
{
@@ -6583,7 +6540,7 @@ sctp_bindx_delete_address(struct socket *so, struct sctp_inpcb *inp,
return;
}
addr_touse = sa;
-#if defined(INET6) && !defined(__Userspace__) /* TODO port in6_sin6_2_sin */
+#ifdef INET6
if (sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6;
@@ -6612,6 +6569,7 @@ sctp_bindx_delete_address(struct socket *so, struct sctp_inpcb *inp,
}
}
#endif
+#ifdef INET
if (sa->sa_family == AF_INET) {
if (sa->sa_len != sizeof(struct sockaddr_in)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
@@ -6626,6 +6584,7 @@ sctp_bindx_delete_address(struct socket *so, struct sctp_inpcb *inp,
return;
}
}
+#endif
/*
* No lock required mgmt_ep_sa does its own locking. If the FIX:
* below is ever changed we may need to lock before calling
@@ -6658,20 +6617,12 @@ sctp_local_addr_count(struct sctp_tcb *stcb)
int count = 0;
/* Turn on all the appropriate scopes */
- loopback_scope = stcb->asoc.loopback_scope;
- ipv4_local_scope = stcb->asoc.ipv4_local_scope;
- local_scope = stcb->asoc.local_scope;
- site_scope = stcb->asoc.site_scope;
- ipv4_addr_legal = ipv6_addr_legal = 0;
- if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- ipv6_addr_legal = 1;
- if (SCTP_IPV6_V6ONLY(stcb->sctp_ep) == 0) {
- ipv4_addr_legal = 1;
- }
- } else {
- ipv4_addr_legal = 1;
- }
-
+ loopback_scope = stcb->asoc.scope.loopback_scope;
+ ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope;
+ local_scope = stcb->asoc.scope.local_scope;
+ site_scope = stcb->asoc.scope.site_scope;
+ ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal;
+ ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal;
SCTP_IPI_ADDR_RLOCK();
vrf = sctp_find_vrf(stcb->asoc.vrf_id);
if (vrf == NULL) {
@@ -6692,6 +6643,7 @@ sctp_local_addr_count(struct sctp_tcb *stcb)
if (sctp_is_addr_restricted(stcb, sctp_ifa))
continue;
switch (sctp_ifa->address.sa.sa_family) {
+#ifdef INET
case AF_INET:
if (ipv4_addr_legal) {
struct sockaddr_in *sin;
@@ -6714,6 +6666,7 @@ sctp_local_addr_count(struct sctp_tcb *stcb)
continue;
}
break;
+#endif
#ifdef INET6
case AF_INET6:
if (ipv6_addr_legal) {
@@ -6808,170 +6761,181 @@ sctp_log_trace(uint32_t subsys, const char *str SCTP_UNUSED, uint32_t a, uint32_
}
#endif
-/* We will need to add support
- * to bind the ports and such here
- * so we can do UDP tunneling. In
- * the mean-time, we return error
- */
-#include <netinet/udp.h>
-#include <netinet/udp_var.h>
-#include <sys/proc.h>
-#ifdef INET6
-#include <netinet6/sctp6_var.h>
-#endif
-
static void
sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *ignored)
{
struct ip *iph;
+
+#ifdef INET6
+ struct ip6_hdr *ip6;
+
+#endif
struct mbuf *sp, *last;
struct udphdr *uhdr;
- uint16_t port = 0, len;
- int header_size = sizeof(struct udphdr) + sizeof(struct sctphdr);
+ uint16_t port;
- /*
- * Split out the mbuf chain. Leave the IP header in m, place the
- * rest in the sp.
- */
if ((m->m_flags & M_PKTHDR) == 0) {
/* Can't handle one that is not a pkt hdr */
goto out;
}
- /* pull the src port */
+ /* Pull the src port */
iph = mtod(m, struct ip *);
uhdr = (struct udphdr *)((caddr_t)iph + off);
-
port = uhdr->uh_sport;
+ /*
+ * Split out the mbuf chain. Leave the IP header in m, place the
+ * rest in the sp.
+ */
sp = m_split(m, off, M_DONTWAIT);
if (sp == NULL) {
/* Gak, drop packet, we can't do a split */
goto out;
}
- if (sp->m_pkthdr.len < header_size) {
- /* Gak, packet can't have an SCTP header in it - to small */
+ if (sp->m_pkthdr.len < sizeof(struct udphdr) + sizeof(struct sctphdr)) {
+ /* Gak, packet can't have an SCTP header in it - too small */
m_freem(sp);
goto out;
}
- /* ok now pull up the UDP header and SCTP header together */
- sp = m_pullup(sp, header_size);
+ /* Now pull up the UDP header and SCTP header together */
+ sp = m_pullup(sp, sizeof(struct udphdr) + sizeof(struct sctphdr));
if (sp == NULL) {
/* Gak pullup failed */
goto out;
}
- /* trim out the UDP header */
+ /* Trim out the UDP header */
m_adj(sp, sizeof(struct udphdr));
/* Now reconstruct the mbuf chain */
- /* 1) find last one */
- last = m;
- while (last->m_next != NULL) {
- last = last->m_next;
- }
+ for (last = m; last->m_next; last = last->m_next);
last->m_next = sp;
m->m_pkthdr.len += sp->m_pkthdr.len;
- last = m;
- while (last != NULL) {
- last = last->m_next;
- }
- /* Now its ready for sctp_input or sctp6_input */
iph = mtod(m, struct ip *);
switch (iph->ip_v) {
+#ifdef INET
case IPVERSION:
- {
- /* its IPv4 */
- len = SCTP_GET_IPV4_LENGTH(iph);
- len -= sizeof(struct udphdr);
- SCTP_GET_IPV4_LENGTH(iph) = len;
- sctp_input_with_port(m, off, port);
- break;
- }
+ iph->ip_len -= sizeof(struct udphdr);
+ sctp_input_with_port(m, off, port);
+ break;
+#endif
#ifdef INET6
case IPV6_VERSION >> 4:
- {
- /* its IPv6 - NOT supported */
- goto out;
- break;
-
- }
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - sizeof(struct udphdr));
+ sctp6_input_with_port(&m, &off, port);
+ break;
#endif
default:
- {
- m_freem(m);
- break;
- }
+ goto out;
+ break;
}
return;
out:
m_freem(m);
}
-void
+void
sctp_over_udp_stop(void)
{
- struct socket *sop;
-
/*
* This function assumes sysctl caller holds sctp_sysctl_info_lock()
* for writting!
*/
- if (SCTP_BASE_INFO(udp_tun_socket) == NULL) {
- /* Nothing to do */
- return;
+#ifdef INET
+ if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) {
+ soclose(SCTP_BASE_INFO(udp4_tun_socket));
+ SCTP_BASE_INFO(udp4_tun_socket) = NULL;
}
- sop = SCTP_BASE_INFO(udp_tun_socket);
- soclose(sop);
- SCTP_BASE_INFO(udp_tun_socket) = NULL;
+#endif
+#ifdef INET6
+ if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) {
+ soclose(SCTP_BASE_INFO(udp6_tun_socket));
+ SCTP_BASE_INFO(udp6_tun_socket) = NULL;
+ }
+#endif
}
-int
+
+int
sctp_over_udp_start(void)
{
uint16_t port;
int ret;
+
+#ifdef INET
struct sockaddr_in sin;
- struct socket *sop = NULL;
- struct thread *th;
- struct ucred *cred;
+#endif
+#ifdef INET6
+ struct sockaddr_in6 sin6;
+
+#endif
/*
* This function assumes sysctl caller holds sctp_sysctl_info_lock()
* for writting!
*/
port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port);
- if (port == 0) {
+ if (ntohs(port) == 0) {
/* Must have a port set */
return (EINVAL);
}
- if (SCTP_BASE_INFO(udp_tun_socket) != NULL) {
+#ifdef INET
+ if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) {
+ /* Already running -- must stop first */
+ return (EALREADY);
+ }
+#endif
+#ifdef INET6
+ if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) {
/* Already running -- must stop first */
return (EALREADY);
}
- th = curthread;
- cred = th->td_ucred;
- if ((ret = socreate(PF_INET, &sop,
- SOCK_DGRAM, IPPROTO_UDP, cred, th))) {
+#endif
+#ifdef INET
+ if ((ret = socreate(PF_INET, &SCTP_BASE_INFO(udp4_tun_socket),
+ SOCK_DGRAM, IPPROTO_UDP,
+ curthread->td_ucred, curthread))) {
+ sctp_over_udp_stop();
return (ret);
}
- SCTP_BASE_INFO(udp_tun_socket) = sop;
- /* call the special UDP hook */
- ret = udp_set_kernel_tunneling(sop, sctp_recv_udp_tunneled_packet);
- if (ret) {
- goto exit_stage_left;
+ /* Call the special UDP hook. */
+ if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp4_tun_socket),
+ sctp_recv_udp_tunneled_packet))) {
+ sctp_over_udp_stop();
+ return (ret);
}
- /* Ok we have a socket, bind it to the port */
- memset(&sin, 0, sizeof(sin));
- sin.sin_len = sizeof(sin);
+ /* Ok, we have a socket, bind it to the port. */
+ memset(&sin, 0, sizeof(struct sockaddr_in));
+ sin.sin_len = sizeof(struct sockaddr_in);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
- ret = sobind(sop, (struct sockaddr *)&sin, th);
- if (ret) {
- /* Close up we cant get the port */
-exit_stage_left:
+ if ((ret = sobind(SCTP_BASE_INFO(udp4_tun_socket),
+ (struct sockaddr *)&sin, curthread))) {
sctp_over_udp_stop();
return (ret);
}
- /*
- * Ok we should now get UDP packets directly to our input routine
- * sctp_recv_upd_tunneled_packet().
- */
+#endif
+#ifdef INET6
+ if ((ret = socreate(PF_INET6, &SCTP_BASE_INFO(udp6_tun_socket),
+ SOCK_DGRAM, IPPROTO_UDP,
+ curthread->td_ucred, curthread))) {
+ sctp_over_udp_stop();
+ return (ret);
+ }
+ /* Call the special UDP hook. */
+ if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp6_tun_socket),
+ sctp_recv_udp_tunneled_packet))) {
+ sctp_over_udp_stop();
+ return (ret);
+ }
+ /* Ok, we have a socket, bind it to the port. */
+ memset(&sin6, 0, sizeof(struct sockaddr_in6));
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(port);
+ if ((ret = sobind(SCTP_BASE_INFO(udp6_tun_socket),
+ (struct sockaddr *)&sin6, curthread))) {
+ sctp_over_udp_stop();
+ return (ret);
+ }
+#endif
return (0);
}