diff options
-rw-r--r-- | sys/netinet/icmp6.h | 15 | ||||
-rw-r--r-- | sys/netinet/tcp_input.c | 4 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 107 | ||||
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 5 | ||||
-rw-r--r-- | sys/netinet/tcp_var.h | 6 | ||||
-rw-r--r-- | sys/netinet/udp_usrreq.c | 141 | ||||
-rw-r--r-- | sys/netinet6/icmp6.c | 111 | ||||
-rw-r--r-- | sys/netinet6/in6_proto.c | 86 | ||||
-rw-r--r-- | sys/netinet6/ip6protosw.h | 21 |
9 files changed, 321 insertions, 175 deletions
diff --git a/sys/netinet/icmp6.h b/sys/netinet/icmp6.h index 95e38d4801c..749cc8a7567 100644 --- a/sys/netinet/icmp6.h +++ b/sys/netinet/icmp6.h @@ -1,5 +1,5 @@ -/* $OpenBSD: icmp6.h,v 1.11 2000/10/10 15:53:07 itojun Exp $ */ -/* $KAME: icmp6.h,v 1.23 2000/10/10 15:35:45 itojun Exp $ */ +/* $OpenBSD: icmp6.h,v 1.12 2000/12/11 08:04:55 itojun Exp $ */ +/* $KAME: icmp6.h,v 1.24 2000/10/18 19:24:24 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -536,6 +536,7 @@ struct icmp6stat { #define icp6s_oparamprob_option icp6s_outerrhist.icp6errs_paramprob_option #define icp6s_oredirect icp6s_outerrhist.icp6errs_redirect #define icp6s_ounknown icp6s_outerrhist.icp6errs_unknown + u_quad_t icp6s_pmtuchg; /* path MTU changes */ }; /* @@ -556,7 +557,9 @@ struct icmp6stat { #define ICMPV6CTL_NODEINFO 13 #define ICMPV6CTL_ERRPPSLIMIT 14 /* ICMPv6 error pps limitation */ #define ICMPV6CTL_ND6_MAXNUDHINT 15 -#define ICMPV6CTL_MAXID 16 +#define ICMPV6CTL_MTUDISC_HIWAT 16 +#define ICMPV6CTL_MTUDISC_LOWAT 17 +#define ICMPV6CTL_MAXID 18 #define ICMPV6CTL_NAMES { \ { 0, 0 }, \ @@ -575,6 +578,8 @@ struct icmp6stat { { "nodeinfo", CTLTYPE_INT }, \ { "errppslimit", CTLTYPE_INT }, \ { "nd6_maxnudhint", CTLTYPE_INT }, \ + { "mtudisc_hiwat", CTLTYPE_INT }, \ + { "mtudisc_lowat", CTLTYPE_INT }, \ } #define RTF_PROBEMTU RTF_PROTO1 @@ -596,6 +601,10 @@ void icmp6_redirect_input __P((struct mbuf *, int)); void icmp6_redirect_output __P((struct mbuf *, struct rtentry *)); int icmp6_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); +struct ip6ctlparam; +void icmp6_mtudisc_update __P((struct ip6ctlparam *, int)); +void icmp6_mtudisc_callback_register __P((void (*)(struct in6_addr *))); + /* XXX: is this the right place for these macros? */ #define icmp6_ifstat_inc(ifp, tag) \ do { \ diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index f45766afc53..8fc588e947f 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_input.c,v 1.79 2000/10/14 01:04:10 itojun Exp $ */ +/* $OpenBSD: tcp_input.c,v 1.80 2000/12/11 08:04:55 itojun Exp $ */ /* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */ /* @@ -319,7 +319,7 @@ done: splx(s); } -#if defined(INET6) && !defined(TCP6) +#ifdef INET6 int tcp6_input(mp, offp, proto) struct mbuf **mp; diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 39043f8e7cc..e57ac20961c 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_subr.c,v 1.35 2000/10/13 17:58:36 itojun Exp $ */ +/* $OpenBSD: tcp_subr.c,v 1.36 2000/12/11 08:04:55 itojun Exp $ */ /* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */ /* @@ -152,6 +152,8 @@ tcp_init() if ((max_linkhdr + sizeof(struct ip6_hdr) + sizeof(struct tcphdr)) > MHLEN) panic("tcp_init"); + + icmp6_mtudisc_callback_register(tcp6_mtudisc_callback); #endif /* INET6 */ } @@ -715,30 +717,39 @@ tcp_notify(inp, error) sowwakeup(so); } -#if defined(INET6) && !defined(TCP6) +#ifdef INET6 void tcp6_ctlinput(cmd, sa, d) int cmd; struct sockaddr *sa; void *d; { - register struct tcphdr *thp; + struct tcphdr *thp; struct tcphdr th; void (*notify) __P((struct inpcb *, int)) = tcp_notify; + int nmatch; struct sockaddr_in6 sa6; - struct mbuf *m; struct ip6_hdr *ip6; + struct mbuf *m; int off; - + struct in6_addr finaldst; + struct in6_addr s; + if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) return; - if (cmd == PRC_QUENCH) + if ((unsigned)cmd >= PRC_NCMDS) + return; + else if (cmd == PRC_QUENCH) { + /* XXX there's no PRC_QUENCH in IPv6 */ notify = tcp_quench; + } else if (PRC_IS_REDIRECT(cmd)) + notify = in_rtchange, d = NULL; else if (cmd == PRC_MSGSIZE) - notify = tcp_mtudisc; - else if (!PRC_IS_REDIRECT(cmd) && - ((unsigned)cmd > PRC_NCMDS || inet6ctlerrmap[cmd] == 0)) + ; /* special code is present, see below */ + else if (cmd == PRC_HOSTDEAD) + d = NULL; + else if (inet6ctlerrmap[cmd] == 0) return; /* if the parameter is from icmp6, decode it. */ @@ -747,6 +758,16 @@ tcp6_ctlinput(cmd, sa, d) m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; + + /* translate addresses into internal form */ + bcopy(ip6cp->ip6c_finaldst, &finaldst, sizeof(finaldst)); + if (IN6_IS_ADDR_LINKLOCAL(&finaldst)) { + finaldst.s6_addr16[1] = + htons(m->m_pkthdr.rcvif->if_index); + } + bcopy(&ip6->ip6_src, &s, sizeof(s)); + if (IN6_IS_ADDR_LINKLOCAL(&s)) + s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); } else { m = NULL; ip6 = NULL; @@ -756,21 +777,12 @@ tcp6_ctlinput(cmd, sa, d) sa6 = *(struct sockaddr_in6 *)sa; if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif) sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); + if (ip6) { /* - * XXX: We assume that when IPV6 is non NULL, + * XXX: We assume that when ip6 is non NULL, * M and OFF are valid. */ - struct ip6_hdr ip6_tmp; - - /* translate addresses into internal form */ - ip6_tmp = *ip6; - if (IN6_IS_ADDR_LINKLOCAL(&ip6_tmp.ip6_src)) - ip6_tmp.ip6_src.s6_addr16[1] = - htons(m->m_pkthdr.rcvif->if_index); - if (IN6_IS_ADDR_LINKLOCAL(&ip6_tmp.ip6_dst)) - ip6_tmp.ip6_dst.s6_addr16[1] = - htons(m->m_pkthdr.rcvif->if_index); /* check if we can safely examine src and dst ports */ if (m->m_pkthdr.len < off + sizeof(th)) @@ -785,12 +797,36 @@ tcp6_ctlinput(cmd, sa, d) thp = &th; } else thp = (struct tcphdr *)(mtod(m, caddr_t) + off); - (void)in6_pcbnotify(&tcbtable, (struct sockaddr *)&sa6, - thp->th_dport, &ip6_tmp.ip6_src, - thp->th_sport, cmd, notify); + + if (cmd == PRC_MSGSIZE) { + int valid = 0; + + /* + * Check to see if we have a valid TCP connection + * corresponding to the address in the ICMPv6 message + * payload. + */ + if (in_pcblookup(&tcbtable, &finaldst, + thp->th_dport, &s, thp->th_sport, + INPLOOKUP_WILDCARD)) + valid++; + + /* + * Now that we've validated that we are actually + * communicating with the host indicated in the ICMPv6 + * message, recalculate the new MTU, and create the + * corresponding routing entry. + */ + icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); + + return; + } + + nmatch = in6_pcbnotify(&tcbtable, (struct sockaddr *)&sa6, + thp->th_dport, &s, thp->th_sport, cmd, notify); } else { - (void)in6_pcbnotify(&tcbtable, (struct sockaddr *)&sa6, 0, - &zeroin6_addr, 0, cmd, notify); + (void) in6_pcbnotify(&tcbtable, (struct sockaddr *)&sa6, 0, + &zeroin6_addr, 0, cmd, notify); } } #endif @@ -845,7 +881,7 @@ tcp_ctlinput(cmd, sa, v) if (ip) { th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); in_pcbnotify(&tcbtable, sa, th->th_dport, ip->ip_src, - th->th_sport, errno, notify); + th->th_sport, errno, notify); } else in_pcbnotifyall(&tcbtable, sa, errno, notify); @@ -925,6 +961,25 @@ tcp_mtudisc_increase(inp, errno) } } +#ifdef INET6 +/* + * Path MTU Discovery handlers. + */ +void +tcp6_mtudisc_callback(faddr) + struct in6_addr *faddr; +{ + struct sockaddr_in6 sin6; + + bzero(&sin6, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_addr = *faddr; + (void) in6_pcbnotify(&tcbtable, (struct sockaddr *)&sin6, 0, + &zeroin6_addr, 0, EMSGSIZE, tcp_mtudisc); +} +#endif /* INET6 */ + #ifdef TCP_SIGNATURE int tcp_signature_tdb_attach() diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index dbcc84d3f25..38a4fc02830 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_usrreq.c,v 1.48 2000/10/14 01:04:11 itojun Exp $ */ +/* $OpenBSD: tcp_usrreq.c,v 1.49 2000/12/11 08:04:56 itojun Exp $ */ /* $NetBSD: tcp_usrreq.c,v 1.20 1996/02/13 23:44:16 christos Exp $ */ /* @@ -95,7 +95,7 @@ extern struct baddynamicports baddynamicports; int tcp_ident __P((void *, size_t *, void *, size_t)); -#if defined(INET6) && !defined(TCP6) +#ifdef INET6 int tcp6_usrreq(so, req, m, nam, control, p) struct socket *so; @@ -103,6 +103,7 @@ tcp6_usrreq(so, req, m, nam, control, p) struct mbuf *m, *nam, *control; struct proc *p; { + return tcp_usrreq(so, req, m, nam, control); } #endif diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index c8416d8cc02..fa07feff32b 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_var.h,v 1.33 2000/10/14 01:04:11 itojun Exp $ */ +/* $OpenBSD: tcp_var.h,v 1.34 2000/12/11 08:04:56 itojun Exp $ */ /* $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $ */ /* @@ -349,6 +349,10 @@ int tcp_mss __P((struct tcpcb *, int)); void tcp_mss_update __P((struct tcpcb *)); void tcp_mtudisc __P((struct inpcb *, int)); void tcp_mtudisc_increase __P((struct inpcb *, int)); +#ifdef INET6 +void tcp6_mtudisc __P((struct inpcb *, int)); +void tcp6_mtudisc_callback __P((struct in6_addr *)); +#endif struct tcpcb * tcp_newtcpcb __P((struct inpcb *)); void tcp_notify __P((struct inpcb *, int)); diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index d3ecb7d686f..6d8bc00de36 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: udp_usrreq.c,v 1.51 2000/10/13 17:58:37 itojun Exp $ */ +/* $OpenBSD: udp_usrreq.c,v 1.52 2000/12/11 08:04:56 itojun Exp $ */ /* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */ /* @@ -122,7 +122,7 @@ udp_init() in_pcbinit(&udbtable, udbhashsize); } -#if defined(INET6) && !defined(TCP6) +#ifdef INET6 int udp6_input(mp, offp, proto) struct mbuf **mp; @@ -650,39 +650,127 @@ udp_notify(inp, errno) sowwakeup(inp->inp_socket); } -#if defined(INET6) && !defined(TCP6) +#ifdef INET6 void udp6_ctlinput(cmd, sa, d) int cmd; struct sockaddr *sa; void *d; { + struct udphdr *uhp; + struct udphdr uh; struct sockaddr_in6 sa6; struct ip6_hdr *ip6; struct mbuf *m; int off; + struct in6_addr s; + struct in6_addr finaldst; + void (*notify) __P((struct inpcb *, int)) = udp_notify; - if (sa == NULL) + if (!sa) return; - if (sa->sa_family != AF_INET6) + if (sa->sa_family != AF_INET6 || + sa->sa_len != sizeof(struct sockaddr_in6)) return; - /* decode parameter from icmp6. */ + if ((unsigned)cmd >= PRC_NCMDS) + return; + if (PRC_IS_REDIRECT(cmd)) + notify = in_rtchange, d = NULL; + else if (cmd == PRC_HOSTDEAD) + d = NULL; + else if (cmd == PRC_MSGSIZE) + ; /* special code is present, see below */ + else if (inet6ctlerrmap[cmd] == 0) + return; + + /* if the parameter is from icmp6, decode it. */ if (d != NULL) { struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; - ip6 = ip6cp->ip6c_ip6; m = ip6cp->ip6c_m; + ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; - } else - return; + + /* translate addresses into internal form */ + bcopy(ip6cp->ip6c_finaldst, &finaldst, sizeof(finaldst)); + if (IN6_IS_ADDR_LINKLOCAL(&finaldst)) { + finaldst.s6_addr16[1] = + htons(m->m_pkthdr.rcvif->if_index); + } + bcopy(&ip6->ip6_src, &s, sizeof(s)); + if (IN6_IS_ADDR_LINKLOCAL(&s)) + s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); + } else { + m = NULL; + ip6 = NULL; + } /* translate addresses into internal form */ sa6 = *(struct sockaddr_in6 *)sa; if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif) sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - sa = (struct sockaddr *)&sa6; - (void)udp_ctlinput(cmd, sa, (void *)ip6); + if (ip6) { + /* + * XXX: We assume that when IPV6 is non NULL, + * M and OFF are valid. + */ + + /* check if we can safely examine src and dst ports */ + if (m->m_pkthdr.len < off + sizeof(uh)) + return; + + if (m->m_len < off + sizeof(uh)) { + /* + * this should be rare case, + * so we compromise on this copy... + */ + m_copydata(m, off, sizeof(uh), (caddr_t)&uh); + uhp = &uh; + } else + uhp = (struct udphdr *)(mtod(m, caddr_t) + off); + + if (cmd == PRC_MSGSIZE) { + int valid = 0; + /* + * Check to see if we have a valid UDP socket + * corresponding to the address in the ICMPv6 message + * payload. + */ + if (in_pcblookup(&udbtable, &finaldst, uhp->uh_dport, + &s, uhp->uh_sport, INPLOOKUP_IPV6)) + valid++; +#if 0 + /* + * As the use of sendto(2) is fairly popular, + * we may want to allow non-connected pcb too. + * But it could be too weak against attacks... + * We should at least check if the local address (= s) + * is really ours. + */ + else if (in_pcblookup(&udbtable, &finaldst, + uhp->uh_dport, &s, uhp->uh_sport, + INPLOOKUP_WILDCARD | INPLOOKUP_IPV6)) + valid++; +#endif + + /* + * Now that we've validated that we are actually + * communicating with the host indicated in the ICMPv6 + * message, recalculate the new MTU, and create the + * corresponding routing entry. + */ + icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); + + return; + } + + (void) in6_pcbnotify(&udbtable, (struct sockaddr *)&sa6, + uhp->uh_dport, &s, uhp->uh_sport, cmd, notify); + } else { + (void) in6_pcbnotify(&udbtable, (struct sockaddr *)&sa6, 0, + &zeroin6_addr, 0, cmd, notify); + } } #endif @@ -698,6 +786,12 @@ udp_ctlinput(cmd, sa, v) void (*notify) __P((struct inpcb *, int)) = udp_notify; int errno; + if (!sa) + return NULL; + if (sa->sa_family != AF_INET || + sa->sa_len != sizeof(struct sockaddr_in)) + return NULL; + if ((unsigned)cmd >= PRC_NCMDS) return NULL; errno = inetctlerrmap[cmd]; @@ -707,28 +801,6 @@ udp_ctlinput(cmd, sa, v) ip = 0; else if (errno == 0) return NULL; - if (sa == NULL) - return NULL; -#ifdef INET6 - if (sa->sa_family == AF_INET6) { - if (ip) { - struct ip6_hdr *ip6 = (struct ip6_hdr *)ip; - - /* XXX we assume that the mbuf is sane enough */ - - uhp = (struct udphdr *)((caddr_t)ip6 + sizeof(*ip6)); -#if 0 /*XXX*/ - in6_pcbnotify(&udbtable, sa, uhp->uh_dport, - &(ip6->ip6_src), uhp->uh_sport, cmd, udp_notify); -#endif - } else { -#if 0 /*XXX*/ - in6_pcbnotify(&udbtable, sa, 0, - (struct in6_addr *)&in6addr_any, 0, cmd, udp_notify); -#endif - } - } else -#endif /* INET6 */ if (ip) { uhp = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); in_pcbnotify(&udbtable, sa, uhp->uh_dport, ip->ip_src, @@ -1014,7 +1086,7 @@ u_int udp_sendspace = 9216; /* really max datagram size */ u_int udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); /* 40 1K datagrams */ -#if defined(INET6) && !defined(TCP6) +#ifdef INET6 /*ARGSUSED*/ int udp6_usrreq(so, req, m, addr, control, p) @@ -1023,6 +1095,7 @@ udp6_usrreq(so, req, m, addr, control, p) struct mbuf *m, *addr, *control; struct proc *p; { + return udp_usrreq(so, req, m, addr, control); } #endif diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 52c8fb72b94..086f2b8da03 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -1,4 +1,4 @@ -/* $OpenBSD: icmp6.c,v 1.25 2000/11/11 00:45:39 itojun Exp $ */ +/* $OpenBSD: icmp6.c,v 1.26 2000/12/11 08:04:56 itojun Exp $ */ /* $KAME: icmp6.c,v 1.156 2000/10/19 19:21:07 itojun Exp $ */ /* @@ -112,12 +112,26 @@ extern int icmp6errppslim; static int icmp6errpps_count = 0; static struct timeval icmp6errppslim_last; extern int icmp6_nodeinfo; + +/* + * List of callbacks to notify when Path MTU changes are made. + */ +struct icmp6_mtudisc_callback { + LIST_ENTRY(icmp6_mtudisc_callback) mc_list; + void (*mc_func) __P((struct in6_addr *)); +}; + +LIST_HEAD(, icmp6_mtudisc_callback) icmp6_mtudisc_callbacks = + LIST_HEAD_INITIALIZER(&icmp6_mtudisc_callbacks); + static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL; extern int pmtu_expire; +/* XXX do these values make any sense? */ +int icmp6_mtudisc_hiwat = 1280; +int icmp6_mtudisc_lowat = 256; + static void icmp6_errcount __P((struct icmp6errstat *, int, int)); -static void icmp6_mtudisc_update __P((struct in6_addr *, struct icmp6_hdr *, - struct mbuf *)); static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int)); static const char *icmp6_redirect_diag __P((struct in6_addr *, struct in6_addr *, struct in6_addr *)); @@ -201,6 +215,29 @@ icmp6_errcount(stat, type, code) } /* + * Register a Path MTU Discovery callback. + */ +void +icmp6_mtudisc_callback_register(func) + void (*func) __P((struct in6_addr *)); +{ + struct icmp6_mtudisc_callback *mc; + + for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL; + mc = LIST_NEXT(mc, mc_list)) { + if (mc->mc_func == func) + return; + } + + mc = malloc(sizeof(*mc), M_PCB, M_NOWAIT); + if (mc == NULL) + panic("icmp6_mtudisc_callback_register"); + + mc->mc_func = func; + LIST_INSERT_HEAD(&icmp6_mtudisc_callbacks, mc, mc_list); +} + +/* * Generate an error packet of type error in response to bad IP6 packet. */ void @@ -410,7 +447,7 @@ icmp6_input(mp, offp, proto) #ifdef IPSEC /* drop it if it does not match the default policy */ if (ipsec6_in_reject(m, NULL)) { - ipsecstat.in_polvio++; + ipsec6stat.in_polvio++; goto freeit; } #endif @@ -822,7 +859,6 @@ icmp6_input(mp, offp, proto) sizeof(struct ip6_hdr); struct ip6ctlparam ip6cp; struct in6_addr *finaldst = NULL; - int icmp6type = icmp6->icmp6_type; struct ip6_frag *fh; struct ip6_rthdr *rth; struct ip6_rthdr0 *rth0; @@ -962,19 +998,19 @@ icmp6_input(mp, offp, proto) return IPPROTO_DONE; } #endif - if (icmp6type == ICMP6_PACKET_TOO_BIG) { - if (finaldst == NULL) - finaldst = &((struct ip6_hdr *)(icmp6 + 1))->ip6_dst; - icmp6_mtudisc_update(finaldst, icmp6, m); - } + if (finaldst == NULL) + finaldst = &((struct ip6_hdr *)(icmp6 + 1))->ip6_dst; + ip6cp.ip6c_m = m; + ip6cp.ip6c_icmp6 = icmp6; + ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1); + ip6cp.ip6c_off = eoff; + ip6cp.ip6c_finaldst = finaldst; ctlfunc = (void (*) __P((int, struct sockaddr *, void *))) (inet6sw[ip6_protox[nxt]].pr_ctlinput); if (ctlfunc) { - ip6cp.ip6c_m = m; - ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1); - ip6cp.ip6c_off = eoff; - (*ctlfunc)(code, (struct sockaddr *)&icmp6src, &ip6cp); + (void) (*ctlfunc)(code, (struct sockaddr *)&icmp6src, + &ip6cp); } } break; @@ -996,16 +1032,38 @@ icmp6_input(mp, offp, proto) return IPPROTO_DONE; } -static void -icmp6_mtudisc_update(dst, icmp6, m) - struct in6_addr *dst; - struct icmp6_hdr *icmp6;/* we can assume the validity of the pointer */ - struct mbuf *m; /* currently unused but added for scoped addrs */ +void +icmp6_mtudisc_update(ip6cp, validated) + struct ip6ctlparam *ip6cp; + int validated; { + unsigned long rtcount; + struct icmp6_mtudisc_callback *mc; + struct in6_addr *dst = ip6cp->ip6c_finaldst; + 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); struct rtentry *rt = NULL; struct sockaddr_in6 sin6; + /* + * allow non-validated cases if memory is plenty, to make traffic + * from non-connected pcb happy. + */ + rtcount = rt_timer_count(icmp6_mtudisc_timeout_q); + if (validated) { + if (rtcount > icmp6_mtudisc_hiwat) + return; + else if (rtcount > icmp6_mtudisc_lowat) { + /* + * XXX nuke a victim, install the new one. + */ + } + } else { + if (rtcount > icmp6_mtudisc_lowat) + return; + } + bzero(&sin6, sizeof(sin6)); sin6.sin6_family = PF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); @@ -1030,11 +1088,20 @@ icmp6_mtudisc_update(dst, icmp6, m) rt->rt_rmx.rmx_locks |= RTV_MTU; } else if (mtu < rt->rt_ifp->if_mtu && rt->rt_rmx.rmx_mtu > mtu) { + icmp6stat.icp6s_pmtuchg++; rt->rt_rmx.rmx_mtu = mtu; } } if (rt) RTFREE(rt); + + /* + * Notify protocols that the MTU for this destination + * has changed. + */ + for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL; + mc = LIST_NEXT(mc, mc_list)) + (*mc->mc_func)(&sin6.sin6_addr); } /* @@ -2573,6 +2640,12 @@ icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) case ICMPV6CTL_ND6_MAXNUDHINT: return sysctl_int(oldp, oldlenp, newp, newlen, &nd6_maxnudhint); + case ICMPV6CTL_MTUDISC_HIWAT: + return sysctl_int(oldp, oldlenp, newp, newlen, + &icmp6_mtudisc_hiwat); + case ICMPV6CTL_MTUDISC_LOWAT: + return sysctl_int(oldp, oldlenp, newp, newlen, + &icmp6_mtudisc_lowat); default: return ENOPROTOOPT; } diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index e373faa046c..d46491b9cf6 100644 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_proto.c,v 1.25 2000/10/10 15:53:09 itojun Exp $ */ +/* $OpenBSD: in6_proto.c,v 1.26 2000/12/11 08:04:56 itojun Exp $ */ /* $KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $ */ /* @@ -130,14 +130,6 @@ struct ip6protosw inet6sw[] = { 0, 0, 0, udp_sysctl, }, -#ifdef TCP6 -{ SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED | PR_WANTRCVD, - tcp6_input, 0, tcp6_ctlinput, tcp6_ctloutput, - tcp6_usrreq, - tcp6_init, tcp6_fasttimo, tcp6_slowtimo, tcp6_drain, - tcp6_sysctl, -}, -#else { SOCK_STREAM, &inet6domain, IPPROTO_TCP, PR_CONNREQUIRED | PR_WANTRCVD, tcp6_input, 0, tcp6_ctlinput, tcp_ctloutput, tcp6_usrreq, @@ -148,7 +140,6 @@ struct ip6protosw inet6sw[] = { #endif tcp_sysctl, }, -#endif /*TCP6*/ { SOCK_RAW, &inet6domain, IPPROTO_RAW, PR_ATOMIC | PR_ADDR, rip6_input, rip6_output, rip6_ctlinput, rip6_ctloutput, rip6_usrreq, @@ -304,81 +295,6 @@ struct timeval icmp6errratelim = { 0, 0 }; /* no ratelimit */ int icmp6errppslim = 100; /* 100pps */ int icmp6_nodeinfo = 1; /* enable/disable NI response */ -#ifdef TCP6 -/* TCP on IP6 parameters */ -int tcp6_sendspace = 1024 * 8; -int tcp6_recvspace = 1024 * 8; -int tcp6_mssdflt = TCP6_MSS; -int tcp6_rttdflt = TCP6TV_SRTTDFLT / PR_SLOWHZ; -int tcp6_do_rfc1323 = 1; -int tcp6_conntimeo = TCP6TV_KEEP_INIT; /* initial connection timeout */ -int tcp6_43maxseg = 0; -int tcp6_pmtu = 0; - -/* - * Parameters for keepalive option. - * Connections for which SO_KEEPALIVE is set will be probed - * after being idle for a time of tcp6_keepidle (in units of PR_SLOWHZ). - * Starting at that time, the connection is probed at intervals - * of tcp6_keepintvl (same units) until a response is received - * or until tcp6_keepcnt probes have been made, at which time - * the connection is dropped. Note that a tcp6_keepidle value - * under 2 hours is nonconformant with RFC-1122, Internet Host Requirements. - */ -int tcp6_keepidle = TCP6TV_KEEP_IDLE; /* time before probing idle */ -int tcp6_keepintvl = TCP6TV_KEEPINTVL; /* interval betwn idle probes */ -int tcp6_keepcnt = TCP6TV_KEEPCNT; /* max idle probes */ -int tcp6_maxpersistidle = TCP6TV_KEEP_IDLE; /* max idle time in persist */ - -#ifndef INET_SERVER -#define TCP6_LISTEN_HASH_SIZE 17 -#define TCP6_CONN_HASH_SIZE 97 -#define TCP6_SYN_HASH_SIZE 293 -#define TCP6_SYN_BUCKET_SIZE 35 -#else -#define TCP6_LISTEN_HASH_SIZE 97 -#define TCP6_CONN_HASH_SIZE 9973 -#define TCP6_SYN_HASH_SIZE 997 -#define TCP6_SYN_BUCKET_SIZE 35 -#endif -int tcp6_listen_hash_size = TCP6_LISTEN_HASH_SIZE; -int tcp6_conn_hash_size = TCP6_CONN_HASH_SIZE; -struct tcp6_hash_list tcp6_listen_hash[TCP6_LISTEN_HASH_SIZE], - tcp6_conn_hash[TCP6_CONN_HASH_SIZE]; - -int tcp6_syn_cache_size = TCP6_SYN_HASH_SIZE; -int tcp6_syn_cache_limit = TCP6_SYN_HASH_SIZE*TCP6_SYN_BUCKET_SIZE; -int tcp6_syn_bucket_limit = 3*TCP6_SYN_BUCKET_SIZE; -struct syn_cache_head6 tcp6_syn_cache[TCP6_SYN_HASH_SIZE]; -struct syn_cache_head6 *tcp6_syn_cache_first; -int tcp6_syn_cache_interval = 8; /* runs timer every 4 seconds */ -int tcp6_syn_cache_timeo = TCP6TV_KEEP_INIT; - -/* - * Parameters for computing a desirable data segment size - * given an upper bound (either interface MTU, or peer's MSS option)_. - * As applications tend to use a buffer size that is a multiple - * of kilobytes, try for something that divides evenly. However, - * do not round down too much. - * - * Round segment size down to a multiple of TCP6_ROUNDSIZE if this - * does not result in lowering by more than (size/TCP6_ROUNDFRAC). - * For example, round 536 to 512. Older versions of the system - * effectively used MCLBYTES (1K or 2K) as TCP6_ROUNDSIZE, with - * a value of 1 for TCP6_ROUNDFRAC (eliminating its effect). - * We round to a multiple of 256 for SLIP. - */ -#ifndef TCP6_ROUNDSIZE -#define TCP6_ROUNDSIZE 256 /* round to multiple of 256 */ -#endif -#ifndef TCP6_ROUNDFRAC -#define TCP6_ROUNDFRAC 10 /* round down at most N/10, or 10% */ -#endif - -int tcp6_roundsize = TCP6_ROUNDSIZE; -int tcp6_roundfrac = TCP6_ROUNDFRAC; -#endif /*TCP6*/ - /* UDP on IP6 parameters */ int udp6_sendspace = 9216; /* really max datagram size */ int udp6_recvspace = 40 * (1024 + sizeof(struct sockaddr_in6)); diff --git a/sys/netinet6/ip6protosw.h b/sys/netinet6/ip6protosw.h index 7797403e251..dcbae2d90ae 100644 --- a/sys/netinet6/ip6protosw.h +++ b/sys/netinet6/ip6protosw.h @@ -1,9 +1,10 @@ -/* $OpenBSD: ip6protosw.h,v 1.2 1999/12/10 10:04:28 angelos Exp $ */ +/* $OpenBSD: ip6protosw.h,v 1.3 2000/12/11 08:04:56 itojun Exp $ */ +/* $KAME: ip6protosw.h,v 1.14 2000/10/18 18:15:53 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -15,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -81,15 +82,29 @@ struct socket; struct domain; struct proc; struct ip6_hdr; +struct icmp6_hdr; +struct in6_addr; /* * argument type for the last arg of pr_ctlinput(). * should be consulted only with AF_INET6 family. + * + * IPv6 ICMP IPv6 [exthdrs] finalhdr paylaod + * ^ ^ ^ ^ + * | | ip6c_ip6 ip6c_off + * | 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 + * dstination address in the routing header. */ struct ip6ctlparam { struct mbuf *ip6c_m; /* start of mbuf chain */ + struct icmp6_hdr *ip6c_icmp6; /* icmp6 header of target packet */ struct ip6_hdr *ip6c_ip6; /* ip6 header of target packet */ int ip6c_off; /* offset of the target proto header */ + struct in6_addr *ip6c_finaldst; /* final destination address */ }; struct ip6protosw { |