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
This commit is contained in:
parent
809fef2913
commit
fcb3f813f3
@ -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);
|
||||
|
@ -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
|
||||
/*
|
||||
|
@ -403,6 +403,55 @@ stdreply: icmpelen = max(8, min(V_icmp_quotelen, ntohs(oip->ip_len) -
|
||||
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:
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 { \
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -7190,11 +7190,11 @@ sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp,
|
||||
|
||||
#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.
|
||||
*/
|
||||
|
@ -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 @@ tcp_ctlinput_with_port(int cmd, struct sockaddr_in *sin, struct ip *ip,
|
||||
}
|
||||
|
||||
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 @@ tcp6_ctlinput_with_port(int cmd, struct sockaddr_in6 *sin6,
|
||||
}
|
||||
|
||||
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 */
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -680,10 +680,11 @@ inp_match6(const struct inpcb *inp, void *v __unused)
|
||||
|
||||
return ((inp->inp_vflag & INP_IPV6) != 0);
|
||||
}
|
||||
|
||||
void
|
||||
in6_pcbnotify(struct inpcbinfo *pcbinfo, struct sockaddr_in6 *sa6_dst,
|
||||
u_int fport_arg, const struct sockaddr_in6 *src, u_int lport_arg,
|
||||
int cmd, void *cmdarg,
|
||||
int errno, void *cmdarg,
|
||||
struct inpcb *(*notify)(struct inpcb *, int))
|
||||
{
|
||||
struct inpcb_iterator inpi = INP_ITERATOR(pcbinfo, INPLOOKUP_WLOCKPCB,
|
||||
@ -692,10 +693,6 @@ in6_pcbnotify(struct inpcbinfo *pcbinfo, struct sockaddr_in6 *sa6_dst,
|
||||
struct sockaddr_in6 sa6_src;
|
||||
u_short fport = fport_arg, lport = lport_arg;
|
||||
u_int32_t flowinfo;
|
||||
int errno;
|
||||
|
||||
if ((unsigned)cmd >= PRC_NCMDS)
|
||||
return;
|
||||
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&sa6_dst->sin6_addr))
|
||||
return;
|
||||
@ -706,23 +703,6 @@ in6_pcbnotify(struct inpcbinfo *pcbinfo, struct sockaddr_in6 *sa6_dst,
|
||||
sa6_src = (src == NULL) ? sa6_any : *src;
|
||||
flowinfo = sa6_src.sin6_flowinfo;
|
||||
|
||||
/*
|
||||
* Redirects go to all references to the destination,
|
||||
* and use in6_rtchange to invalidate the route cache.
|
||||
* Dead host indications: also use in6_rtchange to invalidate
|
||||
* the cache, and deliver the error to all the sockets.
|
||||
* Otherwise, if we have knowledge of the local port and address,
|
||||
* deliver only to that socket.
|
||||
*/
|
||||
if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
|
||||
fport = 0;
|
||||
lport = 0;
|
||||
bzero((caddr_t)&sa6_src.sin6_addr, sizeof(sa6_src.sin6_addr));
|
||||
|
||||
if (cmd != PRC_HOSTDEAD)
|
||||
notify = in6_rtchange;
|
||||
}
|
||||
errno = inet6ctlerrmap[cmd];
|
||||
while ((inp = inp_next(&inpi)) != NULL) {
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
/*
|
||||
@ -731,7 +711,7 @@ in6_pcbnotify(struct inpcbinfo *pcbinfo, struct sockaddr_in6 *sa6_dst,
|
||||
* know the value, notify.
|
||||
* XXX: should we avoid to notify the value to TCP sockets?
|
||||
*/
|
||||
if (cmd == PRC_MSGSIZE && cmdarg != NULL)
|
||||
if (errno == EMSGSIZE && cmdarg != NULL)
|
||||
ip6_notify_pmtu(inp, sa6_dst, *(uint32_t *)cmdarg);
|
||||
|
||||
/*
|
||||
|
@ -553,7 +553,6 @@ do { \
|
||||
offsetof(struct in6_ifstat, tag) / sizeof(uint64_t)], 1);\
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
extern u_char inet6ctlerrmap[];
|
||||
VNET_DECLARE(unsigned long, in6_maxmtu);
|
||||
#define V_in6_maxmtu VNET(in6_maxmtu)
|
||||
#endif /* _KERNEL */
|
||||
|
@ -1707,23 +1707,3 @@ ip6_lasthdr(const struct mbuf *m, int off, int proto, int *nxtp)
|
||||
proto = *nxtp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* System control for IP6
|
||||
* (x) - issued by icmp6_input()
|
||||
*/
|
||||
u_char inet6ctlerrmap[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) */
|
||||
};
|
||||
|
@ -421,9 +421,9 @@ void in6_delayed_cksum(struct mbuf *m, uint32_t plen, u_short offset);
|
||||
* | ip6c_icmp6
|
||||
* ip6c_m
|
||||
*
|
||||
* ip6c_finaldst usually points to ip6c_ip6->ip6_dst. if the original
|
||||
* (internal) packet carries a routing header, it may point the final
|
||||
* destination address in the routing header.
|
||||
* ip6c_finaldst's sin6_addr usually points to ip6c_ip6->ip6_dst. If the
|
||||
* original * (internal) packet carries a routing header, it may point the
|
||||
* final * destination address in the routing header.
|
||||
*
|
||||
* ip6c_src: ip6c_ip6->ip6_src + scope info + flowlabel in ip6c_ip6
|
||||
* (beware of flowlabel, if you try to compare it against others)
|
||||
@ -436,14 +436,13 @@ struct ip6ctlparam {
|
||||
int ip6c_off; /* offset of the target proto header */
|
||||
struct sockaddr_in6 *ip6c_src; /* srcaddr w/ additional info */
|
||||
struct sockaddr_in6 *ip6c_dst; /* (final) dstaddr w/ additional info */
|
||||
struct in6_addr *ip6c_finaldst; /* final destination address */
|
||||
struct sockaddr_in6 *ip6c_finaldst; /* final destination address */
|
||||
void *ip6c_cmdarg; /* control command dependent data */
|
||||
u_int8_t ip6c_nxt; /* final next header field */
|
||||
};
|
||||
|
||||
typedef int ip6proto_input_t(struct mbuf **, int *, int);
|
||||
typedef void ip6proto_ctlinput_t(int, struct sockaddr_in6 *,
|
||||
struct ip6ctlparam *);
|
||||
typedef void ip6proto_ctlinput_t(struct ip6ctlparam *);
|
||||
int ip6proto_register(uint8_t, ip6proto_input_t, ip6proto_ctlinput_t);
|
||||
int ip6proto_unregister(uint8_t);
|
||||
#define IP6PROTO_REGISTER(prot, input, ctl) do { \
|
||||
|
@ -323,33 +323,14 @@ rip6_input(struct mbuf **mp, int *offp, int proto)
|
||||
}
|
||||
|
||||
void
|
||||
rip6_ctlinput(int cmd, struct sockaddr_in6 *sin6, struct ip6ctlparam *ip6cp)
|
||||
rip6_ctlinput(struct ip6ctlparam *ip6cp)
|
||||
{
|
||||
const struct sockaddr_in6 *sa6_src;
|
||||
void *cmdarg;
|
||||
struct inpcb *(*notify)(struct inpcb *, int) = in6_rtchange;
|
||||
int errno;
|
||||
|
||||
if ((unsigned)cmd >= PRC_NCMDS)
|
||||
return;
|
||||
if (PRC_IS_REDIRECT(cmd))
|
||||
notify = in6_rtchange, ip6cp = NULL;
|
||||
else if (cmd == PRC_HOSTDEAD)
|
||||
ip6cp = NULL;
|
||||
else if (inet6ctlerrmap[cmd] == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If the parameter is from icmp6, decode it.
|
||||
*/
|
||||
if (ip6cp != NULL) {
|
||||
cmdarg = ip6cp->ip6c_cmdarg;
|
||||
sa6_src = ip6cp->ip6c_src;
|
||||
} else {
|
||||
cmdarg = NULL;
|
||||
sa6_src = &sa6_any;
|
||||
}
|
||||
|
||||
in6_pcbnotify(&V_ripcbinfo, sin6, 0, sa6_src, 0, cmd, cmdarg, notify);
|
||||
if ((errno = icmp6_errmap(ip6cp->ip6c_icmp6)) != 0)
|
||||
in6_pcbnotify(&V_ripcbinfo, ip6cp->ip6c_finaldst, 0,
|
||||
ip6cp->ip6c_src, 0, errno, ip6cp->ip6c_cmdarg,
|
||||
in6_rtchange);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -248,7 +248,7 @@ sctp6_notify(struct sctp_inpcb *inp,
|
||||
}
|
||||
|
||||
void
|
||||
sctp6_ctlinput(int cmd, struct sockaddr_in6 *pktdst, struct ip6ctlparam *ip6cp)
|
||||
sctp6_ctlinput(struct ip6ctlparam *ip6cp)
|
||||
{
|
||||
struct sctp_inpcb *inp;
|
||||
struct sctp_tcb *stcb;
|
||||
@ -256,13 +256,9 @@ sctp6_ctlinput(int cmd, struct sockaddr_in6 *pktdst, struct ip6ctlparam *ip6cp)
|
||||
struct sctphdr sh;
|
||||
struct sockaddr_in6 src, dst;
|
||||
|
||||
if (inet6ctlerrmap[cmd] == 0)
|
||||
if (icmp6_errmap(ip6cp->ip6c_icmp6) == 0)
|
||||
return;
|
||||
|
||||
if (ip6cp->ip6c_m == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we can safely examine the ports and the
|
||||
* verification tag of the SCTP common header.
|
||||
|
@ -547,28 +547,24 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
}
|
||||
|
||||
static void
|
||||
udp6_common_ctlinput(int cmd, struct sockaddr_in6 *sin6,
|
||||
struct ip6ctlparam *ip6cp, struct inpcbinfo *pcbinfo)
|
||||
udp6_common_ctlinput(struct ip6ctlparam *ip6cp, struct inpcbinfo *pcbinfo)
|
||||
{
|
||||
struct udphdr uh;
|
||||
struct ip6_hdr *ip6;
|
||||
struct mbuf *m;
|
||||
struct inpcb *inp;
|
||||
int off = 0;
|
||||
void *cmdarg;
|
||||
struct inpcb *(*notify)(struct inpcb *, int) = udp_notify;
|
||||
int errno, off = 0;
|
||||
struct udp_portonly {
|
||||
u_int16_t uh_sport;
|
||||
u_int16_t uh_dport;
|
||||
} *uhp;
|
||||
|
||||
if (inet6ctlerrmap[cmd] == 0)
|
||||
if ((errno = icmp6_errmap(ip6cp->ip6c_icmp6)) == 0)
|
||||
return;
|
||||
|
||||
m = ip6cp->ip6c_m;
|
||||
ip6 = ip6cp->ip6c_ip6;
|
||||
off = ip6cp->ip6c_off;
|
||||
cmdarg = ip6cp->ip6c_cmdarg;
|
||||
|
||||
/* Check if we can safely examine src and dst ports. */
|
||||
if (m->m_pkthdr.len < off + sizeof(*uhp))
|
||||
@ -589,25 +585,25 @@ udp6_common_ctlinput(int cmd, struct sockaddr_in6 *sin6,
|
||||
func = up->u_icmp_func;
|
||||
INP_RUNLOCK(inp);
|
||||
if (func != NULL)
|
||||
func(cmd, (struct sockaddr *)ip6cp->ip6c_src, ip6cp,
|
||||
up->u_tun_ctx);
|
||||
func(ip6cp);
|
||||
}
|
||||
in6_pcbnotify(pcbinfo, sin6, uh.uh_dport, ip6cp->ip6c_src,
|
||||
uh.uh_sport, cmd, cmdarg, notify);
|
||||
in6_pcbnotify(pcbinfo, ip6cp->ip6c_finaldst, uh.uh_dport,
|
||||
ip6cp->ip6c_src, uh.uh_sport, errno, ip6cp->ip6c_cmdarg,
|
||||
udp_notify);
|
||||
}
|
||||
|
||||
static void
|
||||
udp6_ctlinput(int cmd, struct sockaddr_in6 *sin6, struct ip6ctlparam *ctl)
|
||||
udp6_ctlinput(struct ip6ctlparam *ctl)
|
||||
{
|
||||
|
||||
return (udp6_common_ctlinput(cmd, sin6, ctl, &V_udbinfo));
|
||||
return (udp6_common_ctlinput(ctl, &V_udbinfo));
|
||||
}
|
||||
|
||||
static void
|
||||
udplite6_ctlinput(int cmd, struct sockaddr_in6 *sin6, struct ip6ctlparam *ctl)
|
||||
udplite6_ctlinput(struct ip6ctlparam *ctl)
|
||||
{
|
||||
|
||||
return (udp6_common_ctlinput(cmd, sin6, ctl, &V_ulitecbinfo));
|
||||
return (udp6_common_ctlinput(ctl, &V_ulitecbinfo));
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -279,23 +279,21 @@ ipsec4_input(struct mbuf *m, int offset, int proto)
|
||||
}
|
||||
|
||||
int
|
||||
ipsec4_ctlinput(int code, struct sockaddr *sa, void *v)
|
||||
ipsec4_ctlinput(ipsec_ctlinput_param_t param)
|
||||
{
|
||||
struct icmp *icp = param.icmp;
|
||||
struct ip *ip = &icp->icmp_ip;
|
||||
struct sockaddr_in icmpsrc = {
|
||||
.sin_len = sizeof(struct sockaddr_in),
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr = ip->ip_dst,
|
||||
};
|
||||
struct in_conninfo inc;
|
||||
struct secasvar *sav;
|
||||
struct icmp *icp;
|
||||
struct ip *ip = v;
|
||||
uint32_t pmtu, spi;
|
||||
uint32_t max_pmtu;
|
||||
uint8_t proto;
|
||||
|
||||
if (code != PRC_MSGSIZE || ip == NULL)
|
||||
return (EINVAL);
|
||||
if (sa->sa_family != AF_INET ||
|
||||
sa->sa_len != sizeof(struct sockaddr_in))
|
||||
return (EAFNOSUPPORT);
|
||||
|
||||
icp = __containerof(ip, struct icmp, icmp_ip);
|
||||
pmtu = ntohs(icp->icmp_nextmtu);
|
||||
|
||||
if (pmtu < V_ip4_ipsec_min_pmtu)
|
||||
@ -307,14 +305,14 @@ ipsec4_ctlinput(int code, struct sockaddr *sa, void *v)
|
||||
return (EINVAL);
|
||||
|
||||
memcpy(&spi, (caddr_t)ip + (ip->ip_hl << 2), sizeof(spi));
|
||||
sav = key_allocsa((union sockaddr_union *)sa, proto, spi);
|
||||
sav = key_allocsa((union sockaddr_union *)&icmpsrc, proto, spi);
|
||||
if (sav == NULL)
|
||||
return (ENOENT);
|
||||
|
||||
key_freesav(&sav);
|
||||
|
||||
memset(&inc, 0, sizeof(inc));
|
||||
inc.inc_faddr = satosin(sa)->sin_addr;
|
||||
inc.inc_faddr = ip->ip_dst;
|
||||
|
||||
/* Update pmtu only if its smaller than the current one. */
|
||||
max_pmtu = tcp_hc_getmtu(&inc);
|
||||
@ -568,7 +566,7 @@ ipsec6_input(struct mbuf *m, int offset, int proto)
|
||||
}
|
||||
|
||||
int
|
||||
ipsec6_ctlinput(int code, struct sockaddr *sa, void *v)
|
||||
ipsec6_ctlinput(ipsec_ctlinput_param_t param)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
@ -38,6 +38,13 @@ struct sockopt;
|
||||
struct sockaddr;
|
||||
struct ipsec_support;
|
||||
struct tcpmd5_support;
|
||||
struct icmp;
|
||||
struct ip6ctlparam;
|
||||
|
||||
typedef union {
|
||||
struct icmp *icmp;
|
||||
struct ip6ctlparam *ip6cp;
|
||||
} ipsec_ctlinput_param_t __attribute__((__transparent_union__));
|
||||
|
||||
size_t ipsec_hdrsiz_inpcb(struct inpcb *);
|
||||
int ipsec_init_pcbpolicy(struct inpcb *);
|
||||
@ -53,7 +60,7 @@ int ipsec4_forward(struct mbuf *);
|
||||
int ipsec4_pcbctl(struct inpcb *, struct sockopt *);
|
||||
int ipsec4_output(struct mbuf *, struct inpcb *);
|
||||
int ipsec4_capability(struct mbuf *, u_int);
|
||||
int ipsec4_ctlinput(int, struct sockaddr *, void *);
|
||||
int ipsec4_ctlinput(ipsec_ctlinput_param_t);
|
||||
#endif /* INET */
|
||||
|
||||
#ifdef INET6
|
||||
@ -63,7 +70,7 @@ int ipsec6_forward(struct mbuf *);
|
||||
int ipsec6_pcbctl(struct inpcb *, struct sockopt *);
|
||||
int ipsec6_output(struct mbuf *, struct inpcb *);
|
||||
int ipsec6_capability(struct mbuf *, u_int);
|
||||
int ipsec6_ctlinput(int, struct sockaddr *, void *);
|
||||
int ipsec6_ctlinput(ipsec_ctlinput_param_t);
|
||||
#endif /* INET6 */
|
||||
|
||||
struct ipsec_methods {
|
||||
@ -74,7 +81,7 @@ struct ipsec_methods {
|
||||
int (*pcbctl)(struct inpcb *, struct sockopt *);
|
||||
size_t (*hdrsize)(struct inpcb *);
|
||||
int (*capability)(struct mbuf *, u_int);
|
||||
int (*ctlinput)(int, struct sockaddr *, void *);
|
||||
int (*ctlinput)(ipsec_ctlinput_param_t);
|
||||
|
||||
int (*udp_input)(struct mbuf *, int, int);
|
||||
int (*udp_pcbctl)(struct inpcb *, struct sockopt *);
|
||||
@ -156,8 +163,8 @@ extern const struct ipsec_support * const ipv6_ipsec_support;
|
||||
(*(proto ## _ipsec_support)->methods->capability)(m, __VA_ARGS__)
|
||||
#define IPSEC_HDRSIZE(proto, inp) \
|
||||
(*(proto ## _ipsec_support)->methods->hdrsize)(inp)
|
||||
#define IPSEC_CTLINPUT(proto, code, sa, v) \
|
||||
(*(proto ## _ipsec_support)->methods->ctlinput)(code, sa, v)
|
||||
#define IPSEC_CTLINPUT(proto, param) \
|
||||
(*(proto ## _ipsec_support)->methods->ctlinput)(param)
|
||||
|
||||
#define UDPENCAP_INPUT(m, ...) \
|
||||
(*ipv4_ipsec_support->methods->udp_input)(m, __VA_ARGS__)
|
||||
|
@ -169,49 +169,6 @@ struct protosw {
|
||||
#define PR_CAPATTACH 0x80 /* socket can attach in cap mode */
|
||||
#define PR_SOCKBUF 0x100 /* private implementation of buffers */
|
||||
|
||||
/*
|
||||
* The arguments to the ctlinput routine are
|
||||
* (*protosw[].pr_ctlinput)(cmd, sa, arg);
|
||||
* where cmd is one of the commands below, sa is a pointer to a sockaddr,
|
||||
* and arg is a `void *' argument used within a protocol family.
|
||||
*/
|
||||
#define PRC_ROUTEDEAD 1 /* select new route if possible ??? */
|
||||
/* was PRC_QUENCH2 3 DEC congestion bit says slow down */
|
||||
/* was PRC_QUENCH 4 Deprecated by RFC 6633 */
|
||||
#define PRC_MSGSIZE 5 /* message size forced drop */
|
||||
#define PRC_HOSTDEAD 6 /* host appears to be down */
|
||||
#define PRC_HOSTUNREACH 7 /* deprecated (use PRC_UNREACH_HOST) */
|
||||
#define PRC_UNREACH_NET 8 /* no route to network */
|
||||
#define PRC_UNREACH_HOST 9 /* no route to host */
|
||||
#define PRC_UNREACH_PROTOCOL 10 /* dst says bad protocol */
|
||||
#define PRC_UNREACH_PORT 11 /* bad port # */
|
||||
/* was PRC_UNREACH_NEEDFRAG 12 (use PRC_MSGSIZE) */
|
||||
#define PRC_UNREACH_SRCFAIL 13 /* source route failed */
|
||||
#define PRC_REDIRECT_NET 14 /* net routing redirect */
|
||||
#define PRC_REDIRECT_HOST 15 /* host routing redirect */
|
||||
#define PRC_REDIRECT_TOSNET 16 /* redirect for type of service & net */
|
||||
#define PRC_REDIRECT_TOSHOST 17 /* redirect for tos & host */
|
||||
#define PRC_TIMXCEED_INTRANS 18 /* packet lifetime expired in transit */
|
||||
#define PRC_TIMXCEED_REASS 19 /* lifetime expired on reass q */
|
||||
#define PRC_PARAMPROB 20 /* header incorrect */
|
||||
#define PRC_UNREACH_ADMIN_PROHIB 21 /* packet administrativly prohibited */
|
||||
|
||||
#define PRC_NCMDS 22
|
||||
|
||||
#define PRC_IS_REDIRECT(cmd) \
|
||||
((cmd) >= PRC_REDIRECT_NET && (cmd) <= PRC_REDIRECT_TOSHOST)
|
||||
|
||||
#ifdef PRCREQUESTS
|
||||
char *prcrequests[] = {
|
||||
"IFDOWN", "ROUTEDEAD", "IFUP", "DEC-BIT-QUENCH2",
|
||||
"QUENCH", "MSGSIZE", "HOSTDEAD", "#7",
|
||||
"NET-UNREACH", "HOST-UNREACH", "PROTO-UNREACH", "PORT-UNREACH",
|
||||
"#12", "SRCFAIL-UNREACH", "NET-REDIRECT", "HOST-REDIRECT",
|
||||
"TOSNET-REDIRECT", "TOSHOST-REDIRECT", "TX-INTRANS", "TX-REASS",
|
||||
"PARAMPROB", "ADMIN-UNREACH"
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The arguments to ctloutput are:
|
||||
* (*protosw[].pr_ctloutput)(req, so, level, optname, optval, p);
|
||||
|
Loading…
Reference in New Issue
Block a user