svn commit: r236956 - head/sys/netinet
Michael Tuexen
tuexen at FreeBSD.org
Tue Jun 12 13:15:28 UTC 2012
Author: tuexen
Date: Tue Jun 12 13:15:27 2012
New Revision: 236956
URL: http://svn.freebsd.org/changeset/base/236956
Log:
Unify the sending of ABORT, SHUTDOWN-COMPLETE and ERROR chunks.
While there: Fix also some minor bugs and prepare for SCTP/DTLS.
MFC after: 3 days
Modified:
head/sys/netinet/sctp_input.c
head/sys/netinet/sctp_output.c
head/sys/netinet/sctp_output.h
Modified: head/sys/netinet/sctp_input.c
==============================================================================
--- head/sys/netinet/sctp_input.c Tue Jun 12 12:44:17 2012 (r236955)
+++ head/sys/netinet/sctp_input.c Tue Jun 12 13:15:27 2012 (r236956)
@@ -1442,7 +1442,7 @@ sctp_process_cookie_existing(struct mbuf
ph = mtod(op_err, struct sctp_paramhdr *);
ph->param_type = htons(SCTP_CAUSE_COOKIE_IN_SHUTDOWN);
ph->param_length = htons(sizeof(struct sctp_paramhdr));
- sctp_send_operr_to(m, iphlen, op_err, cookie->peers_vtag,
+ sctp_send_operr_to(m, sh, cookie->peers_vtag, op_err,
vrf_id, net->port);
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 2;
@@ -2570,7 +2570,7 @@ sctp_handle_cookie_echo(struct mbuf *m,
if (tim == 0)
tim = now.tv_usec - cookie->time_entered.tv_usec;
scm->time_usec = htonl(tim);
- sctp_send_operr_to(m, iphlen, op_err, cookie->peers_vtag,
+ sctp_send_operr_to(m, sh, cookie->peers_vtag, op_err,
vrf_id, port);
return (NULL);
}
Modified: head/sys/netinet/sctp_output.c
==============================================================================
--- head/sys/netinet/sctp_output.c Tue Jun 12 12:44:17 2012 (r236955)
+++ head/sys/netinet/sctp_output.c Tue Jun 12 13:15:27 2012 (r236956)
@@ -4478,7 +4478,7 @@ sctp_lowlevel_chunk_output(struct sctp_i
#if defined(SCTP_WITH_NO_CSUM)
SCTP_STAT_INCR(sctps_sendnocrc);
#else
- m->m_pkthdr.csum_flags = CSUM_SCTP_IPV6;
+ m->m_pkthdr.csum_flags = CSUM_SCTP;
m->m_pkthdr.csum_data = 0;
SCTP_STAT_INCR(sctps_sendhwcrc);
#endif
@@ -10854,19 +10854,20 @@ sctp_send_shutdown_complete(struct sctp_
return;
}
-void
-sctp_send_shutdown_complete2(struct mbuf *m, struct sctphdr *sh,
- uint32_t vrf_id, uint16_t port)
+static void
+sctp_send_resp_msg(struct mbuf *m, struct sctphdr *sh, uint32_t vtag,
+ uint8_t type, struct mbuf *cause, uint32_t vrf_id, uint16_t port)
{
- /* formulate and SEND a SHUTDOWN-COMPLETE */
struct mbuf *o_pak;
struct mbuf *mout;
+ struct sctphdr *shout;
+ struct sctp_chunkhdr *ch;
struct ip *iph;
- struct udphdr *udp = NULL;
- int offset_out, len, mlen;
- struct sctp_shutdown_complete_msg *comp_cp;
+ struct udphdr *udp;
+ int len, cause_len, padding_len, ret;
#ifdef INET
+ sctp_route_t ro;
struct ip *iph_out;
#endif
@@ -10875,31 +10876,59 @@ sctp_send_shutdown_complete2(struct mbuf
#endif
+ /* Compute the length of the cause and add final padding. */
+ cause_len = 0;
+ if (cause != NULL) {
+ struct mbuf *m_at, *m_last = NULL;
+
+ for (m_at = cause; m_at; m_at = SCTP_BUF_NEXT(m_at)) {
+ if (SCTP_BUF_NEXT(m_at) == NULL)
+ m_last = m_at;
+ cause_len += SCTP_BUF_LEN(m_at);
+ }
+ padding_len = cause_len % 4;
+ if (padding_len != 0) {
+ padding_len = 4 - padding_len;
+ }
+ if (padding_len != 0) {
+ if (sctp_add_pad_tombuf(m_last, padding_len)) {
+ sctp_m_freem(cause);
+ return;
+ }
+ }
+ } else {
+ padding_len = 0;
+ }
+ /* Get an mbuf for the header. */
+ len = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
iph = mtod(m, struct ip *);
switch (iph->ip_v) {
#ifdef INET
case IPVERSION:
- len = (sizeof(struct ip) + sizeof(struct sctp_shutdown_complete_msg));
+ len += sizeof(struct ip);
break;
#endif
#ifdef INET6
case IPV6_VERSION >> 4:
- len = (sizeof(struct ip6_hdr) + sizeof(struct sctp_shutdown_complete_msg));
+ len += sizeof(struct ip6_hdr);
break;
#endif
default:
- return;
+ break;
}
if (port) {
len += sizeof(struct udphdr);
}
mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_DONTWAIT, 1, MT_DATA);
if (mout == NULL) {
+ if (cause) {
+ sctp_m_freem(cause);
+ }
return;
}
SCTP_BUF_RESV_UF(mout, max_linkhdr);
SCTP_BUF_LEN(mout) = len;
- SCTP_BUF_NEXT(mout) = NULL;
+ SCTP_BUF_NEXT(mout) = cause;
if (m->m_flags & M_FLOWID) {
mout->m_pkthdr.flowid = m->m_pkthdr.flowid;
mout->m_flags |= M_FLOWID;
@@ -10910,18 +10939,14 @@ sctp_send_shutdown_complete2(struct mbuf
#ifdef INET6
ip6_out = NULL;
#endif
- offset_out = 0;
-
switch (iph->ip_v) {
#ifdef INET
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_hl = (sizeof(struct ip) >> 2);
+ iph_out->ip_tos = 0;
+ iph_out->ip_id = ip_newid();
iph_out->ip_off = 0;
iph_out->ip_ttl = MODULE_GLOBAL(ip_defttl);
if (port) {
@@ -10931,21 +10956,19 @@ sctp_send_shutdown_complete2(struct mbuf
}
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;
- offset_out += sizeof(*iph_out);
- comp_cp = (struct sctp_shutdown_complete_msg *)(
- (caddr_t)iph_out + offset_out);
+ len = sizeof(struct ip);
+ shout = (struct sctphdr *)((caddr_t)iph_out + len);
break;
#endif
#ifdef INET6
case IPV6_VERSION >> 4:
ip6 = (struct ip6_hdr *)iph;
ip6_out = mtod(mout, struct ip6_hdr *);
-
- /* Fill in the IPv6 header for the ABORT */
- ip6_out->ip6_flow = ip6->ip6_flow;
+ ip6_out->ip6_flow = htonl(0x60000000);
+ if (V_ip6_auto_flowlabel) {
+ ip6_out->ip6_flow |= (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK);
+ }
ip6_out->ip6_hlim = MODULE_GLOBAL(ip6_defhlim);
if (port) {
ip6_out->ip6_nxt = IPPROTO_UDP;
@@ -10954,78 +10977,84 @@ sctp_send_shutdown_complete2(struct mbuf
}
ip6_out->ip6_src = ip6->ip6_dst;
ip6_out->ip6_dst = ip6->ip6_src;
- /*
- * ?? The old code had both the iph len + payload, I think
- * this is wrong and would never have worked
- */
- ip6_out->ip6_plen = sizeof(struct sctp_shutdown_complete_msg);
- offset_out += sizeof(*ip6_out);
- comp_cp = (struct sctp_shutdown_complete_msg *)(
- (caddr_t)ip6_out + offset_out);
+ len = sizeof(struct ip6_hdr);
+ shout = (struct sctphdr *)((caddr_t)ip6_out + len);
break;
-#endif /* INET6 */
+#endif
default:
- /* Currently not supported. */
- sctp_m_freem(mout);
- return;
+ len = 0;
+ shout = mtod(mout, struct sctphdr *);
+ break;
}
if (port) {
if (htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)) == 0) {
sctp_m_freem(mout);
return;
}
- udp = (struct udphdr *)comp_cp;
+ udp = (struct udphdr *)shout;
udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
udp->uh_dport = port;
- udp->uh_ulen = htons(sizeof(struct sctp_shutdown_complete_msg) + sizeof(struct udphdr));
-#ifdef INET
- if (iph_out) {
- if (V_udp_cksum) {
- udp->uh_sum = in_pseudo(iph_out->ip_src.s_addr, iph_out->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP));
- } else {
- udp->uh_sum = 0;
- }
- }
-#endif
- offset_out += sizeof(struct udphdr);
- comp_cp = (struct sctp_shutdown_complete_msg *)((caddr_t)comp_cp + sizeof(struct udphdr));
+ udp->uh_sum = 0;
+ udp->uh_ulen = htons(sizeof(struct udphdr) +
+ sizeof(struct sctphdr) +
+ sizeof(struct sctp_chunkhdr) +
+ cause_len + padding_len);
+ len += sizeof(struct udphdr);
+ shout = (struct sctphdr *)((caddr_t)shout + sizeof(struct udphdr));
+ } else {
+ udp = NULL;
+ }
+ shout->src_port = sh->dest_port;
+ shout->dest_port = sh->src_port;
+ shout->checksum = 0;
+ if (vtag) {
+ shout->v_tag = htonl(vtag);
+ } else {
+ shout->v_tag = sh->v_tag;
}
+ len += sizeof(struct sctphdr);
+ ch = (struct sctp_chunkhdr *)((caddr_t)shout + sizeof(struct sctphdr));
+ ch->chunk_type = type;
+ if (vtag) {
+ ch->chunk_flags = 0;
+ } else {
+ ch->chunk_flags = SCTP_HAD_NO_TCB;
+ }
+ ch->chunk_length = htons(sizeof(struct sctp_chunkhdr) + cause_len);
+ len += sizeof(struct sctp_chunkhdr);
+ len += cause_len + padding_len;
+
if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) {
- /* no mbuf's */
sctp_m_freem(mout);
return;
}
- /* Now copy in and fill in the ABORT tags etc. */
- comp_cp->sh.src_port = sh->dest_port;
- comp_cp->sh.dest_port = sh->src_port;
- comp_cp->sh.checksum = 0;
- comp_cp->sh.v_tag = sh->v_tag;
- comp_cp->shut_cmp.ch.chunk_flags = SCTP_HAD_NO_TCB;
- comp_cp->shut_cmp.ch.chunk_type = SCTP_SHUTDOWN_COMPLETE;
- comp_cp->shut_cmp.ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk));
-
+ SCTP_ATTACH_CHAIN(o_pak, mout, len);
#ifdef INET
if (iph_out != NULL) {
- sctp_route_t ro;
- int ret;
-
- mlen = SCTP_BUF_LEN(mout);
- bzero(&ro, sizeof ro);
- /* set IPv4 length */
- iph_out->ip_len = mlen;
-#ifdef SCTP_PACKET_LOGGING
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING)
- sctp_packet_log(mout, mlen);
+ /* zap the stack pointer to the route */
+ bzero(&ro, sizeof(sctp_route_t));
+ if (port) {
+ if (V_udp_cksum) {
+ udp->uh_sum = in_pseudo(iph_out->ip_src.s_addr, iph_out->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP));
+ } else {
+ udp->uh_sum = 0;
+ }
+ }
+ iph_out->ip_len = len;
+#ifdef SCTP_PACKET_LOGGING
+ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) {
+ sctp_packet_log(mout, len);
+ }
#endif
if (port) {
#if defined(SCTP_WITH_NO_CSUM)
SCTP_STAT_INCR(sctps_sendnocrc);
#else
- comp_cp->sh.checksum = sctp_calculate_cksum(mout, offset_out);
+ shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip) + sizeof(struct udphdr));
SCTP_STAT_INCR(sctps_sendswcrc);
#endif
if (V_udp_cksum) {
- SCTP_ENABLE_UDP_CSUM(mout);
+ SCTP_ENABLE_UDP_CSUM(o_pak);
}
} else {
#if defined(SCTP_WITH_NO_CSUM)
@@ -11036,40 +11065,36 @@ sctp_send_shutdown_complete2(struct mbuf
SCTP_STAT_INCR(sctps_sendhwcrc);
#endif
}
- SCTP_ATTACH_CHAIN(o_pak, mout, mlen);
- /* out it goes */
SCTP_IP_OUTPUT(ret, o_pak, &ro, NULL, vrf_id);
-
/* Free the route if we got one back */
- if (ro.ro_rt)
+ if (ro.ro_rt) {
RTFREE(ro.ro_rt);
+ }
}
#endif
#ifdef INET6
if (ip6_out != NULL) {
- int ret;
-
- mlen = SCTP_BUF_LEN(mout);
+ ip6_out->ip6_plen = len - sizeof(struct ip6_hdr);
#ifdef SCTP_PACKET_LOGGING
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING)
- sctp_packet_log(mout, mlen);
+ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) {
+ sctp_packet_log(mout, len);
+ }
#endif
- SCTP_ATTACH_CHAIN(o_pak, mout, mlen);
if (port) {
#if defined(SCTP_WITH_NO_CSUM)
SCTP_STAT_INCR(sctps_sendnocrc);
#else
- comp_cp->sh.checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr) + sizeof(struct udphdr));
+ shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr) + sizeof(struct udphdr));
SCTP_STAT_INCR(sctps_sendswcrc);
#endif
- if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), mlen - sizeof(struct ip6_hdr))) == 0) {
+ if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) {
udp->uh_sum = 0xffff;
}
} else {
#if defined(SCTP_WITH_NO_CSUM)
SCTP_STAT_INCR(sctps_sendnocrc);
#else
- mout->m_pkthdr.csum_flags = CSUM_SCTP_IPV6;
+ mout->m_pkthdr.csum_flags = CSUM_SCTP;
mout->m_pkthdr.csum_data = 0;
SCTP_STAT_INCR(sctps_sendhwcrc);
#endif
@@ -11081,7 +11106,13 @@ sctp_send_shutdown_complete2(struct mbuf
SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
return;
+}
+void
+sctp_send_shutdown_complete2(struct mbuf *m, struct sctphdr *sh,
+ uint32_t vrf_id, uint16_t port)
+{
+ sctp_send_resp_msg(m, sh, 0, SCTP_SHUTDOWN_COMPLETE, NULL, vrf_id, port);
}
void
@@ -11913,528 +11944,24 @@ skip_stuff:
void
sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
- struct mbuf *err_cause, uint32_t vrf_id, uint16_t port)
+ struct mbuf *cause, uint32_t vrf_id, uint16_t port)
{
- /*-
- * Formulate the abort message, and send it back down.
- */
- struct mbuf *o_pak;
- struct mbuf *mout;
- struct sctp_abort_msg *abm;
- struct ip *iph;
- struct udphdr *udp;
- int iphlen_out, len;
-
-#ifdef INET
- struct ip *iph_out;
-
-#endif
-#ifdef INET6
- struct ip6_hdr *ip6, *ip6_out;
-
-#endif
-
- /* don't respond to ABORT with ABORT */
+ /* Don't respond to an ABORT with an ABORT. */
if (sctp_is_there_an_abort_here(m, iphlen, &vtag)) {
- if (err_cause)
- sctp_m_freem(err_cause);
+ if (cause)
+ sctp_m_freem(cause);
return;
}
- iph = mtod(m, struct ip *);
- switch (iph->ip_v) {
-#ifdef INET
- case IPVERSION:
- len = (sizeof(struct ip) + sizeof(struct sctp_abort_msg));
- break;
-#endif
-#ifdef INET6
- case IPV6_VERSION >> 4:
- len = (sizeof(struct ip6_hdr) + sizeof(struct sctp_abort_msg));
- 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 + max_linkhdr, 1, M_DONTWAIT, 1, MT_DATA);
- if (mout == NULL) {
- 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;
- if (m->m_flags & M_FLOWID) {
- mout->m_pkthdr.flowid = m->m_pkthdr.flowid;
- mout->m_flags |= M_FLOWID;
- }
-#ifdef INET
- iph_out = NULL;
-#endif
-#ifdef INET6
- ip6_out = NULL;
-#endif
- switch (iph->ip_v) {
-#ifdef INET
- 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 = MODULE_GLOBAL(ip_defttl);
- 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(*iph_out);
- abm = (struct sctp_abort_msg *)((caddr_t)iph_out + iphlen_out);
- break;
-#endif
-#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(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(*ip6_out);
- abm = (struct sctp_abort_msg *)((caddr_t)ip6_out + iphlen_out);
- break;
-#endif /* INET6 */
- default:
- /* Currently not supported */
- sctp_m_freem(mout);
- return;
- }
-
- udp = (struct udphdr *)abm;
- if (port) {
- if (htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)) == 0) {
- sctp_m_freem(mout);
- return;
- }
- 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);
- abm = (struct sctp_abort_msg *)((caddr_t)abm + sizeof(struct udphdr));
- }
- abm->sh.src_port = sh->dest_port;
- abm->sh.dest_port = sh->src_port;
- abm->sh.checksum = 0;
- if (vtag == 0) {
- abm->sh.v_tag = sh->v_tag;
- abm->msg.ch.chunk_flags = SCTP_HAD_NO_TCB;
- } else {
- abm->sh.v_tag = htonl(vtag);
- abm->msg.ch.chunk_flags = 0;
- }
- abm->msg.ch.chunk_type = SCTP_ABORT_ASSOCIATION;
-
- if (err_cause) {
- struct mbuf *m_tmp = err_cause;
- int err_len = 0;
-
- /* get length of the err_cause chain */
- while (m_tmp != NULL) {
- err_len += SCTP_BUF_LEN(m_tmp);
- m_tmp = SCTP_BUF_NEXT(m_tmp);
- }
- len = SCTP_BUF_LEN(mout) + err_len;
- if (err_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;
- }
- abm->msg.ch.chunk_length = htons(sizeof(abm->msg.ch) + err_len);
- } else {
- len = SCTP_BUF_LEN(mout);
- abm->msg.ch.chunk_length = htons(sizeof(abm->msg.ch));
- }
-
- if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) {
- /* no mbuf's */
- sctp_m_freem(mout);
- return;
- }
-#ifdef INET
- if (iph_out != NULL) {
- sctp_route_t ro;
- int ret;
-
- /* zap the stack pointer to the route */
- bzero(&ro, sizeof ro);
- if (port) {
- udp->uh_ulen = htons(len - sizeof(struct ip));
- if (V_udp_cksum) {
- udp->uh_sum = in_pseudo(iph_out->ip_src.s_addr, iph_out->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP));
- } else {
- udp->uh_sum = 0;
- }
- }
- SCTPDBG(SCTP_DEBUG_OUTPUT2, "sctp_send_abort calling ip_output:\n");
- SCTPDBG_PKT(SCTP_DEBUG_OUTPUT2, iph_out, &abm->sh);
- /* 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);
-#endif
- SCTP_ATTACH_CHAIN(o_pak, mout, len);
- if (port) {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
- abm->sh.checksum = sctp_calculate_cksum(mout, iphlen_out);
- SCTP_STAT_INCR(sctps_sendswcrc);
-#endif
- if (V_udp_cksum) {
- SCTP_ENABLE_UDP_CSUM(o_pak);
- }
- } else {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
- mout->m_pkthdr.csum_flags = CSUM_SCTP;
- mout->m_pkthdr.csum_data = 0;
- SCTP_STAT_INCR(sctps_sendhwcrc);
-#endif
- }
- SCTP_IP_OUTPUT(ret, o_pak, &ro, NULL, vrf_id);
-
- /* Free the route if we got one back */
- if (ro.ro_rt)
- RTFREE(ro.ro_rt);
- }
-#endif
-#ifdef INET6
- if (ip6_out != NULL) {
- int ret;
-
- if (port) {
- udp->uh_ulen = htons(len - sizeof(struct ip6_hdr));
- }
- SCTPDBG(SCTP_DEBUG_OUTPUT2, "sctp_send_abort calling ip6_output:\n");
- SCTPDBG_PKT(SCTP_DEBUG_OUTPUT2, (struct ip *)ip6_out, &abm->sh);
- 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);
-#endif
- SCTP_ATTACH_CHAIN(o_pak, mout, len);
- if (port) {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
- abm->sh.checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr) + sizeof(struct udphdr));
- SCTP_STAT_INCR(sctps_sendswcrc);
-#endif
- if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) {
- udp->uh_sum = 0xffff;
- }
- } else {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
- mout->m_pkthdr.csum_flags = CSUM_SCTP_IPV6;
- mout->m_pkthdr.csum_data = 0;
- SCTP_STAT_INCR(sctps_sendhwcrc);
-#endif
- }
- SCTP_IP6_OUTPUT(ret, o_pak, NULL, NULL, NULL, vrf_id);
- }
-#endif
- SCTP_STAT_INCR(sctps_sendpackets);
- SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
- SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
+ sctp_send_resp_msg(m, sh, vtag, SCTP_ABORT_ASSOCIATION, cause, vrf_id, port);
+ return;
}
void
-sctp_send_operr_to(struct mbuf *m, int iphlen, struct mbuf *scm, uint32_t vtag,
- uint32_t vrf_id, uint16_t port)
+sctp_send_operr_to(struct mbuf *m, struct sctphdr *sh, uint32_t vtag,
+ struct mbuf *cause, uint32_t vrf_id, uint16_t port)
{
- struct mbuf *o_pak;
- struct sctphdr *sh, *sh_out;
- struct sctp_chunkhdr *ch;
- struct ip *iph;
- struct udphdr *udp = NULL;
- struct mbuf *mout;
- int iphlen_out, len;
-
-#ifdef INET
- struct ip *iph_out;
-
-#endif
-#ifdef INET6
- struct ip6_hdr *ip6, *ip6_out;
-
-#endif
-
- iph = mtod(m, struct ip *);
- sh = (struct sctphdr *)((caddr_t)iph + iphlen);
- switch (iph->ip_v) {
-#ifdef INET
- case IPVERSION:
- len = (sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr));
- break;
-#endif
-#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;
- }
- if (port) {
- len += sizeof(struct udphdr);
- }
- 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;
- }
- SCTP_BUF_RESV_UF(mout, max_linkhdr);
- SCTP_BUF_LEN(mout) = len;
- SCTP_BUF_NEXT(mout) = scm;
- if (m->m_flags & M_FLOWID) {
- mout->m_pkthdr.flowid = m->m_pkthdr.flowid;
- mout->m_flags |= M_FLOWID;
- }
-#ifdef INET
- iph_out = NULL;
-#endif
-#ifdef INET6
- ip6_out = NULL;
-#endif
- switch (iph->ip_v) {
-#ifdef INET
- 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 = MODULE_GLOBAL(ip_defttl);
- 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;
-#endif
-#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(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;
- }
-
- udp = (struct udphdr *)sh_out;
- if (port) {
- if (htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)) == 0) {
- sctp_m_freem(mout);
- return;
- }
- 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));
- }
- 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));
- }
-
- if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) {
- /* no mbuf's */
- sctp_m_freem(mout);
- return;
- }
-#ifdef INET
- if (iph_out != NULL) {
- sctp_route_t ro;
- int ret;
-
- /* zap the stack pointer to the route */
- bzero(&ro, sizeof ro);
- if (port) {
- udp->uh_ulen = htons(len - sizeof(struct ip));
- if (V_udp_cksum) {
- udp->uh_sum = in_pseudo(iph_out->ip_src.s_addr, iph_out->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP));
- } else {
- udp->uh_sum = 0;
- }
- }
- /* 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);
-#endif
- SCTP_ATTACH_CHAIN(o_pak, mout, len);
- if (port) {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
- sh_out->checksum = sctp_calculate_cksum(mout, iphlen_out);
- SCTP_STAT_INCR(sctps_sendswcrc);
-#endif
- if (V_udp_cksum) {
- SCTP_ENABLE_UDP_CSUM(o_pak);
- }
- } else {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
- mout->m_pkthdr.csum_flags = CSUM_SCTP;
- mout->m_pkthdr.csum_data = 0;
- SCTP_STAT_INCR(sctps_sendhwcrc);
-#endif
- }
- SCTP_IP_OUTPUT(ret, o_pak, &ro, NULL, vrf_id);
-
- /* Free the route if we got one back */
- if (ro.ro_rt)
- RTFREE(ro.ro_rt);
- }
-#endif
-#ifdef INET6
- if (ip6_out != NULL) {
- int ret;
-
- 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);
-#endif
- SCTP_ATTACH_CHAIN(o_pak, mout, len);
- if (port) {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
- sh_out->checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr) + sizeof(struct udphdr));
- SCTP_STAT_INCR(sctps_sendswcrc);
-#endif
- if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) {
- udp->uh_sum = 0xffff;
- }
- } else {
-#if defined(SCTP_WITH_NO_CSUM)
- SCTP_STAT_INCR(sctps_sendnocrc);
-#else
- mout->m_pkthdr.csum_flags = CSUM_SCTP_IPV6;
- mout->m_pkthdr.csum_data = 0;
- SCTP_STAT_INCR(sctps_sendhwcrc);
-#endif
- }
- SCTP_IP6_OUTPUT(ret, o_pak, NULL, NULL, NULL, vrf_id);
- }
-#endif
- SCTP_STAT_INCR(sctps_sendpackets);
- SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
- SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
+ sctp_send_resp_msg(m, sh, vtag, SCTP_OPERATION_ERROR, cause, vrf_id, port);
+ return;
}
static struct mbuf *
Modified: head/sys/netinet/sctp_output.h
==============================================================================
--- head/sys/netinet/sctp_output.h Tue Jun 12 12:44:17 2012 (r236955)
+++ head/sys/netinet/sctp_output.h Tue Jun 12 13:15:27 2012 (r236956)
@@ -204,7 +204,9 @@ void
sctp_send_abort(struct mbuf *, int, struct sctphdr *, uint32_t,
struct mbuf *, uint32_t, uint16_t);
-void sctp_send_operr_to(struct mbuf *, int, struct mbuf *, uint32_t, uint32_t, uint16_t);
+void
+sctp_send_operr_to(struct mbuf *, struct sctphdr *, uint32_t,
+ struct mbuf *, uint32_t, uint16_t);
#endif /* _KERNEL || __Userspace__ */
More information about the svn-src-all
mailing list