summaryrefslogtreecommitdiffstats
path: root/sys/netinet6
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2004-02-13 14:50:01 +0000
committerume <ume@FreeBSD.org>2004-02-13 14:50:01 +0000
commitf35565e63f9461f81b17f432764b5ca25e02856c (patch)
treef952cbefcf8a041f874d6e06257be2836aede356 /sys/netinet6
parent326680c1492004585de0fab05ad78cb474e6f539 (diff)
downloadFreeBSD-src-f35565e63f9461f81b17f432764b5ca25e02856c.zip
FreeBSD-src-f35565e63f9461f81b17f432764b5ca25e02856c.tar.gz
supported IPV6_RECVPATHMTU socket option.
Obtained from: KAME
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/in6_pcb.c19
-rw-r--r--sys/netinet6/in6_pcb.h2
-rw-r--r--sys/netinet6/ip6_input.c39
-rw-r--r--sys/netinet6/raw_ip6.c5
-rw-r--r--sys/netinet6/udp6_usrreq.c9
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
OpenPOWER on IntegriCloud