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
This commit is contained in:
parent
f77b842746
commit
4d6b853ad6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=297990
@ -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.
|
||||
|
@ -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 *sa, void *vip)
|
||||
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 */
|
||||
|
Loading…
Reference in New Issue
Block a user