From nobody Tue Oct 04 03:57:37 2022 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4MhP6p3yxxz4dl9B; Tue, 4 Oct 2022 03:57:38 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4MhP6p21Wjz3sSw; Tue, 4 Oct 2022 03:57:38 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1664855858; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=EbZa8I7FQY4qM5tp03DczZd4HfrdzrU4q0ZpMZFc9jU=; b=C7l2yyKtyvPGxGrriRZMXp9uljYnRPdxzkV4KVWKL6l4YfnsWaSutXsuwepImEtIt+rXn4 fSST9zyYgII9e/62KSlTJYJCaBo4kQ4d2Mm5ltxj+rAIZODOFeKwdbMsRjFGrk49NjTCXj qGc07fiHu7kEaatxiAfNb6RnYIhhSkU1pt2dKl/3YHonVwi8+9wlcgoKLSgiobwaMpJlVU ohpKHIhR7VxGvDWrKDU4vq/G0OkrfgLDrAZ9dmq4lXr34UNNSXR90Kyd6JuIiOB77UBPNl 64zkdmrAm5uAyrRKaSRt9NitapbsQ2Z2YVBUkEr8pX56tuSAoN+GhW2+GwuKoA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4MhP6n3kmqzR3q; Tue, 4 Oct 2022 03:57:37 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 2943vbk4015437; Tue, 4 Oct 2022 03:57:37 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 2943vbxw015435; Tue, 4 Oct 2022 03:57:37 GMT (envelope-from git) Date: Tue, 4 Oct 2022 03:57:37 GMT Message-Id: <202210040357.2943vbxw015435@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Gleb Smirnoff Subject: git: fcb3f813f379 - main - netinet*: remove PRC_ constants and streamline ICMP processing List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: glebius X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: fcb3f813f379f544f9cd2a10d18045588da0e132 Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1664855858; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=EbZa8I7FQY4qM5tp03DczZd4HfrdzrU4q0ZpMZFc9jU=; b=mN7cb0yL31oSWXbv+Gm0isvnUQpS3modisGxaUXCnkII391Go4H0ikFoPOEStTtdvxfTZ8 fzaqjQfjzFANaF72EusPSjBt7GMxkMMkHSOaf5BzIFg94kDseVh+nxZivlc9dB20Ot6fFd mzGEIuTVYtKx04VuE97lU1PAwoWAxaJwyrPD03bo9DSiKo61D5oFSrc5SSPvtzYZRCXOvq fe3l7yQFQyIAz7RJeqA4tVez3Mt4h/naOLEQhPO+Ct1rUvS+aLFbySnieT5sz0NxqbNNUS lNEa2GPMoliYA8e9vp+a3NBW2aK1iswySJzxdmW0e9WNVJU7PCOrkUIjaMpD8Q== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1664855858; a=rsa-sha256; cv=none; b=Y5TzgS4sV7RMracPvDkZIOBGRj1OsjW8JOLFqByX/FdhwA2qqAMVvILSxOel4Ds8TLAxI5 ZaHMuihMwes80SLHWyt1eYN0Br7p2InVSGWuWF3kgV60htV8Lvw35f/wdL8ibvE0o0aUnx px5UN9+rNiMo1K/jWHmJKevQLTHbS46xQSmRhQO2qydI7kT3pJXSXyU9AdB21MgzAblsLq 4qRQrrFwB9EOLTQ0dY8F3SeC9Tuoq4L0bo5zXIsq2GSHJfdatmwfffmAbZb6J1+BSY59G8 pSZz8r/cT8Oq9J9U+f7btqfTQvFA9t/4cE65LrHnyt4FRSpFcu0+ST7griz/OA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=fcb3f813f379f544f9cd2a10d18045588da0e132 commit fcb3f813f379f544f9cd2a10d18045588da0e132 Author: Gleb Smirnoff AuthorDate: 2022-10-04 03:53:04 +0000 Commit: Gleb Smirnoff CommitDate: 2022-10-04 03:53:04 +0000 netinet*: remove PRC_ constants and streamline ICMP processing In the original design of the network stack from the protocol control input method pr_ctlinput was used notify the protocols about two very different kinds of events: internal system events and receival of an ICMP messages from outside. These events were coded with PRC_ codes. Today these methods are removed from the protosw(9) and are isolated to IPv4 and IPv6 stacks and are called only from icmp*_input(). The PRC_ codes now just create a shim layer between ICMP codes and errors or actions taken by protocols. - Change ipproto_ctlinput_t to pass just pointer to ICMP header. This allows protocols to not deduct it from the internal IP header. - Change ip6proto_ctlinput_t to pass just struct ip6ctlparam pointer. It has all the information needed to the protocols. In the structure, change ip6c_finaldst fields to sockaddr_in6. The reason is that icmp6_input() already has this address wrapped in sockaddr, and the protocols want this address as sockaddr. - For UDP tunneling control input, as well as for IPSEC control input, change the prototypes to accept a transparent union of either ICMP header pointer or struct ip6ctlparam pointer. - In icmp_input() and icmp6_input() do only validation of ICMP header and count bad packets. The translation of ICMP codes to errors/actions is done by protocols. - Provide icmp_errmap() and icmp6_errmap() as substitute to inetctlerrmap, inet6ctlerrmap arrays. - In protocol ctlinput methods either trust what icmp_errmap() recommend, or do our own logic based on the ICMP header. Differential revision: https://reviews.freebsd.org/D36731 --- sys/netinet/icmp6.h | 1 + sys/netinet/in_var.h | 2 - sys/netinet/ip_icmp.c | 106 +++++++++++++++++++---------------- sys/netinet/ip_icmp.h | 1 + sys/netinet/ip_input.c | 17 ------ sys/netinet/ip_var.h | 3 +- sys/netinet/raw_ip.c | 11 +--- sys/netinet/sctp_usrreq.c | 10 ++-- sys/netinet/sctp_var.h | 2 +- sys/netinet/sctputil.c | 13 ++--- sys/netinet/tcp_subr.c | 128 +++++++++++++++++++++++++------------------ sys/netinet/udp_usrreq.c | 24 ++++---- sys/netinet/udp_var.h | 6 +- sys/netinet6/icmp6.c | 100 ++++++++++++++++++--------------- sys/netinet6/in6_pcb.c | 26 +-------- sys/netinet6/in6_var.h | 1 - sys/netinet6/ip6_input.c | 20 ------- sys/netinet6/ip6_var.h | 11 ++-- sys/netinet6/raw_ip6.c | 31 ++--------- sys/netinet6/sctp6_usrreq.c | 8 +-- sys/netinet6/udp6_usrreq.c | 26 ++++----- sys/netipsec/ipsec_input.c | 24 ++++---- sys/netipsec/ipsec_support.h | 17 ++++-- sys/sys/protosw.h | 43 --------------- 24 files changed, 274 insertions(+), 357 deletions(-) diff --git a/sys/netinet/icmp6.h b/sys/netinet/icmp6.h index 9628c0957c4a..7429b8173b6a 100644 --- a/sys/netinet/icmp6.h +++ b/sys/netinet/icmp6.h @@ -701,6 +701,7 @@ struct rttimer; struct in6_multi; # endif void icmp6_paramerror(struct mbuf *, int); +int icmp6_errmap(const struct icmp6_hdr *); void icmp6_error(struct mbuf *, int, int, int); void icmp6_error2(struct mbuf *, int, int, int, struct ifnet *); int icmp6_input(struct mbuf **, int *, int); diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h index 40e1c1a23c40..c4cfeea66ba8 100644 --- a/sys/netinet/in_var.h +++ b/sys/netinet/in_var.h @@ -100,8 +100,6 @@ struct in_ifaddr { #define IN_LNAOF(in, ifa) \ ((ntohl((in).s_addr) & ~((struct in_ifaddr *)(ifa)->ia_subnetmask)) -extern u_char inetctlerrmap[]; - #define LLTABLE(ifp) \ ((struct in_ifinfo *)(ifp)->if_afdata[AF_INET])->ii_llt /* diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index f0cc703c2757..fdde24fd94be 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -403,6 +403,55 @@ freeit: m_freem(n); } +int +icmp_errmap(const struct icmp *icp) +{ + + switch (icp->icmp_type) { + case ICMP_UNREACH: + switch (icp->icmp_code) { + case ICMP_UNREACH_NET: + case ICMP_UNREACH_HOST: + case ICMP_UNREACH_SRCFAIL: + case ICMP_UNREACH_NET_UNKNOWN: + case ICMP_UNREACH_HOST_UNKNOWN: + case ICMP_UNREACH_ISOLATED: + case ICMP_UNREACH_TOSNET: + case ICMP_UNREACH_TOSHOST: + case ICMP_UNREACH_HOST_PRECEDENCE: + case ICMP_UNREACH_PRECEDENCE_CUTOFF: + return (EHOSTUNREACH); + case ICMP_UNREACH_NEEDFRAG: + return (EMSGSIZE); + case ICMP_UNREACH_PROTOCOL: + case ICMP_UNREACH_PORT: + case ICMP_UNREACH_NET_PROHIB: + case ICMP_UNREACH_HOST_PROHIB: + case ICMP_UNREACH_FILTER_PROHIB: + return (ECONNREFUSED); + default: + return (0); + } + case ICMP_TIMXCEED: + switch (icp->icmp_code) { + case ICMP_TIMXCEED_INTRANS: + return (EHOSTUNREACH); + default: + return (0); + } + case ICMP_PARAMPROB: + switch (icp->icmp_code) { + case ICMP_PARAMPROB_ERRATPTR: + case ICMP_PARAMPROB_OPTABSENT: + return (ENOPROTOOPT); + default: + return (0); + } + default: + return (0); + } +} + /* * Process a received ICMP message. */ @@ -484,56 +533,21 @@ icmp_input(struct mbuf **mp, int *offp, int proto) code = icp->icmp_code; switch (icp->icmp_type) { case ICMP_UNREACH: - switch (code) { - case ICMP_UNREACH_NET: - case ICMP_UNREACH_HOST: - case ICMP_UNREACH_SRCFAIL: - case ICMP_UNREACH_NET_UNKNOWN: - case ICMP_UNREACH_HOST_UNKNOWN: - case ICMP_UNREACH_ISOLATED: - case ICMP_UNREACH_TOSNET: - case ICMP_UNREACH_TOSHOST: - case ICMP_UNREACH_HOST_PRECEDENCE: - case ICMP_UNREACH_PRECEDENCE_CUTOFF: - code = PRC_UNREACH_NET; - break; - - case ICMP_UNREACH_NEEDFRAG: - code = PRC_MSGSIZE; - break; - - /* - * RFC 1122, Sections 3.2.2.1 and 4.2.3.9. - * Treat subcodes 2,3 as immediate RST - */ - case ICMP_UNREACH_PROTOCOL: - code = PRC_UNREACH_PROTOCOL; - break; - case ICMP_UNREACH_PORT: - code = PRC_UNREACH_PORT; - break; - - case ICMP_UNREACH_NET_PROHIB: - case ICMP_UNREACH_HOST_PROHIB: - case ICMP_UNREACH_FILTER_PROHIB: - code = PRC_UNREACH_ADMIN_PROHIB; - break; - - default: - goto badcode; - } - goto deliver; + if (code > ICMP_UNREACH_PRECEDENCE_CUTOFF) + goto badcode; + else + goto deliver; case ICMP_TIMXCEED: - if (code > 1) + if (code > ICMP_TIMXCEED_REASS) goto badcode; - code += PRC_TIMXCEED_INTRANS; - goto deliver; + else + goto deliver; case ICMP_PARAMPROB: - if (code > 1) + if (code > ICMP_PARAMPROB_LENGTH) goto badcode; - code = PRC_PARAMPROB; + deliver: /* * Problem with datagram; advise higher level routines. @@ -553,7 +567,6 @@ icmp_input(struct mbuf **mp, int *offp, int proto) if (icmpprintfs) printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); #endif - icmpsrc.sin_addr = icp->icmp_ip.ip_dst; /* * XXX if the packet contains [IPv4 AH TCP], we can't make a * notification to TCP layer. @@ -576,8 +589,7 @@ icmp_input(struct mbuf **mp, int *offp, int proto) * ICMP_ADVLENPREF. See its definition in ip_icmp.h. */ if (ip_ctlprotox[icp->icmp_ip.ip_p] != NULL) - ip_ctlprotox[icp->icmp_ip.ip_p](code, &icmpsrc, - &icp->icmp_ip); + ip_ctlprotox[icp->icmp_ip.ip_p](icp); break; badcode: diff --git a/sys/netinet/ip_icmp.h b/sys/netinet/ip_icmp.h index 0303a09509c7..fefece665a00 100644 --- a/sys/netinet/ip_icmp.h +++ b/sys/netinet/ip_icmp.h @@ -216,6 +216,7 @@ struct icmp { (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) #ifdef _KERNEL +int icmp_errmap(const struct icmp *); void icmp_error(struct mbuf *, int, int, uint32_t, int); int icmp_input(struct mbuf **, int *, int); int ip_next_mtu(int, int); diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 145c4464b855..88fd4f5e4def 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -873,23 +873,6 @@ ipproto_unregister(uint8_t proto) return (ENOENT); } -/* (x) - issued by icmp_input() */ -u_char inetctlerrmap[PRC_NCMDS] = { - [PRC_MSGSIZE] = EMSGSIZE, /* (x) */ - [PRC_HOSTDEAD] = EHOSTDOWN, - [PRC_HOSTUNREACH] = EHOSTUNREACH, - [PRC_UNREACH_NET] = EHOSTUNREACH, /* (x) */ - [PRC_UNREACH_HOST] = EHOSTUNREACH, - [PRC_UNREACH_PROTOCOL] = ECONNREFUSED, /* (x) */ - [PRC_UNREACH_PORT] = ECONNREFUSED, /* (x) */ - [12] = EMSGSIZE, - [PRC_UNREACH_SRCFAIL] = EHOSTUNREACH, - [PRC_TIMXCEED_INTRANS] = EHOSTUNREACH, /* (x) */ - [PRC_TIMXCEED_REASS] = 0, /* (x) */ - [PRC_PARAMPROB] = ENOPROTOOPT, /* (x) */ - [PRC_UNREACH_ADMIN_PROHIB] = ECONNREFUSED, /* (x) */ -}; - /* * Forward a packet. If some error occurs return the sender * an icmp packet. Note we can't always generate a meaningful diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index 070c82677150..0a2d915b12b3 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -238,7 +238,8 @@ extern void (*ip_rsvp_force_done)(struct socket *); extern int (*rsvp_input_p)(struct mbuf **, int *, int); typedef int ipproto_input_t(struct mbuf **, int *, int); -typedef void ipproto_ctlinput_t(int, struct sockaddr_in *, struct ip *); +struct icmp; +typedef void ipproto_ctlinput_t(struct icmp *); int ipproto_register(uint8_t, ipproto_input_t, ipproto_ctlinput_t); int ipproto_unregister(uint8_t); #define IPPROTO_REGISTER(prot, input, ctl) do { \ diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index fb692e0822cf..2065b47883bb 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -804,17 +804,12 @@ rip_ctloutput(struct socket *so, struct sockopt *sopt) } void -rip_ctlinput(int cmd, struct sockaddr_in *sin, struct ip *ip) +rip_ctlinput(struct icmp *icmp) { - - switch (cmd) { #if defined(IPSEC) || defined(IPSEC_SUPPORT) - case PRC_MSGSIZE: - if (IPSEC_ENABLED(ipv4)) - IPSEC_CTLINPUT(ipv4, cmd, (struct sockaddr *)sin, ip); - break; + if (IPSEC_ENABLED(ipv4)) + IPSEC_CTLINPUT(ipv4, icmp); #endif - } } static int diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 4c70b618bf41..b06920529f44 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -260,23 +260,21 @@ sctp_notify(struct sctp_inpcb *inp, } void -sctp_ctlinput(int cmd, struct sockaddr_in *sin, struct ip *inner_ip) +sctp_ctlinput(struct icmp *icmp) { - struct ip *outer_ip; + struct ip *inner_ip, *outer_ip; struct sctphdr *sh; - struct icmp *icmp; struct sctp_inpcb *inp; struct sctp_tcb *stcb; struct sctp_nets *net; struct sctp_init_chunk *ch; struct sockaddr_in src, dst; - if (inetctlerrmap[cmd] == 0) + if (icmp_errmap(icmp) == 0) return; - icmp = (struct icmp *)((caddr_t)inner_ip - - (sizeof(struct icmp) - sizeof(struct ip))); outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip)); + inner_ip = &icmp->icmp_ip; sh = (struct sctphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2)); memset(&src, 0, sizeof(struct sockaddr_in)); src.sin_family = AF_INET; diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h index 77516db37773..fc0b491bf4bb 100644 --- a/sys/netinet/sctp_var.h +++ b/sys/netinet/sctp_var.h @@ -322,7 +322,7 @@ struct sctphdr; void sctp_close(struct socket *so); int sctp_disconnect(struct socket *so); -void sctp_ctlinput(int, struct sockaddr_in *, struct ip *); +ipproto_ctlinput_t sctp_ctlinput; int sctp_ctloutput(struct socket *, struct sockopt *); void sctp_input_with_port(struct mbuf *, int, uint16_t); int sctp_input(struct mbuf **, int *, int); diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index bdb35b988ae6..677040cd1d31 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -7190,11 +7190,11 @@ out: #ifdef INET static void -sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ctx SCTP_UNUSED) +sctp_recv_icmp_tunneled_packet(udp_tun_icmp_param_t param) { + struct icmp *icmp = param.icmp; struct ip *outer_ip, *inner_ip; struct sctphdr *sh; - struct icmp *icmp; struct udphdr *udp; struct sctp_inpcb *inp; struct sctp_tcb *stcb; @@ -7203,9 +7203,7 @@ sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ct struct sockaddr_in src, dst; uint8_t type, code; - inner_ip = (struct ip *)vip; - icmp = (struct icmp *)((caddr_t)inner_ip - - (sizeof(struct icmp) - sizeof(struct ip))); + inner_ip = &icmp->icmp_ip; outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip)); if (ntohs(outer_ip->ip_len) < sizeof(struct ip) + 8 + (inner_ip->ip_hl << 2) + sizeof(struct udphdr) + 8) { @@ -7300,9 +7298,9 @@ sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ct #ifdef INET6 static void -sctp_recv_icmp6_tunneled_packet(int cmd, struct sockaddr *sa, void *d, void *ctx SCTP_UNUSED) +sctp_recv_icmp6_tunneled_packet(udp_tun_icmp_param_t param) { - struct ip6ctlparam *ip6cp; + struct ip6ctlparam *ip6cp = param.ip6cp; struct sctp_inpcb *inp; struct sctp_tcb *stcb; struct sctp_nets *net; @@ -7311,7 +7309,6 @@ sctp_recv_icmp6_tunneled_packet(int cmd, struct sockaddr *sa, void *d, void *ctx struct sockaddr_in6 src, dst; uint8_t type, code; - ip6cp = (struct ip6ctlparam *)d; /* * XXX: We assume that when IPV6 is non NULL, M and OFF are valid. */ diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 7e9fe9e4ff5f..5bbea0176303 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -2854,38 +2854,44 @@ tcp_next_pmtu(const struct icmp *icp, const struct ip *ip) } static void -tcp_ctlinput_with_port(int cmd, struct sockaddr_in *sin, struct ip *ip, - uint16_t port) +tcp_ctlinput_with_port(struct icmp *icp, uint16_t port) { + struct ip *ip; struct tcphdr *th; struct inpcb *inp; struct tcpcb *tp; - struct inpcb *(*notify)(struct inpcb *, int) = tcp_notify; - struct icmp *icp; + struct inpcb *(*notify)(struct inpcb *, int); struct in_conninfo inc; tcp_seq icmp_tcp_seq; - int mtu; + int errno, mtu; - switch (cmd) { - case PRC_MSGSIZE: + errno = icmp_errmap(icp); + switch (errno) { + case 0: + return; + case EMSGSIZE: notify = tcp_mtudisc_notify; break; - case PRC_UNREACH_PORT: - case PRC_UNREACH_PROTOCOL: - case PRC_TIMXCEED_INTRANS: - case PRC_UNREACH_ADMIN_PROHIB: + case ECONNREFUSED: if (V_icmp_may_rst) notify = tcp_drop_syn_sent; + else + notify = tcp_notify; break; + case EHOSTUNREACH: + if (V_icmp_may_rst && icp->icmp_type == ICMP_TIMXCEED) + notify = tcp_drop_syn_sent; + else + notify = tcp_notify; + break; + default: + notify = tcp_notify; } - if (inetctlerrmap[cmd] == 0) - return; - - icp = (struct icmp *)((caddr_t)ip - offsetof(struct icmp, icmp_ip)); + ip = &icp->icmp_ip; th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); icmp_tcp_seq = th->th_seq; - inp = in_pcblookup(&V_tcbinfo, sin->sin_addr, th->th_dport, ip->ip_src, + inp = in_pcblookup(&V_tcbinfo, ip->ip_dst, th->th_dport, ip->ip_src, th->th_sport, INPLOOKUP_WLOCKPCB, NULL); if (inp != NULL) { if (!(inp->inp_flags & INP_TIMEWAIT) && @@ -2893,7 +2899,7 @@ tcp_ctlinput_with_port(int cmd, struct sockaddr_in *sin, struct ip *ip, !(inp->inp_socket == NULL)) { tp = intotcpcb(inp); #ifdef TCP_OFFLOAD - if (tp->t_flags & TF_TOE && cmd == PRC_MSGSIZE) { + if (tp->t_flags & TF_TOE && errno == EMSGSIZE) { /* * MTU discovery for offloaded connections. Let * the TOE driver verify seq# and process it. @@ -2908,7 +2914,7 @@ tcp_ctlinput_with_port(int cmd, struct sockaddr_in *sin, struct ip *ip, } if (SEQ_GEQ(ntohl(icmp_tcp_seq), tp->snd_una) && SEQ_LT(ntohl(icmp_tcp_seq), tp->snd_max)) { - if (cmd == PRC_MSGSIZE) { + if (errno == EMSGSIZE) { /* * MTU discovery: we got a needfrag and * will potentially try a lower MTU. @@ -2922,22 +2928,21 @@ tcp_ctlinput_with_port(int cmd, struct sockaddr_in *sin, struct ip *ip, if (mtu < tp->t_maxseg + sizeof(struct tcpiphdr)) { bzero(&inc, sizeof(inc)); - inc.inc_faddr = sin->sin_addr; + inc.inc_faddr = ip->ip_dst; inc.inc_fibnum = inp->inp_inc.inc_fibnum; tcp_hc_updatemtu(&inc, mtu); inp = tcp_mtudisc(inp, mtu); } } else - inp = (*notify)(inp, - inetctlerrmap[cmd]); + inp = (*notify)(inp, errno); } } } else { bzero(&inc, sizeof(inc)); inc.inc_fport = th->th_dport; inc.inc_lport = th->th_sport; - inc.inc_faddr = sin->sin_addr; + inc.inc_faddr = ip->ip_dst; inc.inc_laddr = ip->ip_src; syncache_unreach(&inc, icmp_tcp_seq, port); } @@ -2947,26 +2952,24 @@ out: } static void -tcp_ctlinput(int cmd, struct sockaddr_in *sin, struct ip *ip) +tcp_ctlinput(struct icmp *icmp) { - tcp_ctlinput_with_port(cmd, sin, ip, htons(0)); + tcp_ctlinput_with_port(icmp, htons(0)); } static void -tcp_ctlinput_viaudp(int cmd, struct sockaddr *sa, void *vip, void *unused) +tcp_ctlinput_viaudp(udp_tun_icmp_param_t param) { /* Its a tunneled TCP over UDP icmp */ + struct icmp *icmp = param.icmp; struct ip *outer_ip, *inner_ip; - struct icmp *icmp; struct udphdr *udp; struct tcphdr *th, ttemp; int i_hlen, o_len; uint16_t port; - 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)); + inner_ip = &icmp->icmp_ip; i_hlen = inner_ip->ip_hl << 2; o_len = ntohs(outer_ip->ip_len); if (o_len < @@ -2987,7 +2990,7 @@ tcp_ctlinput_viaudp(int cmd, struct sockaddr *sa, void *vip, void *unused) o_len -= sizeof(struct udphdr); outer_ip->ip_len = htons(o_len); /* Now call in to the normal handling code */ - tcp_ctlinput_with_port(cmd, (struct sockaddr_in *)sa, vip, port); + tcp_ctlinput_with_port(icmp, port); } #endif /* INET */ @@ -3007,11 +3010,10 @@ tcp6_next_pmtu(const struct icmp6_hdr *icmp6) } static void -tcp6_ctlinput_with_port(int cmd, struct sockaddr_in6 *sin6, - struct ip6ctlparam *ip6cp, uint16_t port) +tcp6_ctlinput_with_port(struct ip6ctlparam *ip6cp, uint16_t port) { struct in6_addr *dst; - struct inpcb *(*notify)(struct inpcb *, int) = tcp_notify; + struct inpcb *(*notify)(struct inpcb *, int); struct ip6_hdr *ip6; struct mbuf *m; struct inpcb *inp; @@ -3025,29 +3027,51 @@ tcp6_ctlinput_with_port(int cmd, struct sockaddr_in6 *sin6, tcp_seq icmp_tcp_seq; unsigned int mtu; unsigned int off; + int errno; icmp6 = ip6cp->ip6c_icmp6; m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; - dst = ip6cp->ip6c_finaldst; + dst = &ip6cp->ip6c_finaldst->sin6_addr; - switch (cmd) { - case PRC_MSGSIZE: + errno = icmp6_errmap(icmp6); + switch (errno) { + case 0: + return; + case EMSGSIZE: notify = tcp_mtudisc_notify; break; - case PRC_UNREACH_ADMIN_PROHIB: - case PRC_UNREACH_PORT: - case PRC_UNREACH_PROTOCOL: - case PRC_TIMXCEED_INTRANS: + case ECONNREFUSED: if (V_icmp_may_rst) notify = tcp_drop_syn_sent; + else + notify = tcp_notify; + break; + case EHOSTUNREACH: + /* + * There are only four ICMPs that may reset connection: + * - administratively prohibited + * - port unreachable + * - time exceeded in transit + * - unknown next header + */ + if (V_icmp_may_rst && + ((icmp6->icmp6_type == ICMP6_DST_UNREACH && + (icmp6->icmp6_code == ICMP6_DST_UNREACH_ADMIN || + icmp6->icmp6_code == ICMP6_DST_UNREACH_NOPORT)) || + (icmp6->icmp6_type == ICMP6_TIME_EXCEEDED && + icmp6->icmp6_code == ICMP6_TIME_EXCEED_TRANSIT) || + (icmp6->icmp6_type == ICMP6_PARAM_PROB && + icmp6->icmp6_code == ICMP6_PARAMPROB_NEXTHEADER))) + notify = tcp_drop_syn_sent; + else + notify = tcp_notify; break; + default: + notify = tcp_notify; } - if (inet6ctlerrmap[cmd] == 0) - return; - /* Check if we can safely get the ports from the tcp hdr */ if (m == NULL || (m->m_pkthdr.len < @@ -3069,7 +3093,7 @@ tcp6_ctlinput_with_port(int cmd, struct sockaddr_in6 *sin6, !(inp->inp_socket == NULL)) { tp = intotcpcb(inp); #ifdef TCP_OFFLOAD - if (tp->t_flags & TF_TOE && cmd == PRC_MSGSIZE) { + if (tp->t_flags & TF_TOE && errno == EMSGSIZE) { /* MTU discovery for offloaded connections. */ mtu = tcp6_next_pmtu(icmp6); tcp_offload_pmtu_update(tp, icmp_tcp_seq, mtu); @@ -3081,7 +3105,7 @@ tcp6_ctlinput_with_port(int cmd, struct sockaddr_in6 *sin6, } if (SEQ_GEQ(ntohl(icmp_tcp_seq), tp->snd_una) && SEQ_LT(ntohl(icmp_tcp_seq), tp->snd_max)) { - if (cmd == PRC_MSGSIZE) { + if (errno == EMSGSIZE) { /* * MTU discovery: * If we got a needfrag set the MTU @@ -3109,8 +3133,7 @@ tcp6_ctlinput_with_port(int cmd, struct sockaddr_in6 *sin6, ICMP6STAT_INC(icp6s_pmtuchg); } } else - inp = (*notify)(inp, - inet6ctlerrmap[cmd]); + inp = (*notify)(inp, errno); } } } else { @@ -3129,20 +3152,19 @@ out: } static void -tcp6_ctlinput(int cmd, struct sockaddr_in6 *sin6, struct ip6ctlparam *ctl) +tcp6_ctlinput(struct ip6ctlparam *ctl) { - tcp6_ctlinput_with_port(cmd, sin6, ctl, htons(0)); + tcp6_ctlinput_with_port(ctl, htons(0)); } static void -tcp6_ctlinput_viaudp(int cmd, struct sockaddr *sa, void *d, void *unused) +tcp6_ctlinput_viaudp(udp_tun_icmp_param_t param) { - struct ip6ctlparam *ip6cp; + struct ip6ctlparam *ip6cp = param.ip6cp; struct mbuf *m; struct udphdr *udp; uint16_t port; - ip6cp = (struct ip6ctlparam *)d; m = m_pulldown(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(struct udphdr), NULL); if (m == NULL) { return; @@ -3157,7 +3179,7 @@ tcp6_ctlinput_viaudp(int cmd, struct sockaddr *sa, void *d, void *unused) ip6cp->ip6c_m->m_pkthdr.len -= sizeof(struct udphdr); } /* Now call in to the normal handling code */ - tcp6_ctlinput_with_port(cmd, (struct sockaddr_in6 *)sa, ip6cp, port); + tcp6_ctlinput_with_port(ip6cp, port); } #endif /* INET6 */ diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 70474fa18f92..8e8547a42922 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -740,54 +740,52 @@ udp_notify(struct inpcb *inp, int errno) #ifdef INET static void -udp_common_ctlinput(int cmd, struct sockaddr_in *sin, struct ip *ip, - struct inpcbinfo *pcbinfo) +udp_common_ctlinput(struct icmp *icmp, struct inpcbinfo *pcbinfo) { + struct ip *ip = &icmp->icmp_ip; struct udphdr *uh; struct inpcb *inp; - if (inetctlerrmap[cmd] == 0) + if (icmp_errmap(icmp) == 0) return; uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); - inp = in_pcblookup(pcbinfo, sin->sin_addr, uh->uh_dport, ip->ip_src, + inp = in_pcblookup(pcbinfo, ip->ip_dst, uh->uh_dport, ip->ip_src, uh->uh_sport, INPLOOKUP_WLOCKPCB, NULL); if (inp != NULL) { INP_WLOCK_ASSERT(inp); if (inp->inp_socket != NULL) - udp_notify(inp, inetctlerrmap[cmd]); + udp_notify(inp, icmp_errmap(icmp)); INP_WUNLOCK(inp); } else { - inp = in_pcblookup(pcbinfo, sin->sin_addr, uh->uh_dport, + inp = in_pcblookup(pcbinfo, ip->ip_dst, uh->uh_dport, ip->ip_src, uh->uh_sport, INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, NULL); if (inp != NULL) { struct udpcb *up; - void *ctx; udp_tun_icmp_t *func; up = intoudpcb(inp); - ctx = up->u_tun_ctx; func = up->u_icmp_func; INP_RUNLOCK(inp); if (func != NULL) - (*func)(cmd, (struct sockaddr *)sin, ip, ctx); + func(icmp); } } } static void -udp_ctlinput(int cmd, struct sockaddr_in *sin, struct ip *ip) +udp_ctlinput(struct icmp *icmp) { - return (udp_common_ctlinput(cmd, sin, ip, &V_udbinfo)); + return (udp_common_ctlinput(icmp, &V_udbinfo)); } static void -udplite_ctlinput(int cmd, struct sockaddr_in *sin, struct ip *ip) +udplite_ctlinput(struct icmp *icmp) { - return (udp_common_ctlinput(cmd, sin, ip, &V_ulitecbinfo)); + return (udp_common_ctlinput(icmp, &V_ulitecbinfo)); } #endif /* INET */ diff --git a/sys/netinet/udp_var.h b/sys/netinet/udp_var.h index 2f3db518b26a..84ed16aa32f7 100644 --- a/sys/netinet/udp_var.h +++ b/sys/netinet/udp_var.h @@ -64,7 +64,11 @@ struct mbuf; #ifdef _KERNEL typedef bool udp_tun_func_t(struct mbuf *, int, struct inpcb *, const struct sockaddr *, void *); -typedef void udp_tun_icmp_t(int, struct sockaddr *, void *, void *); +typedef union { + struct icmp *icmp; + struct ip6ctlparam *ip6cp; +} udp_tun_icmp_param_t __attribute__((__transparent_union__)); +typedef void udp_tun_icmp_t(udp_tun_icmp_param_t); /* * UDP control block; one per udp. diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 5f49b2215cde..4497041f0330 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -147,7 +147,7 @@ static int ni6_addrs(struct icmp6_nodeinfo *, struct mbuf *, struct ifnet **, struct in6_addr *); static int ni6_store_addrs(struct icmp6_nodeinfo *, struct icmp6_nodeinfo *, struct ifnet *, int); -static int icmp6_notify_error(struct mbuf **, int, int, int); +static int icmp6_notify_error(struct mbuf **, int, int); /* * Kernel module interface for updating icmp6stat. The argument is an index @@ -390,6 +390,50 @@ icmp6_error(struct mbuf *m, int type, int code, int param) m_freem(m); } +int +icmp6_errmap(const struct icmp6_hdr *icmp6) +{ + + switch (icmp6->icmp6_type) { + case ICMP6_DST_UNREACH: + switch (icmp6->icmp6_code) { + case ICMP6_DST_UNREACH_NOROUTE: + case ICMP6_DST_UNREACH_ADDR: + return (EHOSTUNREACH); + case ICMP6_DST_UNREACH_NOPORT: + case ICMP6_DST_UNREACH_ADMIN: + return (ECONNREFUSED); + case ICMP6_DST_UNREACH_BEYONDSCOPE: + return (ENOPROTOOPT); + default: + return (0); /* Shouldn't happen. */ + } + case ICMP6_PACKET_TOO_BIG: + return (EMSGSIZE); + case ICMP6_TIME_EXCEEDED: + switch (icmp6->icmp6_code) { + case ICMP6_TIME_EXCEED_TRANSIT: + return (EHOSTUNREACH); + case ICMP6_TIME_EXCEED_REASSEMBLY: + return (0); + default: + return (0); /* Shouldn't happen. */ + } + case ICMP6_PARAM_PROB: + switch (icmp6->icmp6_code) { + case ICMP6_PARAMPROB_NEXTHEADER: + return (ECONNREFUSED); + case ICMP6_PARAMPROB_HEADER: + case ICMP6_PARAMPROB_OPTION: + return (ENOPROTOOPT); + default: + return (0); /* Shouldn't happen. */ + } + default: + return (0); + } +} + /* * Process a received ICMP6 message. */ @@ -467,72 +511,43 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) case ICMP6_DST_UNREACH: icmp6_ifstat_inc(ifp, ifs6_in_dstunreach); switch (code) { - case ICMP6_DST_UNREACH_NOROUTE: - case ICMP6_DST_UNREACH_ADDR: /* PRC_HOSTDEAD is a DOS */ - code = PRC_UNREACH_NET; - break; case ICMP6_DST_UNREACH_ADMIN: icmp6_ifstat_inc(ifp, ifs6_in_adminprohib); - code = PRC_UNREACH_ADMIN_PROHIB; - break; + case ICMP6_DST_UNREACH_NOROUTE: + case ICMP6_DST_UNREACH_ADDR: case ICMP6_DST_UNREACH_BEYONDSCOPE: - /* I mean "source address was incorrect." */ - code = PRC_PARAMPROB; - break; case ICMP6_DST_UNREACH_NOPORT: - code = PRC_UNREACH_PORT; - break; + goto deliver; default: goto badcode; } - goto deliver; - break; - case ICMP6_PACKET_TOO_BIG: icmp6_ifstat_inc(ifp, ifs6_in_pkttoobig); - - /* validation is made in icmp6_mtudisc_update */ - - code = PRC_MSGSIZE; - /* + * Validation is made in icmp6_mtudisc_update. * Updating the path MTU will be done after examining * intermediate extension headers. */ goto deliver; - break; - case ICMP6_TIME_EXCEEDED: icmp6_ifstat_inc(ifp, ifs6_in_timeexceed); switch (code) { case ICMP6_TIME_EXCEED_TRANSIT: - code = PRC_TIMXCEED_INTRANS; - break; case ICMP6_TIME_EXCEED_REASSEMBLY: - code = PRC_TIMXCEED_REASS; - break; + goto deliver; default: goto badcode; } - goto deliver; - break; - case ICMP6_PARAM_PROB: icmp6_ifstat_inc(ifp, ifs6_in_paramprob); switch (code) { case ICMP6_PARAMPROB_NEXTHEADER: - code = PRC_UNREACH_PROTOCOL; - break; case ICMP6_PARAMPROB_HEADER: case ICMP6_PARAMPROB_OPTION: - code = PRC_PARAMPROB; - break; + goto deliver; default: goto badcode; } - goto deliver; - break; - case ICMP6_ECHO_REQUEST: icmp6_ifstat_inc(ifp, ifs6_in_echo); if (code != 0) @@ -856,14 +871,13 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) ifp ? ifp->if_index : 0)); if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) { /* ICMPv6 error: MUST deliver it by spec... */ - code = PRC_NCMDS; - /* deliver */ + goto deliver; } else { /* ICMPv6 informational: MUST not deliver */ break; } deliver: - if (icmp6_notify_error(&m, off, icmp6len, code) != 0) { + if (icmp6_notify_error(&m, off, icmp6len) != 0) { /* In this case, m should've been freed. */ *mp = NULL; return (IPPROTO_DONE); @@ -892,7 +906,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) } static int -icmp6_notify_error(struct mbuf **mp, int off, int icmp6len, int code) +icmp6_notify_error(struct mbuf **mp, int off, int icmp6len) { struct mbuf *m; struct icmp6_hdr *icmp6; @@ -1075,7 +1089,7 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp6len, int code) ip6cp.ip6c_icmp6 = icmp6; ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1); ip6cp.ip6c_off = eoff; - ip6cp.ip6c_finaldst = &icmp6dst.sin6_addr; + ip6cp.ip6c_finaldst = &icmp6dst; ip6cp.ip6c_src = &icmp6src; ip6cp.ip6c_nxt = nxt; @@ -1086,7 +1100,7 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp6len, int code) } if (ip6_ctlprotox[nxt] != NULL) - ip6_ctlprotox[nxt](code, &icmp6dst, &ip6cp); + ip6_ctlprotox[nxt](&ip6cp); } *mp = m; return (0); @@ -1100,7 +1114,7 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp6len, int code) void icmp6_mtudisc_update(struct ip6ctlparam *ip6cp, int validated) { - struct in6_addr *dst = ip6cp->ip6c_finaldst; + struct in6_addr *dst = &ip6cp->ip6c_finaldst->sin6_addr; struct icmp6_hdr *icmp6 = ip6cp->ip6c_icmp6; struct mbuf *m = ip6cp->ip6c_m; /* will be necessary for scope issue */ u_int mtu = ntohl(icmp6->icmp6_mtu); diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 9a055dcb0563..40aaff592a6c 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -680,10 +680,11 @@ inp_match6(const struct inpcb *inp, void *v __unused) return ((inp->inp_vflag & INP_IPV6) != 0); *** 442 LINES SKIPPED ***