summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet/sctp_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet/sctp_output.c')
-rw-r--r--freebsd/sys/netinet/sctp_output.c2326
1 files changed, 1296 insertions, 1030 deletions
diff --git a/freebsd/sys/netinet/sctp_output.c b/freebsd/sys/netinet/sctp_output.c
index cbc25b9c..9e12e775 100644
--- a/freebsd/sys/netinet/sctp_output.c
+++ b/freebsd/sys/netinet/sctp_output.c
@@ -52,7 +52,9 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_bsd_addr.h>
#include <netinet/sctp_input.h>
#include <netinet/sctp_crc32.h>
+#if defined(INET) || defined(INET6)
#include <netinet/udp.h>
+#endif
#include <netinet/udp_var.h>
#include <machine/in_cksum.h>
@@ -67,7 +69,7 @@ struct sack_track {
struct sctp_gap_ack_block gaps[SCTP_MAX_GAPS_INARRAY];
};
-struct sack_track sack_array[256] = {
+const struct sack_track sack_array[256] = {
{0, 0, 0, 0, /* 0x00 */
{{0, 0},
{0, 0},
@@ -1881,7 +1883,7 @@ sctp_is_address_in_scope(struct sctp_ifa *ifa,
if (scope->ipv4_addr_legal) {
struct sockaddr_in *sin;
- sin = (struct sockaddr_in *)&ifa->address.sin;
+ sin = &ifa->address.sin;
if (sin->sin_addr.s_addr == 0) {
/* not in scope , unspecified */
return (0);
@@ -1912,7 +1914,7 @@ sctp_is_address_in_scope(struct sctp_ifa *ifa,
return (0);
}
/* ok to use deprecated addresses? */
- sin6 = (struct sockaddr_in6 *)&ifa->address.sin6;
+ sin6 = &ifa->address.sin6;
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
/* skip unspecifed addresses */
return (0);
@@ -1971,7 +1973,7 @@ sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t * len)
while (SCTP_BUF_NEXT(mret) != NULL) {
mret = SCTP_BUF_NEXT(mret);
}
- SCTP_BUF_NEXT(mret) = sctp_get_mbuf_for_msg(plen, 0, M_DONTWAIT, 1, MT_DATA);
+ SCTP_BUF_NEXT(mret) = sctp_get_mbuf_for_msg(plen, 0, M_NOWAIT, 1, MT_DATA);
if (SCTP_BUF_NEXT(mret) == NULL) {
/* We are hosed, can't add more addresses */
return (m);
@@ -1987,7 +1989,7 @@ sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t * len)
struct sctp_ipv4addr_param *ipv4p;
struct sockaddr_in *sin;
- sin = (struct sockaddr_in *)&ifa->address.sin;
+ sin = &ifa->address.sin;
ipv4p = (struct sctp_ipv4addr_param *)parmh;
parmh->param_type = htons(SCTP_IPV4_ADDRESS);
parmh->param_length = htons(plen);
@@ -2002,7 +2004,7 @@ sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t * len)
struct sctp_ipv6addr_param *ipv6p;
struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)&ifa->address.sin6;
+ sin6 = &ifa->address.sin6;
ipv6p = (struct sctp_ipv6addr_param *)parmh;
parmh->param_type = htons(SCTP_IPV6_ADDRESS);
parmh->param_length = htons(plen);
@@ -2417,7 +2419,7 @@ sctp_is_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
LIST_FOREACH(laddr, &stcb->asoc.sctp_restricted_addrs, sctp_nxt_addr) {
if (laddr->ifa == NULL) {
SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
- __FUNCTION__);
+ __func__);
continue;
}
if (laddr->ifa == ifa) {
@@ -2439,7 +2441,7 @@ sctp_is_addr_in_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa)
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
if (laddr->ifa == NULL) {
SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
- __FUNCTION__);
+ __func__);
continue;
}
if ((laddr->ifa == ifa) && laddr->action == 0)
@@ -3071,7 +3073,7 @@ bound_all_plan_b:
ifn, num_preferred);
if (num_preferred == 0) {
/* None on this interface. */
- SCTPDBG(SCTP_DEBUG_OUTPUT2, "No prefered -- skipping to next\n");
+ SCTPDBG(SCTP_DEBUG_OUTPUT2, "No preferred -- skipping to next\n");
continue;
}
SCTPDBG(SCTP_DEBUG_OUTPUT2,
@@ -3156,12 +3158,10 @@ again_with_private_addresses_allowed:
* It is restricted for some reason..
* probably not yet added.
*/
- SCTPDBG(SCTP_DEBUG_OUTPUT2, "Its resticted\n");
+ SCTPDBG(SCTP_DEBUG_OUTPUT2, "Its restricted\n");
sifa = NULL;
continue;
}
- } else {
- SCTP_PRINTF("Stcb is null - no print\n");
}
atomic_add_int(&sifa->refcount, 1);
goto out;
@@ -3224,12 +3224,14 @@ plan_d:
}
}
#ifdef INET
- if ((retried == 0) && (stcb->asoc.scope.ipv4_local_scope == 0)) {
- stcb->asoc.scope.ipv4_local_scope = 1;
- retried = 1;
- goto again_with_private_addresses_allowed;
- } else if (retried == 1) {
- stcb->asoc.scope.ipv4_local_scope = 0;
+ if (stcb) {
+ if ((retried == 0) && (stcb->asoc.scope.ipv4_local_scope == 0)) {
+ stcb->asoc.scope.ipv4_local_scope = 1;
+ retried = 1;
+ goto again_with_private_addresses_allowed;
+ } else if (retried == 1) {
+ stcb->asoc.scope.ipv4_local_scope = 0;
+ }
}
#endif
out:
@@ -3326,10 +3328,11 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
#endif
/**
- * Rules: - Find the route if needed, cache if I can. - Look at
- * interface address in route, Is it in the bound list. If so we
- * have the best source. - If not we must rotate amongst the
- * addresses.
+ * Rules:
+ * - Find the route if needed, cache if I can.
+ * - Look at interface address in route, Is it in the bound list. If so we
+ * have the best source.
+ * - If not we must rotate amongst the addresses.
*
* Cavets and issues
*
@@ -3391,7 +3394,7 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
/*
* Need a route to cache.
*/
- SCTP_RTALLOC(ro, vrf_id);
+ SCTP_RTALLOC(ro, vrf_id, inp->fibnum);
}
if (ro->ro_rt == NULL) {
return (NULL);
@@ -3508,7 +3511,7 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize)
return (found);
}
/* It is exactly what we want. Copy it out. */
- m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), cpsize, (caddr_t)data);
+ m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), (int)cpsize, (caddr_t)data);
return (1);
} else {
struct sctp_sndrcvinfo *sndrcvinfo;
@@ -3618,6 +3621,11 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
struct sctp_stream_out *tmp_str;
unsigned int i;
+#if defined(SCTP_DETAILED_STR_STATS)
+ int j;
+
+#endif
+
/* Default is NOT correct */
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Ok, default:%d pre_open:%d\n",
stcb->asoc.streamoutcnt, stcb->asoc.pre_open_streams);
@@ -3637,10 +3645,21 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
stcb->asoc.strmout[i].chunks_on_queues = 0;
- stcb->asoc.strmout[i].next_sequence_send = 0;
+ stcb->asoc.strmout[i].next_mid_ordered = 0;
+ stcb->asoc.strmout[i].next_mid_unordered = 0;
+#if defined(SCTP_DETAILED_STR_STATS)
+ for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) {
+ stcb->asoc.strmout[i].abandoned_sent[j] = 0;
+ stcb->asoc.strmout[i].abandoned_unsent[j] = 0;
+ }
+#else
+ stcb->asoc.strmout[i].abandoned_sent[0] = 0;
+ stcb->asoc.strmout[i].abandoned_unsent[0] = 0;
+#endif
stcb->asoc.strmout[i].stream_no = i;
stcb->asoc.strmout[i].last_msg_incomplete = 0;
- stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL);
+ stcb->asoc.strmout[i].state = SCTP_STREAM_OPENING;
+ stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], NULL);
}
}
break;
@@ -3661,7 +3680,7 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
*error = EINVAL;
return (1);
}
- if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL,
+ if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, stcb->asoc.port,
SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
*error = ENOBUFS;
return (1);
@@ -3693,14 +3712,14 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
*error = EINVAL;
return (1);
}
- if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL,
+ if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, stcb->asoc.port,
SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
*error = ENOBUFS;
return (1);
}
} else
#endif
- if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, NULL,
+ if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, NULL, stcb->asoc.port,
SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
*error = ENOBUFS;
return (1);
@@ -3821,28 +3840,22 @@ sctp_add_cookie(struct mbuf *init, int init_offset,
mret = sctp_get_mbuf_for_msg((sizeof(struct sctp_state_cookie) +
sizeof(struct sctp_paramhdr)), 0,
- M_DONTWAIT, 1, MT_DATA);
+ M_NOWAIT, 1, MT_DATA);
if (mret == NULL) {
return (NULL);
}
- copy_init = SCTP_M_COPYM(init, init_offset, M_COPYALL, M_DONTWAIT);
+ copy_init = SCTP_M_COPYM(init, init_offset, M_COPYALL, M_NOWAIT);
if (copy_init == NULL) {
sctp_m_freem(mret);
return (NULL);
}
#ifdef SCTP_MBUF_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
- struct mbuf *mat;
-
- for (mat = copy_init; mat; mat = SCTP_BUF_NEXT(mat)) {
- if (SCTP_BUF_IS_EXTENDED(mat)) {
- sctp_log_mb(mat, SCTP_MBUF_ICOPY);
- }
- }
+ sctp_log_mbc(copy_init, SCTP_MBUF_ICOPY);
}
#endif
copy_initack = SCTP_M_COPYM(initack, initack_offset, M_COPYALL,
- M_DONTWAIT);
+ M_NOWAIT);
if (copy_initack == NULL) {
sctp_m_freem(mret);
sctp_m_freem(copy_init);
@@ -3850,13 +3863,7 @@ sctp_add_cookie(struct mbuf *init, int init_offset,
}
#ifdef SCTP_MBUF_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
- struct mbuf *mat;
-
- for (mat = copy_initack; mat; mat = SCTP_BUF_NEXT(mat)) {
- if (SCTP_BUF_IS_EXTENDED(mat)) {
- sctp_log_mb(mat, SCTP_MBUF_ICOPY);
- }
- }
+ sctp_log_mbc(copy_initack, SCTP_MBUF_ICOPY);
}
#endif
/* easy side we just drop it on the end */
@@ -3892,7 +3899,7 @@ sctp_add_cookie(struct mbuf *init, int init_offset,
break;
}
}
- sig = sctp_get_mbuf_for_msg(SCTP_SECRET_SIZE, 0, M_DONTWAIT, 1, MT_DATA);
+ sig = sctp_get_mbuf_for_msg(SCTP_SECRET_SIZE, 0, M_NOWAIT, 1, MT_DATA);
if (sig == NULL) {
/* no space, so free the entire chain */
sctp_m_freem(mret);
@@ -3914,7 +3921,7 @@ sctp_add_cookie(struct mbuf *init, int init_offset,
static uint8_t
sctp_get_ect(struct sctp_tcb *stcb)
{
- if ((stcb != NULL) && (stcb->asoc.ecn_allowed == 1)) {
+ if ((stcb != NULL) && (stcb->asoc.ecn_supported == 1)) {
return (SCTP_ECT0_BIT);
} else {
return (0);
@@ -3985,7 +3992,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
uint32_t v_tag,
uint16_t port,
union sctp_sockstore *over_addr,
- uint8_t use_mflowid, uint32_t mflowid,
+ uint8_t mflowtype, uint32_t mflowid,
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
int so_locked SCTP_UNUSED
#else
@@ -4061,11 +4068,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctp_route_t iproute;
int len;
- len = sizeof(struct ip) + sizeof(struct sctphdr);
+ len = SCTP_MIN_V4_OVERHEAD;
if (port) {
len += sizeof(struct udphdr);
}
- newm = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA);
+ newm = sctp_get_mbuf_for_msg(len, 1, M_NOWAIT, 1, MT_DATA);
if (newm == NULL) {
sctp_m_freem(m);
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
@@ -4076,18 +4083,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
SCTP_BUF_NEXT(newm) = m;
m = newm;
if (net != NULL) {
-#ifdef INVARIANTS
- if (net->flowidset == 0) {
- panic("Flow ID not set");
- }
-#endif
m->m_pkthdr.flowid = net->flowid;
- m->m_flags |= M_FLOWID;
+ M_HASHTYPE_SET(m, net->flowtype);
} else {
- if (use_mflowid != 0) {
- m->m_pkthdr.flowid = mflowid;
- m->m_flags |= M_FLOWID;
- }
+ m->m_pkthdr.flowid = mflowid;
+ M_HASHTYPE_SET(m, mflowtype);
}
packet_length = sctp_calculate_len(m);
ip = mtod(m, struct ip *);
@@ -4106,15 +4106,15 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
tos_value |= sctp_get_ect(stcb);
}
if ((nofragment_flag) && (port == 0)) {
- ip->ip_off = IP_DF;
+ ip->ip_off = htons(IP_DF);
} else {
- ip->ip_off = 0;
+ ip->ip_off = htons(0);
}
/* FreeBSD has a function for ip_id's */
- ip->ip_id = ip_newid();
+ ip_fillid(ip);
ip->ip_ttl = inp->ip_inp.inp.inp_ip_ttl;
- ip->ip_len = packet_length;
+ ip->ip_len = htons(packet_length);
ip->ip_tos = tos_value;
if (port) {
ip->ip_p = IPPROTO_UDP;
@@ -4177,7 +4177,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctp_free_ifa(_lsrc);
} else {
ip->ip_src = over_addr->sin.sin_addr;
- SCTP_RTALLOC(ro, vrf_id);
+ SCTP_RTALLOC(ro, vrf_id, inp->fibnum);
}
}
if (port) {
@@ -4190,7 +4190,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
udp = (struct udphdr *)((caddr_t)ip + sizeof(struct ip));
udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
udp->uh_dport = port;
- udp->uh_ulen = htons(packet_length - sizeof(struct ip));
+ udp->uh_ulen = htons((uint16_t) (packet_length - sizeof(struct ip)));
if (V_udp_cksum) {
udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP));
} else {
@@ -4350,11 +4350,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
flowlabel = ntohl(((struct in6pcb *)inp)->in6p_flowinfo);
}
flowlabel &= 0x000fffff;
- len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr);
+ len = SCTP_MIN_OVERHEAD;
if (port) {
len += sizeof(struct udphdr);
}
- newm = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA);
+ newm = sctp_get_mbuf_for_msg(len, 1, M_NOWAIT, 1, MT_DATA);
if (newm == NULL) {
sctp_m_freem(m);
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
@@ -4365,18 +4365,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
SCTP_BUF_NEXT(newm) = m;
m = newm;
if (net != NULL) {
-#ifdef INVARIANTS
- if (net->flowidset == 0) {
- panic("Flow ID not set");
- }
-#endif
m->m_pkthdr.flowid = net->flowid;
- m->m_flags |= M_FLOWID;
+ M_HASHTYPE_SET(m, net->flowtype);
} else {
- if (use_mflowid != 0) {
- m->m_pkthdr.flowid = mflowid;
- m->m_flags |= M_FLOWID;
- }
+ m->m_pkthdr.flowid = mflowid;
+ M_HASHTYPE_SET(m, mflowtype);
}
packet_length = sctp_calculate_len(m);
@@ -4425,7 +4418,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
} else {
ip6h->ip6_nxt = IPPROTO_SCTP;
}
- ip6h->ip6_plen = (packet_length - sizeof(struct ip6_hdr));
+ ip6h->ip6_plen = (uint16_t) (packet_length - sizeof(struct ip6_hdr));
ip6h->ip6_dst = sin6->sin6_addr;
/*
@@ -4498,7 +4491,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctp_free_ifa(_lsrc);
} else {
lsa6->sin6_addr = over_addr->sin6.sin6_addr;
- SCTP_RTALLOC(ro, vrf_id);
+ SCTP_RTALLOC(ro, vrf_id, inp->fibnum);
}
(void)sa6_recoverscope(sin6);
}
@@ -4544,7 +4537,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
udp = (struct udphdr *)((caddr_t)ip6h + sizeof(struct ip6_hdr));
udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
udp->uh_dport = port;
- udp->uh_ulen = htons(packet_length - sizeof(struct ip6_hdr));
+ udp->uh_ulen = htons((uint16_t) (packet_length - sizeof(struct ip6_hdr)));
udp->uh_sum = 0;
sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr));
} else {
@@ -4700,7 +4693,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
#endif
)
{
- struct mbuf *m;
+ struct mbuf *m, *m_last;
struct sctp_nets *net;
struct sctp_init_chunk *init;
struct sctp_supported_addr_param *sup_addr;
@@ -4745,7 +4738,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
/* start the INIT timer */
sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, net);
- m = sctp_get_mbuf_for_msg(MCLBYTES, 1, M_DONTWAIT, 1, MT_DATA);
+ m = sctp_get_mbuf_for_msg(MCLBYTES, 1, M_NOWAIT, 1, MT_DATA);
if (m == NULL) {
/* No memory, INIT timer will re-attempt. */
SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - mbuf?\n");
@@ -4753,12 +4746,6 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
}
chunk_len = (uint16_t) sizeof(struct sctp_init_chunk);
padding_len = 0;
- /*
- * assume peer supports asconf in order to be able to queue local
- * address changes while an INIT is in flight and before the assoc
- * is established.
- */
- stcb->asoc.peer_supports_asconf = 1;
/* Now lets put the chunk header in place */
init = mtod(m, struct sctp_init_chunk *);
/* now the chunk header */
@@ -4775,120 +4762,76 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
init->init.num_inbound_streams = htons(stcb->asoc.max_inbound_streams);
init->init.initial_tsn = htonl(stcb->asoc.init_seq_number);
- if (stcb->asoc.scope.ipv4_addr_legal || stcb->asoc.scope.ipv6_addr_legal) {
- uint8_t i;
-
- parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
- if (stcb->asoc.scope.ipv4_addr_legal) {
- parameter_len += (uint16_t) sizeof(uint16_t);
- }
- if (stcb->asoc.scope.ipv6_addr_legal) {
- parameter_len += (uint16_t) sizeof(uint16_t);
- }
- sup_addr = (struct sctp_supported_addr_param *)(mtod(m, caddr_t)+chunk_len);
- sup_addr->ph.param_type = htons(SCTP_SUPPORTED_ADDRTYPE);
- sup_addr->ph.param_length = htons(parameter_len);
- i = 0;
- if (stcb->asoc.scope.ipv4_addr_legal) {
- sup_addr->addr_type[i++] = htons(SCTP_IPV4_ADDRESS);
- }
- if (stcb->asoc.scope.ipv6_addr_legal) {
- sup_addr->addr_type[i++] = htons(SCTP_IPV6_ADDRESS);
- }
- padding_len = 4 - 2 * i;
- chunk_len += parameter_len;
- }
/* Adaptation layer indication parameter */
if (inp->sctp_ep.adaptation_layer_indicator_provided) {
- if (padding_len > 0) {
- memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
- chunk_len += padding_len;
- padding_len = 0;
- }
parameter_len = (uint16_t) sizeof(struct sctp_adaptation_layer_indication);
ali = (struct sctp_adaptation_layer_indication *)(mtod(m, caddr_t)+chunk_len);
ali->ph.param_type = htons(SCTP_ULP_ADAPTATION);
ali->ph.param_length = htons(parameter_len);
- ali->indication = ntohl(inp->sctp_ep.adaptation_layer_indicator);
+ ali->indication = htonl(inp->sctp_ep.adaptation_layer_indicator);
chunk_len += parameter_len;
}
- if (SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly)) {
- /* Add NAT friendly parameter. */
- if (padding_len > 0) {
- memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
- chunk_len += padding_len;
- padding_len = 0;
- }
+ /* ECN parameter */
+ if (stcb->asoc.ecn_supported == 1) {
parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
- ph->param_type = htons(SCTP_HAS_NAT_SUPPORT);
+ ph->param_type = htons(SCTP_ECN_CAPABLE);
ph->param_length = htons(parameter_len);
chunk_len += parameter_len;
}
- /* now any cookie time extensions */
- if (stcb->asoc.cookie_preserve_req) {
- struct sctp_cookie_perserve_param *cookie_preserve;
-
- if (padding_len > 0) {
- memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
- chunk_len += padding_len;
- padding_len = 0;
- }
- parameter_len = (uint16_t) sizeof(struct sctp_cookie_perserve_param);
- cookie_preserve = (struct sctp_cookie_perserve_param *)(mtod(m, caddr_t)+chunk_len);
- cookie_preserve->ph.param_type = htons(SCTP_COOKIE_PRESERVE);
- cookie_preserve->ph.param_length = htons(parameter_len);
- cookie_preserve->time = htonl(stcb->asoc.cookie_preserve_req);
- stcb->asoc.cookie_preserve_req = 0;
+ /* PR-SCTP supported parameter */
+ if (stcb->asoc.prsctp_supported == 1) {
+ parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
+ ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
+ ph->param_type = htons(SCTP_PRSCTP_SUPPORTED);
+ ph->param_length = htons(parameter_len);
chunk_len += parameter_len;
}
- /* ECN parameter */
- if (stcb->asoc.ecn_allowed == 1) {
- if (padding_len > 0) {
- memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
- chunk_len += padding_len;
- padding_len = 0;
- }
+ /* Add NAT friendly parameter. */
+ if (SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly)) {
parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
- ph->param_type = htons(SCTP_ECN_CAPABLE);
+ ph->param_type = htons(SCTP_HAS_NAT_SUPPORT);
ph->param_length = htons(parameter_len);
chunk_len += parameter_len;
}
- /* And now tell the peer we do support PR-SCTP. */
- if (padding_len > 0) {
- memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
- chunk_len += padding_len;
- padding_len = 0;
- }
- parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
- ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
- ph->param_type = htons(SCTP_PRSCTP_SUPPORTED);
- ph->param_length = htons(parameter_len);
- chunk_len += parameter_len;
-
- /* And now tell the peer we do all the extensions */
- pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t)+chunk_len);
- pr_supported->ph.param_type = htons(SCTP_SUPPORTED_CHUNK_EXT);
+ /* And now tell the peer which extensions we support */
num_ext = 0;
- pr_supported->chunk_types[num_ext++] = SCTP_ASCONF;
- pr_supported->chunk_types[num_ext++] = SCTP_ASCONF_ACK;
- pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN;
- pr_supported->chunk_types[num_ext++] = SCTP_PACKET_DROPPED;
- pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET;
- if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) {
+ pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t)+chunk_len);
+ if (stcb->asoc.prsctp_supported == 1) {
+ pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN;
+ if (stcb->asoc.idata_supported) {
+ pr_supported->chunk_types[num_ext++] = SCTP_IFORWARD_CUM_TSN;
+ }
+ }
+ if (stcb->asoc.auth_supported == 1) {
pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION;
}
- if (stcb->asoc.sctp_nr_sack_on_off == 1) {
+ if (stcb->asoc.asconf_supported == 1) {
+ pr_supported->chunk_types[num_ext++] = SCTP_ASCONF;
+ pr_supported->chunk_types[num_ext++] = SCTP_ASCONF_ACK;
+ }
+ if (stcb->asoc.reconfig_supported == 1) {
+ pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET;
+ }
+ if (stcb->asoc.idata_supported) {
+ pr_supported->chunk_types[num_ext++] = SCTP_IDATA;
+ }
+ if (stcb->asoc.nrsack_supported == 1) {
pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK;
}
- parameter_len = (uint16_t) sizeof(struct sctp_supported_chunk_types_param) + num_ext;
- pr_supported->ph.param_length = htons(parameter_len);
- padding_len = SCTP_SIZE32(parameter_len) - parameter_len;
- chunk_len += parameter_len;
-
+ if (stcb->asoc.pktdrop_supported == 1) {
+ pr_supported->chunk_types[num_ext++] = SCTP_PACKET_DROPPED;
+ }
+ if (num_ext > 0) {
+ parameter_len = (uint16_t) sizeof(struct sctp_supported_chunk_types_param) + num_ext;
+ pr_supported->ph.param_type = htons(SCTP_SUPPORTED_CHUNK_EXT);
+ pr_supported->ph.param_length = htons(parameter_len);
+ padding_len = SCTP_SIZE32(parameter_len) - parameter_len;
+ chunk_len += parameter_len;
+ }
/* add authentication parameters */
- if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) {
+ if (stcb->asoc.auth_supported) {
/* attach RANDOM parameter, if available */
if (stcb->asoc.authinfo.random != NULL) {
struct sctp_auth_random *randp;
@@ -4906,8 +4849,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
chunk_len += parameter_len;
}
/* add HMAC_ALGO parameter */
- if ((stcb->asoc.local_hmacs != NULL) &&
- (stcb->asoc.local_hmacs->num_algo > 0)) {
+ if (stcb->asoc.local_hmacs != NULL) {
struct sctp_auth_hmac_algo *hmacs;
if (padding_len > 0) {
@@ -4925,7 +4867,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
chunk_len += parameter_len;
}
/* add CHUNKS parameter */
- if (sctp_auth_get_chklist_size(stcb->asoc.local_auth_chunks) > 0) {
+ if (stcb->asoc.local_auth_chunks != NULL) {
struct sctp_auth_chunk_list *chunks;
if (padding_len > 0) {
@@ -4943,8 +4885,52 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
chunk_len += parameter_len;
}
}
- SCTP_BUF_LEN(m) = chunk_len;
+ /* now any cookie time extensions */
+ if (stcb->asoc.cookie_preserve_req) {
+ struct sctp_cookie_perserve_param *cookie_preserve;
+
+ if (padding_len > 0) {
+ memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
+ chunk_len += padding_len;
+ padding_len = 0;
+ }
+ parameter_len = (uint16_t) sizeof(struct sctp_cookie_perserve_param);
+ cookie_preserve = (struct sctp_cookie_perserve_param *)(mtod(m, caddr_t)+chunk_len);
+ cookie_preserve->ph.param_type = htons(SCTP_COOKIE_PRESERVE);
+ cookie_preserve->ph.param_length = htons(parameter_len);
+ cookie_preserve->time = htonl(stcb->asoc.cookie_preserve_req);
+ stcb->asoc.cookie_preserve_req = 0;
+ chunk_len += parameter_len;
+ }
+ if (stcb->asoc.scope.ipv4_addr_legal || stcb->asoc.scope.ipv6_addr_legal) {
+ uint8_t i;
+ if (padding_len > 0) {
+ memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
+ chunk_len += padding_len;
+ padding_len = 0;
+ }
+ parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
+ if (stcb->asoc.scope.ipv4_addr_legal) {
+ parameter_len += (uint16_t) sizeof(uint16_t);
+ }
+ if (stcb->asoc.scope.ipv6_addr_legal) {
+ parameter_len += (uint16_t) sizeof(uint16_t);
+ }
+ sup_addr = (struct sctp_supported_addr_param *)(mtod(m, caddr_t)+chunk_len);
+ sup_addr->ph.param_type = htons(SCTP_SUPPORTED_ADDRTYPE);
+ sup_addr->ph.param_length = htons(parameter_len);
+ i = 0;
+ if (stcb->asoc.scope.ipv4_addr_legal) {
+ sup_addr->addr_type[i++] = htons(SCTP_IPV4_ADDRESS);
+ }
+ if (stcb->asoc.scope.ipv6_addr_legal) {
+ sup_addr->addr_type[i++] = htons(SCTP_IPV6_ADDRESS);
+ }
+ padding_len = 4 - 2 * i;
+ chunk_len += parameter_len;
+ }
+ SCTP_BUF_LEN(m) = chunk_len;
/* now the addresses */
/*
* To optimize this we could put the scoping stuff into a structure
@@ -4952,18 +4938,13 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
* we could just sifa in the address within the stcb. But for now
* this is a quick hack to get the address stuff teased apart.
*/
- sctp_add_addresses_to_i_ia(inp, stcb, &stcb->asoc.scope, m, cnt_inits_to, &padding_len, &chunk_len);
+ m_last = sctp_add_addresses_to_i_ia(inp, stcb, &stcb->asoc.scope,
+ m, cnt_inits_to,
+ &padding_len, &chunk_len);
init->ch.chunk_length = htons(chunk_len);
if (padding_len > 0) {
- struct mbuf *m_at, *mp_last;
-
- mp_last = NULL;
- for (m_at = m; m_at; m_at = SCTP_BUF_NEXT(m_at)) {
- if (SCTP_BUF_NEXT(m_at) == NULL)
- mp_last = m_at;
- }
- if ((mp_last == NULL) || sctp_add_pad_tombuf(mp_last, padding_len)) {
+ if (sctp_add_pad_tombuf(m_last, padding_len) == NULL) {
sctp_m_freem(m);
return;
}
@@ -5100,7 +5081,6 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
*nat_friendly = 1;
/* fall through */
case SCTP_PRSCTP_SUPPORTED:
-
if (padded_size != sizeof(struct sctp_paramhdr)) {
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error prsctp/nat support %d\n", plen);
goto invalid_size;
@@ -5108,7 +5088,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
at += padded_size;
break;
case SCTP_ECN_CAPABLE:
- if (padded_size != sizeof(struct sctp_ecn_supported_param)) {
+ if (padded_size != sizeof(struct sctp_paramhdr)) {
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error ecn %d\n", plen);
goto invalid_size;
}
@@ -5138,13 +5118,14 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
if (op_err == NULL) {
/* Ok need to try to get a mbuf */
#ifdef INET6
- l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ l_len = SCTP_MIN_OVERHEAD;
#else
- l_len = sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ l_len = SCTP_MIN_V4_OVERHEAD;
#endif
+ l_len += sizeof(struct sctp_chunkhdr);
l_len += plen;
l_len += sizeof(struct sctp_paramhdr);
- op_err = sctp_get_mbuf_for_msg(l_len, 0, M_DONTWAIT, 1, MT_DATA);
+ op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA);
if (op_err) {
SCTP_BUF_LEN(op_err) = 0;
/*
@@ -5207,13 +5188,14 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
/* Ok need to try to get an mbuf */
#ifdef INET6
- l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ l_len = SCTP_MIN_OVERHEAD;
#else
- l_len = sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ l_len = SCTP_MIN_V4_OVERHEAD;
#endif
+ l_len += sizeof(struct sctp_chunkhdr);
l_len += plen;
l_len += sizeof(struct sctp_paramhdr);
- op_err = sctp_get_mbuf_for_msg(l_len, 0, M_DONTWAIT, 1, MT_DATA);
+ op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA);
if (op_err) {
SCTP_BUF_LEN(op_err) = 0;
#ifdef INET6
@@ -5282,12 +5264,13 @@ invalid_size:
int l_len;
#ifdef INET6
- l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ l_len = SCTP_MIN_OVERHEAD;
#else
- l_len = sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ l_len = SCTP_MIN_V4_OVERHEAD;
#endif
+ l_len += sizeof(struct sctp_chunkhdr);
l_len += (2 * sizeof(struct sctp_paramhdr));
- op_err = sctp_get_mbuf_for_msg(l_len, 0, M_DONTWAIT, 1, MT_DATA);
+ op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA);
if (op_err) {
SCTP_BUF_LEN(op_err) = 0;
#ifdef INET6
@@ -5336,6 +5319,7 @@ sctp_are_there_new_addresses(struct sctp_association *asoc,
uint16_t ptype, plen;
uint8_t fnd;
struct sctp_nets *net;
+ int check_src;
#ifdef INET
struct sockaddr_in sin4, *sa4;
@@ -5357,39 +5341,61 @@ sctp_are_there_new_addresses(struct sctp_association *asoc,
sin6.sin6_len = sizeof(sin6);
#endif
/* First what about the src address of the pkt ? */
- fnd = 0;
- TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
- sa = (struct sockaddr *)&net->ro._l_addr;
- if (sa->sa_family == src->sa_family) {
+ check_src = 0;
+ switch (src->sa_family) {
+#ifdef INET
+ case AF_INET:
+ if (asoc->scope.ipv4_addr_legal) {
+ check_src = 1;
+ }
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ if (asoc->scope.ipv6_addr_legal) {
+ check_src = 1;
+ }
+ break;
+#endif
+ default:
+ /* TSNH */
+ break;
+ }
+ if (check_src) {
+ fnd = 0;
+ TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
+ sa = (struct sockaddr *)&net->ro._l_addr;
+ if (sa->sa_family == src->sa_family) {
#ifdef INET
- if (sa->sa_family == AF_INET) {
- struct sockaddr_in *src4;
+ if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *src4;
- sa4 = (struct sockaddr_in *)sa;
- src4 = (struct sockaddr_in *)src;
- if (sa4->sin_addr.s_addr == src4->sin_addr.s_addr) {
- fnd = 1;
- break;
+ sa4 = (struct sockaddr_in *)sa;
+ src4 = (struct sockaddr_in *)src;
+ if (sa4->sin_addr.s_addr == src4->sin_addr.s_addr) {
+ fnd = 1;
+ break;
+ }
}
- }
#endif
#ifdef INET6
- if (sa->sa_family == AF_INET6) {
- struct sockaddr_in6 *src6;
+ if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *src6;
- sa6 = (struct sockaddr_in6 *)sa;
- src6 = (struct sockaddr_in6 *)src;
- if (SCTP6_ARE_ADDR_EQUAL(sa6, src6)) {
- fnd = 1;
- break;
+ sa6 = (struct sockaddr_in6 *)sa;
+ src6 = (struct sockaddr_in6 *)src;
+ if (SCTP6_ARE_ADDR_EQUAL(sa6, src6)) {
+ fnd = 1;
+ break;
+ }
}
- }
#endif
+ }
+ }
+ if (fnd == 0) {
+ /* New address added! no need to look further. */
+ return (1);
}
- }
- if (fnd == 0) {
- /* New address added! no need to look futher. */
- return (1);
}
/* Ok so far lets munge through the rest of the packet */
offset += sizeof(struct sctp_init_chunk);
@@ -5410,9 +5416,11 @@ sctp_are_there_new_addresses(struct sctp_association *asoc,
phdr == NULL) {
return (1);
}
- p4 = (struct sctp_ipv4addr_param *)phdr;
- sin4.sin_addr.s_addr = p4->addr;
- sa_touse = (struct sockaddr *)&sin4;
+ if (asoc->scope.ipv4_addr_legal) {
+ p4 = (struct sctp_ipv4addr_param *)phdr;
+ sin4.sin_addr.s_addr = p4->addr;
+ sa_touse = (struct sockaddr *)&sin4;
+ }
break;
}
#endif
@@ -5427,10 +5435,12 @@ sctp_are_there_new_addresses(struct sctp_association *asoc,
phdr == NULL) {
return (1);
}
- p6 = (struct sctp_ipv6addr_param *)phdr;
- memcpy((caddr_t)&sin6.sin6_addr, p6->addr,
- sizeof(p6->addr));
- sa_touse = (struct sockaddr *)&sin6;
+ if (asoc->scope.ipv6_addr_legal) {
+ p6 = (struct sctp_ipv6addr_param *)phdr;
+ memcpy((caddr_t)&sin6.sin6_addr, p6->addr,
+ sizeof(p6->addr));
+ sa_touse = (struct sockaddr *)&sin6;
+ }
break;
}
#endif
@@ -5486,20 +5496,21 @@ sctp_are_there_new_addresses(struct sctp_association *asoc,
*/
void
sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
- struct mbuf *init_pkt, int iphlen, int offset,
+ struct sctp_nets *src_net, struct mbuf *init_pkt,
+ int iphlen, int offset,
struct sockaddr *src, struct sockaddr *dst,
struct sctphdr *sh, struct sctp_init_chunk *init_chk,
- uint8_t use_mflowid, uint32_t mflowid,
+ uint8_t mflowtype, uint32_t mflowid,
uint32_t vrf_id, uint16_t port, int hold_inp_lock)
{
struct sctp_association *asoc;
- struct mbuf *m, *m_at, *m_tmp, *m_cookie, *op_err, *mp_last;
+ struct mbuf *m, *m_tmp, *m_last, *m_cookie, *op_err;
struct sctp_init_ack_chunk *initack;
struct sctp_adaptation_layer_indication *ali;
- struct sctp_ecn_supported_param *ecn;
- struct sctp_prsctp_supported_param *prsctp;
struct sctp_supported_chunk_types_param *pr_supported;
+ struct sctp_paramhdr *ph;
union sctp_sockstore *over_addr;
+ struct sctp_scoping scp;
#ifdef INET
struct sockaddr_in *dst4 = (struct sockaddr_in *)dst;
@@ -5519,33 +5530,50 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
uint8_t *signature = NULL;
int cnt_inits_to = 0;
uint16_t his_limit, i_want;
- int abort_flag, padval;
- int num_ext;
- int p_len;
+ int abort_flag;
int nat_friendly = 0;
struct socket *so;
+ uint16_t num_ext, chunk_len, padding_len, parameter_len;
if (stcb) {
asoc = &stcb->asoc;
} else {
asoc = NULL;
}
- mp_last = NULL;
if ((asoc != NULL) &&
- (SCTP_GET_STATE(asoc) != SCTP_STATE_COOKIE_WAIT) &&
- (sctp_are_there_new_addresses(asoc, init_pkt, offset, src))) {
- /* new addresses, out of here in non-cookie-wait states */
- /*
- * Send a ABORT, we don't add the new address error clause
- * though we even set the T bit and copy in the 0 tag.. this
- * looks no different than if no listener was present.
- */
- op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
- "Address added");
- sctp_send_abort(init_pkt, iphlen, src, dst, sh, 0, op_err,
- use_mflowid, mflowid,
- vrf_id, port);
- return;
+ (SCTP_GET_STATE(asoc) != SCTP_STATE_COOKIE_WAIT)) {
+ if (sctp_are_there_new_addresses(asoc, init_pkt, offset, src)) {
+ /*
+ * new addresses, out of here in non-cookie-wait
+ * states
+ *
+ * Send an ABORT, without the new address error cause.
+ * This looks no different than if no listener was
+ * present.
+ */
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ "Address added");
+ sctp_send_abort(init_pkt, iphlen, src, dst, sh, 0, op_err,
+ mflowtype, mflowid, inp->fibnum,
+ vrf_id, port);
+ return;
+ }
+ if (src_net != NULL && (src_net->port != port)) {
+ /*
+ * change of remote encapsulation port, out of here
+ * in non-cookie-wait states
+ *
+ * Send an ABORT, without an specific error cause. This
+ * looks no different than if no listener was
+ * present.
+ */
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ "Remote encapsulation port changed");
+ sctp_send_abort(init_pkt, iphlen, src, dst, sh, 0, op_err,
+ mflowtype, mflowid, inp->fibnum,
+ vrf_id, port);
+ return;
+ }
}
abort_flag = 0;
op_err = sctp_arethere_unrecognized_parameters(init_pkt,
@@ -5556,24 +5584,25 @@ do_a_abort:
if (op_err == NULL) {
char msg[SCTP_DIAG_INFO_LEN];
- snprintf(msg, sizeof(msg), "%s:%d at %s\n", __FILE__, __LINE__, __FUNCTION__);
+ snprintf(msg, sizeof(msg), "%s:%d at %s", __FILE__, __LINE__, __func__);
op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
msg);
}
sctp_send_abort(init_pkt, iphlen, src, dst, sh,
init_chk->init.initiate_tag, op_err,
- use_mflowid, mflowid,
+ mflowtype, mflowid, inp->fibnum,
vrf_id, port);
return;
}
- m = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA);
+ m = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
if (m == NULL) {
/* No memory, INIT timer will re-attempt. */
if (op_err)
sctp_m_freem(op_err);
return;
}
- SCTP_BUF_LEN(m) = sizeof(struct sctp_init_chunk);
+ chunk_len = (uint16_t) sizeof(struct sctp_init_ack_chunk);
+ padding_len = 0;
/*
* We might not overwrite the identification[] completely and on
@@ -5605,7 +5634,7 @@ do_a_abort:
stc.peerport = sh->src_port;
/*
- * If we wanted to honor cookie life extentions, we would add to
+ * If we wanted to honor cookie life extensions, we would add to
* stc.cookie_life. For now we should NOT honor any extension
*/
stc.site_scope = stc.local_scope = stc.loopback_scope = 0;
@@ -5620,11 +5649,7 @@ do_a_abort:
stc.ipv6_addr_legal = 0;
stc.ipv4_addr_legal = 1;
}
-#ifdef SCTP_DONT_DO_PRIVADDR_SCOPE
- stc.ipv4_scope = 1;
-#else
stc.ipv4_scope = 0;
-#endif
if (net == NULL) {
to = src;
switch (dst->sa_family) {
@@ -5645,13 +5670,10 @@ do_a_abort:
stc.laddr_type = SCTP_IPV4_ADDRESS;
/* scope_id is only for v6 */
stc.scope_id = 0;
-#ifndef SCTP_DONT_DO_PRIVADDR_SCOPE
- if (IN4_ISPRIVATE_ADDRESS(&src4->sin_addr)) {
+ if ((IN4_ISPRIVATE_ADDRESS(&src4->sin_addr)) ||
+ (IN4_ISPRIVATE_ADDRESS(&dst4->sin_addr))) {
stc.ipv4_scope = 1;
}
-#else
- stc.ipv4_scope = 1;
-#endif /* SCTP_DONT_DO_PRIVADDR_SCOPE */
/* Must use the address in this case */
if (sctp_is_address_on_local_host(src, vrf_id)) {
stc.loopback_scope = 1;
@@ -5667,22 +5689,24 @@ do_a_abort:
{
stc.addr_type = SCTP_IPV6_ADDRESS;
memcpy(&stc.address, &src6->sin6_addr, sizeof(struct in6_addr));
- stc.scope_id = in6_getscope(&src6->sin6_addr);
+ stc.scope_id = ntohs(in6_getscope(&src6->sin6_addr));
if (sctp_is_address_on_local_host(src, vrf_id)) {
stc.loopback_scope = 1;
stc.local_scope = 0;
stc.site_scope = 1;
stc.ipv4_scope = 1;
- } else if (IN6_IS_ADDR_LINKLOCAL(&src6->sin6_addr)) {
+ } else if (IN6_IS_ADDR_LINKLOCAL(&src6->sin6_addr) ||
+ IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr)) {
/*
- * If the new destination is a
- * LINK_LOCAL we must have common
- * both site and local scope. Don't
- * set local scope though since we
- * must depend on the source to be
- * added implicitly. We cannot
- * assure just because we share one
- * link that all links are common.
+ * If the new destination or source
+ * is a LINK_LOCAL we must have
+ * common both site and local scope.
+ * Don't set local scope though
+ * since we must depend on the
+ * source to be added implicitly. We
+ * cannot assure just because we
+ * share one link that all links are
+ * common.
*/
stc.local_scope = 0;
stc.site_scope = 1;
@@ -5698,11 +5722,12 @@ do_a_abort:
* pull out the scope_id from
* incoming pkt
*/
- } else if (IN6_IS_ADDR_SITELOCAL(&src6->sin6_addr)) {
+ } else if (IN6_IS_ADDR_SITELOCAL(&src6->sin6_addr) ||
+ IN6_IS_ADDR_SITELOCAL(&dst6->sin6_addr)) {
/*
- * If the new destination is
- * SITE_LOCAL then we must have site
- * scope in common.
+ * If the new destination or source
+ * is SITE_LOCAL then we must have
+ * site scope in common.
*/
stc.site_scope = 1;
}
@@ -5806,7 +5831,7 @@ do_a_abort:
/* Now lets put the SCTP header in place */
initack = mtod(m, struct sctp_init_ack_chunk *);
/* Save it off for quick ref */
- stc.peers_vtag = init_chk->init.initiate_tag;
+ stc.peers_vtag = ntohl(init_chk->init.initiate_tag);
/* who are we */
memcpy(stc.identification, SCTP_VERSION_STRING,
min(strlen(SCTP_VERSION_STRING), sizeof(stc.identification)));
@@ -5876,10 +5901,10 @@ do_a_abort:
his_limit = ntohs(init_chk->init.num_inbound_streams);
/* choose what I want */
if (asoc != NULL) {
- if (asoc->streamoutcnt > inp->sctp_ep.pre_open_stream_count) {
+ if (asoc->streamoutcnt > asoc->pre_open_streams) {
i_want = asoc->streamoutcnt;
} else {
- i_want = inp->sctp_ep.pre_open_stream_count;
+ i_want = asoc->pre_open_streams;
}
} else {
i_want = inp->sctp_ep.pre_open_stream_count;
@@ -5897,161 +5922,182 @@ do_a_abort:
/* adaptation layer indication parameter */
if (inp->sctp_ep.adaptation_layer_indicator_provided) {
- ali = (struct sctp_adaptation_layer_indication *)((caddr_t)initack + sizeof(*initack));
+ parameter_len = (uint16_t) sizeof(struct sctp_adaptation_layer_indication);
+ ali = (struct sctp_adaptation_layer_indication *)(mtod(m, caddr_t)+chunk_len);
ali->ph.param_type = htons(SCTP_ULP_ADAPTATION);
- ali->ph.param_length = htons(sizeof(*ali));
- ali->indication = ntohl(inp->sctp_ep.adaptation_layer_indicator);
- SCTP_BUF_LEN(m) += sizeof(*ali);
- ecn = (struct sctp_ecn_supported_param *)((caddr_t)ali + sizeof(*ali));
- } else {
- ecn = (struct sctp_ecn_supported_param *)((caddr_t)initack + sizeof(*initack));
+ ali->ph.param_length = htons(parameter_len);
+ ali->indication = htonl(inp->sctp_ep.adaptation_layer_indicator);
+ chunk_len += parameter_len;
}
-
/* ECN parameter */
- if (((asoc != NULL) && (asoc->ecn_allowed == 1)) ||
- (inp->sctp_ecn_enable == 1)) {
- ecn->ph.param_type = htons(SCTP_ECN_CAPABLE);
- ecn->ph.param_length = htons(sizeof(*ecn));
- SCTP_BUF_LEN(m) += sizeof(*ecn);
-
- prsctp = (struct sctp_prsctp_supported_param *)((caddr_t)ecn +
- sizeof(*ecn));
- } else {
- prsctp = (struct sctp_prsctp_supported_param *)((caddr_t)ecn);
+ if (((asoc != NULL) && (asoc->ecn_supported == 1)) ||
+ ((asoc == NULL) && (inp->ecn_supported == 1))) {
+ parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
+ ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
+ ph->param_type = htons(SCTP_ECN_CAPABLE);
+ ph->param_length = htons(parameter_len);
+ chunk_len += parameter_len;
+ }
+ /* PR-SCTP supported parameter */
+ if (((asoc != NULL) && (asoc->prsctp_supported == 1)) ||
+ ((asoc == NULL) && (inp->prsctp_supported == 1))) {
+ parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
+ ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
+ ph->param_type = htons(SCTP_PRSCTP_SUPPORTED);
+ ph->param_length = htons(parameter_len);
+ chunk_len += parameter_len;
}
- /* And now tell the peer we do pr-sctp */
- prsctp->ph.param_type = htons(SCTP_PRSCTP_SUPPORTED);
- prsctp->ph.param_length = htons(sizeof(*prsctp));
- SCTP_BUF_LEN(m) += sizeof(*prsctp);
+ /* Add NAT friendly parameter */
if (nat_friendly) {
- /* Add NAT friendly parameter */
- struct sctp_paramhdr *ph;
-
- ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m));
+ parameter_len = (uint16_t) sizeof(struct sctp_paramhdr);
+ ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+chunk_len);
ph->param_type = htons(SCTP_HAS_NAT_SUPPORT);
- ph->param_length = htons(sizeof(struct sctp_paramhdr));
- SCTP_BUF_LEN(m) += sizeof(struct sctp_paramhdr);
+ ph->param_length = htons(parameter_len);
+ chunk_len += parameter_len;
}
- /* And now tell the peer we do all the extensions */
- pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m));
- pr_supported->ph.param_type = htons(SCTP_SUPPORTED_CHUNK_EXT);
+ /* And now tell the peer which extensions we support */
num_ext = 0;
- pr_supported->chunk_types[num_ext++] = SCTP_ASCONF;
- pr_supported->chunk_types[num_ext++] = SCTP_ASCONF_ACK;
- pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN;
- pr_supported->chunk_types[num_ext++] = SCTP_PACKET_DROPPED;
- pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET;
- if (!SCTP_BASE_SYSCTL(sctp_auth_disable))
+ pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t)+chunk_len);
+ if (((asoc != NULL) && (asoc->prsctp_supported == 1)) ||
+ ((asoc == NULL) && (inp->prsctp_supported == 1))) {
+ pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN;
+ if (((asoc != NULL) && (asoc->idata_supported == 1)) ||
+ ((asoc == NULL) && (inp->idata_supported == 1))) {
+ pr_supported->chunk_types[num_ext++] = SCTP_IFORWARD_CUM_TSN;
+ }
+ }
+ if (((asoc != NULL) && (asoc->auth_supported == 1)) ||
+ ((asoc == NULL) && (inp->auth_supported == 1))) {
pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION;
- if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off))
+ }
+ if (((asoc != NULL) && (asoc->asconf_supported == 1)) ||
+ ((asoc == NULL) && (inp->asconf_supported == 1))) {
+ pr_supported->chunk_types[num_ext++] = SCTP_ASCONF;
+ pr_supported->chunk_types[num_ext++] = SCTP_ASCONF_ACK;
+ }
+ if (((asoc != NULL) && (asoc->reconfig_supported == 1)) ||
+ ((asoc == NULL) && (inp->reconfig_supported == 1))) {
+ pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET;
+ }
+ if (((asoc != NULL) && (asoc->idata_supported == 1)) ||
+ ((asoc == NULL) && (inp->idata_supported == 1))) {
+ pr_supported->chunk_types[num_ext++] = SCTP_IDATA;
+ }
+ if (((asoc != NULL) && (asoc->nrsack_supported == 1)) ||
+ ((asoc == NULL) && (inp->nrsack_supported == 1))) {
pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK;
- p_len = sizeof(*pr_supported) + num_ext;
- pr_supported->ph.param_length = htons(p_len);
- bzero((caddr_t)pr_supported + p_len, SCTP_SIZE32(p_len) - p_len);
- SCTP_BUF_LEN(m) += SCTP_SIZE32(p_len);
-
+ }
+ if (((asoc != NULL) && (asoc->pktdrop_supported == 1)) ||
+ ((asoc == NULL) && (inp->pktdrop_supported == 1))) {
+ pr_supported->chunk_types[num_ext++] = SCTP_PACKET_DROPPED;
+ }
+ if (num_ext > 0) {
+ parameter_len = (uint16_t) sizeof(struct sctp_supported_chunk_types_param) + num_ext;
+ pr_supported->ph.param_type = htons(SCTP_SUPPORTED_CHUNK_EXT);
+ pr_supported->ph.param_length = htons(parameter_len);
+ padding_len = SCTP_SIZE32(parameter_len) - parameter_len;
+ chunk_len += parameter_len;
+ }
/* add authentication parameters */
- if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) {
+ if (((asoc != NULL) && (asoc->auth_supported == 1)) ||
+ ((asoc == NULL) && (inp->auth_supported == 1))) {
struct sctp_auth_random *randp;
struct sctp_auth_hmac_algo *hmacs;
struct sctp_auth_chunk_list *chunks;
- uint16_t random_len;
+ if (padding_len > 0) {
+ memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
+ chunk_len += padding_len;
+ padding_len = 0;
+ }
/* generate and add RANDOM parameter */
- random_len = SCTP_AUTH_RANDOM_SIZE_DEFAULT;
- randp = (struct sctp_auth_random *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m));
+ randp = (struct sctp_auth_random *)(mtod(m, caddr_t)+chunk_len);
+ parameter_len = (uint16_t) sizeof(struct sctp_auth_random) +
+ SCTP_AUTH_RANDOM_SIZE_DEFAULT;
randp->ph.param_type = htons(SCTP_RANDOM);
- p_len = sizeof(*randp) + random_len;
- randp->ph.param_length = htons(p_len);
- SCTP_READ_RANDOM(randp->random_data, random_len);
- /* zero out any padding required */
- bzero((caddr_t)randp + p_len, SCTP_SIZE32(p_len) - p_len);
- SCTP_BUF_LEN(m) += SCTP_SIZE32(p_len);
+ randp->ph.param_length = htons(parameter_len);
+ SCTP_READ_RANDOM(randp->random_data, SCTP_AUTH_RANDOM_SIZE_DEFAULT);
+ padding_len = SCTP_SIZE32(parameter_len) - parameter_len;
+ chunk_len += parameter_len;
+ if (padding_len > 0) {
+ memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
+ chunk_len += padding_len;
+ padding_len = 0;
+ }
/* add HMAC_ALGO parameter */
- hmacs = (struct sctp_auth_hmac_algo *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m));
- p_len = sctp_serialize_hmaclist(inp->sctp_ep.local_hmacs,
+ hmacs = (struct sctp_auth_hmac_algo *)(mtod(m, caddr_t)+chunk_len);
+ parameter_len = (uint16_t) sizeof(struct sctp_auth_hmac_algo) +
+ sctp_serialize_hmaclist(inp->sctp_ep.local_hmacs,
(uint8_t *) hmacs->hmac_ids);
- if (p_len > 0) {
- p_len += sizeof(*hmacs);
- hmacs->ph.param_type = htons(SCTP_HMAC_LIST);
- hmacs->ph.param_length = htons(p_len);
- /* zero out any padding required */
- bzero((caddr_t)hmacs + p_len, SCTP_SIZE32(p_len) - p_len);
- SCTP_BUF_LEN(m) += SCTP_SIZE32(p_len);
+ hmacs->ph.param_type = htons(SCTP_HMAC_LIST);
+ hmacs->ph.param_length = htons(parameter_len);
+ padding_len = SCTP_SIZE32(parameter_len) - parameter_len;
+ chunk_len += parameter_len;
+
+ if (padding_len > 0) {
+ memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
+ chunk_len += padding_len;
+ padding_len = 0;
}
/* add CHUNKS parameter */
- chunks = (struct sctp_auth_chunk_list *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m));
- p_len = sctp_serialize_auth_chunks(inp->sctp_ep.local_auth_chunks,
+ chunks = (struct sctp_auth_chunk_list *)(mtod(m, caddr_t)+chunk_len);
+ parameter_len = (uint16_t) sizeof(struct sctp_auth_chunk_list) +
+ sctp_serialize_auth_chunks(inp->sctp_ep.local_auth_chunks,
chunks->chunk_types);
- if (p_len > 0) {
- p_len += sizeof(*chunks);
- chunks->ph.param_type = htons(SCTP_CHUNK_LIST);
- chunks->ph.param_length = htons(p_len);
- /* zero out any padding required */
- bzero((caddr_t)chunks + p_len, SCTP_SIZE32(p_len) - p_len);
- SCTP_BUF_LEN(m) += SCTP_SIZE32(p_len);
- }
+ chunks->ph.param_type = htons(SCTP_CHUNK_LIST);
+ chunks->ph.param_length = htons(parameter_len);
+ padding_len = SCTP_SIZE32(parameter_len) - parameter_len;
+ chunk_len += parameter_len;
}
- m_at = m;
+ SCTP_BUF_LEN(m) = chunk_len;
+ m_last = m;
/* now the addresses */
- {
- struct sctp_scoping scp;
-
- /*
- * To optimize this we could put the scoping stuff into a
- * structure and remove the individual uint8's from the stc
- * structure. Then we could just sifa in the address within
- * the stc.. but for now this is a quick hack to get the
- * address stuff teased apart.
- */
- scp.ipv4_addr_legal = stc.ipv4_addr_legal;
- scp.ipv6_addr_legal = stc.ipv6_addr_legal;
- scp.loopback_scope = stc.loopback_scope;
- scp.ipv4_local_scope = stc.ipv4_scope;
- scp.local_scope = stc.local_scope;
- scp.site_scope = stc.site_scope;
- m_at = sctp_add_addresses_to_i_ia(inp, stcb, &scp, m_at, cnt_inits_to, NULL, NULL);
+ /*
+ * To optimize this we could put the scoping stuff into a structure
+ * and remove the individual uint8's from the stc structure. Then we
+ * could just sifa in the address within the stc.. but for now this
+ * is a quick hack to get the address stuff teased apart.
+ */
+ scp.ipv4_addr_legal = stc.ipv4_addr_legal;
+ scp.ipv6_addr_legal = stc.ipv6_addr_legal;
+ scp.loopback_scope = stc.loopback_scope;
+ scp.ipv4_local_scope = stc.ipv4_scope;
+ scp.local_scope = stc.local_scope;
+ scp.site_scope = stc.site_scope;
+ m_last = sctp_add_addresses_to_i_ia(inp, stcb, &scp, m_last,
+ cnt_inits_to,
+ &padding_len, &chunk_len);
+ /* padding_len can only be positive, if no addresses have been added */
+ if (padding_len > 0) {
+ memset(mtod(m, caddr_t)+chunk_len, 0, padding_len);
+ chunk_len += padding_len;
+ SCTP_BUF_LEN(m) += padding_len;
+ padding_len = 0;
}
-
/* tack on the operational error if present */
if (op_err) {
- struct mbuf *ol;
- int llen;
-
- llen = 0;
- ol = op_err;
-
- while (ol) {
- llen += SCTP_BUF_LEN(ol);
- ol = SCTP_BUF_NEXT(ol);
- }
- if (llen % 4) {
- /* must add a pad to the param */
- uint32_t cpthis = 0;
- int padlen;
-
- padlen = 4 - (llen % 4);
- m_copyback(op_err, llen, padlen, (caddr_t)&cpthis);
+ parameter_len = 0;
+ for (m_tmp = op_err; m_tmp != NULL; m_tmp = SCTP_BUF_NEXT(m_tmp)) {
+ parameter_len += SCTP_BUF_LEN(m_tmp);
}
- while (SCTP_BUF_NEXT(m_at) != NULL) {
- m_at = SCTP_BUF_NEXT(m_at);
- }
- SCTP_BUF_NEXT(m_at) = op_err;
- while (SCTP_BUF_NEXT(m_at) != NULL) {
- m_at = SCTP_BUF_NEXT(m_at);
+ padding_len = SCTP_SIZE32(parameter_len) - parameter_len;
+ SCTP_BUF_NEXT(m_last) = op_err;
+ while (SCTP_BUF_NEXT(m_last) != NULL) {
+ m_last = SCTP_BUF_NEXT(m_last);
}
+ chunk_len += parameter_len;
}
- /* pre-calulate the size and update pkt header and chunk header */
- p_len = 0;
- for (m_tmp = m; m_tmp; m_tmp = SCTP_BUF_NEXT(m_tmp)) {
- p_len += SCTP_BUF_LEN(m_tmp);
- if (SCTP_BUF_NEXT(m_tmp) == NULL) {
- /* m_tmp should now point to last one */
- break;
+ if (padding_len > 0) {
+ m_last = sctp_add_pad_tombuf(m_last, padding_len);
+ if (m_last == NULL) {
+ /* Houston we have a problem, no space */
+ sctp_m_freem(m);
+ return;
}
+ chunk_len += padding_len;
+ padding_len = 0;
}
-
/* Now we must build a cookie */
m_cookie = sctp_add_cookie(init_pkt, offset, m, 0, &stc, &signature);
if (m_cookie == NULL) {
@@ -6060,21 +6106,22 @@ do_a_abort:
return;
}
/* Now append the cookie to the end and update the space/size */
- SCTP_BUF_NEXT(m_tmp) = m_cookie;
-
- for (m_tmp = m_cookie; m_tmp; m_tmp = SCTP_BUF_NEXT(m_tmp)) {
- p_len += SCTP_BUF_LEN(m_tmp);
+ SCTP_BUF_NEXT(m_last) = m_cookie;
+ parameter_len = 0;
+ for (m_tmp = m_cookie; m_tmp != NULL; m_tmp = SCTP_BUF_NEXT(m_tmp)) {
+ parameter_len += SCTP_BUF_LEN(m_tmp);
if (SCTP_BUF_NEXT(m_tmp) == NULL) {
- /* m_tmp should now point to last one */
- mp_last = m_tmp;
- break;
+ m_last = m_tmp;
}
}
+ padding_len = SCTP_SIZE32(parameter_len) - parameter_len;
+ chunk_len += parameter_len;
+
/*
* Place in the size, but we don't include the last pad (if any) in
* the INIT-ACK.
*/
- initack->ch.chunk_length = htons(p_len);
+ initack->ch.chunk_length = htons(chunk_len);
/*
* Time to sign the cookie, we don't sign over the cookie signature
@@ -6088,11 +6135,8 @@ do_a_abort:
* We sifa 0 here to NOT set IP_DF if its IPv4, we ignore the return
* here since the timer will drive a retranmission.
*/
- padval = p_len % 4;
- if ((padval) && (mp_last)) {
- /* see my previous comments on mp_last */
- if (sctp_add_pad_tombuf(mp_last, (4 - padval))) {
- /* Houston we have a problem, no space */
+ if (padding_len > 0) {
+ if (sctp_add_pad_tombuf(m_last, padding_len) == NULL) {
sctp_m_freem(m);
return;
}
@@ -6107,7 +6151,7 @@ do_a_abort:
0, 0,
inp->sctp_lport, sh->src_port, init_chk->init.initiate_tag,
port, over_addr,
- use_mflowid, mflowid,
+ mflowtype, mflowid,
SCTP_SO_NOT_LOCKED);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
}
@@ -6123,7 +6167,7 @@ sctp_prune_prsctp(struct sctp_tcb *stcb,
struct sctp_tmit_chunk *chk, *nchk;
SCTP_TCB_LOCK_ASSERT(stcb);
- if ((asoc->peer_supports_prsctp) &&
+ if ((asoc->prsctp_supported) &&
(asoc->sent_queue_cnt_removeable > 0)) {
TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
/*
@@ -6165,7 +6209,7 @@ sctp_prune_prsctp(struct sctp_tcb *stcb,
return;
}
} /* if chunk was present */
- } /* if of sufficent priority */
+ } /* if of sufficient priority */
} /* if chunk has enabled */
} /* tailqforeach */
@@ -6206,11 +6250,15 @@ sctp_get_frag_point(struct sctp_tcb *stcb,
* we use a larger frag point.
*/
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- ovh = SCTP_MED_OVERHEAD;
+ ovh = SCTP_MIN_OVERHEAD;
} else {
- ovh = SCTP_MED_V4_OVERHEAD;
+ ovh = SCTP_MIN_V4_OVERHEAD;
+ }
+ if (stcb->asoc.idata_supported) {
+ ovh += sizeof(struct sctp_idata_chunk);
+ } else {
+ ovh += sizeof(struct sctp_data_chunk);
}
-
if (stcb->asoc.sctp_frag_point > asoc->smallest_mtu)
siz = asoc->smallest_mtu - ovh;
else
@@ -6335,6 +6383,7 @@ sctp_msg_append(struct sctp_tcb *stcb,
sp->timetolive = srcv->sinfo_timetolive;
sp->ppid = srcv->sinfo_ppid;
sp->context = srcv->sinfo_context;
+ sp->fsn = 0;
if (sp->sinfo_flags & SCTP_ADDR_OVER) {
sp->net = net;
atomic_add_int(&sp->net->ref_count, 1);
@@ -6420,7 +6469,7 @@ error_out:
if (outchain == NULL) {
/* This is the general case */
new_mbuf:
- outchain = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_HEADER);
+ outchain = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_HEADER);
if (outchain == NULL) {
goto error_out;
}
@@ -6453,10 +6502,10 @@ error_out:
}
}
/* get the new end of length */
- len = M_TRAILINGSPACE(*endofchain);
+ len = (int)M_TRAILINGSPACE(*endofchain);
} else {
/* how much is left at the end? */
- len = M_TRAILINGSPACE(*endofchain);
+ len = (int)M_TRAILINGSPACE(*endofchain);
}
/* Find the end of the data, for appending */
cp = (mtod((*endofchain), caddr_t)+SCTP_BUF_LEN((*endofchain)));
@@ -6474,7 +6523,7 @@ error_out:
/* now we need another one */
sizeofcpy -= len;
}
- m = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_HEADER);
+ m = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_HEADER);
if (m == NULL) {
/* We failed */
goto error_out;
@@ -6488,16 +6537,10 @@ error_out:
return (outchain);
} else {
/* copy the old fashion way */
- appendchain = SCTP_M_COPYM(clonechain, 0, M_COPYALL, M_DONTWAIT);
+ appendchain = SCTP_M_COPYM(clonechain, 0, M_COPYALL, M_NOWAIT);
#ifdef SCTP_MBUF_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
- struct mbuf *mat;
-
- for (mat = appendchain; mat; mat = SCTP_BUF_NEXT(mat)) {
- if (SCTP_BUF_IS_EXTENDED(mat)) {
- sctp_log_mb(mat, SCTP_MBUF_ICOPY);
- }
- }
+ sctp_log_mbc(appendchain, SCTP_MBUF_ICOPY);
}
#endif
}
@@ -6523,7 +6566,7 @@ error_out:
}
}
/*
- * save off the end and update the end-chain postion
+ * save off the end and update the end-chain position
*/
m = appendchain;
while (m) {
@@ -6535,7 +6578,7 @@ error_out:
}
return (outchain);
} else {
- /* save off the end and update the end-chain postion */
+ /* save off the end and update the end-chain position */
m = appendchain;
while (m) {
if (SCTP_BUF_NEXT(m) == NULL) {
@@ -6582,7 +6625,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
return;
}
if (ca->sndlen > 0) {
- m = SCTP_M_COPYM(ca->m, 0, M_COPYALL, M_DONTWAIT);
+ m = SCTP_M_COPYM(ca->m, 0, M_COPYALL, M_NOWAIT);
if (m == NULL) {
/* can't copy so we are done */
ca->cnt_failed++;
@@ -6590,13 +6633,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
}
#ifdef SCTP_MBUF_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
- struct mbuf *mat;
-
- for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) {
- if (SCTP_BUF_IS_EXTENDED(mat)) {
- sctp_log_mb(mat, SCTP_MBUF_ICOPY);
- }
- }
+ sctp_log_mbc(m, SCTP_MBUF_ICOPY);
}
#endif
} else {
@@ -6622,7 +6659,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
ph = mtod(m, struct sctp_paramhdr *);
ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
- ph->param_length = htons(sizeof(struct sctp_paramhdr) + ca->sndlen);
+ ph->param_length = htons((uint16_t) (sizeof(struct sctp_paramhdr) + ca->sndlen));
}
/*
* We add one here to keep the assoc from dis-appearing on
@@ -6652,14 +6689,10 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
asoc = &stcb->asoc;
if (ca->sndrcv.sinfo_flags & SCTP_EOF) {
/* shutdown this assoc */
- int cnt;
-
- cnt = sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED);
-
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
- (cnt == 0)) {
- if (asoc->locked_on_sending) {
+ sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED) == 0) {
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
goto abort_anyway;
}
/*
@@ -6701,27 +6734,24 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
- if (asoc->locked_on_sending) {
- /*
- * Locked to send out the
- * data
- */
- struct sctp_stream_queue_pending *sp;
-
- sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
- if (sp) {
- if ((sp->length == 0) && (sp->msg_is_complete == 0))
- asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
- }
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
+ asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
}
asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
(asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
+ struct mbuf *op_err;
+ char msg[SCTP_DIAG_INFO_LEN];
+
abort_anyway:
+ snprintf(msg, sizeof(msg),
+ "%s:%d at %s", __FILE__, __LINE__, __func__);
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ msg);
atomic_add_int(&stcb->asoc.refcnt, 1);
sctp_abort_an_association(stcb->sctp_ep, stcb,
- NULL, SCTP_SO_NOT_LOCKED);
+ op_err, SCTP_SO_NOT_LOCKED);
atomic_add_int(&stcb->asoc.refcnt, -1);
goto no_chunk_output;
}
@@ -6743,7 +6773,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
if (do_chunk_output)
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_NOT_LOCKED);
else if (added_control) {
- int num_out = 0, reason = 0, now_filled = 0;
+ int num_out, reason, now_filled = 0;
struct timeval now;
int frag_point;
@@ -6768,7 +6798,7 @@ sctp_sendall_completes(void *ptr, uint32_t val SCTP_UNUSED)
/*
* Do a notify here? Kacheong suggests that the notify be done at
* the send time.. so you would push up a notification if any send
- * failed. Don't know if this is feasable since the only failures we
+ * failed. Don't know if this is feasible since the only failures we
* have is "memory" related and if you cannot get an mbuf to send
* the data you surely can't get an mbuf to send up to notify the
* user you can't send the data :->
@@ -6779,20 +6809,13 @@ sctp_sendall_completes(void *ptr, uint32_t val SCTP_UNUSED)
SCTP_FREE(ca, SCTP_M_COPYAL);
}
-
-#define MC_ALIGN(m, len) do { \
- SCTP_BUF_RESV_UF(m, ((MCLBYTES - (len)) & ~(sizeof(long) - 1)); \
-} while (0)
-
-
-
static struct mbuf *
sctp_copy_out_all(struct uio *uio, int len)
{
struct mbuf *ret, *at;
int left, willcpy, cancpy, error;
- ret = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_WAIT, 1, MT_DATA);
+ ret = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_WAITOK, 1, MT_DATA);
if (ret == NULL) {
/* TSNH */
return (NULL);
@@ -6800,7 +6823,7 @@ sctp_copy_out_all(struct uio *uio, int len)
left = len;
SCTP_BUF_LEN(ret) = 0;
/* save space for the data chunk header */
- cancpy = M_TRAILINGSPACE(ret);
+ cancpy = (int)M_TRAILINGSPACE(ret);
willcpy = min(cancpy, left);
at = ret;
while (left > 0) {
@@ -6815,13 +6838,13 @@ sctp_copy_out_all(struct uio *uio, int len)
SCTP_BUF_NEXT_PKT(at) = SCTP_BUF_NEXT(at) = 0;
left -= willcpy;
if (left > 0) {
- SCTP_BUF_NEXT(at) = sctp_get_mbuf_for_msg(left, 0, M_WAIT, 1, MT_DATA);
+ SCTP_BUF_NEXT(at) = sctp_get_mbuf_for_msg(left, 0, M_WAITOK, 1, MT_DATA);
if (SCTP_BUF_NEXT(at) == NULL) {
goto err_out_now;
}
at = SCTP_BUF_NEXT(at);
SCTP_BUF_LEN(at) = 0;
- cancpy = M_TRAILINGSPACE(at);
+ cancpy = (int)M_TRAILINGSPACE(at);
willcpy = min(cancpy, left);
}
}
@@ -6855,7 +6878,7 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
ca->sndrcv.sinfo_flags &= ~SCTP_SENDALL;
/* get length and mbuf chain */
if (uio) {
- ca->sndlen = uio->uio_resid;
+ ca->sndlen = (int)uio->uio_resid;
ca->m = sctp_copy_out_all(uio, ca->sndlen);
if (ca->m == NULL) {
SCTP_FREE(ca, SCTP_M_COPYAL);
@@ -7005,7 +7028,7 @@ all_done:
sctp_misc_ints(SCTP_FLIGHT_LOG_UP,
data_list[i]->whoTo->flight_size,
data_list[i]->book_size,
- (uintptr_t) data_list[i]->whoTo,
+ (uint32_t) (uintptr_t) data_list[i]->whoTo,
data_list[i]->rec.data.TSN_seq);
}
sctp_flight_size_increase(data_list[i]);
@@ -7135,7 +7158,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb,
struct sctp_stream_out *strq,
uint32_t goal_mtu,
uint32_t frag_point,
- int *locked,
int *giveup,
int eeor_mode,
int *bail,
@@ -7149,8 +7171,10 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb,
struct sctp_association *asoc;
struct sctp_stream_queue_pending *sp;
struct sctp_tmit_chunk *chk;
- struct sctp_data_chunk *dchkh;
+ struct sctp_data_chunk *dchkh = NULL;
+ struct sctp_idata_chunk *ndchkh = NULL;
uint32_t to_move, length;
+ int leading;
uint8_t rcv_flags = 0;
uint8_t some_taken;
uint8_t send_lock_up = 0;
@@ -7161,7 +7185,6 @@ one_more_time:
/* sa_ignore FREED_MEMORY */
sp = TAILQ_FIRST(&strq->outqueue);
if (sp == NULL) {
- *locked = 0;
if (send_lock_up == 0) {
SCTP_TCB_SEND_LOCK(stcb);
send_lock_up = 1;
@@ -7170,7 +7193,9 @@ one_more_time:
if (sp) {
goto one_more_time;
}
- if (strq->last_msg_incomplete) {
+ if ((sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_EXPLICIT_EOR) == 0) &&
+ (stcb->asoc.idata_supported == 0) &&
+ (strq->last_msg_incomplete)) {
SCTP_PRINTF("Huh? Stream:%d lm_in_c=%d but queue is NULL\n",
strq->stream_no,
strq->last_msg_incomplete);
@@ -7206,6 +7231,11 @@ one_more_time:
atomic_subtract_int(&asoc->stream_queue_cnt, 1);
TAILQ_REMOVE(&strq->outqueue, sp, next);
stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp, send_lock_up);
+ if ((strq->state == SCTP_STREAM_RESET_PENDING) &&
+ (strq->chunks_on_queues == 0) &&
+ TAILQ_EMPTY(&strq->outqueue)) {
+ stcb->asoc.trigger_reset = 1;
+ }
if (sp->net) {
sctp_free_remote_addr(sp->net);
sp->net = NULL;
@@ -7216,8 +7246,6 @@ one_more_time:
}
sctp_free_a_strmoq(stcb, sp, so_locked);
/* we can't be locked to it */
- *locked = 0;
- stcb->asoc.locked_on_sending = NULL;
if (send_lock_up) {
SCTP_TCB_SEND_UNLOCK(stcb);
send_lock_up = 0;
@@ -7229,7 +7257,6 @@ one_more_time:
* sender just finished this but still holds a
* reference
*/
- *locked = 1;
*giveup = 1;
to_move = 0;
goto out_of;
@@ -7238,7 +7265,6 @@ one_more_time:
/* is there some to get */
if (sp->length == 0) {
/* no */
- *locked = 1;
*giveup = 1;
to_move = 0;
goto out_of;
@@ -7249,7 +7275,7 @@ one_more_time:
}
/* Whack down the size */
atomic_subtract_int(&stcb->asoc.total_output_queue_size, sp->length);
- if ((stcb->sctp_socket != NULL) && \
+ if ((stcb->sctp_socket != NULL) &&
((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
atomic_subtract_int(&stcb->sctp_socket->so_snd.sb_cc, sp->length);
@@ -7261,16 +7287,12 @@ one_more_time:
}
sp->length = 0;
sp->some_taken = 1;
- *locked = 1;
*giveup = 1;
to_move = 0;
goto out_of;
}
}
some_taken = sp->some_taken;
- if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
- sp->msg_is_complete = 1;
- }
re_look:
length = sp->length;
if (sp->msg_is_complete) {
@@ -7280,10 +7302,12 @@ re_look:
/* All of it fits in the MTU */
if (sp->some_taken) {
rcv_flags |= SCTP_DATA_LAST_FRAG;
- sp->put_last_out = 1;
} else {
rcv_flags |= SCTP_DATA_NOT_FRAG;
- sp->put_last_out = 1;
+ }
+ sp->put_last_out = 1;
+ if (sp->sinfo_flags & SCTP_SACK_IMMEDIATELY) {
+ rcv_flags |= SCTP_DATA_SACK_IMMEDIATELY;
}
} else {
/* Not all of it fits, we fragment */
@@ -7326,9 +7350,6 @@ re_look:
}
} else {
/* Nothing to take. */
- if (sp->some_taken) {
- *locked = 1;
- }
*giveup = 1;
to_move = 0;
goto out_of;
@@ -7350,8 +7371,8 @@ re_look:
if (sp->sinfo_flags & SCTP_UNORDERED) {
rcv_flags |= SCTP_DATA_UNORDERED;
}
- if ((SCTP_BASE_SYSCTL(sctp_enable_sack_immediately) && ((sp->sinfo_flags & SCTP_EOF) == SCTP_EOF)) ||
- ((sp->sinfo_flags & SCTP_SACK_IMMEDIATELY) == SCTP_SACK_IMMEDIATELY)) {
+ if (SCTP_BASE_SYSCTL(sctp_enable_sack_immediately) &&
+ (sp->sinfo_flags & SCTP_EOF) == SCTP_EOF) {
rcv_flags |= SCTP_DATA_SACK_IMMEDIATELY;
}
/* clear out the chunk before setting up */
@@ -7376,7 +7397,7 @@ re_look:
struct mbuf *m;
dont_do_it:
- chk->data = SCTP_M_COPYM(sp->data, 0, to_move, M_DONTWAIT);
+ chk->data = SCTP_M_COPYM(sp->data, 0, to_move, M_NOWAIT);
chk->last_mbuf = NULL;
if (chk->data == NULL) {
sp->some_taken = some_taken;
@@ -7387,13 +7408,7 @@ dont_do_it:
}
#ifdef SCTP_MBUF_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
- struct mbuf *mat;
-
- for (mat = chk->data; mat; mat = SCTP_BUF_NEXT(mat)) {
- if (SCTP_BUF_IS_EXTENDED(mat)) {
- sctp_log_mb(mat, SCTP_MBUF_ICOPY);
- }
- }
+ sctp_log_mbc(chk->data, SCTP_MBUF_ICOPY);
}
#endif
/* Pull off the data */
@@ -7428,7 +7443,7 @@ dont_do_it:
chk->copy_by_ref = 0;
}
/*
- * get last_mbuf and counts of mb useage This is ugly but hopefully
+ * get last_mbuf and counts of mb usage This is ugly but hopefully
* its only one mbuf.
*/
if (chk->last_mbuf == NULL) {
@@ -7451,11 +7466,16 @@ dont_do_it:
} else {
atomic_subtract_int(&sp->length, to_move);
}
- if (M_LEADINGSPACE(chk->data) < (int)sizeof(struct sctp_data_chunk)) {
+ if (stcb->asoc.idata_supported == 0) {
+ leading = sizeof(struct sctp_data_chunk);
+ } else {
+ leading = sizeof(struct sctp_idata_chunk);
+ }
+ if (M_LEADINGSPACE(chk->data) < leading) {
/* Not enough room for a chunk header, get some */
struct mbuf *m;
- m = sctp_get_mbuf_for_msg(1, 0, M_DONTWAIT, 0, MT_DATA);
+ m = sctp_get_mbuf_for_msg(1, 0, M_NOWAIT, 0, MT_DATA);
if (m == NULL) {
/*
* we're in trouble here. _PREPEND below will free
@@ -7466,7 +7486,7 @@ dont_do_it:
SCTP_TCB_SEND_LOCK(stcb);
send_lock_up = 1;
}
- if (chk->data == NULL) {
+ if (sp->data == NULL) {
/* unsteal the data */
sp->data = chk->data;
sp->tail_mbuf = chk->last_mbuf;
@@ -7492,7 +7512,11 @@ dont_do_it:
M_ALIGN(chk->data, 4);
}
}
- SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_data_chunk), M_DONTWAIT);
+ if (stcb->asoc.idata_supported == 0) {
+ SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_data_chunk), M_NOWAIT);
+ } else {
+ SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_idata_chunk), M_NOWAIT);
+ }
if (chk->data == NULL) {
/* HELP, TSNH since we assured it would not above? */
#ifdef INVARIANTS
@@ -7505,8 +7529,13 @@ dont_do_it:
to_move = 0;
goto out_of;
}
- sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk));
- chk->book_size = chk->send_size = (to_move + sizeof(struct sctp_data_chunk));
+ if (stcb->asoc.idata_supported == 0) {
+ sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk));
+ chk->book_size = chk->send_size = (uint16_t) (to_move + sizeof(struct sctp_data_chunk));
+ } else {
+ sctp_snd_sb_alloc(stcb, sizeof(struct sctp_idata_chunk));
+ chk->book_size = chk->send_size = (uint16_t) (to_move + sizeof(struct sctp_idata_chunk));
+ }
chk->book_size_scale = 0;
chk->sent = SCTP_DATAGRAM_UNSENT;
@@ -7514,10 +7543,28 @@ dont_do_it:
chk->asoc = &stcb->asoc;
chk->pad_inplace = 0;
chk->no_fr_allowed = 0;
- chk->rec.data.stream_seq = strq->next_sequence_send;
- if ((rcv_flags & SCTP_DATA_LAST_FRAG) &&
- !(rcv_flags & SCTP_DATA_UNORDERED)) {
- strq->next_sequence_send++;
+ if (stcb->asoc.idata_supported == 0) {
+ if (rcv_flags & SCTP_DATA_UNORDERED) {
+ /* Just use 0. The receiver ignores the values. */
+ chk->rec.data.stream_seq = 0;
+ } else {
+ chk->rec.data.stream_seq = strq->next_mid_ordered;
+ if (rcv_flags & SCTP_DATA_LAST_FRAG) {
+ strq->next_mid_ordered++;
+ }
+ }
+ } else {
+ if (rcv_flags & SCTP_DATA_UNORDERED) {
+ chk->rec.data.stream_seq = strq->next_mid_unordered;
+ if (rcv_flags & SCTP_DATA_LAST_FRAG) {
+ strq->next_mid_unordered++;
+ }
+ } else {
+ chk->rec.data.stream_seq = strq->next_mid_ordered;
+ if (rcv_flags & SCTP_DATA_LAST_FRAG) {
+ strq->next_mid_ordered++;
+ }
+ }
}
chk->rec.data.stream_number = sp->stream;
chk->rec.data.payloadtype = sp->ppid;
@@ -7541,11 +7588,15 @@ dont_do_it:
chk->rec.data.TSN_seq = atomic_fetchadd_int(&asoc->sending_seq, 1);
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_AT_SEND_2_OUTQ) {
sctp_misc_ints(SCTP_STRMOUT_LOG_SEND,
- (uintptr_t) stcb, sp->length,
+ (uint32_t) (uintptr_t) stcb, sp->length,
(uint32_t) ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq),
chk->rec.data.TSN_seq);
}
- dchkh = mtod(chk->data, struct sctp_data_chunk *);
+ if (stcb->asoc.idata_supported == 0) {
+ dchkh = mtod(chk->data, struct sctp_data_chunk *);
+ } else {
+ ndchkh = mtod(chk->data, struct sctp_idata_chunk *);
+ }
/*
* Put the rest of the things in place now. Size was done earlier in
* previous loop prior to padding.
@@ -7567,14 +7618,28 @@ dont_do_it:
asoc->out_tsnlog[asoc->tsn_out_at].in_out = 2;
asoc->tsn_out_at++;
#endif
-
- dchkh->ch.chunk_type = SCTP_DATA;
- dchkh->ch.chunk_flags = chk->rec.data.rcv_flags;
- dchkh->dp.tsn = htonl(chk->rec.data.TSN_seq);
- dchkh->dp.stream_id = htons(strq->stream_no);
- dchkh->dp.stream_sequence = htons(chk->rec.data.stream_seq);
- dchkh->dp.protocol_id = chk->rec.data.payloadtype;
- dchkh->ch.chunk_length = htons(chk->send_size);
+ if (stcb->asoc.idata_supported == 0) {
+ dchkh->ch.chunk_type = SCTP_DATA;
+ dchkh->ch.chunk_flags = chk->rec.data.rcv_flags;
+ dchkh->dp.tsn = htonl(chk->rec.data.TSN_seq);
+ dchkh->dp.stream_id = htons((strq->stream_no & 0x0000ffff));
+ dchkh->dp.stream_sequence = htons((uint16_t) chk->rec.data.stream_seq);
+ dchkh->dp.protocol_id = chk->rec.data.payloadtype;
+ dchkh->ch.chunk_length = htons(chk->send_size);
+ } else {
+ ndchkh->ch.chunk_type = SCTP_IDATA;
+ ndchkh->ch.chunk_flags = chk->rec.data.rcv_flags;
+ ndchkh->dp.tsn = htonl(chk->rec.data.TSN_seq);
+ ndchkh->dp.stream_id = htons(strq->stream_no);
+ ndchkh->dp.reserved = htons(0);
+ ndchkh->dp.msg_id = htonl(chk->rec.data.stream_seq);
+ if (sp->fsn == 0)
+ ndchkh->dp.ppid_fsn.protocol_id = chk->rec.data.payloadtype;
+ else
+ ndchkh->dp.ppid_fsn.fsn = htonl(sp->fsn);
+ sp->fsn++;
+ ndchkh->ch.chunk_length = htons(chk->send_size);
+ }
/* Now advance the chk->send_size by the actual pad needed. */
if (chk->send_size < SCTP_SIZE32(chk->book_size)) {
/* need a pad */
@@ -7582,12 +7647,10 @@ dont_do_it:
int pads;
pads = SCTP_SIZE32(chk->book_size) - chk->send_size;
- if (sctp_pad_lastmbuf(chk->data, pads, chk->last_mbuf) == 0) {
- chk->pad_inplace = 1;
- }
- if ((lm = SCTP_BUF_NEXT(chk->last_mbuf)) != NULL) {
- /* pad added an mbuf */
+ lm = sctp_pad_lastmbuf(chk->data, pads, chk->last_mbuf);
+ if (lm != NULL) {
chk->last_mbuf = lm;
+ chk->pad_inplace = 1;
}
chk->send_size += pads;
}
@@ -7596,7 +7659,6 @@ dont_do_it:
}
if (sp->msg_is_complete && (sp->length == 0) && (sp->sender_all_done)) {
/* All done pull and kill the message */
- atomic_subtract_int(&asoc->stream_queue_cnt, 1);
if (sp->put_last_out == 0) {
SCTP_PRINTF("Gak, put out entire msg with NO end!-2\n");
SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d send_lock:%d\n",
@@ -7610,8 +7672,14 @@ dont_do_it:
SCTP_TCB_SEND_LOCK(stcb);
send_lock_up = 1;
}
+ atomic_subtract_int(&asoc->stream_queue_cnt, 1);
TAILQ_REMOVE(&strq->outqueue, sp, next);
stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp, send_lock_up);
+ if ((strq->state == SCTP_STREAM_RESET_PENDING) &&
+ (strq->chunks_on_queues == 0) &&
+ TAILQ_EMPTY(&strq->outqueue)) {
+ stcb->asoc.trigger_reset = 1;
+ }
if (sp->net) {
sctp_free_remote_addr(sp->net);
sp->net = NULL;
@@ -7621,13 +7689,6 @@ dont_do_it:
sp->data = NULL;
}
sctp_free_a_strmoq(stcb, sp, so_locked);
-
- /* we can't be locked to it */
- *locked = 0;
- stcb->asoc.locked_on_sending = NULL;
- } else {
- /* more to go, we are locked */
- *locked = 1;
}
asoc->chunks_on_out_queue++;
strq->chunks_on_queues++;
@@ -7652,7 +7713,7 @@ sctp_fill_outqueue(struct sctp_tcb *stcb,
struct sctp_association *asoc;
struct sctp_stream_out *strq;
int goal_mtu, moved_how_much, total_moved = 0, bail = 0;
- int locked, giveup;
+ int giveup;
SCTP_TCB_LOCK_ASSERT(stcb);
asoc = &stcb->asoc;
@@ -7673,40 +7734,28 @@ sctp_fill_outqueue(struct sctp_tcb *stcb,
break;
}
/* Need an allowance for the data chunk header too */
- goal_mtu -= sizeof(struct sctp_data_chunk);
+ if (stcb->asoc.idata_supported == 0) {
+ goal_mtu -= sizeof(struct sctp_data_chunk);
+ } else {
+ goal_mtu -= sizeof(struct sctp_idata_chunk);
+ }
/* must make even word boundary */
goal_mtu &= 0xfffffffc;
- if (asoc->locked_on_sending) {
- /* We are stuck on one stream until the message completes. */
- strq = asoc->locked_on_sending;
- locked = 1;
- } else {
- strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
- locked = 0;
- }
+ strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
while ((goal_mtu > 0) && strq) {
giveup = 0;
bail = 0;
- moved_how_much = sctp_move_to_outqueue(stcb, strq, goal_mtu, frag_point, &locked,
+ moved_how_much = sctp_move_to_outqueue(stcb, strq, goal_mtu, frag_point,
&giveup, eeor_mode, &bail, so_locked);
- if (moved_how_much)
- stcb->asoc.ss_functions.sctp_ss_scheduled(stcb, net, asoc, strq, moved_how_much);
+ stcb->asoc.ss_functions.sctp_ss_scheduled(stcb, net, asoc, strq, moved_how_much);
- if (locked) {
- asoc->locked_on_sending = strq;
- if ((moved_how_much == 0) || (giveup) || bail)
- /* no more to move for now */
- break;
- } else {
- asoc->locked_on_sending = NULL;
- if ((giveup) || bail) {
- break;
- }
- strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
- if (strq == NULL) {
- break;
- }
+ if ((giveup) || bail) {
+ break;
+ }
+ strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
+ if (strq == NULL) {
+ break;
}
total_moved += moved_how_much;
goal_mtu -= (moved_how_much + sizeof(struct sctp_data_chunk));
@@ -7784,12 +7833,15 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
{
/**
* Ok this is the generic chunk service queue. we must do the
- * following: - Service the stream queue that is next, moving any
- * message (note I must get a complete message i.e. FIRST/MIDDLE and
- * LAST to the out queue in one pass) and assigning TSN's - Check to
- * see if the cwnd/rwnd allows any output, if so we go ahead and
- * fomulate and send the low level chunks. Making sure to combine
- * any control in the control chunk queue also.
+ * following:
+ * - Service the stream queue that is next, moving any
+ * message (note I must get a complete message i.e. FIRST/MIDDLE and
+ * LAST to the out queue in one pass) and assigning TSN's. This
+ * only applys though if the peer does not support NDATA. For NDATA
+ * chunks its ok to not send the entire message ;-)
+ * - Check to see if the cwnd/rwnd allows any output, if so we go ahead and
+ * fomulate and send the low level chunks. Making sure to combine
+ * any control in the control chunk queue also.
*/
struct sctp_nets *net, *start_at, *sack_goes_to = NULL, *old_start_at = NULL;
struct mbuf *outchain, *endoutchain;
@@ -7818,8 +7870,8 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
int quit_now = 0;
*num_out = 0;
+ *reason_code = 0;
auth_keyid = stcb->asoc.authinfo.active_keyid;
-
if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
(asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED) ||
(sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) {
@@ -7838,7 +7890,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
#endif
SCTP_TCB_LOCK_ASSERT(stcb);
hbflag = 0;
- if ((control_only) || (asoc->stream_reset_outstanding))
+ if (control_only)
no_data_chunks = 1;
else
no_data_chunks = 0;
@@ -7848,7 +7900,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
(asoc->ctrl_queue_cnt == stcb->asoc.ecn_echo_cnt_onq)) &&
TAILQ_EMPTY(&asoc->asconf_send_queue) &&
TAILQ_EMPTY(&asoc->send_queue) &&
- stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) {
+ sctp_is_there_unsent_data(stcb, so_locked) == 0) {
nothing_to_send:
*reason_code = 9;
return (0);
@@ -8006,31 +8058,15 @@ again_one_more_time:
} else {
skip_data_for_this_net = 0;
}
- if ((net->ro.ro_rt) && (net->ro.ro_rt->rt_ifp)) {
- /*
- * if we have a route and an ifp check to see if we
- * have room to send to this guy
- */
- struct ifnet *ifp;
-
- ifp = net->ro.ro_rt->rt_ifp;
- if ((ifp->if_snd.ifq_len + 2) >= ifp->if_snd.ifq_maxlen) {
- SCTP_STAT_INCR(sctps_ifnomemqueued);
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_MAXBURST_ENABLE) {
- sctp_log_maxburst(stcb, net, ifp->if_snd.ifq_len, ifp->if_snd.ifq_maxlen, SCTP_MAX_IFP_APPLIED);
- }
- continue;
- }
- }
switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
#ifdef INET
case AF_INET:
- mtu = net->mtu - (sizeof(struct ip) + sizeof(struct sctphdr));
+ mtu = net->mtu - SCTP_MIN_V4_OVERHEAD;
break;
#endif
#ifdef INET6
case AF_INET6:
- mtu = net->mtu - (sizeof(struct ip6_hdr) + sizeof(struct sctphdr));
+ mtu = net->mtu - SCTP_MIN_OVERHEAD;
break;
#endif
default:
@@ -8052,6 +8088,7 @@ again_one_more_time:
} else {
r_mtu = mtu;
}
+ error = 0;
/************************/
/* ASCONF transmission */
/************************/
@@ -8175,6 +8212,12 @@ again_one_more_time:
* it is used to do appropriate
* source address selection.
*/
+ if (*now_filled == 0) {
+ (void)SCTP_GETTIME_TIMEVAL(now);
+ *now_filled = 1;
+ }
+ net->last_sent_time = *now;
+ hbflag = 0;
if ((error = sctp_lowlevel_chunk_output(inp, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
outchain, auth_offset, auth,
@@ -8185,21 +8228,18 @@ again_one_more_time:
net->port, NULL,
0, 0,
so_locked))) {
- if (error == ENOBUFS) {
- asoc->ifp_had_enobuf = 1;
- SCTP_STAT_INCR(sctps_lowlevelerr);
- }
+ /*
+ * error, we could not
+ * output
+ */
+ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
if (from_where == 0) {
SCTP_STAT_INCR(sctps_lowlevelerrusr);
}
- if (*now_filled == 0) {
- (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time);
- *now_filled = 1;
- *now = net->last_sent_time;
- } else {
- net->last_sent_time = *now;
+ if (error == ENOBUFS) {
+ asoc->ifp_had_enobuf = 1;
+ SCTP_STAT_INCR(sctps_lowlevelerr);
}
- hbflag = 0;
/* error, could not output */
if (error == EHOSTUNREACH) {
/*
@@ -8210,17 +8250,10 @@ again_one_more_time:
sctp_move_chunks_from_net(stcb, net);
}
*reason_code = 7;
- continue;
- } else
- asoc->ifp_had_enobuf = 0;
- if (*now_filled == 0) {
- (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time);
- *now_filled = 1;
- *now = net->last_sent_time;
+ break;
} else {
- net->last_sent_time = *now;
+ asoc->ifp_had_enobuf = 0;
}
- hbflag = 0;
/*
* increase the number we sent, if a
* cookie is sent we don't tell them
@@ -8253,6 +8286,10 @@ again_one_more_time:
}
}
}
+ if (error != 0) {
+ /* try next net */
+ continue;
+ }
/************************/
/* Control transmission */
/************************/
@@ -8391,7 +8428,8 @@ again_one_more_time:
/* turn off the timer */
if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
- inp, stcb, net, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_1);
+ inp, stcb, net,
+ SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_1);
}
}
ctl_cnt++;
@@ -8448,6 +8486,15 @@ again_one_more_time:
sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net);
cookie = 0;
}
+ /* Only HB or ASCONF advances time */
+ if (hbflag) {
+ if (*now_filled == 0) {
+ (void)SCTP_GETTIME_TIMEVAL(now);
+ *now_filled = 1;
+ }
+ net->last_sent_time = *now;
+ hbflag = 0;
+ }
if ((error = sctp_lowlevel_chunk_output(inp, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
outchain,
@@ -8459,23 +8506,17 @@ again_one_more_time:
net->port, NULL,
0, 0,
so_locked))) {
- if (error == ENOBUFS) {
- asoc->ifp_had_enobuf = 1;
- SCTP_STAT_INCR(sctps_lowlevelerr);
- }
+ /*
+ * error, we could not
+ * output
+ */
+ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
if (from_where == 0) {
SCTP_STAT_INCR(sctps_lowlevelerrusr);
}
- /* error, could not output */
- if (hbflag) {
- if (*now_filled == 0) {
- (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time);
- *now_filled = 1;
- *now = net->last_sent_time;
- } else {
- net->last_sent_time = *now;
- }
- hbflag = 0;
+ if (error == ENOBUFS) {
+ asoc->ifp_had_enobuf = 1;
+ SCTP_STAT_INCR(sctps_lowlevelerr);
}
if (error == EHOSTUNREACH) {
/*
@@ -8486,19 +8527,9 @@ again_one_more_time:
sctp_move_chunks_from_net(stcb, net);
}
*reason_code = 7;
- continue;
- } else
+ break;
+ } else {
asoc->ifp_had_enobuf = 0;
- /* Only HB or ASCONF advances time */
- if (hbflag) {
- if (*now_filled == 0) {
- (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time);
- *now_filled = 1;
- *now = net->last_sent_time;
- } else {
- net->last_sent_time = *now;
- }
- hbflag = 0;
}
/*
* increase the number we sent, if a
@@ -8532,6 +8563,10 @@ again_one_more_time:
}
}
}
+ if (error != 0) {
+ /* try next net */
+ continue;
+ }
/* JRI: if dest is in PF state, do not send data to it */
if ((asoc->sctp_cmt_on_off > 0) &&
(net != stcb->asoc.alternate) &&
@@ -8576,16 +8611,16 @@ again_one_more_time:
switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
#ifdef INET
case AF_INET:
- if (net->mtu > (sizeof(struct ip) + sizeof(struct sctphdr)))
- omtu = net->mtu - (sizeof(struct ip) + sizeof(struct sctphdr));
+ if (net->mtu > SCTP_MIN_V4_OVERHEAD)
+ omtu = net->mtu - SCTP_MIN_V4_OVERHEAD;
else
omtu = 0;
break;
#endif
#ifdef INET6
case AF_INET6:
- if (net->mtu > (sizeof(struct ip6_hdr) + sizeof(struct sctphdr)))
- omtu = net->mtu - (sizeof(struct ip6_hdr) + sizeof(struct sctphdr));
+ if (net->mtu > SCTP_MIN_OVERHEAD)
+ omtu = net->mtu - SCTP_MIN_OVERHEAD;
else
omtu = 0;
break;
@@ -8595,7 +8630,8 @@ again_one_more_time:
omtu = 0;
break;
}
- if ((((asoc->state & SCTP_STATE_OPEN) == SCTP_STATE_OPEN) &&
+ if ((((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
(skip_data_for_this_net == 0)) ||
(cookie)) {
TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) {
@@ -8785,6 +8821,14 @@ no_data_fill:
*/
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
}
+ if (bundle_at || hbflag) {
+ /* For data/asconf and hb set time */
+ if (*now_filled == 0) {
+ (void)SCTP_GETTIME_TIMEVAL(now);
+ *now_filled = 1;
+ }
+ net->last_sent_time = *now;
+ }
/* Now send it, if there is anything to send :> */
if ((error = sctp_lowlevel_chunk_output(inp,
stcb,
@@ -8803,23 +8847,13 @@ no_data_fill:
0, 0,
so_locked))) {
/* error, we could not output */
- if (error == ENOBUFS) {
- SCTP_STAT_INCR(sctps_lowlevelerr);
- asoc->ifp_had_enobuf = 1;
- }
+ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
if (from_where == 0) {
SCTP_STAT_INCR(sctps_lowlevelerrusr);
}
- SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
- if (hbflag) {
- if (*now_filled == 0) {
- (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time);
- *now_filled = 1;
- *now = net->last_sent_time;
- } else {
- net->last_sent_time = *now;
- }
- hbflag = 0;
+ if (error == ENOBUFS) {
+ SCTP_STAT_INCR(sctps_lowlevelerr);
+ asoc->ifp_had_enobuf = 1;
}
if (error == EHOSTUNREACH) {
/*
@@ -8844,16 +8878,6 @@ no_data_fill:
endoutchain = NULL;
auth = NULL;
auth_offset = 0;
- if (bundle_at || hbflag) {
- /* For data/asconf and hb set time */
- if (*now_filled == 0) {
- (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time);
- *now_filled = 1;
- *now = net->last_sent_time;
- } else {
- net->last_sent_time = *now;
- }
- }
if (!no_out_cnt) {
*num_out += (ctl_cnt + bundle_at);
}
@@ -8914,9 +8938,37 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err)
*/
struct sctp_chunkhdr *hdr;
struct sctp_tmit_chunk *chk;
- struct mbuf *mat;
+ struct mbuf *mat, *last_mbuf;
+ uint32_t chunk_length;
+ uint16_t padding_length;
SCTP_TCB_LOCK_ASSERT(stcb);
+ SCTP_BUF_PREPEND(op_err, sizeof(struct sctp_chunkhdr), M_NOWAIT);
+ if (op_err == NULL) {
+ return;
+ }
+ last_mbuf = NULL;
+ chunk_length = 0;
+ for (mat = op_err; mat != NULL; mat = SCTP_BUF_NEXT(mat)) {
+ chunk_length += SCTP_BUF_LEN(mat);
+ if (SCTP_BUF_NEXT(mat) == NULL) {
+ last_mbuf = mat;
+ }
+ }
+ if (chunk_length > SCTP_MAX_CHUNK_LENGTH) {
+ sctp_m_freem(op_err);
+ return;
+ }
+ padding_length = chunk_length % 4;
+ if (padding_length != 0) {
+ padding_length = 4 - padding_length;
+ }
+ if (padding_length != 0) {
+ if (sctp_add_pad_tombuf(last_mbuf, padding_length) == NULL) {
+ sctp_m_freem(op_err);
+ return;
+ }
+ }
sctp_alloc_a_chunk(stcb, chk);
if (chk == NULL) {
/* no memory */
@@ -8924,32 +8976,19 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err)
return;
}
chk->copy_by_ref = 0;
- SCTP_BUF_PREPEND(op_err, sizeof(struct sctp_chunkhdr), M_DONTWAIT);
- if (op_err == NULL) {
- sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
- return;
- }
- chk->send_size = 0;
- mat = op_err;
- while (mat != NULL) {
- chk->send_size += SCTP_BUF_LEN(mat);
- mat = SCTP_BUF_NEXT(mat);
- }
- chk->rec.chunk_id.id = SCTP_OPERATION_ERROR;
- chk->rec.chunk_id.can_take_data = 1;
+ chk->send_size = (uint16_t) chunk_length;
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
- chk->flags = 0;
chk->asoc = &stcb->asoc;
chk->data = op_err;
chk->whoTo = NULL;
+ chk->rec.chunk_id.id = SCTP_OPERATION_ERROR;
+ chk->rec.chunk_id.can_take_data = 0;
hdr = mtod(op_err, struct sctp_chunkhdr *);
hdr->chunk_type = SCTP_OPERATION_ERROR;
hdr->chunk_flags = 0;
hdr->chunk_length = htons(chk->send_size);
- TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue,
- chk,
- sctp_next);
+ TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next);
chk->asoc->ctrl_queue_cnt++;
}
@@ -8970,12 +9009,11 @@ sctp_send_cookie_echo(struct mbuf *m,
struct sctp_tmit_chunk *chk;
uint16_t ptype, plen;
+ SCTP_TCB_LOCK_ASSERT(stcb);
/* First find the cookie in the param area */
cookie = NULL;
at = offset + sizeof(struct sctp_init_chunk);
-
- SCTP_TCB_LOCK_ASSERT(stcb);
- do {
+ for (;;) {
phdr = sctp_get_next_param(m, at, &parm, sizeof(parm));
if (phdr == NULL) {
return (-3);
@@ -8989,32 +9027,21 @@ sctp_send_cookie_echo(struct mbuf *m,
if ((pad = (plen % 4))) {
plen += 4 - pad;
}
- cookie = SCTP_M_COPYM(m, at, plen, M_DONTWAIT);
+ cookie = SCTP_M_COPYM(m, at, plen, M_NOWAIT);
if (cookie == NULL) {
/* No memory */
return (-2);
}
#ifdef SCTP_MBUF_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
- struct mbuf *mat;
-
- for (mat = cookie; mat; mat = SCTP_BUF_NEXT(mat)) {
- if (SCTP_BUF_IS_EXTENDED(mat)) {
- sctp_log_mb(mat, SCTP_MBUF_ICOPY);
- }
- }
+ sctp_log_mbc(cookie, SCTP_MBUF_ICOPY);
}
#endif
break;
}
at += SCTP_SIZE32(plen);
- } while (phdr);
- if (cookie == NULL) {
- /* Did not find the cookie */
- return (-3);
}
/* ok, we got the cookie lets change it into a cookie echo chunk */
-
/* first the change from param to cookie */
hdr = mtod(cookie, struct sctp_chunkhdr *);
hdr->chunk_type = SCTP_COOKIE_ECHO;
@@ -9027,12 +9054,12 @@ sctp_send_cookie_echo(struct mbuf *m,
return (-5);
}
chk->copy_by_ref = 0;
- chk->send_size = plen;
chk->rec.chunk_id.id = SCTP_COOKIE_ECHO;
chk->rec.chunk_id.can_take_data = 0;
+ chk->flags = CHUNK_FLAGS_FRAGMENT_OK;
+ chk->send_size = plen;
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
- chk->flags = CHUNK_FLAGS_FRAGMENT_OK;
chk->asoc = &stcb->asoc;
chk->data = cookie;
chk->whoTo = net;
@@ -9061,20 +9088,14 @@ sctp_send_heartbeat_ack(struct sctp_tcb *stcb,
/* must have a net pointer */
return;
- outchain = SCTP_M_COPYM(m, offset, chk_length, M_DONTWAIT);
+ outchain = SCTP_M_COPYM(m, offset, chk_length, M_NOWAIT);
if (outchain == NULL) {
/* gak out of memory */
return;
}
#ifdef SCTP_MBUF_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
- struct mbuf *mat;
-
- for (mat = outchain; mat; mat = SCTP_BUF_NEXT(mat)) {
- if (SCTP_BUF_IS_EXTENDED(mat)) {
- sctp_log_mb(mat, SCTP_MBUF_ICOPY);
- }
- }
+ sctp_log_mbc(outchain, SCTP_MBUF_ICOPY);
}
#endif
chdr = mtod(outchain, struct sctp_chunkhdr *);
@@ -9095,12 +9116,12 @@ sctp_send_heartbeat_ack(struct sctp_tcb *stcb,
return;
}
chk->copy_by_ref = 0;
- chk->send_size = chk_length;
chk->rec.chunk_id.id = SCTP_HEARTBEAT_ACK;
chk->rec.chunk_id.can_take_data = 1;
+ chk->flags = 0;
+ chk->send_size = chk_length;
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
- chk->flags = 0;
chk->asoc = &stcb->asoc;
chk->data = outchain;
chk->whoTo = net;
@@ -9119,7 +9140,7 @@ sctp_send_cookie_ack(struct sctp_tcb *stcb)
SCTP_TCB_LOCK_ASSERT(stcb);
- cookie_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_chunkhdr), 0, M_DONTWAIT, 1, MT_HEADER);
+ cookie_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_chunkhdr), 0, M_NOWAIT, 1, MT_HEADER);
if (cookie_ack == NULL) {
/* no mbuf's */
return;
@@ -9132,12 +9153,12 @@ sctp_send_cookie_ack(struct sctp_tcb *stcb)
return;
}
chk->copy_by_ref = 0;
- chk->send_size = sizeof(struct sctp_chunkhdr);
chk->rec.chunk_id.id = SCTP_COOKIE_ACK;
chk->rec.chunk_id.can_take_data = 1;
+ chk->flags = 0;
+ chk->send_size = sizeof(struct sctp_chunkhdr);
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
- chk->flags = 0;
chk->asoc = &stcb->asoc;
chk->data = cookie_ack;
if (chk->asoc->last_control_chunk_from != NULL) {
@@ -9165,7 +9186,7 @@ sctp_send_shutdown_ack(struct sctp_tcb *stcb, struct sctp_nets *net)
struct sctp_shutdown_ack_chunk *ack_cp;
struct sctp_tmit_chunk *chk;
- m_shutdown_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_ack_chunk), 0, M_DONTWAIT, 1, MT_HEADER);
+ m_shutdown_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_ack_chunk), 0, M_NOWAIT, 1, MT_HEADER);
if (m_shutdown_ack == NULL) {
/* no mbuf's */
return;
@@ -9178,9 +9199,10 @@ sctp_send_shutdown_ack(struct sctp_tcb *stcb, struct sctp_nets *net)
return;
}
chk->copy_by_ref = 0;
- chk->send_size = sizeof(struct sctp_chunkhdr);
chk->rec.chunk_id.id = SCTP_SHUTDOWN_ACK;
chk->rec.chunk_id.can_take_data = 1;
+ chk->flags = 0;
+ chk->send_size = sizeof(struct sctp_chunkhdr);
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
chk->flags = 0;
@@ -9208,7 +9230,7 @@ sctp_send_shutdown(struct sctp_tcb *stcb, struct sctp_nets *net)
struct sctp_shutdown_chunk *shutdown_cp;
struct sctp_tmit_chunk *chk;
- m_shutdown = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_chunk), 0, M_DONTWAIT, 1, MT_HEADER);
+ m_shutdown = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_chunk), 0, M_NOWAIT, 1, MT_HEADER);
if (m_shutdown == NULL) {
/* no mbuf's */
return;
@@ -9221,9 +9243,10 @@ sctp_send_shutdown(struct sctp_tcb *stcb, struct sctp_nets *net)
return;
}
chk->copy_by_ref = 0;
- chk->send_size = sizeof(struct sctp_shutdown_chunk);
chk->rec.chunk_id.id = SCTP_SHUTDOWN;
chk->rec.chunk_id.can_take_data = 1;
+ chk->flags = 0;
+ chk->send_size = sizeof(struct sctp_shutdown_chunk);
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
chk->flags = 0;
@@ -9274,13 +9297,13 @@ sctp_send_asconf(struct sctp_tcb *stcb, struct sctp_nets *net, int addr_locked)
return;
}
chk->copy_by_ref = 0;
- chk->data = m_asconf;
- chk->send_size = len;
chk->rec.chunk_id.id = SCTP_ASCONF;
chk->rec.chunk_id.can_take_data = 0;
+ chk->flags = CHUNK_FLAGS_FRAGMENT_OK;
+ chk->data = m_asconf;
+ chk->send_size = len;
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
- chk->flags = CHUNK_FLAGS_FRAGMENT_OK;
chk->asoc = &stcb->asoc;
chk->whoTo = net;
if (chk->whoTo) {
@@ -9344,20 +9367,14 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb)
continue;
}
/* copy the asconf_ack */
- m_ack = SCTP_M_COPYM(ack->data, 0, M_COPYALL, M_DONTWAIT);
+ m_ack = SCTP_M_COPYM(ack->data, 0, M_COPYALL, M_NOWAIT);
if (m_ack == NULL) {
/* couldn't copy it */
return;
}
#ifdef SCTP_MBUF_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
- struct mbuf *mat;
-
- for (mat = m_ack; mat; mat = SCTP_BUF_NEXT(mat)) {
- if (SCTP_BUF_IS_EXTENDED(mat)) {
- sctp_log_mb(mat, SCTP_MBUF_ICOPY);
- }
- }
+ sctp_log_mbc(m_ack, SCTP_MBUF_ICOPY);
}
#endif
@@ -9369,20 +9386,17 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb)
return;
}
chk->copy_by_ref = 0;
-
+ chk->rec.chunk_id.id = SCTP_ASCONF_ACK;
+ chk->rec.chunk_id.can_take_data = 1;
+ chk->flags = CHUNK_FLAGS_FRAGMENT_OK;
chk->whoTo = net;
if (chk->whoTo) {
atomic_add_int(&chk->whoTo->ref_count, 1);
}
chk->data = m_ack;
- chk->send_size = 0;
- /* Get size */
chk->send_size = ack->len;
- chk->rec.chunk_id.id = SCTP_ASCONF_ACK;
- chk->rec.chunk_id.can_take_data = 1;
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
- chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; /* XXX */
chk->asoc = &stcb->asoc;
TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next);
@@ -9491,7 +9505,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
cnt_thru = 0;
/* do we have control chunks to retransmit? */
if (m != NULL) {
- /* Start a timer no matter if we suceed or fail */
+ /* Start a timer no matter if we succeed or fail */
if (chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) {
sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, chk->whoTo);
} else if (chk->rec.chunk_id.id == SCTP_ASCONF)
@@ -9555,12 +9569,16 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
}
if ((SCTP_BASE_SYSCTL(sctp_max_retran_chunk)) &&
(chk->snd_count >= SCTP_BASE_SYSCTL(sctp_max_retran_chunk))) {
- /* Gak, we have exceeded max unlucky retran, abort! */
- SCTP_PRINTF("Gak, chk->snd_count:%d >= max:%d - send abort\n",
- chk->snd_count,
- SCTP_BASE_SYSCTL(sctp_max_retran_chunk));
+ struct mbuf *op_err;
+ char msg[SCTP_DIAG_INFO_LEN];
+
+ snprintf(msg, sizeof(msg), "TSN %8.8x retransmitted %d times, giving up",
+ chk->rec.data.TSN_seq, chk->snd_count);
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ msg);
atomic_add_int(&stcb->asoc.refcnt, 1);
- sctp_abort_an_association(stcb->sctp_ep, stcb, NULL, so_locked);
+ sctp_abort_an_association(stcb->sctp_ep, stcb, op_err,
+ so_locked);
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (SCTP_RETRAN_EXIT);
@@ -9752,7 +9770,7 @@ one_chunk_around:
/* Is there something to send for this destination? */
if (m) {
/*
- * No matter if we fail/or suceed we should start a
+ * No matter if we fail/or succeed we should start a
* timer. A failure is like a lost IP packet :-)
*/
if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
@@ -9850,7 +9868,7 @@ one_chunk_around:
sctp_misc_ints(SCTP_FLIGHT_LOG_UP_RSND,
data_list[i]->whoTo->flight_size,
data_list[i]->book_size,
- (uintptr_t) data_list[i]->whoTo,
+ (uint32_t) (uintptr_t) data_list[i]->whoTo,
data_list[i]->rec.data.TSN_seq);
}
sctp_flight_size_increase(data_list[i]);
@@ -9874,7 +9892,7 @@ one_chunk_around:
* t3-expiring.
*/
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, inp, stcb, net,
- SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_4);
+ SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_2);
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
}
}
@@ -9954,7 +9972,7 @@ sctp_chunk_output(struct sctp_inpcb *inp,
*/
struct sctp_association *asoc;
struct sctp_nets *net;
- int error = 0, num_out = 0, tot_out = 0, ret = 0, reason_code = 0;
+ int error = 0, num_out, tot_out = 0, ret = 0, reason_code;
unsigned int burst_cnt = 0;
struct timeval now;
int now_filled = 0;
@@ -9965,6 +9983,7 @@ sctp_chunk_output(struct sctp_inpcb *inp,
unsigned int tot_frs = 0;
asoc = &stcb->asoc;
+do_it_again:
/* The Nagle algorithm is only applied when handling a send call. */
if (from_where == SCTP_OUTPUT_FROM_USR_SEND) {
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY)) {
@@ -9982,7 +10001,8 @@ sctp_chunk_output(struct sctp_inpcb *inp,
if ((un_sent <= 0) &&
(TAILQ_EMPTY(&asoc->control_send_queue)) &&
(TAILQ_EMPTY(&asoc->asconf_send_queue)) &&
- (asoc->sent_queue_retran_cnt == 0)) {
+ (asoc->sent_queue_retran_cnt == 0) &&
+ (asoc->trigger_reset == 0)) {
/* Nothing to do unless there is something to be sent left */
return;
}
@@ -10156,15 +10176,14 @@ sctp_chunk_output(struct sctp_inpcb *inp,
un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) +
(stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
if ((un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD)) &&
- (stcb->asoc.total_flight > 0) &&
- ((stcb->asoc.locked_on_sending == NULL) ||
- sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) {
+ (stcb->asoc.total_flight > 0)) {
+/* && sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) {*/
break;
}
}
if (TAILQ_EMPTY(&asoc->control_send_queue) &&
TAILQ_EMPTY(&asoc->send_queue) &&
- stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) {
+ sctp_is_there_unsent_data(stcb, so_locked) == 0) {
/* Nothing left to send */
break;
}
@@ -10201,6 +10220,12 @@ sctp_chunk_output(struct sctp_inpcb *inp,
*/
if (stcb->asoc.ecn_echo_cnt_onq)
sctp_fix_ecn_echo(asoc);
+
+ if (stcb->asoc.trigger_reset) {
+ if (sctp_send_stream_reset_out_if_possible(stcb, so_locked) == 0) {
+ goto do_it_again;
+ }
+ }
return;
}
@@ -10235,10 +10260,21 @@ void
send_forward_tsn(struct sctp_tcb *stcb,
struct sctp_association *asoc)
{
- struct sctp_tmit_chunk *chk;
+ struct sctp_tmit_chunk *chk, *at, *tp1, *last;
struct sctp_forward_tsn_chunk *fwdtsn;
+ struct sctp_strseq *strseq;
+ struct sctp_strseq_mid *strseq_m;
uint32_t advance_peer_ack_point;
+ unsigned int cnt_of_space, i, ovh;
+ unsigned int space_needed;
+ unsigned int cnt_of_skipped = 0;
+ int old;
+ if (asoc->idata_supported) {
+ old = 0;
+ } else {
+ old = 1;
+ }
SCTP_TCB_LOCK_ASSERT(stcb);
TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
if (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN) {
@@ -10260,11 +10296,17 @@ send_forward_tsn(struct sctp_tcb *stcb,
}
asoc->fwd_tsn_cnt++;
chk->copy_by_ref = 0;
+ /*
+ * We don't do the old thing here since this is used not for on-wire
+ * but to tell if we are sending a fwd-tsn by the stack during
+ * output. And if its a IFORWARD or a FORWARD it is a fwd-tsn.
+ */
chk->rec.chunk_id.id = SCTP_FORWARD_CUM_TSN;
chk->rec.chunk_id.can_take_data = 0;
+ chk->flags = 0;
chk->asoc = asoc;
chk->whoTo = NULL;
- chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA);
+ chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
if (chk->data == NULL) {
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
return;
@@ -10280,132 +10322,155 @@ sctp_fill_in_rest:
* stream/seq of the ones we skip.
*/
SCTP_BUF_LEN(chk->data) = 0;
- {
- struct sctp_tmit_chunk *at, *tp1, *last;
- struct sctp_strseq *strseq;
- unsigned int cnt_of_space, i, ovh;
- unsigned int space_needed;
- unsigned int cnt_of_skipped = 0;
-
- TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) {
- if ((at->sent != SCTP_FORWARD_TSN_SKIP) &&
- (at->sent != SCTP_DATAGRAM_NR_ACKED)) {
- /* no more to look at */
- break;
- }
- if (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED) {
- /* We don't report these */
- continue;
- }
- cnt_of_skipped++;
+ TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) {
+ if ((at->sent != SCTP_FORWARD_TSN_SKIP) &&
+ (at->sent != SCTP_DATAGRAM_NR_ACKED)) {
+ /* no more to look at */
+ break;
+ }
+ if (old && (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) {
+ /* We don't report these */
+ continue;
}
+ cnt_of_skipped++;
+ }
+ if (old) {
space_needed = (sizeof(struct sctp_forward_tsn_chunk) +
(cnt_of_skipped * sizeof(struct sctp_strseq)));
+ } else {
+ space_needed = (sizeof(struct sctp_forward_tsn_chunk) +
+ (cnt_of_skipped * sizeof(struct sctp_strseq_mid)));
+ }
+ cnt_of_space = (unsigned int)M_TRAILINGSPACE(chk->data);
- cnt_of_space = M_TRAILINGSPACE(chk->data);
-
- if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- ovh = SCTP_MIN_OVERHEAD;
- } else {
- ovh = SCTP_MIN_V4_OVERHEAD;
- }
- if (cnt_of_space > (asoc->smallest_mtu - ovh)) {
- /* trim to a mtu size */
- cnt_of_space = asoc->smallest_mtu - ovh;
- }
+ if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
+ ovh = SCTP_MIN_OVERHEAD;
+ } else {
+ ovh = SCTP_MIN_V4_OVERHEAD;
+ }
+ if (cnt_of_space > (asoc->smallest_mtu - ovh)) {
+ /* trim to a mtu size */
+ cnt_of_space = asoc->smallest_mtu - ovh;
+ }
+ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
+ sctp_misc_ints(SCTP_FWD_TSN_CHECK,
+ 0xff, 0, cnt_of_skipped,
+ asoc->advanced_peer_ack_point);
+ }
+ advance_peer_ack_point = asoc->advanced_peer_ack_point;
+ if (cnt_of_space < space_needed) {
+ /*-
+ * ok we must trim down the chunk by lowering the
+ * advance peer ack point.
+ */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
sctp_misc_ints(SCTP_FWD_TSN_CHECK,
- 0xff, 0, cnt_of_skipped,
- asoc->advanced_peer_ack_point);
-
+ 0xff, 0xff, cnt_of_space,
+ space_needed);
}
- advance_peer_ack_point = asoc->advanced_peer_ack_point;
- if (cnt_of_space < space_needed) {
- /*-
- * ok we must trim down the chunk by lowering the
- * advance peer ack point.
- */
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
- sctp_misc_ints(SCTP_FWD_TSN_CHECK,
- 0xff, 0xff, cnt_of_space,
- space_needed);
- }
+ if (old) {
cnt_of_skipped = cnt_of_space - sizeof(struct sctp_forward_tsn_chunk);
cnt_of_skipped /= sizeof(struct sctp_strseq);
- /*-
- * Go through and find the TSN that will be the one
- * we report.
- */
- at = TAILQ_FIRST(&asoc->sent_queue);
- if (at != NULL) {
- for (i = 0; i < cnt_of_skipped; i++) {
- tp1 = TAILQ_NEXT(at, sctp_next);
- if (tp1 == NULL) {
- break;
- }
- at = tp1;
+ } else {
+ cnt_of_skipped = cnt_of_space - sizeof(struct sctp_forward_tsn_chunk);
+ cnt_of_skipped /= sizeof(struct sctp_strseq_mid);
+ }
+ /*-
+ * Go through and find the TSN that will be the one
+ * we report.
+ */
+ at = TAILQ_FIRST(&asoc->sent_queue);
+ if (at != NULL) {
+ for (i = 0; i < cnt_of_skipped; i++) {
+ tp1 = TAILQ_NEXT(at, sctp_next);
+ if (tp1 == NULL) {
+ break;
}
+ at = tp1;
}
- if (at && SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
- sctp_misc_ints(SCTP_FWD_TSN_CHECK,
- 0xff, cnt_of_skipped, at->rec.data.TSN_seq,
- asoc->advanced_peer_ack_point);
- }
- last = at;
- /*-
- * last now points to last one I can report, update
- * peer ack point
- */
- if (last)
- advance_peer_ack_point = last->rec.data.TSN_seq;
+ }
+ if (at && SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
+ sctp_misc_ints(SCTP_FWD_TSN_CHECK,
+ 0xff, cnt_of_skipped, at->rec.data.TSN_seq,
+ asoc->advanced_peer_ack_point);
+ }
+ last = at;
+ /*-
+ * last now points to last one I can report, update
+ * peer ack point
+ */
+ if (last) {
+ advance_peer_ack_point = last->rec.data.TSN_seq;
+ }
+ if (old) {
space_needed = sizeof(struct sctp_forward_tsn_chunk) +
cnt_of_skipped * sizeof(struct sctp_strseq);
+ } else {
+ space_needed = sizeof(struct sctp_forward_tsn_chunk) +
+ cnt_of_skipped * sizeof(struct sctp_strseq_mid);
}
- chk->send_size = space_needed;
- /* Setup the chunk */
- fwdtsn = mtod(chk->data, struct sctp_forward_tsn_chunk *);
- fwdtsn->ch.chunk_length = htons(chk->send_size);
- fwdtsn->ch.chunk_flags = 0;
+ }
+ chk->send_size = space_needed;
+ /* Setup the chunk */
+ fwdtsn = mtod(chk->data, struct sctp_forward_tsn_chunk *);
+ fwdtsn->ch.chunk_length = htons(chk->send_size);
+ fwdtsn->ch.chunk_flags = 0;
+ if (old) {
fwdtsn->ch.chunk_type = SCTP_FORWARD_CUM_TSN;
- fwdtsn->new_cumulative_tsn = htonl(advance_peer_ack_point);
- SCTP_BUF_LEN(chk->data) = chk->send_size;
- fwdtsn++;
- /*-
- * Move pointer to after the fwdtsn and transfer to the
- * strseq pointer.
- */
+ } else {
+ fwdtsn->ch.chunk_type = SCTP_IFORWARD_CUM_TSN;
+ }
+ fwdtsn->new_cumulative_tsn = htonl(advance_peer_ack_point);
+ SCTP_BUF_LEN(chk->data) = chk->send_size;
+ fwdtsn++;
+ /*-
+ * Move pointer to after the fwdtsn and transfer to the
+ * strseq pointer.
+ */
+ if (old) {
strseq = (struct sctp_strseq *)fwdtsn;
- /*-
- * Now populate the strseq list. This is done blindly
- * without pulling out duplicate stream info. This is
- * inefficent but won't harm the process since the peer will
- * look at these in sequence and will thus release anything.
- * It could mean we exceed the PMTU and chop off some that
- * we could have included.. but this is unlikely (aka 1432/4
- * would mean 300+ stream seq's would have to be reported in
- * one FWD-TSN. With a bit of work we can later FIX this to
- * optimize and pull out duplcates.. but it does add more
- * overhead. So for now... not!
- */
- at = TAILQ_FIRST(&asoc->sent_queue);
- for (i = 0; i < cnt_of_skipped; i++) {
- tp1 = TAILQ_NEXT(at, sctp_next);
- if (tp1 == NULL)
- break;
+ } else {
+ strseq_m = (struct sctp_strseq_mid *)fwdtsn;
+ }
+ /*-
+ * Now populate the strseq list. This is done blindly
+ * without pulling out duplicate stream info. This is
+ * inefficent but won't harm the process since the peer will
+ * look at these in sequence and will thus release anything.
+ * It could mean we exceed the PMTU and chop off some that
+ * we could have included.. but this is unlikely (aka 1432/4
+ * would mean 300+ stream seq's would have to be reported in
+ * one FWD-TSN. With a bit of work we can later FIX this to
+ * optimize and pull out duplicates.. but it does add more
+ * overhead. So for now... not!
+ */
+ i = 0;
+ TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) {
+ if (i >= cnt_of_skipped) {
+ break;
+ }
+ if (old && (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) {
+ /* We don't report these */
+ continue;
+ }
+ if (at->rec.data.TSN_seq == advance_peer_ack_point) {
+ at->rec.data.fwd_tsn_cnt = 0;
+ }
+ if (old) {
+ strseq->stream = htons(at->rec.data.stream_number);
+ strseq->sequence = htons((uint16_t) at->rec.data.stream_seq);
+ strseq++;
+ } else {
+ strseq_m->stream = htons(at->rec.data.stream_number);
if (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED) {
- /* We don't report these */
- i--;
- at = tp1;
- continue;
- }
- if (at->rec.data.TSN_seq == advance_peer_ack_point) {
- at->rec.data.fwd_tsn_cnt = 0;
+ strseq_m->flags = htons(PR_SCTP_UNORDERED_FLAG);
+ } else {
+ strseq_m->flags = 0;
}
- strseq->stream = ntohs(at->rec.data.stream_number);
- strseq->sequence = ntohs(at->rec.data.stream_seq);
- strseq++;
- at = tp1;
+ strseq_m->msg_id = htonl(at->rec.data.stream_seq);
+ strseq_m++;
}
+ i++;
}
return;
}
@@ -10428,7 +10493,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
struct sctp_sack_chunk *sack;
struct sctp_nr_sack_chunk *nr_sack;
struct sctp_gap_ack_block *gap_descriptor;
- struct sack_track *selector;
+ const struct sack_track *selector;
int mergeable = 0;
int offset;
caddr_t limit;
@@ -10443,8 +10508,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
uint8_t type;
uint8_t tsn_map;
- if ((stcb->asoc.sctp_nr_sack_on_off == 1) &&
- (stcb->asoc.peer_supports_nr_sack == 1)) {
+ if (stcb->asoc.nrsack_supported == 1) {
type = SCTP_NR_SELECTIVE_ACK;
} else {
type = SCTP_SELECTIVE_ACK;
@@ -10481,7 +10545,8 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
/* No memory so we drop the idea, and set a timer */
if (stcb->asoc.delayed_ack) {
sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
- stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_5);
+ stcb->sctp_ep, stcb, NULL,
+ SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_3);
sctp_timer_start(SCTP_TIMER_TYPE_RECV,
stcb->sctp_ep, stcb, NULL);
} else {
@@ -10496,38 +10561,24 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
/* Clear our pkt counts */
asoc->data_pkts_seen = 0;
+ a_chk->flags = 0;
a_chk->asoc = asoc;
a_chk->snd_count = 0;
a_chk->send_size = 0; /* fill in later */
a_chk->sent = SCTP_DATAGRAM_UNSENT;
a_chk->whoTo = NULL;
- if ((asoc->numduptsns) ||
- (!(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE))) {
+ if (!(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE)) {
/*-
- * Ok, we have some duplicates or the destination for the
- * sack is unreachable, lets see if we can select an
- * alternate than asoc->last_data_chunk_from
+ * Ok, the destination for the SACK is unreachable, lets see if
+ * we can select an alternate to asoc->last_data_chunk_from
*/
- if ((asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE) &&
- (asoc->used_alt_onsack > asoc->numnets)) {
- /* We used an alt last time, don't this time */
- a_chk->whoTo = NULL;
- } else {
- asoc->used_alt_onsack++;
- a_chk->whoTo = sctp_find_alternate_net(stcb, asoc->last_data_chunk_from, 0);
- }
+ a_chk->whoTo = sctp_find_alternate_net(stcb, asoc->last_data_chunk_from, 0);
if (a_chk->whoTo == NULL) {
/* Nope, no alternate */
a_chk->whoTo = asoc->last_data_chunk_from;
- asoc->used_alt_onsack = 0;
}
} else {
- /*
- * No duplicates so we use the last place we received data
- * from.
- */
- asoc->used_alt_onsack = 0;
a_chk->whoTo = asoc->last_data_chunk_from;
}
if (a_chk->whoTo) {
@@ -10550,7 +10601,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
space_req = MCLBYTES;
}
/* Ok now lets formulate a MBUF with our sack */
- a_chk->data = sctp_get_mbuf_for_msg(space_req, 0, M_DONTWAIT, 1, MT_DATA);
+ a_chk->data = sctp_get_mbuf_for_msg(space_req, 0, M_NOWAIT, 1, MT_DATA);
if ((a_chk->data == NULL) ||
(a_chk->whoTo == NULL)) {
/* rats, no mbuf memory */
@@ -10563,7 +10614,8 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
/* sa_ignore NO_NULL_CHK */
if (stcb->asoc.delayed_ack) {
sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
- stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6);
+ stcb->sctp_ep, stcb, NULL,
+ SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_4);
sctp_timer_start(SCTP_TIMER_TYPE_RECV,
stcb->sctp_ep, stcb, NULL);
} else {
@@ -10573,7 +10625,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
}
/* ok, lets go through and fill it in */
SCTP_BUF_RESV_UF(a_chk->data, SCTP_MIN_OVERHEAD);
- space = M_TRAILINGSPACE(a_chk->data);
+ space = (unsigned int)M_TRAILINGSPACE(a_chk->data);
if (space > (a_chk->whoTo->mtu - SCTP_MIN_OVERHEAD)) {
space = (a_chk->whoTo->mtu - SCTP_MIN_OVERHEAD);
}
@@ -10642,7 +10694,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
* Clear all bits corresponding to TSNs
* smaller or equal to the cumulative TSN.
*/
- tsn_map &= (~0 << (1 - offset));
+ tsn_map &= (~0U << (1 - offset));
}
selector = &sack_array[tsn_map];
if (mergeable && selector->right_edge) {
@@ -10717,7 +10769,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
* TSNs smaller or equal to the
* cumulative TSN.
*/
- tsn_map &= (~0 << (1 - offset));
+ tsn_map &= (~0U << (1 - offset));
}
selector = &sack_array[tsn_map];
if (mergeable && selector->right_edge) {
@@ -10787,9 +10839,9 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
* queue.
*/
if (type == SCTP_SELECTIVE_ACK) {
- a_chk->send_size = sizeof(struct sctp_sack_chunk) +
+ a_chk->send_size = (uint16_t) (sizeof(struct sctp_sack_chunk) +
(num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) +
- num_dups * sizeof(int32_t);
+ num_dups * sizeof(int32_t));
SCTP_BUF_LEN(a_chk->data) = a_chk->send_size;
sack->sack.cum_tsn_ack = htonl(asoc->cumulative_tsn);
sack->sack.a_rwnd = htonl(asoc->my_rwnd);
@@ -10799,9 +10851,9 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
sack->ch.chunk_flags = flags;
sack->ch.chunk_length = htons(a_chk->send_size);
} else {
- a_chk->send_size = sizeof(struct sctp_nr_sack_chunk) +
+ a_chk->send_size = (uint16_t) (sizeof(struct sctp_nr_sack_chunk) +
(num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) +
- num_dups * sizeof(int32_t);
+ num_dups * sizeof(int32_t));
SCTP_BUF_LEN(a_chk->data) = a_chk->send_size;
nr_sack->nr_sack.cum_tsn_ack = htonl(asoc->cumulative_tsn);
nr_sack->nr_sack.a_rwnd = htonl(asoc->my_rwnd);
@@ -10850,7 +10902,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
} else {
m_out = NULL;
}
- m_abort = sctp_get_mbuf_for_msg(sizeof(struct sctp_abort_chunk), 0, M_DONTWAIT, 1, MT_HEADER);
+ m_abort = sctp_get_mbuf_for_msg(sizeof(struct sctp_abort_chunk), 0, M_NOWAIT, 1, MT_HEADER);
if (m_abort == NULL) {
if (m_out) {
sctp_m_freem(m_out);
@@ -10900,7 +10952,8 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
abort->ch.chunk_length = htons(chunk_len);
/* Add padding, if necessary. */
if (padding_len > 0) {
- if ((m_last == NULL) || sctp_add_pad_tombuf(m_last, padding_len)) {
+ if ((m_last == NULL) ||
+ (sctp_add_pad_tombuf(m_last, padding_len) == NULL)) {
sctp_m_freem(m_out);
return;
}
@@ -10926,7 +10979,7 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb,
uint32_t vtag;
uint8_t flags;
- m_shutdown_comp = sctp_get_mbuf_for_msg(sizeof(struct sctp_chunkhdr), 0, M_DONTWAIT, 1, MT_HEADER);
+ m_shutdown_comp = sctp_get_mbuf_for_msg(sizeof(struct sctp_chunkhdr), 0, M_NOWAIT, 1, MT_HEADER);
if (m_shutdown_comp == NULL) {
/* no mbuf's */
return;
@@ -10959,20 +11012,21 @@ static void
sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
struct sctphdr *sh, uint32_t vtag,
uint8_t type, struct mbuf *cause,
- uint8_t use_mflowid, uint32_t mflowid,
+ uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum,
uint32_t vrf_id, uint16_t port)
{
struct mbuf *o_pak;
struct mbuf *mout;
struct sctphdr *shout;
struct sctp_chunkhdr *ch;
- struct udphdr *udp;
- int len, cause_len, padding_len;
#if defined(INET) || defined(INET6)
+ struct udphdr *udp;
int ret;
#endif
+ int len, cause_len, padding_len;
+
#ifdef INET
struct sockaddr_in *src_sin, *dst_sin;
struct ip *ip;
@@ -10999,7 +11053,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
padding_len = 4 - padding_len;
}
if (padding_len != 0) {
- if (sctp_add_pad_tombuf(m_last, padding_len)) {
+ if (sctp_add_pad_tombuf(m_last, padding_len) == NULL) {
sctp_m_freem(cause);
return;
}
@@ -11023,10 +11077,12 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
default:
break;
}
+#if defined(INET) || defined(INET6)
if (port) {
len += sizeof(struct udphdr);
}
- mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_DONTWAIT, 1, MT_DATA);
+#endif
+ mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_NOWAIT, 1, MT_DATA);
if (mout == NULL) {
if (cause) {
sctp_m_freem(cause);
@@ -11036,10 +11092,9 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
SCTP_BUF_RESV_UF(mout, max_linkhdr);
SCTP_BUF_LEN(mout) = len;
SCTP_BUF_NEXT(mout) = cause;
- if (use_mflowid != 0) {
- mout->m_pkthdr.flowid = mflowid;
- mout->m_flags |= M_FLOWID;
- }
+ M_SETFIB(mout, fibnum);
+ mout->m_pkthdr.flowid = mflowid;
+ M_HASHTYPE_SET(mout, mflowtype);
#ifdef INET
ip = NULL;
#endif
@@ -11055,8 +11110,8 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
ip->ip_v = IPVERSION;
ip->ip_hl = (sizeof(struct ip) >> 2);
ip->ip_tos = 0;
- ip->ip_id = ip_newid();
ip->ip_off = 0;
+ ip_fillid(ip);
ip->ip_ttl = MODULE_GLOBAL(ip_defttl);
if (port) {
ip->ip_p = IPPROTO_UDP;
@@ -11096,6 +11151,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
shout = mtod(mout, struct sctphdr *);
break;
}
+#if defined(INET) || defined(INET6)
if (port) {
if (htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)) == 0) {
sctp_m_freem(mout);
@@ -11105,15 +11161,16 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
udp->uh_dport = port;
udp->uh_sum = 0;
- udp->uh_ulen = htons(sizeof(struct udphdr) +
+ udp->uh_ulen = htons((uint16_t) (sizeof(struct udphdr) +
sizeof(struct sctphdr) +
sizeof(struct sctp_chunkhdr) +
- cause_len + padding_len);
+ cause_len + padding_len));
len += sizeof(struct udphdr);
shout = (struct sctphdr *)((caddr_t)shout + sizeof(struct udphdr));
} else {
udp = NULL;
}
+#endif
shout->src_port = sh->dest_port;
shout->dest_port = sh->src_port;
shout->checksum = 0;
@@ -11130,7 +11187,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
} else {
ch->chunk_flags = SCTP_HAD_NO_TCB;
}
- ch->chunk_length = htons(sizeof(struct sctp_chunkhdr) + cause_len);
+ ch->chunk_length = htons((uint16_t) (sizeof(struct sctp_chunkhdr) + cause_len));
len += sizeof(struct sctp_chunkhdr);
len += cause_len + padding_len;
@@ -11149,7 +11206,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
udp->uh_sum = 0;
}
}
- ip->ip_len = len;
+ ip->ip_len = htons(len);
if (port) {
#if defined(SCTP_WITH_NO_CSUM)
SCTP_STAT_INCR(sctps_sendnocrc);
@@ -11179,7 +11236,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
#endif
#ifdef INET6
case AF_INET6:
- ip6->ip6_plen = len - sizeof(struct ip6_hdr);
+ ip6->ip6_plen = (uint16_t) (len - sizeof(struct ip6_hdr));
if (port) {
#if defined(SCTP_WITH_NO_CSUM)
SCTP_STAT_INCR(sctps_sendnocrc);
@@ -11223,11 +11280,11 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
void
sctp_send_shutdown_complete2(struct sockaddr *src, struct sockaddr *dst,
struct sctphdr *sh,
- uint8_t use_mflowid, uint32_t mflowid,
+ uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum,
uint32_t vrf_id, uint16_t port)
{
sctp_send_resp_msg(src, dst, sh, 0, SCTP_SHUTDOWN_COMPLETE, NULL,
- use_mflowid, mflowid,
+ mflowtype, mflowid, fibnum,
vrf_id, port);
}
@@ -11267,10 +11324,11 @@ sctp_send_hb(struct sctp_tcb *stcb, struct sctp_nets *net, int so_locked
chk->copy_by_ref = 0;
chk->rec.chunk_id.id = SCTP_HEARTBEAT_REQUEST;
chk->rec.chunk_id.can_take_data = 1;
+ chk->flags = 0;
chk->asoc = &stcb->asoc;
chk->send_size = sizeof(struct sctp_heartbeat_chunk);
- chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_DONTWAIT, 1, MT_HEADER);
+ chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_NOWAIT, 1, MT_HEADER);
if (chk->data == NULL) {
sctp_free_a_chunk(stcb, chk, so_locked);
return;
@@ -11294,7 +11352,7 @@ sctp_send_hb(struct sctp_tcb *stcb, struct sctp_nets *net, int so_locked
hb->heartbeat.hb_info.time_value_1 = now.tv_sec;
hb->heartbeat.hb_info.time_value_2 = now.tv_usec;
/* Did our user request this one, put it in */
- hb->heartbeat.hb_info.addr_family = net->ro._l_addr.sa.sa_family;
+ hb->heartbeat.hb_info.addr_family = (uint8_t) net->ro._l_addr.sa.sa_family;
hb->heartbeat.hb_info.addr_len = net->ro._l_addr.sa.sa_len;
if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
/*
@@ -11323,6 +11381,11 @@ sctp_send_hb(struct sctp_tcb *stcb, struct sctp_nets *net, int so_locked
break;
#endif
default:
+ if (chk->data) {
+ sctp_m_freem(chk->data);
+ chk->data = NULL;
+ }
+ sctp_free_a_chunk(stcb, chk, so_locked);
return;
break;
}
@@ -11368,13 +11431,14 @@ sctp_send_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
if (chk == NULL) {
return;
}
- chk->copy_by_ref = 0;
SCTP_STAT_INCR(sctps_queue_upd_ecne);
+ chk->copy_by_ref = 0;
chk->rec.chunk_id.id = SCTP_ECN_ECHO;
chk->rec.chunk_id.can_take_data = 0;
+ chk->flags = 0;
chk->asoc = &stcb->asoc;
chk->send_size = sizeof(struct sctp_ecne_chunk);
- chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_DONTWAIT, 1, MT_HEADER);
+ chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_NOWAIT, 1, MT_HEADER);
if (chk->data == NULL) {
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
return;
@@ -11417,7 +11481,7 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net,
}
asoc = &stcb->asoc;
SCTP_TCB_LOCK_ASSERT(stcb);
- if (asoc->peer_supports_pktdrop == 0) {
+ if (asoc->pktdrop_supported == 0) {
/*-
* peer must declare support before I send one.
*/
@@ -11431,6 +11495,9 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net,
return;
}
chk->copy_by_ref = 0;
+ chk->rec.chunk_id.id = SCTP_PACKET_DROPPED;
+ chk->rec.chunk_id.can_take_data = 1;
+ chk->flags = 0;
len -= iphlen;
chk->send_size = len;
/* Validate that we do not have an ABORT in here. */
@@ -11473,7 +11540,7 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net,
was_trunc = 1;
}
chk->asoc = &stcb->asoc;
- chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA);
+ chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
if (chk->data == NULL) {
jump_out:
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
@@ -11496,7 +11563,7 @@ jump_out:
* Len is already adjusted to size minus overhead above take
* out the pkt_drop chunk itself from it.
*/
- chk->send_size = len - sizeof(struct sctp_pktdrop_chunk);
+ chk->send_size = (uint16_t) (len - sizeof(struct sctp_pktdrop_chunk));
len = chk->send_size;
} else {
/* no truncation needed */
@@ -11517,8 +11584,6 @@ jump_out:
} else {
chk->whoTo = NULL;
}
- chk->rec.chunk_id.id = SCTP_PACKET_DROPPED;
- chk->rec.chunk_id.can_take_data = 1;
drp->ch.chunk_type = SCTP_PACKET_DROPPED;
drp->ch.chunk_length = htons(chk->send_size);
spc = SCTP_SB_LIMIT_RCV(stcb->sctp_socket);
@@ -11584,9 +11649,10 @@ sctp_send_cwr(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t high_tsn, u
chk->copy_by_ref = 0;
chk->rec.chunk_id.id = SCTP_ECN_CWR;
chk->rec.chunk_id.can_take_data = 1;
+ chk->flags = 0;
chk->asoc = &stcb->asoc;
chk->send_size = sizeof(struct sctp_cwr_chunk);
- chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_DONTWAIT, 1, MT_HEADER);
+ chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_NOWAIT, 1, MT_HEADER);
if (chk->data == NULL) {
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
return;
@@ -11606,30 +11672,60 @@ sctp_send_cwr(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t high_tsn, u
asoc->ctrl_queue_cnt++;
}
-void
-sctp_add_stream_reset_out(struct sctp_tmit_chunk *chk,
- int number_entries, uint16_t * list,
+static int
+sctp_add_stream_reset_out(struct sctp_tcb *stcb, struct sctp_tmit_chunk *chk,
uint32_t seq, uint32_t resp_seq, uint32_t last_sent)
{
uint16_t len, old_len, i;
struct sctp_stream_reset_out_request *req_out;
struct sctp_chunkhdr *ch;
+ int at;
+ int number_entries = 0;
ch = mtod(chk->data, struct sctp_chunkhdr *);
old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length));
-
/* get to new offset for the param. */
req_out = (struct sctp_stream_reset_out_request *)((caddr_t)ch + len);
/* now how long will this param be? */
- len = (sizeof(struct sctp_stream_reset_out_request) + (sizeof(uint16_t) * number_entries));
+ for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
+ if ((stcb->asoc.strmout[i].state == SCTP_STREAM_RESET_PENDING) &&
+ (stcb->asoc.strmout[i].chunks_on_queues == 0) &&
+ TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
+ number_entries++;
+ }
+ }
+ if (number_entries == 0) {
+ return (0);
+ }
+ if (number_entries == stcb->asoc.streamoutcnt) {
+ number_entries = 0;
+ }
+ if (number_entries > SCTP_MAX_STREAMS_AT_ONCE_RESET) {
+ number_entries = SCTP_MAX_STREAMS_AT_ONCE_RESET;
+ }
+ len = (uint16_t) (sizeof(struct sctp_stream_reset_out_request) + (sizeof(uint16_t) * number_entries));
req_out->ph.param_type = htons(SCTP_STR_RESET_OUT_REQUEST);
req_out->ph.param_length = htons(len);
req_out->request_seq = htonl(seq);
req_out->response_seq = htonl(resp_seq);
req_out->send_reset_at_tsn = htonl(last_sent);
+ at = 0;
if (number_entries) {
- for (i = 0; i < number_entries; i++) {
- req_out->list_of_streams[i] = htons(list[i]);
+ for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
+ if ((stcb->asoc.strmout[i].state == SCTP_STREAM_RESET_PENDING) &&
+ (stcb->asoc.strmout[i].chunks_on_queues == 0) &&
+ TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
+ req_out->list_of_streams[at] = htons(i);
+ at++;
+ stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_IN_FLIGHT;
+ if (at >= number_entries) {
+ break;
+ }
+ }
+ }
+ } else {
+ for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
+ stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_IN_FLIGHT;
}
}
if (SCTP_SIZE32(len) > len) {
@@ -11646,7 +11742,7 @@ sctp_add_stream_reset_out(struct sctp_tmit_chunk *chk,
chk->book_size_scale = 0;
chk->send_size = SCTP_SIZE32(chk->book_size);
SCTP_BUF_LEN(chk->data) = chk->send_size;
- return;
+ return (1);
}
static void
@@ -11664,7 +11760,7 @@ sctp_add_stream_reset_in(struct sctp_tmit_chunk *chk,
/* get to new offset for the param. */
req_in = (struct sctp_stream_reset_in_request *)((caddr_t)ch + len);
/* now how long will this param be? */
- len = (sizeof(struct sctp_stream_reset_in_request) + (sizeof(uint16_t) * number_entries));
+ len = (uint16_t) (sizeof(struct sctp_stream_reset_in_request) + (sizeof(uint16_t) * number_entries));
req_in->ph.param_type = htons(SCTP_STR_RESET_IN_REQUEST);
req_in->ph.param_length = htons(len);
req_in->request_seq = htonl(seq);
@@ -11748,6 +11844,68 @@ sctp_add_stream_reset_result(struct sctp_tmit_chunk *chk,
}
void
+sctp_send_deferred_reset_response(struct sctp_tcb *stcb,
+ struct sctp_stream_reset_list *ent,
+ int response)
+{
+ struct sctp_association *asoc;
+ struct sctp_tmit_chunk *chk;
+ struct sctp_chunkhdr *ch;
+
+ asoc = &stcb->asoc;
+
+ /*
+ * Reset our last reset action to the new one IP -> response
+ * (PERFORMED probably). This assures that if we fail to send, a
+ * retran from the peer will get the new response.
+ */
+ asoc->last_reset_action[0] = response;
+ if (asoc->stream_reset_outstanding) {
+ return;
+ }
+ sctp_alloc_a_chunk(stcb, chk);
+ if (chk == NULL) {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
+ return;
+ }
+ chk->copy_by_ref = 0;
+ chk->rec.chunk_id.id = SCTP_STREAM_RESET;
+ chk->rec.chunk_id.can_take_data = 0;
+ chk->flags = 0;
+ chk->asoc = &stcb->asoc;
+ chk->book_size = sizeof(struct sctp_chunkhdr);
+ chk->send_size = SCTP_SIZE32(chk->book_size);
+ chk->book_size_scale = 0;
+ chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
+ if (chk->data == NULL) {
+ sctp_free_a_chunk(stcb, chk, SCTP_SO_LOCKED);
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
+ return;
+ }
+ SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD);
+ /* setup chunk parameters */
+ chk->sent = SCTP_DATAGRAM_UNSENT;
+ chk->snd_count = 0;
+ if (stcb->asoc.alternate) {
+ chk->whoTo = stcb->asoc.alternate;
+ } else {
+ chk->whoTo = stcb->asoc.primary_destination;
+ }
+ ch = mtod(chk->data, struct sctp_chunkhdr *);
+ ch->chunk_type = SCTP_STREAM_RESET;
+ ch->chunk_flags = 0;
+ ch->chunk_length = htons(chk->book_size);
+ atomic_add_int(&chk->whoTo->ref_count, 1);
+ SCTP_BUF_LEN(chk->data) = chk->send_size;
+ sctp_add_stream_reset_result(chk, ent->seq, response);
+ /* insert the chunk for sending */
+ TAILQ_INSERT_TAIL(&asoc->control_send_queue,
+ chk,
+ sctp_next);
+ asoc->ctrl_queue_cnt++;
+}
+
+void
sctp_add_stream_reset_result_tsn(struct sctp_tmit_chunk *chk,
uint32_t resp_seq, uint32_t result,
uint32_t send_una, uint32_t recv_next)
@@ -11845,19 +12003,90 @@ sctp_add_an_in_stream(struct sctp_tmit_chunk *chk,
}
int
+sctp_send_stream_reset_out_if_possible(struct sctp_tcb *stcb, int so_locked)
+{
+ struct sctp_association *asoc;
+ struct sctp_tmit_chunk *chk;
+ struct sctp_chunkhdr *ch;
+ uint32_t seq;
+
+ asoc = &stcb->asoc;
+ asoc->trigger_reset = 0;
+ if (asoc->stream_reset_outstanding) {
+ return (EALREADY);
+ }
+ sctp_alloc_a_chunk(stcb, chk);
+ if (chk == NULL) {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
+ return (ENOMEM);
+ }
+ chk->copy_by_ref = 0;
+ chk->rec.chunk_id.id = SCTP_STREAM_RESET;
+ chk->rec.chunk_id.can_take_data = 0;
+ chk->flags = 0;
+ chk->asoc = &stcb->asoc;
+ chk->book_size = sizeof(struct sctp_chunkhdr);
+ chk->send_size = SCTP_SIZE32(chk->book_size);
+ chk->book_size_scale = 0;
+ chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
+ if (chk->data == NULL) {
+ sctp_free_a_chunk(stcb, chk, so_locked);
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
+ return (ENOMEM);
+ }
+ SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD);
+
+ /* setup chunk parameters */
+ chk->sent = SCTP_DATAGRAM_UNSENT;
+ chk->snd_count = 0;
+ if (stcb->asoc.alternate) {
+ chk->whoTo = stcb->asoc.alternate;
+ } else {
+ chk->whoTo = stcb->asoc.primary_destination;
+ }
+ ch = mtod(chk->data, struct sctp_chunkhdr *);
+ ch->chunk_type = SCTP_STREAM_RESET;
+ ch->chunk_flags = 0;
+ ch->chunk_length = htons(chk->book_size);
+ atomic_add_int(&chk->whoTo->ref_count, 1);
+ SCTP_BUF_LEN(chk->data) = chk->send_size;
+ seq = stcb->asoc.str_reset_seq_out;
+ if (sctp_add_stream_reset_out(stcb, chk, seq, (stcb->asoc.str_reset_seq_in - 1), (stcb->asoc.sending_seq - 1))) {
+ seq++;
+ asoc->stream_reset_outstanding++;
+ } else {
+ m_freem(chk->data);
+ chk->data = NULL;
+ sctp_free_a_chunk(stcb, chk, so_locked);
+ return (ENOENT);
+ }
+ asoc->str_reset = chk;
+ /* insert the chunk for sending */
+ TAILQ_INSERT_TAIL(&asoc->control_send_queue,
+ chk,
+ sctp_next);
+ asoc->ctrl_queue_cnt++;
+
+ if (stcb->asoc.send_sack) {
+ sctp_send_sack(stcb, so_locked);
+ }
+ sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo);
+ return (0);
+}
+
+int
sctp_send_str_reset_req(struct sctp_tcb *stcb,
- int number_entries, uint16_t * list,
- uint8_t send_out_req,
+ uint16_t number_entries, uint16_t * list,
uint8_t send_in_req,
uint8_t send_tsn_req,
uint8_t add_stream,
uint16_t adding_o,
uint16_t adding_i, uint8_t peer_asked)
{
-
struct sctp_association *asoc;
struct sctp_tmit_chunk *chk;
struct sctp_chunkhdr *ch;
+ int can_send_out_req = 0;
uint32_t seq;
asoc = &stcb->asoc;
@@ -11868,16 +12097,26 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EBUSY);
return (EBUSY);
}
- if ((send_out_req == 0) && (send_in_req == 0) && (send_tsn_req == 0) &&
+ if ((send_in_req == 0) && (send_tsn_req == 0) &&
(add_stream == 0)) {
/* nothing to do */
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL);
return (EINVAL);
}
- if (send_tsn_req && (send_out_req || send_in_req)) {
+ if (send_tsn_req && send_in_req) {
/* error, can't do that */
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL);
return (EINVAL);
+ } else if (send_in_req) {
+ can_send_out_req = 1;
+ }
+ if (number_entries > (MCLBYTES -
+ SCTP_MIN_OVERHEAD -
+ sizeof(struct sctp_chunkhdr) -
+ sizeof(struct sctp_stream_reset_out_request)) /
+ sizeof(uint16_t)) {
+ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
+ return (ENOMEM);
}
sctp_alloc_a_chunk(stcb, chk);
if (chk == NULL) {
@@ -11887,12 +12126,13 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
chk->copy_by_ref = 0;
chk->rec.chunk_id.id = SCTP_STREAM_RESET;
chk->rec.chunk_id.can_take_data = 0;
+ chk->flags = 0;
chk->asoc = &stcb->asoc;
chk->book_size = sizeof(struct sctp_chunkhdr);
chk->send_size = SCTP_SIZE32(chk->book_size);
chk->book_size_scale = 0;
- chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA);
+ chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
if (chk->data == NULL) {
sctp_free_a_chunk(stcb, chk, SCTP_SO_LOCKED);
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
@@ -11916,12 +12156,14 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
SCTP_BUF_LEN(chk->data) = chk->send_size;
seq = stcb->asoc.str_reset_seq_out;
- if (send_out_req) {
- sctp_add_stream_reset_out(chk, number_entries, list,
- seq, (stcb->asoc.str_reset_seq_in - 1), (stcb->asoc.sending_seq - 1));
- asoc->stream_reset_out_is_outstanding = 1;
- seq++;
- asoc->stream_reset_outstanding++;
+ if (can_send_out_req) {
+ int ret;
+
+ ret = sctp_add_stream_reset_out(stcb, chk, seq, (stcb->asoc.str_reset_seq_in - 1), (stcb->asoc.sending_seq - 1));
+ if (ret) {
+ seq++;
+ asoc->stream_reset_outstanding++;
+ }
}
if ((add_stream & 1) &&
((stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt) < adding_o)) {
@@ -11930,10 +12172,15 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
struct sctp_stream_queue_pending *sp, *nsp;
int i;
+#if defined(SCTP_DETAILED_STR_STATS)
+ int j;
+
+#endif
+
oldstream = stcb->asoc.strmout;
/* get some more */
SCTP_MALLOC(stcb->asoc.strmout, struct sctp_stream_out *,
- ((stcb->asoc.streamoutcnt + adding_o) * sizeof(struct sctp_stream_out)),
+ (stcb->asoc.streamoutcnt + adding_o) * sizeof(struct sctp_stream_out),
SCTP_M_STRMO);
if (stcb->asoc.strmout == NULL) {
uint8_t x;
@@ -11953,32 +12200,44 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
stcb->asoc.strmout[i].chunks_on_queues = oldstream[i].chunks_on_queues;
- stcb->asoc.strmout[i].next_sequence_send = oldstream[i].next_sequence_send;
+ stcb->asoc.strmout[i].next_mid_ordered = oldstream[i].next_mid_ordered;
+ stcb->asoc.strmout[i].next_mid_unordered = oldstream[i].next_mid_unordered;
stcb->asoc.strmout[i].last_msg_incomplete = oldstream[i].last_msg_incomplete;
stcb->asoc.strmout[i].stream_no = i;
- stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], &oldstream[i]);
+ stcb->asoc.strmout[i].state = oldstream[i].state;
+ /* FIX ME FIX ME */
+ /*
+ * This should be a SS_COPY operation FIX ME STREAM
+ * SCHEDULER EXPERT
+ */
+ stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], &oldstream[i]);
/* now anything on those queues? */
TAILQ_FOREACH_SAFE(sp, &oldstream[i].outqueue, next, nsp) {
TAILQ_REMOVE(&oldstream[i].outqueue, sp, next);
TAILQ_INSERT_TAIL(&stcb->asoc.strmout[i].outqueue, sp, next);
}
- /* Now move assoc pointers too */
- if (stcb->asoc.last_out_stream == &oldstream[i]) {
- stcb->asoc.last_out_stream = &stcb->asoc.strmout[i];
- }
- if (stcb->asoc.locked_on_sending == &oldstream[i]) {
- stcb->asoc.locked_on_sending = &stcb->asoc.strmout[i];
- }
+
}
/* now the new streams */
stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
for (i = stcb->asoc.streamoutcnt; i < (stcb->asoc.streamoutcnt + adding_o); i++) {
TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
stcb->asoc.strmout[i].chunks_on_queues = 0;
- stcb->asoc.strmout[i].next_sequence_send = 0x0;
+#if defined(SCTP_DETAILED_STR_STATS)
+ for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) {
+ stcb->asoc.strmout[i].abandoned_sent[j] = 0;
+ stcb->asoc.strmout[i].abandoned_unsent[j] = 0;
+ }
+#else
+ stcb->asoc.strmout[i].abandoned_sent[0] = 0;
+ stcb->asoc.strmout[i].abandoned_unsent[0] = 0;
+#endif
+ stcb->asoc.strmout[i].next_mid_ordered = 0;
+ stcb->asoc.strmout[i].next_mid_unordered = 0;
stcb->asoc.strmout[i].stream_no = i;
stcb->asoc.strmout[i].last_msg_incomplete = 0;
- stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL);
+ stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], NULL);
+ stcb->asoc.strmout[i].state = SCTP_STREAM_CLOSED;
}
stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + adding_o;
SCTP_FREE(oldstream, SCTP_M_STRMO);
@@ -12012,6 +12271,9 @@ skip_stuff:
chk,
sctp_next);
asoc->ctrl_queue_cnt++;
+ if (stcb->asoc.send_sack) {
+ sctp_send_sack(stcb, SCTP_SO_LOCKED);
+ }
sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo);
return (0);
}
@@ -12019,7 +12281,7 @@ skip_stuff:
void
sctp_send_abort(struct mbuf *m, int iphlen, struct sockaddr *src, struct sockaddr *dst,
struct sctphdr *sh, uint32_t vtag, struct mbuf *cause,
- uint8_t use_mflowid, uint32_t mflowid,
+ uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum,
uint32_t vrf_id, uint16_t port)
{
/* Don't respond to an ABORT with an ABORT. */
@@ -12029,7 +12291,7 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sockaddr *src, struct sockadd
return;
}
sctp_send_resp_msg(src, dst, sh, vtag, SCTP_ABORT_ASSOCIATION, cause,
- use_mflowid, mflowid,
+ mflowtype, mflowid, fibnum,
vrf_id, port);
return;
}
@@ -12037,11 +12299,11 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sockaddr *src, struct sockadd
void
sctp_send_operr_to(struct sockaddr *src, struct sockaddr *dst,
struct sctphdr *sh, uint32_t vtag, struct mbuf *cause,
- uint8_t use_mflowid, uint32_t mflowid,
+ uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum,
uint32_t vrf_id, uint16_t port)
{
sctp_send_resp_msg(src, dst, sh, vtag, SCTP_OPERATION_ERROR, cause,
- use_mflowid, mflowid,
+ mflowtype, mflowid, fibnum,
vrf_id, port);
return;
}
@@ -12073,9 +12335,6 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp,
struct uio *uio,
int resv_upfront)
{
- int left;
-
- left = sp->length;
sp->data = m_uiotombuf(uio, M_WAITOK, sp->length,
resv_upfront, 0);
if (sp->data == NULL) {
@@ -12131,10 +12390,11 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
sp->timetolive = srcv->sinfo_timetolive;
sp->ppid = srcv->sinfo_ppid;
sp->context = srcv->sinfo_context;
+ sp->fsn = 0;
(void)SCTP_GETTIME_TIMEVAL(&sp->ts);
sp->stream = srcv->sinfo_stream;
- sp->length = min(uio->uio_resid, max_send_len);
+ sp->length = (uint32_t) min(uio->uio_resid, max_send_len);
if ((sp->length == (uint32_t) uio->uio_resid) &&
((user_marks_eor == 0) ||
(srcv->sinfo_flags & SCTP_EOF) ||
@@ -12293,7 +12553,7 @@ sctp_lower_sosend(struct socket *so,
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
return (EINVAL);
}
- sndlen = uio->uio_resid;
+ sndlen = (unsigned int)uio->uio_resid;
} else {
top = SCTP_HEADER_TO_CHAIN(i_pak);
sndlen = SCTP_HEADER_LEN(i_pak);
@@ -12381,7 +12641,10 @@ sctp_lower_sosend(struct socket *so,
}
SCTP_INP_RUNLOCK(inp);
} else if (sinfo_assoc_id) {
- stcb = sctp_findassociation_ep_asocid(inp, sinfo_assoc_id, 0);
+ stcb = sctp_findassociation_ep_asocid(inp, sinfo_assoc_id, 1);
+ if (stcb != NULL) {
+ hold_tcblock = 1;
+ }
} else if (addr) {
/*-
* Since we did not use findep we must
@@ -12469,8 +12732,9 @@ sctp_lower_sosend(struct socket *so,
}
#endif
stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id,
- p
- );
+ inp->sctp_ep.pre_open_stream_count,
+ inp->sctp_ep.port,
+ p);
if (stcb == NULL) {
/* Error is setup for us in the call */
goto out_unlocked;
@@ -12504,7 +12768,8 @@ sctp_lower_sosend(struct socket *so,
if (control) {
if (sctp_process_cmsgs_for_init(stcb, control, &error)) {
- sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_7);
+ sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE,
+ SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_5);
hold_tcblock = 0;
stcb = NULL;
goto out_unlocked;
@@ -12590,12 +12855,24 @@ sctp_lower_sosend(struct socket *so,
SCTP_ASOC_CREATE_UNLOCK(inp);
create_lock_applied = 0;
}
- if (asoc->stream_reset_outstanding) {
+ /* Is the stream no. valid? */
+ if (srcv->sinfo_stream >= asoc->streamoutcnt) {
+ /* Invalid stream number */
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
+ error = EINVAL;
+ goto out_unlocked;
+ }
+ if ((asoc->strmout[srcv->sinfo_stream].state != SCTP_STREAM_OPEN) &&
+ (asoc->strmout[srcv->sinfo_stream].state != SCTP_STREAM_OPENING)) {
/*
* Can't queue any data while stream reset is underway.
*/
- SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EAGAIN);
- error = EAGAIN;
+ if (asoc->strmout[srcv->sinfo_stream].state > SCTP_STREAM_OPEN) {
+ error = EAGAIN;
+ } else {
+ error = EINVAL;
+ }
+ SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, error);
goto out_unlocked;
}
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) ||
@@ -12646,7 +12923,7 @@ sctp_lower_sosend(struct socket *so,
if (top) {
struct mbuf *cntm = NULL;
- mm = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_WAIT, 1, MT_DATA);
+ mm = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_WAITOK, 1, MT_DATA);
if (sndlen != 0) {
for (cntm = top; cntm; cntm = SCTP_BUF_NEXT(cntm)) {
tot_out += SCTP_BUF_LEN(cntm);
@@ -12662,7 +12939,7 @@ sctp_lower_sosend(struct socket *so,
error = EMSGSIZE;
goto out;
}
- mm = sctp_get_mbuf_for_msg(tot_demand, 0, M_WAIT, 1, MT_DATA);
+ mm = sctp_get_mbuf_for_msg(tot_demand, 0, M_WAITOK, 1, MT_DATA);
}
if (mm == NULL) {
SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
@@ -12680,7 +12957,7 @@ sctp_lower_sosend(struct socket *so,
/* now move forward the data pointer */
ph = mtod(mm, struct sctp_paramhdr *);
ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
- ph->param_length = htons(sizeof(struct sctp_paramhdr) + tot_out);
+ ph->param_length = htons((uint16_t) (sizeof(struct sctp_paramhdr) + tot_out));
ph++;
SCTP_BUF_LEN(mm) = tot_out + sizeof(struct sctp_paramhdr);
if (top == NULL) {
@@ -12736,13 +13013,6 @@ sctp_lower_sosend(struct socket *so,
SCTP_TCB_UNLOCK(stcb);
hold_tcblock = 0;
}
- /* Is the stream no. valid? */
- if (srcv->sinfo_stream >= asoc->streamoutcnt) {
- /* Invalid stream number */
- SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
- error = EINVAL;
- goto out_unlocked;
- }
if (asoc->strmout == NULL) {
/* huh? software error */
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EFAULT);
@@ -12818,6 +13088,7 @@ sctp_lower_sosend(struct socket *so,
asoc, stcb->asoc.total_output_queue_size);
}
if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ SOCKBUF_UNLOCK(&so->so_snd);
goto out_unlocked;
}
inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
@@ -12879,8 +13150,10 @@ skip_preblock:
* interrupt.
*/
strm->last_msg_incomplete = 1;
- asoc->stream_locked = 1;
- asoc->stream_locked_on = srcv->sinfo_stream;
+ if (stcb->asoc.idata_supported == 0) {
+ asoc->stream_locked = 1;
+ asoc->stream_locked_on = srcv->sinfo_stream;
+ }
sp->sender_all_done = 0;
}
sctp_snd_sb_alloc(stcb, sp->length);
@@ -12959,7 +13232,9 @@ skip_preblock:
sctp_snd_sb_alloc(stcb, sndout);
atomic_add_int(&sp->length, sndout);
len += sndout;
-
+ if (srcv->sinfo_flags & SCTP_SACK_IMMEDIATELY) {
+ sp->sinfo_flags |= SCTP_SACK_IMMEDIATELY;
+ }
/* Did we reach EOR? */
if ((uio->uio_resid == 0) &&
((user_marks_eor == 0) ||
@@ -12976,7 +13251,7 @@ skip_preblock:
continue;
}
/* PR-SCTP? */
- if ((asoc->peer_supports_prsctp) && (asoc->sent_queue_cnt_removeable > 0)) {
+ if ((asoc->prsctp_supported) && (asoc->sent_queue_cnt_removeable > 0)) {
/*
* This is ugly but we must assure locking
* order
@@ -13038,7 +13313,7 @@ skip_preblock:
/*-
* Ok, Nagle is set on and we have data outstanding.
* Don't send anything and let SACKs drive out the
- * data unless wen have a "full" segment to send.
+ * data unless we have a "full" segment to send.
*/
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_NAGLE_LOGGING_ENABLE) {
sctp_log_nagle_event(stcb, SCTP_NAGLE_APPLIED);
@@ -13107,7 +13382,7 @@ skip_preblock:
min(SCTP_BASE_SYSCTL(sctp_add_more_threshold), SCTP_SB_LIMIT_SND(so)))) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK,
- asoc, uio->uio_resid);
+ asoc, (size_t)uio->uio_resid);
}
be.error = 0;
stcb->block_entry = &be;
@@ -13136,11 +13411,17 @@ skip_preblock:
}
}
SCTP_TCB_SEND_LOCK(stcb);
+ if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ SCTP_TCB_SEND_UNLOCK(stcb);
+ goto out_unlocked;
+ }
if (sp) {
if (sp->msg_is_complete == 0) {
strm->last_msg_incomplete = 1;
- asoc->stream_locked = 1;
- asoc->stream_locked_on = srcv->sinfo_stream;
+ if (stcb->asoc.idata_supported == 0) {
+ asoc->stream_locked = 1;
+ asoc->stream_locked_on = srcv->sinfo_stream;
+ }
} else {
sp->sender_all_done = 1;
strm->last_msg_incomplete = 0;
@@ -13176,19 +13457,16 @@ dataless_eof:
/* EOF thing ? */
if ((srcv->sinfo_flags & SCTP_EOF) &&
(got_all_of_the_send == 1)) {
- int cnt;
-
SCTP_STAT_INCR(sctps_sends_with_eof);
error = 0;
if (hold_tcblock == 0) {
SCTP_TCB_LOCK(stcb);
hold_tcblock = 1;
}
- cnt = sctp_is_there_unsent_data(stcb, SCTP_SO_LOCKED);
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
- (cnt == 0)) {
- if (asoc->locked_on_sending) {
+ sctp_is_there_unsent_data(stcb, SCTP_SO_LOCKED) == 0) {
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
goto abort_anyway;
}
/* there is nothing queued to send, so I'm done... */
@@ -13233,27 +13511,27 @@ dataless_eof:
SCTP_TCB_LOCK(stcb);
hold_tcblock = 1;
}
- if (asoc->locked_on_sending) {
- /* Locked to send out the data */
- struct sctp_stream_queue_pending *sp;
-
- sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
- if (sp) {
- if ((sp->length == 0) && (sp->msg_is_complete == 0))
- asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
- }
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
+ asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
}
asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
(asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
+ struct mbuf *op_err;
+ char msg[SCTP_DIAG_INFO_LEN];
+
abort_anyway:
if (free_cnt_applied) {
atomic_add_int(&stcb->asoc.refcnt, -1);
free_cnt_applied = 0;
}
+ snprintf(msg, sizeof(msg),
+ "%s:%d at %s", __FILE__, __LINE__, __func__);
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ msg);
sctp_abort_an_association(stcb->sctp_ep, stcb,
- NULL, SCTP_SO_LOCKED);
+ op_err, SCTP_SO_LOCKED);
/*
* now relock the stcb so everything
* is sane
@@ -13393,13 +13671,6 @@ out_unlocked:
}
}
#endif
-#ifdef INVARIANTS
- if (inp) {
- sctp_validate_no_locks(inp);
- } else {
- SCTP_PRINTF("Warning - inp is NULL so cant validate locks\n");
- }
-#endif
if (top) {
sctp_m_freem(top);
}
@@ -13427,19 +13698,14 @@ sctp_add_auth_chunk(struct mbuf *m, struct mbuf **m_end,
(stcb == NULL))
return (m);
- /* sysctl disabled auth? */
- if (SCTP_BASE_SYSCTL(sctp_auth_disable))
- return (m);
-
- /* peer doesn't do auth... */
- if (!stcb->asoc.peer_supports_auth) {
+ if (stcb->asoc.auth_supported == 0) {
return (m);
}
/* does the requested chunk require auth? */
if (!sctp_auth_is_required_chunk(chunk, stcb->asoc.peer_auth_chunks)) {
return (m);
}
- m_auth = sctp_get_mbuf_for_msg(sizeof(*auth), 0, M_DONTWAIT, 1, MT_HEADER);
+ m_auth = sctp_get_mbuf_for_msg(sizeof(*auth), 0, M_NOWAIT, 1, MT_HEADER);
if (m_auth == NULL) {
/* no mbuf's */
return (m);
@@ -13538,7 +13804,7 @@ sctp_v4src_match_nexthop(struct sctp_ifa *sifa, sctp_route_t * ro)
}
ifa = (struct ifaddr *)sifa->ifa;
mask = (struct sockaddr_in *)(ifa->ifa_netmask);
- sin = (struct sockaddr_in *)&sifa->address.sin;
+ sin = &sifa->address.sin;
srcnetaddr.s_addr = (sin->sin_addr.s_addr & mask->sin_addr.s_addr);
SCTPDBG(SCTP_DEBUG_OUTPUT1, "match_nexthop4: src address is ");
SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &sifa->address.sa);