diff options
Diffstat (limited to 'sys/netinet6')
-rw-r--r-- | sys/netinet6/in6_pcb.c | 19 | ||||
-rw-r--r-- | sys/netinet6/in6_pcb.h | 2 | ||||
-rw-r--r-- | sys/netinet6/ip6_input.c | 39 | ||||
-rw-r--r-- | sys/netinet6/raw_ip6.c | 5 | ||||
-rw-r--r-- | sys/netinet6/udp6_usrreq.c | 9 |
5 files changed, 68 insertions, 6 deletions
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index a19a1eb..1c7278c 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -610,12 +610,13 @@ in6_mapped_peeraddr(struct socket *so, struct sockaddr **nam) * Must be called at splnet. */ void -in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, notify) +in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, cmdarg, notify) struct inpcbhead *head; struct sockaddr *dst; const struct sockaddr *src; u_int fport_arg, lport_arg; int cmd; + void *cmdarg; struct inpcb *(*notify) __P((struct inpcb *, int)); { struct inpcb *inp, *ninp; @@ -662,6 +663,22 @@ in6_pcbnotify(head, dst, fport_arg, src, lport_arg, cmd, notify) continue; /* + * If the error designates a new path MTU for a destination + * and the application (associated with this socket) wanted to + * know the value, notify. Note that we notify for all + * disconnected sockets if the corresponding application + * wanted. This is because some UDP applications keep sending + * sockets disconnected. + * XXX: should we avoid to notify the value to TCP sockets? + */ + if (cmd == PRC_MSGSIZE && (inp->inp_flags & IN6P_MTU) != 0 && + (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) || + IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, &sa6_dst->sin6_addr))) { + ip6_notify_pmtu(inp, (struct sockaddr_in6 *)dst, + (u_int32_t *)cmdarg); + } + + /* * Detect if we should notify the error. If no source and * destination ports are specifed, but non-zero flowinfo and * local address match, notify the error. This is the case diff --git a/sys/netinet6/in6_pcb.h b/sys/netinet6/in6_pcb.h index cbe67c7..6cae30b 100644 --- a/sys/netinet6/in6_pcb.h +++ b/sys/netinet6/in6_pcb.h @@ -91,7 +91,7 @@ struct inpcb * struct in6_addr *, u_int, struct in6_addr *, u_int, int, struct ifnet *)); void in6_pcbnotify __P((struct inpcbhead *, struct sockaddr *, - u_int, const struct sockaddr *, u_int, int, + u_int, const struct sockaddr *, u_int, int, void *, struct inpcb *(*)(struct inpcb *, int))); struct inpcb * in6_rtchange __P((struct inpcb *, int)); diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 0715606..d42a444 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1307,6 +1307,45 @@ ip6_savecontrol(in6p, m, mp) #undef IS2292 } +void +ip6_notify_pmtu(in6p, dst, mtu) + struct inpcb *in6p; + struct sockaddr_in6 *dst; + u_int32_t *mtu; +{ + struct socket *so; + struct mbuf *m_mtu; + struct ip6_mtuinfo mtuctl; + + so = in6p->inp_socket; + + if (mtu == NULL) + return; + +#ifdef DIAGNOSTIC + if (so == NULL) /* I believe this is impossible */ + panic("ip6_notify_pmtu: socket is NULL"); +#endif + + bzero(&mtuctl, sizeof(mtuctl)); /* zero-clear for safety */ + mtuctl.ip6m_mtu = *mtu; + mtuctl.ip6m_addr = *dst; + in6_recoverscope(&mtuctl.ip6m_addr, &mtuctl.ip6m_addr.sin6_addr, NULL); + + if ((m_mtu = sbcreatecontrol((caddr_t)&mtuctl, sizeof(mtuctl), + IPV6_PATHMTU, IPPROTO_IPV6)) == NULL) + return; + + if (sbappendaddr(&so->so_rcv, (struct sockaddr *)dst, NULL, m_mtu) + == 0) { + m_freem(m_mtu); + /* XXX: should count statistics */ + } else + sorwakeup(so); + + return; +} + #ifdef PULLDOWN_TEST /* * pull single extension header from mbuf chain. returns single mbuf that diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index 56f3758..00205ff 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -278,6 +278,7 @@ rip6_ctlinput(cmd, sa, d) int off = 0; struct ip6ctlparam *ip6cp = NULL; const struct sockaddr_in6 *sa6_src = NULL; + void *cmdarg; struct inpcb *(*notify) __P((struct inpcb *, int)) = in6_rtchange; if (sa->sa_family != AF_INET6 || @@ -299,15 +300,17 @@ rip6_ctlinput(cmd, sa, d) m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; + cmdarg = ip6cp->ip6c_cmdarg; sa6_src = ip6cp->ip6c_src; } else { m = NULL; ip6 = NULL; + cmdarg = NULL; sa6_src = &sa6_any; } (void) in6_pcbnotify(&ripcb, sa, 0, (const struct sockaddr *)sa6_src, - 0, cmd, notify); + 0, cmd, cmdarg, notify); } /* diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index deb2a31..d95fc26 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -435,6 +435,7 @@ udp6_ctlinput(cmd, sa, d) int off = 0; struct ip6ctlparam *ip6cp = NULL; const struct sockaddr_in6 *sa6_src = NULL; + void *cmdarg; struct inpcb *(*notify) __P((struct inpcb *, int)) = udp_notify; struct udp_portonly { u_int16_t uh_sport; @@ -460,10 +461,12 @@ udp6_ctlinput(cmd, sa, d) m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; + cmdarg = ip6cp->ip6c_cmdarg; sa6_src = ip6cp->ip6c_src; } else { m = NULL; ip6 = NULL; + cmdarg = NULL; sa6_src = &sa6_any; } @@ -481,12 +484,12 @@ udp6_ctlinput(cmd, sa, d) m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh); (void) in6_pcbnotify(&udb, sa, uh.uh_dport, - (struct sockaddr *)ip6cp->ip6c_src, - uh.uh_sport, cmd, notify); + (struct sockaddr *)ip6cp->ip6c_src, + uh.uh_sport, cmd, cmdarg, notify); } else (void) in6_pcbnotify(&udb, sa, 0, (const struct sockaddr *)sa6_src, - 0, cmd, notify); + 0, cmd, cmdarg, notify); } static int |