summaryrefslogtreecommitdiff
path: root/sys/netinet6/ip6_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet6/ip6_output.c')
-rw-r--r--sys/netinet6/ip6_output.c48
1 files changed, 37 insertions, 11 deletions
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 9adc9785508..e9471c1b574 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: ip6_output.c,v 1.13 2000/06/20 20:51:26 itojun Exp $ */
-/* $KAME: ip6_output.c,v 1.112 2000/06/18 01:50:39 itojun Exp $ */
+/* $OpenBSD: ip6_output.c,v 1.14 2000/08/19 09:17:36 itojun Exp $ */
+/* $KAME: ip6_output.c,v 1.122 2000/08/19 02:12:02 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -1150,6 +1150,7 @@ ip6_insert_jumboopt(exthdrs, plen)
{
struct mbuf *mopt;
u_char *optbuf;
+ u_int32_t v;
#define JUMBOOPTLEN 8 /* length of jumbo payload option and padding */
@@ -1172,18 +1173,42 @@ ip6_insert_jumboopt(exthdrs, plen)
mopt = exthdrs->ip6e_hbh;
if (M_TRAILINGSPACE(mopt) < JUMBOOPTLEN) {
- caddr_t oldoptp = mtod(mopt, caddr_t);
+ /*
+ * XXX assumption:
+ * - exthdrs->ip6e_hbh is not referenced from places
+ * other than exthdrs.
+ * - exthdrs->ip6e_hbh is not an mbuf chain.
+ */
int oldoptlen = mopt->m_len;
+ struct mbuf *n;
- if (mopt->m_flags & M_EXT)
- return(ENOBUFS); /* XXX */
- MCLGET(mopt, M_DONTWAIT);
- if ((mopt->m_flags & M_EXT) == 0)
+ /*
+ * XXX: give up if the whole (new) hbh header does
+ * not fit even in an mbuf cluster.
+ */
+ if (oldoptlen + JUMBOOPTLEN > MCLBYTES)
return(ENOBUFS);
- bcopy(oldoptp, mtod(mopt, caddr_t), oldoptlen);
- optbuf = mtod(mopt, caddr_t) + oldoptlen;
- mopt->m_len = oldoptlen + JUMBOOPTLEN;
+ /*
+ * As a consequence, we must always prepare a cluster
+ * at this point.
+ */
+ MGET(n, M_DONTWAIT, MT_DATA);
+ if (n) {
+ MCLGET(n, M_DONTWAIT);
+ if ((n->m_flags & M_EXT) == 0) {
+ m_freem(n);
+ n = NULL;
+ }
+ }
+ if (!n)
+ return(ENOBUFS);
+ n->m_len = oldoptlen + JUMBOOPTLEN;
+ bcopy(mtod(mopt, caddr_t), mtod(n, caddr_t),
+ oldoptlen);
+ optbuf = mtod(n, caddr_t) + oldoptlen;
+ m_freem(mopt);
+ exthdrs->ip6e_hbh = n;
} else {
optbuf = mtod(mopt, u_char *) + mopt->m_len;
mopt->m_len += JUMBOOPTLEN;
@@ -1202,7 +1227,8 @@ ip6_insert_jumboopt(exthdrs, plen)
/* fill in the option. */
optbuf[2] = IP6OPT_JUMBO;
optbuf[3] = 4;
- *(u_int32_t *)&optbuf[4] = htonl(plen + JUMBOOPTLEN);
+ v = (u_int32_t)htonl(plen + JUMBOOPTLEN);
+ bcopy(&v, &optbuf[4], sizeof(u_int32_t));
/* finally, adjust the packet header length */
exthdrs->ip6e_ip6->m_pkthdr.len += JUMBOOPTLEN;