summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/sctp_output.c')
-rw-r--r--sys/netinet/sctp_output.c806
1 files changed, 399 insertions, 407 deletions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 9efff50..eac896c 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_indata.h>
#include <netinet/sctp_bsd_addr.h>
#include <netinet/sctp_input.h>
+#include <netinet/sctp_crc32.h>
#include <netinet/udp.h>
#include <machine/in_cksum.h>
@@ -5213,6 +5214,9 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
int ecn_ok,
struct sctp_tmit_chunk *chk,
int out_of_asoc_ok,
+ uint16_t src_port,
+ uint16_t dest_port,
+ uint32_t v_tag,
uint16_t port,
int so_locked,
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
@@ -5237,7 +5241,6 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
struct mbuf *newm;
struct sctphdr *sctphdr;
int packet_length;
- uint32_t csum;
int ret;
uint32_t vrf_id;
sctp_route_t *ro = NULL;
@@ -5263,51 +5266,27 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
if ((auth != NULL) && (stcb != NULL)) {
sctp_fill_hmac_digest_m(m, auth_offset, auth, stcb, auth_keyid);
}
- /* Calculate the csum and fill in the length of the packet */
- sctphdr = mtod(m, struct sctphdr *);
- if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
- (stcb) &&
- (to->sa_family == AF_INET) &&
- (stcb->asoc.loopback_scope)) {
- sctphdr->checksum = 0;
- /*
- * This can probably now be taken out since my audit shows
- * no more bad pktlen's coming in. But we will wait a while
- * yet.
- */
- packet_length = sctp_calculate_len(m);
- } else {
- sctphdr->checksum = 0;
- csum = sctp_calculate_sum(m, &packet_length, 0);
- sctphdr->checksum = csum;
- }
-
if (to->sa_family == AF_INET) {
struct ip *ip = NULL;
sctp_route_t iproute;
uint8_t tos_value;
+ int len;
+ len = sizeof(struct ip) + sizeof(struct sctphdr);
if (port) {
- newm = sctp_get_mbuf_for_msg(sizeof(struct ip) + sizeof(struct udphdr), 1, M_DONTWAIT, 1, MT_DATA);
- } else {
- newm = sctp_get_mbuf_for_msg(sizeof(struct ip), 1, M_DONTWAIT, 1, MT_DATA);
+ len += sizeof(struct udphdr);
}
+ newm = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA);
if (newm == NULL) {
sctp_m_freem(m);
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
return (ENOMEM);
}
- if (port) {
- SCTP_ALIGN_TO_END(newm, sizeof(struct ip) + sizeof(struct udphdr));
- SCTP_BUF_LEN(newm) = sizeof(struct ip) + sizeof(struct udphdr);
- packet_length += sizeof(struct ip) + sizeof(struct udphdr);
- } else {
- SCTP_ALIGN_TO_END(newm, sizeof(struct ip));
- SCTP_BUF_LEN(newm) = sizeof(struct ip);
- packet_length += sizeof(struct ip);
- }
+ SCTP_ALIGN_TO_END(newm, len);
+ SCTP_BUF_LEN(newm) = len;
SCTP_BUF_NEXT(newm) = m;
m = newm;
+ packet_length = sctp_calculate_len(m);
ip = mtod(m, struct ip *);
ip->ip_v = IPVERSION;
ip->ip_hl = (sizeof(struct ip) >> 2);
@@ -5401,12 +5380,21 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
}
}
if (port) {
- udp = (struct udphdr *)(ip + 1);
+ 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_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP));
+ sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr));
+ } else {
+ sctphdr = (struct sctphdr *)((caddr_t)ip + sizeof(struct ip));
}
+
+ sctphdr->src_port = src_port;
+ sctphdr->dest_port = dest_port;
+ sctphdr->v_tag = v_tag;
+ sctphdr->checksum = 0;
+
/*
* If source address selection fails and we find no route
* then the ip_output should fail as well with a
@@ -5517,7 +5505,25 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
#endif
SCTP_ATTACH_CHAIN(o_pak, m, packet_length);
if (port) {
+ if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
+ (stcb) &&
+ (stcb->asoc.loopback_scope))) {
+ sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip) + sizeof(struct udphdr));
+ SCTP_STAT_INCR(sctps_sendswcrc);
+ } else {
+ SCTP_STAT_INCR(sctps_sendnocrc);
+ }
SCTP_ENABLE_UDP_CSUM(o_pak);
+ } else {
+ if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
+ (stcb) &&
+ (stcb->asoc.loopback_scope))) {
+ m->m_pkthdr.csum_flags = CSUM_SCTP;
+ m->m_pkthdr.csum_data = 0; /* FIXME MT */
+ SCTP_STAT_INCR(sctps_sendhwcrc);
+ } else {
+ SCTP_STAT_INCR(sctps_sendnocrc);
+ }
}
/* send it out. table id is taken from stcb */
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
@@ -5591,6 +5597,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
struct sockaddr_in6 lsa6_storage;
int error;
u_short prev_port = 0;
+ int len;
if (net != NULL) {
flowlabel = net->tos_flowlabel;
@@ -5598,27 +5605,21 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo;
}
+ len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr);
if (port) {
- newm = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr) + sizeof(struct udphdr), 1, M_DONTWAIT, 1, MT_DATA);
- } else {
- newm = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr), 1, M_DONTWAIT, 1, MT_DATA);
+ len += sizeof(struct udphdr);
}
+ newm = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA);
if (newm == NULL) {
sctp_m_freem(m);
SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
return (ENOMEM);
}
- if (port) {
- SCTP_ALIGN_TO_END(newm, sizeof(struct ip6_hdr) + sizeof(struct udphdr));
- SCTP_BUF_LEN(newm) = sizeof(struct ip6_hdr) + sizeof(struct udphdr);
- packet_length += sizeof(struct ip6_hdr) + sizeof(struct udphdr);
- } else {
- SCTP_ALIGN_TO_END(newm, sizeof(struct ip6_hdr));
- SCTP_BUF_LEN(newm) = sizeof(struct ip6_hdr);
- packet_length += sizeof(struct ip6_hdr);
- }
+ SCTP_ALIGN_TO_END(newm, len);
+ SCTP_BUF_LEN(newm) = len;
SCTP_BUF_NEXT(newm) = m;
m = newm;
+ packet_length = sctp_calculate_len(m);
ip6h = mtod(m, struct ip6_hdr *);
/*
@@ -5763,12 +5764,21 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
ip6h->ip6_src = lsa6->sin6_addr;
if (port) {
- udp = (struct udphdr *)(ip6h + 1);
+ 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_sum = 0;
+ sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr));
+ } else {
+ sctphdr = (struct sctphdr *)((caddr_t)ip6h + sizeof(struct ip6_hdr));
}
+
+ sctphdr->src_port = src_port;
+ sctphdr->dest_port = dest_port;
+ sctphdr->v_tag = v_tag;
+ sctphdr->checksum = 0;
+
/*
* We set the hop limit now since there is a good chance
* that our ro pointer is now filled
@@ -5805,9 +5815,27 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
#endif
SCTP_ATTACH_CHAIN(o_pak, m, packet_length);
if (port) {
+ if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
+ (stcb) &&
+ (stcb->asoc.loopback_scope))) {
+ sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr));
+ SCTP_STAT_INCR(sctps_sendswcrc);
+ } else {
+ SCTP_STAT_INCR(sctps_sendnocrc);
+ }
if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), packet_length - sizeof(struct ip6_hdr))) == 0) {
udp->uh_sum = 0xffff;
}
+ } else {
+ if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
+ (stcb) &&
+ (stcb->asoc.loopback_scope))) {
+ m->m_pkthdr.csum_flags = CSUM_SCTP;
+ m->m_pkthdr.csum_data = 0; /* FIXME MT */
+ SCTP_STAT_INCR(sctps_sendhwcrc);
+ } else {
+ SCTP_STAT_INCR(sctps_sendnocrc);
+ }
}
/* send it out. table id is taken from stcb */
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
@@ -5905,7 +5933,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
{
struct mbuf *m, *m_at, *mp_last;
struct sctp_nets *net;
- struct sctp_init_msg *initm;
+ struct sctp_init_chunk *init;
struct sctp_supported_addr_param *sup_addr;
struct sctp_adaptation_layer_indication *ali;
struct sctp_ecn_supported_param *ecn;
@@ -5961,7 +5989,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - mbuf?\n");
return;
}
- SCTP_BUF_LEN(m) = sizeof(struct sctp_init_msg);
+ SCTP_BUF_LEN(m) = sizeof(struct sctp_init_chunk);
/*
* assume peer supports asconf in order to be able to queue local
* address changes while an INIT is in flight and before the assoc
@@ -5969,28 +5997,24 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
*/
stcb->asoc.peer_supports_asconf = 1;
/* Now lets put the SCTP header in place */
- initm = mtod(m, struct sctp_init_msg *);
- initm->sh.src_port = inp->sctp_lport;
- initm->sh.dest_port = stcb->rport;
- initm->sh.v_tag = 0;
- initm->sh.checksum = 0; /* calculate later */
+ init = mtod(m, struct sctp_init_chunk *);
/* now the chunk header */
- initm->msg.ch.chunk_type = SCTP_INITIATION;
- initm->msg.ch.chunk_flags = 0;
+ init->ch.chunk_type = SCTP_INITIATION;
+ init->ch.chunk_flags = 0;
/* fill in later from mbuf we build */
- initm->msg.ch.chunk_length = 0;
+ init->ch.chunk_length = 0;
/* place in my tag */
- initm->msg.init.initiate_tag = htonl(stcb->asoc.my_vtag);
+ init->init.initiate_tag = htonl(stcb->asoc.my_vtag);
/* set up some of the credits. */
- initm->msg.init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(inp->sctp_socket),
+ init->init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(inp->sctp_socket),
SCTP_MINIMAL_RWND));
- initm->msg.init.num_outbound_streams = htons(stcb->asoc.pre_open_streams);
- initm->msg.init.num_inbound_streams = htons(stcb->asoc.max_inbound_streams);
- initm->msg.init.initial_tsn = htonl(stcb->asoc.init_seq_number);
+ init->init.num_outbound_streams = htons(stcb->asoc.pre_open_streams);
+ init->init.num_inbound_streams = htons(stcb->asoc.max_inbound_streams);
+ init->init.initial_tsn = htonl(stcb->asoc.init_seq_number);
/* now the address restriction */
- sup_addr = (struct sctp_supported_addr_param *)((caddr_t)initm +
- sizeof(*initm));
+ sup_addr = (struct sctp_supported_addr_param *)((caddr_t)init +
+ sizeof(*init));
sup_addr->ph.param_type = htons(SCTP_SUPPORTED_ADDRTYPE);
#ifdef INET6
/* we support 2 types: IPv6/IPv4 */
@@ -6004,7 +6028,6 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
sup_addr->addr_type[1] = htons(0); /* this is the padding */
#endif
SCTP_BUF_LEN(m) += sizeof(*sup_addr) + sizeof(uint16_t);
-
/* adaptation layer indication parameter */
ali = (struct sctp_adaptation_layer_indication *)((caddr_t)sup_addr + sizeof(*sup_addr) + sizeof(uint16_t));
ali->ph.param_type = htons(SCTP_ULP_ADAPTATION);
@@ -6013,6 +6036,16 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
SCTP_BUF_LEN(m) += sizeof(*ali);
ecn = (struct sctp_ecn_supported_param *)((caddr_t)ali + sizeof(*ali));
+ if (SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly)) {
+ /* Add NAT friendly parameter */
+ struct sctp_paramhdr *ph;
+
+ ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m));
+ ph->param_type = htons(SCTP_HAS_NAT_SUPPORT);
+ ph->param_length = htons(sizeof(struct sctp_paramhdr));
+ SCTP_BUF_LEN(m) += sizeof(struct sctp_paramhdr);
+ ecn = (struct sctp_ecn_supported_param *)((caddr_t)ph + sizeof(*ph));
+ }
/* now any cookie time extensions */
if (stcb->asoc.cookie_preserve_req) {
struct sctp_cookie_perserve_param *cookie_preserve;
@@ -6052,19 +6085,22 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
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))
+ if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) {
pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION;
+ }
/*
* EY if the initiator supports nr_sacks, need to report that to
* responder in INIT chunk
*/
- if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off))
+ if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) {
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);
+
/* ECN nonce: And now tell the peer we support ECN nonce */
if (SCTP_BASE_SYSCTL(sctp_ecn_nonce)) {
ecn_nonce = (struct sctp_ecn_nonce_supported_param *)
@@ -6073,15 +6109,6 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
ecn_nonce->ph.param_length = htons(sizeof(*ecn_nonce));
SCTP_BUF_LEN(m) += sizeof(*ecn_nonce);
}
- if (SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly)) {
- /* Add NAT friendly parameter */
- struct sctp_paramhdr *ph;
-
- ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m));
- ph->param_type = htons(SCTP_HAS_NAT_SUPPORT);
- ph->param_length = htons(sizeof(struct sctp_paramhdr));
- SCTP_BUF_LEN(m) += sizeof(sizeof(struct sctp_paramhdr));
- }
/* add authentication parameters */
if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) {
struct sctp_auth_random *randp;
@@ -6160,7 +6187,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
mp_last = m_at;
p_len += SCTP_BUF_LEN(m_at);
}
- initm->msg.ch.chunk_length = htons((p_len - sizeof(struct sctphdr)));
+ init->ch.chunk_length = htons(p_len);
/*
* We sifa 0 here to NOT set IP_DF if its IPv4, we ignore the return
* here since the timer will drive a retranmission.
@@ -6185,7 +6212,9 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - calls lowlevel_output\n");
ret = sctp_lowlevel_chunk_output(inp, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
- m, 0, NULL, 0, 0, 0, NULL, 0, net->port, so_locked, NULL);
+ m, 0, NULL, 0, 0, 0, NULL, 0,
+ inp->sctp_lport, stcb->rport, htonl(0),
+ net->port, so_locked, NULL);
SCTPDBG(SCTP_DEBUG_OUTPUT4, "lowlevel_output - %d\n", ret);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, net);
@@ -6711,7 +6740,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
{
struct sctp_association *asoc;
struct mbuf *m, *m_at, *m_tmp, *m_cookie, *op_err, *mp_last;
- struct sctp_init_msg *initackm_out;
+ struct sctp_init_ack_chunk *initack;
struct sctp_adaptation_layer_indication *ali;
struct sctp_ecn_supported_param *ecn;
struct sctp_prsctp_supported_param *prsctp;
@@ -6776,7 +6805,7 @@ do_a_abort:
sctp_m_freem(op_err);
return;
}
- SCTP_BUF_LEN(m) = sizeof(struct sctp_init_msg);
+ SCTP_BUF_LEN(m) = sizeof(struct sctp_init_chunk);
/* the time I built cookie */
(void)SCTP_GETTIME_TIMEVAL(&stc.time_entered);
@@ -7059,29 +7088,25 @@ do_a_abort:
}
}
/* Now lets put the SCTP header in place */
- initackm_out = mtod(m, struct sctp_init_msg *);
- initackm_out->sh.src_port = inp->sctp_lport;
- initackm_out->sh.dest_port = sh->src_port;
- initackm_out->sh.v_tag = init_chk->init.initiate_tag;
+ initack = mtod(m, struct sctp_init_ack_chunk *);
/* Save it off for quick ref */
stc.peers_vtag = init_chk->init.initiate_tag;
- initackm_out->sh.checksum = 0; /* calculate later */
/* who are we */
memcpy(stc.identification, SCTP_VERSION_STRING,
min(strlen(SCTP_VERSION_STRING), sizeof(stc.identification)));
/* now the chunk header */
- initackm_out->msg.ch.chunk_type = SCTP_INITIATION_ACK;
- initackm_out->msg.ch.chunk_flags = 0;
+ initack->ch.chunk_type = SCTP_INITIATION_ACK;
+ initack->ch.chunk_flags = 0;
/* fill in later from mbuf we build */
- initackm_out->msg.ch.chunk_length = 0;
+ initack->ch.chunk_length = 0;
/* place in my tag */
if ((asoc != NULL) &&
((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_INUSE) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED))) {
/* re-use the v-tags and init-seq here */
- initackm_out->msg.init.initiate_tag = htonl(asoc->my_vtag);
- initackm_out->msg.init.initial_tsn = htonl(asoc->init_seq_number);
+ initack->init.initiate_tag = htonl(asoc->my_vtag);
+ initack->init.initial_tsn = htonl(asoc->init_seq_number);
} else {
uint32_t vtag, itsn;
@@ -7101,17 +7126,17 @@ do_a_abort:
*/
goto new_tag;
}
- initackm_out->msg.init.initiate_tag = htonl(vtag);
+ initack->init.initiate_tag = htonl(vtag);
/* get a TSN to use too */
itsn = sctp_select_initial_TSN(&inp->sctp_ep);
- initackm_out->msg.init.initial_tsn = htonl(itsn);
+ initack->init.initial_tsn = htonl(itsn);
SCTP_TCB_LOCK(stcb);
atomic_add_int(&asoc->refcnt, -1);
} else {
vtag = sctp_select_a_tag(inp, inp->sctp_lport, sh->src_port, 1);
- initackm_out->msg.init.initiate_tag = htonl(vtag);
+ initack->init.initiate_tag = htonl(vtag);
/* get a TSN to use too */
- initackm_out->msg.init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep));
+ initack->init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep));
}
if (hold_inp_lock) {
SCTP_INP_RLOCK(inp);
@@ -7119,7 +7144,7 @@ do_a_abort:
}
}
/* save away my tag to */
- stc.my_vtag = initackm_out->msg.init.initiate_tag;
+ stc.my_vtag = initack->init.initiate_tag;
/* set up some of the credits. */
so = inp->sctp_socket;
@@ -7128,7 +7153,7 @@ do_a_abort:
sctp_m_freem(m);
return;
} else {
- initackm_out->msg.init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(so), SCTP_MINIMAL_RWND));
+ initack->init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(so), SCTP_MINIMAL_RWND));
}
/* set what I want */
his_limit = ntohs(init_chk->init.num_inbound_streams);
@@ -7144,17 +7169,17 @@ do_a_abort:
}
if (his_limit < i_want) {
/* I Want more :< */
- initackm_out->msg.init.num_outbound_streams = init_chk->init.num_inbound_streams;
+ initack->init.num_outbound_streams = init_chk->init.num_inbound_streams;
} else {
/* I can have what I want :> */
- initackm_out->msg.init.num_outbound_streams = htons(i_want);
+ initack->init.num_outbound_streams = htons(i_want);
}
/* tell him his limt. */
- initackm_out->msg.init.num_inbound_streams =
+ initack->init.num_inbound_streams =
htons(inp->sctp_ep.max_open_streams_intome);
/* adaptation layer indication parameter */
- ali = (struct sctp_adaptation_layer_indication *)((caddr_t)initackm_out + sizeof(*initackm_out));
+ ali = (struct sctp_adaptation_layer_indication *)((caddr_t)initack + sizeof(*initack));
ali->ph.param_type = htons(SCTP_ULP_ADAPTATION);
ali->ph.param_length = htons(sizeof(*ali));
ali->indication = ntohl(inp->sctp_ep.adaptation_layer_indicator);
@@ -7183,7 +7208,7 @@ do_a_abort:
ph = (struct sctp_paramhdr *)(mtod(m, caddr_t)+SCTP_BUF_LEN(m));
ph->param_type = htons(SCTP_HAS_NAT_SUPPORT);
ph->param_length = htons(sizeof(struct sctp_paramhdr));
- SCTP_BUF_LEN(m) += sizeof(sizeof(struct sctp_paramhdr));
+ SCTP_BUF_LEN(m) += sizeof(struct sctp_paramhdr);
}
/* 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));
@@ -7317,8 +7342,7 @@ do_a_abort:
}
/* Now we must build a cookie */
- m_cookie = sctp_add_cookie(inp, init_pkt, offset, m,
- sizeof(struct sctphdr), &stc, &signature);
+ m_cookie = sctp_add_cookie(inp, init_pkt, offset, m, 0, &stc, &signature);
if (m_cookie == NULL) {
/* memory problem */
sctp_m_freem(m);
@@ -7339,7 +7363,7 @@ do_a_abort:
* Place in the size, but we don't include the last pad (if any) in
* the INIT-ACK.
*/
- initackm_out->msg.ch.chunk_length = htons((p_len - sizeof(struct sctphdr)));
+ initack->ch.chunk_length = htons(p_len);
/*
* Time to sign the cookie, we don't sign over the cookie signature
@@ -7370,11 +7394,12 @@ do_a_abort:
over_addr = &store1;
} else {
over_addr = NULL;
-
}
(void)sctp_lowlevel_chunk_output(inp, NULL, NULL, to, m, 0, NULL, 0, 0,
- 0, NULL, 0, port, SCTP_SO_NOT_LOCKED, over_addr);
+ 0, NULL, 0,
+ inp->sctp_lport, sh->src_port, init_chk->init.initiate_tag,
+ port, SCTP_SO_NOT_LOCKED, over_addr);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
}
@@ -9164,7 +9189,6 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
struct sctp_nets *net;
struct mbuf *outchain, *endoutchain;
struct sctp_tmit_chunk *chk, *nchk;
- struct sctphdr *shdr;
/* temp arrays for unlinking */
struct sctp_tmit_chunk *data_list[SCTP_MAX_DATA_BUNDLING];
@@ -9177,7 +9201,8 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
int tsns_sent = 0;
uint32_t auth_offset = 0;
struct sctp_auth_chunk *auth = NULL;
- uint16_t auth_keyid = 0;
+ uint16_t auth_keyid;
+ int override_ok = 1;
int data_auth_reqd = 0;
/*
@@ -9189,6 +9214,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
*num_out = 0;
cwnd_full_ind = 0;
+ auth_keyid = stcb->asoc.authinfo.active_keyid;
if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
(asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED) ||
@@ -9532,24 +9558,14 @@ again_one_more_time:
* it is used to do appropriate
* source address selection.
*/
- SCTP_BUF_PREPEND(outchain, sizeof(struct sctphdr), M_DONTWAIT);
- if (outchain == NULL) {
- /* no memory */
- SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS);
- error = ENOBUFS;
- *reason_code = 7;
- continue;
- }
- shdr = mtod(outchain, struct sctphdr *);
- shdr->src_port = inp->sctp_lport;
- shdr->dest_port = stcb->rport;
- shdr->v_tag = htonl(stcb->asoc.peer_vtag);
- shdr->checksum = 0;
- auth_offset += sizeof(struct sctphdr);
if ((error = sctp_lowlevel_chunk_output(inp, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
- outchain, auth_offset, auth, stcb->asoc.authinfo.active_keyid,
- no_fragmentflg, 0, NULL, asconf, net->port, so_locked, NULL))) {
+ outchain, auth_offset, auth,
+ stcb->asoc.authinfo.active_keyid,
+ no_fragmentflg, 0, NULL, asconf,
+ inp->sctp_lport, stcb->rport,
+ htonl(stcb->asoc.peer_vtag),
+ net->port, so_locked, NULL))) {
if (error == ENOBUFS) {
asoc->ifp_had_enobuf = 1;
SCTP_STAT_INCR(sctps_lowlevelerr);
@@ -9773,24 +9789,15 @@ again_one_more_time:
sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net);
cookie = 0;
}
- SCTP_BUF_PREPEND(outchain, sizeof(struct sctphdr), M_DONTWAIT);
- if (outchain == NULL) {
- /* no memory */
- SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS);
- error = ENOBUFS;
- goto error_out_again;
- }
- shdr = mtod(outchain, struct sctphdr *);
- shdr->src_port = inp->sctp_lport;
- shdr->dest_port = stcb->rport;
- shdr->v_tag = htonl(stcb->asoc.peer_vtag);
- shdr->checksum = 0;
- auth_offset += sizeof(struct sctphdr);
if ((error = sctp_lowlevel_chunk_output(inp, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
outchain,
- auth_offset, auth, stcb->asoc.authinfo.active_keyid,
- no_fragmentflg, 0, NULL, asconf, net->port, so_locked, NULL))) {
+ auth_offset, auth,
+ stcb->asoc.authinfo.active_keyid,
+ no_fragmentflg, 0, NULL, asconf,
+ inp->sctp_lport, stcb->rport,
+ htonl(stcb->asoc.peer_vtag),
+ net->port, so_locked, NULL))) {
if (error == ENOBUFS) {
asoc->ifp_had_enobuf = 1;
SCTP_STAT_INCR(sctps_lowlevelerr);
@@ -9798,7 +9805,6 @@ again_one_more_time:
if (from_where == 0) {
SCTP_STAT_INCR(sctps_lowlevelerrusr);
}
- error_out_again:
/* error, could not output */
if (hbflag) {
if (*now_filled == 0) {
@@ -9948,8 +9954,16 @@ again_one_more_time:
&auth_offset,
stcb,
SCTP_DATA);
+ auth_keyid = chk->auth_keyid;
+ override_ok = 0;
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
+ } else if (override_ok) {
+ /*
+ * use this data's
+ * keyid
+ */
auth_keyid = chk->auth_keyid;
+ override_ok = 0;
} else if (auth_keyid != chk->auth_keyid) {
/*
* different keyid,
@@ -10072,25 +10086,6 @@ again_one_more_time:
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
}
/* Now send it, if there is anything to send :> */
- SCTP_BUF_PREPEND(outchain, sizeof(struct sctphdr), M_DONTWAIT);
- if (outchain == NULL) {
- /* out of mbufs */
- SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS);
- error = ENOBUFS;
- goto errored_send;
- }
- shdr = mtod(outchain, struct sctphdr *);
- shdr->src_port = inp->sctp_lport;
- shdr->dest_port = stcb->rport;
- shdr->v_tag = htonl(stcb->asoc.peer_vtag);
- shdr->checksum = 0;
- auth_offset += sizeof(struct sctphdr);
- /*
- * if data auth isn't needed, use the assoc active
- * key
- */
- if (!data_auth_reqd)
- auth_keyid = stcb->asoc.authinfo.active_keyid;
if ((error = sctp_lowlevel_chunk_output(inp,
stcb,
net,
@@ -10102,7 +10097,10 @@ again_one_more_time:
no_fragmentflg,
bundle_at,
data_list[0],
- asconf, net->port, so_locked, NULL))) {
+ asconf,
+ inp->sctp_lport, stcb->rport,
+ htonl(stcb->asoc.peer_vtag),
+ net->port, so_locked, NULL))) {
/* error, we could not output */
if (error == ENOBUFS) {
SCTP_STAT_INCR(sctps_lowlevelerr);
@@ -10111,7 +10109,6 @@ again_one_more_time:
if (from_where == 0) {
SCTP_STAT_INCR(sctps_lowlevelerrusr);
}
- errored_send:
SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error);
if (hbflag) {
if (*now_filled == 0) {
@@ -10727,7 +10724,6 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
struct sctp_tmit_chunk *data_list[SCTP_MAX_DATA_BUNDLING];
struct sctp_tmit_chunk *chk, *fwd;
struct mbuf *m, *endofchain;
- struct sctphdr *shdr;
struct sctp_nets *net = NULL;
uint32_t tsns_sent = 0;
int no_fragmentflg, bundle_at, cnt_thru;
@@ -10735,7 +10731,8 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
int error, i, one_chunk, fwd_tsn, ctl_cnt, tmr_started;
struct sctp_auth_chunk *auth = NULL;
uint32_t auth_offset = 0;
- uint16_t auth_keyid = 0;
+ uint16_t auth_keyid;
+ int override_ok = 1;
int data_auth_reqd = 0;
uint32_t dmtu = 0;
@@ -10746,6 +10743,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
*cnt_out = 0;
fwd = NULL;
endofchain = m = NULL;
+ auth_keyid = stcb->asoc.authinfo.active_keyid;
#ifdef SCTP_AUDITING_ENABLED
sctp_audit_log(0xC3, 1);
#endif
@@ -10803,24 +10801,13 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, chk->whoTo);
} else if (chk->rec.chunk_id.id == SCTP_ASCONF)
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, chk->whoTo);
-
- SCTP_BUF_PREPEND(m, sizeof(struct sctphdr), M_DONTWAIT);
- if (m == NULL) {
- SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS);
- return (ENOBUFS);
- }
- shdr = mtod(m, struct sctphdr *);
- shdr->src_port = inp->sctp_lport;
- shdr->dest_port = stcb->rport;
- shdr->v_tag = htonl(stcb->asoc.peer_vtag);
- shdr->checksum = 0;
- auth_offset += sizeof(struct sctphdr);
chk->snd_count++; /* update our count */
-
if ((error = sctp_lowlevel_chunk_output(inp, stcb, chk->whoTo,
(struct sockaddr *)&chk->whoTo->ro._l_addr, m,
auth_offset, auth, stcb->asoc.authinfo.active_keyid,
- no_fragmentflg, 0, NULL, 0, chk->whoTo->port, so_locked, NULL))) {
+ no_fragmentflg, 0, NULL, 0,
+ inp->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag),
+ chk->whoTo->port, so_locked, NULL))) {
SCTP_STAT_INCR(sctps_lowlevelerr);
return (error);
}
@@ -10954,8 +10941,12 @@ one_chunk_around:
&auth_offset,
stcb,
SCTP_DATA);
+ auth_keyid = chk->auth_keyid;
+ override_ok = 0;
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
+ } else if (override_ok) {
auth_keyid = chk->auth_keyid;
+ override_ok = 0;
} else if (chk->auth_keyid != auth_keyid) {
/* different keyid, so done bundling */
break;
@@ -11010,8 +11001,12 @@ one_chunk_around:
&auth_offset,
stcb,
SCTP_DATA);
+ auth_keyid = fwd->auth_keyid;
+ override_ok = 0;
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
+ } else if (override_ok) {
auth_keyid = fwd->auth_keyid;
+ override_ok = 0;
} else if (fwd->auth_keyid != auth_keyid) {
/*
* different keyid,
@@ -11059,28 +11054,13 @@ one_chunk_around:
sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
tmr_started = 1;
}
- SCTP_BUF_PREPEND(m, sizeof(struct sctphdr), M_DONTWAIT);
- if (m == NULL) {
- SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS);
- return (ENOBUFS);
- }
- shdr = mtod(m, struct sctphdr *);
- shdr->src_port = inp->sctp_lport;
- shdr->dest_port = stcb->rport;
- shdr->v_tag = htonl(stcb->asoc.peer_vtag);
- shdr->checksum = 0;
- auth_offset += sizeof(struct sctphdr);
- /*
- * if doing DATA auth, use the data chunk(s) key id,
- * otherwise use the assoc's active key id
- */
- if (!data_auth_reqd)
- auth_keyid = stcb->asoc.authinfo.active_keyid;
/* Now lets send it, if there is anything to send :> */
if ((error = sctp_lowlevel_chunk_output(inp, stcb, net,
(struct sockaddr *)&net->ro._l_addr, m,
auth_offset, auth, auth_keyid,
- no_fragmentflg, 0, NULL, 0, net->port, so_locked, NULL))) {
+ no_fragmentflg, 0, NULL, 0,
+ inp->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag),
+ net->port, so_locked, NULL))) {
/* error, we could not output */
SCTP_STAT_INCR(sctps_lowlevelerr);
return (error);
@@ -12401,7 +12381,6 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
int sz;
uint32_t auth_offset = 0;
struct sctp_auth_chunk *auth = NULL;
- struct sctphdr *shdr;
/*-
* Add an AUTH chunk, if chunk requires it and save the offset into
@@ -12449,23 +12428,12 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
abort->ch.chunk_flags = 0;
abort->ch.chunk_length = htons(sizeof(*abort) + sz);
- /* prepend and fill in the SCTP header */
- SCTP_BUF_PREPEND(m_out, sizeof(struct sctphdr), M_DONTWAIT);
- if (m_out == NULL) {
- /* TSNH: no memory */
- return;
- }
- shdr = mtod(m_out, struct sctphdr *);
- shdr->src_port = stcb->sctp_ep->sctp_lport;
- shdr->dest_port = stcb->rport;
- shdr->v_tag = htonl(stcb->asoc.peer_vtag);
- shdr->checksum = 0;
- auth_offset += sizeof(struct sctphdr);
-
(void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb,
stcb->asoc.primary_destination,
(struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr,
- m_out, auth_offset, auth, stcb->asoc.authinfo.active_keyid, 1, 0, NULL, 0, stcb->asoc.primary_destination->port, so_locked, NULL);
+ m_out, auth_offset, auth, stcb->asoc.authinfo.active_keyid, 1, 0, NULL, 0,
+ stcb->sctp_ep->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag),
+ stcb->asoc.primary_destination->port, so_locked, NULL);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
}
@@ -12475,26 +12443,24 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb,
{
/* formulate and SEND a SHUTDOWN-COMPLETE */
struct mbuf *m_shutdown_comp;
- struct sctp_shutdown_complete_msg *comp_cp;
+ struct sctp_shutdown_complete_chunk *shutdown_complete;
- m_shutdown_comp = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_complete_msg), 0, M_DONTWAIT, 1, MT_HEADER);
+ m_shutdown_comp = sctp_get_mbuf_for_msg(sizeof(struct sctp_chunkhdr), 0, M_DONTWAIT, 1, MT_HEADER);
if (m_shutdown_comp == NULL) {
/* no mbuf's */
return;
}
- comp_cp = mtod(m_shutdown_comp, struct sctp_shutdown_complete_msg *);
- comp_cp->shut_cmp.ch.chunk_type = SCTP_SHUTDOWN_COMPLETE;
- comp_cp->shut_cmp.ch.chunk_flags = 0;
- comp_cp->shut_cmp.ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk));
- comp_cp->sh.src_port = stcb->sctp_ep->sctp_lport;
- comp_cp->sh.dest_port = stcb->rport;
- comp_cp->sh.v_tag = htonl(stcb->asoc.peer_vtag);
- comp_cp->sh.checksum = 0;
-
- SCTP_BUF_LEN(m_shutdown_comp) = sizeof(struct sctp_shutdown_complete_msg);
+ shutdown_complete = mtod(m_shutdown_comp, struct sctp_shutdown_complete_chunk *);
+ shutdown_complete->ch.chunk_type = SCTP_SHUTDOWN_COMPLETE;
+ shutdown_complete->ch.chunk_flags = 0;
+ shutdown_complete->ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk));
+ SCTP_BUF_LEN(m_shutdown_comp) = sizeof(struct sctp_shutdown_complete_chunk);
(void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
- m_shutdown_comp, 0, NULL, 0, 1, 0, NULL, 0, net->port, SCTP_SO_NOT_LOCKED, NULL);
+ m_shutdown_comp, 0, NULL, 0, 1, 0, NULL, 0,
+ stcb->sctp_ep->sctp_lport, stcb->rport,
+ htonl(stcb->asoc.peer_vtag),
+ net->port, SCTP_SO_NOT_LOCKED, NULL);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
return;
}
@@ -12532,10 +12498,11 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh,
if (port) {
len += sizeof(struct udphdr);
}
- mout = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA);
+ mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_DONTWAIT, 1, MT_DATA);
if (mout == NULL) {
return;
}
+ SCTP_BUF_RESV_UF(mout, max_linkhdr);
SCTP_BUF_LEN(mout) = len;
SCTP_BUF_NEXT(mout) = NULL;
iph_out = NULL;
@@ -12596,6 +12563,7 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh,
#endif /* INET6 */
default:
/* Currently not supported. */
+ sctp_m_freem(mout);
return;
}
if (port) {
@@ -12621,8 +12589,6 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh,
comp_cp->shut_cmp.ch.chunk_type = SCTP_SHUTDOWN_COMPLETE;
comp_cp->shut_cmp.ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk));
- /* add checksum */
- comp_cp->sh.checksum = sctp_calculate_sum(mout, NULL, offset_out);
if (iph_out != NULL) {
sctp_route_t ro;
int ret;
@@ -12636,10 +12602,16 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh,
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING)
sctp_packet_log(mout, mlen);
#endif
- SCTP_ATTACH_CHAIN(o_pak, mout, mlen);
if (port) {
- SCTP_ENABLE_UDP_CSUM(o_pak);
+ comp_cp->sh.checksum = sctp_calculate_cksum(mout, offset_out);
+ SCTP_STAT_INCR(sctps_sendswcrc);
+ SCTP_ENABLE_UDP_CSUM(mout);
+ } else {
+ mout->m_pkthdr.csum_flags = CSUM_SCTP;
+ mout->m_pkthdr.csum_data = 0; /* FIXME MT */
+ SCTP_STAT_INCR(sctps_sendhwcrc);
}
+ SCTP_ATTACH_CHAIN(o_pak, mout, mlen);
/* out it goes */
SCTP_IP_OUTPUT(ret, o_pak, &ro, stcb, vrf_id);
@@ -12660,6 +12632,8 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh,
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING)
sctp_packet_log(mout, mlen);
#endif
+ comp_cp->sh.checksum = sctp_calculate_cksum(mout, offset_out);
+ SCTP_STAT_INCR(sctps_sendswcrc);
SCTP_ATTACH_CHAIN(o_pak, mout, mlen);
if (port) {
if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr),
@@ -13493,17 +13467,22 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
break;
#endif
default:
+ if (err_cause) {
+ sctp_m_freem(err_cause);
+ }
return;
}
if (port) {
len += sizeof(struct udphdr);
}
- mout = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA);
+ mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_DONTWAIT, 1, MT_DATA);
if (mout == NULL) {
- if (err_cause)
+ if (err_cause) {
sctp_m_freem(err_cause);
+ }
return;
}
+ SCTP_BUF_RESV_UF(mout, max_linkhdr);
SCTP_BUF_LEN(mout) = len;
SCTP_BUF_NEXT(mout) = err_cause;
iph_out = NULL;
@@ -13556,8 +13535,6 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
#endif /* INET6 */
default:
/* Currently not supported */
- if (err_cause)
- sctp_m_freem(err_cause);
sctp_m_freem(mout);
return;
}
@@ -13608,8 +13585,6 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
abm->msg.ch.chunk_length = htons(sizeof(abm->msg.ch));
}
- /* add checksum */
- abm->sh.checksum = sctp_calculate_sum(mout, NULL, iphlen_out);
if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) {
/* no mbuf's */
sctp_m_freem(mout);
@@ -13637,7 +13612,13 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
#endif
SCTP_ATTACH_CHAIN(o_pak, mout, len);
if (port) {
+ abm->sh.checksum = sctp_calculate_cksum(mout, iphlen_out);
+ SCTP_STAT_INCR(sctps_sendswcrc);
SCTP_ENABLE_UDP_CSUM(o_pak);
+ } else {
+ mout->m_pkthdr.csum_flags = CSUM_SCTP;
+ mout->m_pkthdr.csum_data = 0; /* FIXME MT */
+ SCTP_STAT_INCR(sctps_sendhwcrc);
}
SCTP_IP_OUTPUT(ret, o_pak, &ro, stcb, vrf_id);
@@ -13664,6 +13645,8 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING)
sctp_packet_log(mout, len);
#endif
+ abm->sh.checksum = sctp_calculate_cksum(mout, iphlen_out);
+ SCTP_STAT_INCR(sctps_sendswcrc);
SCTP_ATTACH_CHAIN(o_pak, mout, len);
if (port) {
if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) {
@@ -13679,6 +13662,7 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
#endif
SCTP_STAT_INCR(sctps_sendpackets);
SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
+ SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
}
void
@@ -13686,211 +13670,219 @@ sctp_send_operr_to(struct mbuf *m, int iphlen, struct mbuf *scm, uint32_t vtag,
uint32_t vrf_id, uint16_t port)
{
struct mbuf *o_pak;
- struct sctphdr *ihdr;
- int retcode;
- struct sctphdr *ohdr;
- struct sctp_chunkhdr *ophdr;
- struct ip *iph;
+ struct sctphdr *sh, *sh_out;
+ struct sctp_chunkhdr *ch;
+ struct ip *iph, *iph_out;
struct udphdr *udp = NULL;
struct mbuf *mout;
#ifdef INET6
-#ifdef SCTP_DEBUG
- struct sockaddr_in6 lsa6, fsa6;
+ struct ip6_hdr *ip6, *ip6_out;
#endif
-#endif
- uint32_t val;
- struct mbuf *at;
- int len;
+ int iphlen_out, len;
iph = mtod(m, struct ip *);
- ihdr = (struct sctphdr *)((caddr_t)iph + iphlen);
-
- SCTP_BUF_PREPEND(scm, (sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)), M_DONTWAIT);
- if (scm == NULL) {
- /* can't send because we can't add a mbuf */
+ sh = (struct sctphdr *)((caddr_t)iph + iphlen);
+ switch (iph->ip_v) {
+ case IPVERSION:
+ len = (sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr));
+ break;
+#ifdef INET6
+ case IPV6_VERSION >> 4:
+ len = (sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr));
+ break;
+#endif
+ default:
+ if (scm) {
+ sctp_m_freem(scm);
+ }
return;
}
- ohdr = mtod(scm, struct sctphdr *);
- ohdr->src_port = ihdr->dest_port;
- ohdr->dest_port = ihdr->src_port;
- ohdr->v_tag = vtag;
- ohdr->checksum = 0;
- ophdr = (struct sctp_chunkhdr *)(ohdr + 1);
- ophdr->chunk_type = SCTP_OPERATION_ERROR;
- ophdr->chunk_flags = 0;
- len = 0;
- at = scm;
- while (at) {
- len += SCTP_BUF_LEN(at);
- at = SCTP_BUF_NEXT(at);
+ if (port) {
+ len += sizeof(struct udphdr);
}
- ophdr->chunk_length = htons(len - sizeof(struct sctphdr));
- if (len % 4) {
- /* need padding */
- uint32_t cpthis = 0;
- int padlen;
-
- padlen = 4 - (len % 4);
- m_copyback(scm, len, padlen, (caddr_t)&cpthis);
- len += padlen;
+ mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_DONTWAIT, 1, MT_DATA);
+ if (mout == NULL) {
+ if (scm) {
+ sctp_m_freem(scm);
+ }
+ return;
}
- val = sctp_calculate_sum(scm, NULL, 0);
+ SCTP_BUF_RESV_UF(mout, max_linkhdr);
+ SCTP_BUF_LEN(mout) = len;
+ SCTP_BUF_NEXT(mout) = scm;
+ iph_out = NULL;
#ifdef INET6
- if (port) {
- mout = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr) + sizeof(struct udphdr), 1, M_DONTWAIT, 1, MT_DATA);
- } else {
- mout = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr), 1, M_DONTWAIT, 1, MT_DATA);
+ ip6_out = NULL;
+#endif
+ switch (iph->ip_v) {
+ case IPVERSION:
+ iph_out = mtod(mout, struct ip *);
+
+ /* Fill in the IP header for the ABORT */
+ iph_out->ip_v = IPVERSION;
+ iph_out->ip_hl = (sizeof(struct ip) / 4);
+ iph_out->ip_tos = (u_char)0;
+ iph_out->ip_id = 0;
+ iph_out->ip_off = 0;
+ iph_out->ip_ttl = MAXTTL;
+ if (port) {
+ iph_out->ip_p = IPPROTO_UDP;
+ } else {
+ iph_out->ip_p = IPPROTO_SCTP;
+ }
+ iph_out->ip_src.s_addr = iph->ip_dst.s_addr;
+ iph_out->ip_dst.s_addr = iph->ip_src.s_addr;
+ /* let IP layer calculate this */
+ iph_out->ip_sum = 0;
+
+ iphlen_out = sizeof(struct ip);
+ sh_out = (struct sctphdr *)((caddr_t)iph_out + iphlen_out);
+ break;
+#ifdef INET6
+ case IPV6_VERSION >> 4:
+ ip6 = (struct ip6_hdr *)iph;
+ ip6_out = mtod(mout, struct ip6_hdr *);
+
+ /* Fill in the IP6 header for the ABORT */
+ ip6_out->ip6_flow = ip6->ip6_flow;
+ ip6_out->ip6_hlim = MODULE_GLOBAL(MOD_INET6, ip6_defhlim);
+ if (port) {
+ ip6_out->ip6_nxt = IPPROTO_UDP;
+ } else {
+ ip6_out->ip6_nxt = IPPROTO_SCTP;
+ }
+ ip6_out->ip6_src = ip6->ip6_dst;
+ ip6_out->ip6_dst = ip6->ip6_src;
+
+ iphlen_out = sizeof(struct ip6_hdr);
+ sh_out = (struct sctphdr *)((caddr_t)ip6_out + iphlen_out);
+ break;
+#endif /* INET6 */
+ default:
+ /* Currently not supported */
+ sctp_m_freem(mout);
+ return;
}
-#else
+
+ udp = (struct udphdr *)sh_out;
if (port) {
- mout = sctp_get_mbuf_for_msg(sizeof(struct ip) + sizeof(struct udphdr), 1, M_DONTWAIT, 1, MT_DATA);
- } else {
- mout = sctp_get_mbuf_for_msg(sizeof(struct ip), 1, M_DONTWAIT, 1, MT_DATA);
+ udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
+ udp->uh_dport = port;
+ /* set udp->uh_ulen later */
+ udp->uh_sum = 0;
+ iphlen_out += sizeof(struct udphdr);
+ sh_out = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr));
}
-#endif
- if (mout == NULL) {
- sctp_m_freem(scm);
- return;
+ sh_out->src_port = sh->dest_port;
+ sh_out->dest_port = sh->src_port;
+ sh_out->v_tag = vtag;
+ sh_out->checksum = 0;
+
+ ch = (struct sctp_chunkhdr *)((caddr_t)sh_out + sizeof(struct sctphdr));
+ ch->chunk_type = SCTP_OPERATION_ERROR;
+ ch->chunk_flags = 0;
+
+ if (scm) {
+ struct mbuf *m_tmp = scm;
+ int cause_len = 0;
+
+ /* get length of the err_cause chain */
+ while (m_tmp != NULL) {
+ cause_len += SCTP_BUF_LEN(m_tmp);
+ m_tmp = SCTP_BUF_NEXT(m_tmp);
+ }
+ len = SCTP_BUF_LEN(mout) + cause_len;
+ if (cause_len % 4) {
+ /* need pad at end of chunk */
+ uint32_t cpthis = 0;
+ int padlen;
+
+ padlen = 4 - (len % 4);
+ m_copyback(mout, len, padlen, (caddr_t)&cpthis);
+ len += padlen;
+ }
+ ch->chunk_length = htons(sizeof(struct sctp_chunkhdr) + cause_len);
+ } else {
+ len = SCTP_BUF_LEN(mout);
+ ch->chunk_length = htons(sizeof(struct sctp_chunkhdr));
}
- SCTP_BUF_NEXT(mout) = scm;
+
if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) {
+ /* no mbuf's */
sctp_m_freem(mout);
return;
}
- ohdr->checksum = val;
- switch (iph->ip_v) {
- case IPVERSION:
- {
- /* V4 */
- struct ip *out;
- sctp_route_t ro;
- struct sctp_tcb *stcb = NULL;
-
- SCTP_BUF_LEN(mout) = sizeof(struct ip);
- len += sizeof(struct ip);
- if (port) {
- SCTP_BUF_LEN(mout) += sizeof(struct udphdr);
- len += sizeof(struct udphdr);
- }
- bzero(&ro, sizeof ro);
- out = mtod(mout, struct ip *);
- out->ip_v = iph->ip_v;
- out->ip_hl = (sizeof(struct ip) / 4);
- out->ip_tos = iph->ip_tos;
- out->ip_id = iph->ip_id;
- out->ip_off = 0;
- out->ip_ttl = MAXTTL;
- if (port) {
- out->ip_p = IPPROTO_UDP;
- } else {
- out->ip_p = IPPROTO_SCTP;
- }
- out->ip_sum = 0;
- out->ip_src = iph->ip_dst;
- out->ip_dst = iph->ip_src;
- out->ip_len = len;
- if (port) {
- udp = (struct udphdr *)(out + 1);
- udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
- udp->uh_dport = port;
- udp->uh_ulen = htons(len - sizeof(struct ip));
- udp->uh_sum = in_pseudo(out->ip_src.s_addr, out->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP));
- }
+ if (iph_out != NULL) {
+ sctp_route_t ro;
+ struct sctp_tcb *stcb = NULL;
+ int ret;
+
+ /* zap the stack pointer to the route */
+ bzero(&ro, sizeof ro);
+ if (port) {
+ udp->uh_ulen = htons(len - sizeof(struct ip));
+ udp->uh_sum = in_pseudo(iph_out->ip_src.s_addr, iph_out->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP));
+ }
+ /* set IPv4 length */
+ iph_out->ip_len = len;
+ /* out it goes */
#ifdef SCTP_PACKET_LOGGING
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING)
- sctp_packet_log(mout, len);
+ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING)
+ sctp_packet_log(mout, len);
#endif
- SCTP_ATTACH_CHAIN(o_pak, mout, len);
- if (port) {
- SCTP_ENABLE_UDP_CSUM(o_pak);
- }
- SCTP_IP_OUTPUT(retcode, o_pak, &ro, stcb, vrf_id);
-
- SCTP_STAT_INCR(sctps_sendpackets);
- SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
- /* Free the route if we got one back */
- if (ro.ro_rt)
- RTFREE(ro.ro_rt);
- break;
+ SCTP_ATTACH_CHAIN(o_pak, mout, len);
+ if (port) {
+ sh_out->checksum = sctp_calculate_cksum(mout, iphlen_out);
+ SCTP_STAT_INCR(sctps_sendswcrc);
+ SCTP_ENABLE_UDP_CSUM(o_pak);
+ } else {
+ mout->m_pkthdr.csum_flags = CSUM_SCTP;
+ mout->m_pkthdr.csum_data = 0; /* FIXME MT */
+ SCTP_STAT_INCR(sctps_sendhwcrc);
}
+ SCTP_IP_OUTPUT(ret, o_pak, &ro, stcb, vrf_id);
+
+ /* Free the route if we got one back */
+ if (ro.ro_rt)
+ RTFREE(ro.ro_rt);
+ }
#ifdef INET6
- case IPV6_VERSION >> 4:
- {
- /* V6 */
- struct route_in6 ro;
- int ret;
- struct sctp_tcb *stcb = NULL;
- struct ifnet *ifp = NULL;
- struct ip6_hdr *out6, *in6;
-
- SCTP_BUF_LEN(mout) = sizeof(struct ip6_hdr);
- len += sizeof(struct ip6_hdr);
- bzero(&ro, sizeof ro);
- if (port) {
- SCTP_BUF_LEN(mout) += sizeof(struct udphdr);
- len += sizeof(struct udphdr);
- }
- in6 = mtod(m, struct ip6_hdr *);
- out6 = mtod(mout, struct ip6_hdr *);
- out6->ip6_flow = in6->ip6_flow;
- out6->ip6_hlim = MODULE_GLOBAL(MOD_INET6, ip6_defhlim);
- if (port) {
- out6->ip6_nxt = IPPROTO_UDP;
- } else {
- out6->ip6_nxt = IPPROTO_SCTP;
- }
- out6->ip6_src = in6->ip6_dst;
- out6->ip6_dst = in6->ip6_src;
- out6->ip6_plen = len - sizeof(struct ip6_hdr);
- if (port) {
- udp = (struct udphdr *)(out6 + 1);
- udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
- udp->uh_dport = port;
- udp->uh_ulen = htons(len - sizeof(struct ip6_hdr));
- udp->uh_sum = 0;
- }
-#ifdef SCTP_DEBUG
- bzero(&lsa6, sizeof(lsa6));
- lsa6.sin6_len = sizeof(lsa6);
- lsa6.sin6_family = AF_INET6;
- lsa6.sin6_addr = out6->ip6_src;
- bzero(&fsa6, sizeof(fsa6));
- fsa6.sin6_len = sizeof(fsa6);
- fsa6.sin6_family = AF_INET6;
- fsa6.sin6_addr = out6->ip6_dst;
-#endif
- SCTPDBG(SCTP_DEBUG_OUTPUT2, "sctp_operr_to calling ipv6 output:\n");
- SCTPDBG(SCTP_DEBUG_OUTPUT2, "src: ");
- SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)&lsa6);
- SCTPDBG(SCTP_DEBUG_OUTPUT2, "dst ");
- SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)&fsa6);
+ if (ip6_out != NULL) {
+ struct route_in6 ro;
+ int ret;
+ struct sctp_tcb *stcb = NULL;
+ struct ifnet *ifp = NULL;
+ /* zap the stack pointer to the route */
+ bzero(&ro, sizeof(ro));
+ if (port) {
+ udp->uh_ulen = htons(len - sizeof(struct ip6_hdr));
+ }
+ ip6_out->ip6_plen = len - sizeof(*ip6_out);
#ifdef SCTP_PACKET_LOGGING
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING)
- sctp_packet_log(mout, len);
+ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING)
+ sctp_packet_log(mout, len);
#endif
- SCTP_ATTACH_CHAIN(o_pak, mout, len);
- if (port) {
- if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) {
- udp->uh_sum = 0xffff;
- }
+ sh_out->checksum = sctp_calculate_cksum(mout, iphlen_out);
+ SCTP_STAT_INCR(sctps_sendswcrc);
+ SCTP_ATTACH_CHAIN(o_pak, mout, len);
+ if (port) {
+ if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) {
+ udp->uh_sum = 0xffff;
}
- SCTP_IP6_OUTPUT(ret, o_pak, &ro, &ifp, stcb, vrf_id);
-
- SCTP_STAT_INCR(sctps_sendpackets);
- SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
- /* Free the route if we got one back */
- if (ro.ro_rt)
- RTFREE(ro.ro_rt);
- break;
}
-#endif /* INET6 */
- default:
- /* TSNH */
- break;
+ SCTP_IP6_OUTPUT(ret, o_pak, &ro, &ifp, stcb, vrf_id);
+
+ /* Free the route if we got one back */
+ if (ro.ro_rt)
+ RTFREE(ro.ro_rt);
}
+#endif
+ SCTP_STAT_INCR(sctps_sendpackets);
+ SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
+ SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
}
static struct mbuf *
OpenPOWER on IntegriCloud