svn commit: r297990 - head/sys/netinet
Michael Tuexen
tuexen at FreeBSD.org
Thu Apr 14 19:59:23 UTC 2016
Author: tuexen
Date: Thu Apr 14 19:59:21 2016
New Revision: 297990
URL: https://svnweb.freebsd.org/changeset/base/297990
Log:
Allow the handling of ICMP messages sent in response to SCTP packets
containing an INIT chunk. These need to be handled in case the peer
does not support SCTP and returns an ICMP messages indicating destination
unreachable, protocol unreachable.
MFC after: 1 week
Modified:
head/sys/netinet/ip_icmp.h
head/sys/netinet/sctp_usrreq.c
Modified: head/sys/netinet/ip_icmp.h
==============================================================================
--- head/sys/netinet/ip_icmp.h Thu Apr 14 19:51:29 2016 (r297989)
+++ head/sys/netinet/ip_icmp.h Thu Apr 14 19:59:21 2016 (r297990)
@@ -139,9 +139,10 @@ struct icmp {
/* This is the minimum length required by RFC 792. */
/*
* ICMP_ADVLENPREF is the preferred number of bytes which should be contiguous.
- * It currently reflects the required minimum.
+ * SCTP needs additional 12 bytes to be able to access the initiate tag
+ * in packets containing an INIT chunk.
*/
-#define ICMP_ADVLENPREF(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8)
+#define ICMP_ADVLENPREF(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8 + 12)
/*
* Definition of type and code field values.
Modified: head/sys/netinet/sctp_usrreq.c
==============================================================================
--- head/sys/netinet/sctp_usrreq.c Thu Apr 14 19:51:29 2016 (r297989)
+++ head/sys/netinet/sctp_usrreq.c Thu Apr 14 19:59:21 2016 (r297990)
@@ -254,48 +254,49 @@ sctp_notify(struct sctp_inpcb *inp,
void
sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
{
- struct ip *ip = vip;
+ struct ip *outer_ip, *inner_ip;
struct sctphdr *sh;
- struct icmp *icmph;
- uint32_t vrf_id;
+ struct icmp *icmp;
+ struct sctp_inpcb *inp;
+ struct sctp_tcb *stcb;
+ struct sctp_nets *net;
+ struct sctp_init_chunk *ch;
+ struct sockaddr_in to, from;
- /* FIX, for non-bsd is this right? */
- vrf_id = SCTP_DEFAULT_VRFID;
if (sa->sa_family != AF_INET ||
((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) {
return;
}
if (PRC_IS_REDIRECT(cmd)) {
- ip = 0;
+ vip = NULL;
} else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) {
return;
}
- if (ip) {
- struct sctp_inpcb *inp = NULL;
- struct sctp_tcb *stcb = NULL;
- struct sctp_nets *net = NULL;
- struct sockaddr_in to, from;
-
- icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
- sizeof(struct ip)));
-
- sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2));
+ if (vip != NULL) {
+ inner_ip = (struct ip *)vip;
+ icmp = (struct icmp *)((caddr_t)inner_ip -
+ (sizeof(struct icmp) - sizeof(struct ip)));
+ outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip));
+ sh = (struct sctphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2));
bzero(&to, sizeof(to));
bzero(&from, sizeof(from));
from.sin_family = to.sin_family = AF_INET;
from.sin_len = to.sin_len = sizeof(to);
from.sin_port = sh->src_port;
- from.sin_addr = ip->ip_src;
+ from.sin_addr = inner_ip->ip_src;
to.sin_port = sh->dest_port;
- to.sin_addr = ip->ip_dst;
+ to.sin_addr = inner_ip->ip_dst;
/*
* 'to' holds the dest of the packet that failed to be sent.
* 'from' holds our local endpoint address. Thus we reverse
* the to and the from in the lookup.
*/
+ inp = NULL;
+ net = NULL;
stcb = sctp_findassociation_addr_sa((struct sockaddr *)&to,
(struct sockaddr *)&from,
- &inp, &net, 1, vrf_id);
+ &inp, &net, 1,
+ SCTP_DEFAULT_VRFID);
if ((stcb != NULL) &&
(net != NULL) &&
(inp != NULL) &&
@@ -313,19 +314,30 @@ sctp_ctlinput(int cmd, struct sockaddr *
return;
}
} else {
- /*
- * In this case we could check if we got an
- * INIT chunk and if the initiate tag
- * matches. But this is not there yet...
- */
- SCTP_TCB_UNLOCK(stcb);
- return;
+ if (ntohs(outer_ip->ip_len) >=
+ sizeof(struct ip) +
+ 8 + (inner_ip->ip_hl << 2) + 20) {
+ /*
+ * In this case we can check if we
+ * got an INIT chunk and if the
+ * initiate tag matches.
+ */
+ ch = (struct sctp_init_chunk *)(sh + 1);
+ if ((ch->ch.chunk_type != SCTP_INITIATION) ||
+ (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ } else {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
}
sctp_notify(inp, stcb, net,
- icmph->icmp_type,
- icmph->icmp_code,
- ntohs(ip->ip_len),
- ntohs(icmph->icmp_nextmtu));
+ icmp->icmp_type,
+ icmp->icmp_code,
+ ntohs(inner_ip->ip_len),
+ ntohs(icmp->icmp_nextmtu));
} else {
if ((stcb == NULL) && (inp != NULL)) {
/* reduce ref-count */
More information about the svn-src-head
mailing list