From owner-svn-src-all@freebsd.org Thu Apr 14 19:59:23 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 1AF33ADAC78; Thu, 14 Apr 2016 19:59:23 +0000 (UTC) (envelope-from tuexen@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id CE92712F7; Thu, 14 Apr 2016 19:59:22 +0000 (UTC) (envelope-from tuexen@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u3EJxLcN017730; Thu, 14 Apr 2016 19:59:21 GMT (envelope-from tuexen@FreeBSD.org) Received: (from tuexen@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u3EJxLZm017728; Thu, 14 Apr 2016 19:59:21 GMT (envelope-from tuexen@FreeBSD.org) Message-Id: <201604141959.u3EJxLZm017728@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: tuexen set sender to tuexen@FreeBSD.org using -f From: Michael Tuexen Date: Thu, 14 Apr 2016 19:59:21 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r297990 - head/sys/netinet X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Apr 2016 19:59:23 -0000 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 */