summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorclaudio <claudio@openbsd.org>2019-01-18 02:10:40 +0000
committerclaudio <claudio@openbsd.org>2019-01-18 02:10:40 +0000
commit96ffc0c66ee4e58e63529b22377b95dfa55c3ea0 (patch)
tree9f421fb03d798915b5579d041dd90d57073cd3bd
parentYet another long line broke cover. (diff)
downloadwireguard-openbsd-96ffc0c66ee4e58e63529b22377b95dfa55c3ea0.tar.xz
wireguard-openbsd-96ffc0c66ee4e58e63529b22377b95dfa55c3ea0.zip
Revert Rev 1.351, the change is not quite right yet.
-rw-r--r--sys/netinet/ip_output.c85
1 files changed, 36 insertions, 49 deletions
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index e9c64fd2c75..747e1e72b77 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.351 2019/01/06 11:05:09 claudio Exp $ */
+/* $OpenBSD: ip_output.c,v 1.352 2019/01/18 02:10:40 claudio Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -1234,15 +1234,13 @@ ip_ctloutput(int op, struct socket *so, int level, int optname,
int
ip_pcbopts(struct mbuf **pcbopt, struct mbuf *m)
{
- struct mbuf *n;
- struct ipoption *p;
- int cnt, off, optlen;
+ int cnt, optlen;
u_char *cp;
u_char opt;
/* turn off any old options */
m_free(*pcbopt);
- *pcbopt = NULL;
+ *pcbopt = 0;
if (m == NULL || m->m_len == 0) {
/*
* Only turning off any previous options.
@@ -1250,36 +1248,38 @@ ip_pcbopts(struct mbuf **pcbopt, struct mbuf *m)
return (0);
}
- if (m->m_len % sizeof(int32_t) ||
- m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
+ if (m->m_len % sizeof(int32_t))
return (EINVAL);
- /* Don't sleep because NET_LOCK() is hold. */
- if ((n = m_get(M_NOWAIT, MT_SOOPTS)) == NULL)
- return (ENOBUFS);
- p = mtod(n, struct ipoption *);
- p->ipopt_dst.s_addr = 0;
- n->m_len = sizeof(struct in_addr);
-
- off = 0;
+ /*
+ * IP first-hop destination address will be stored before
+ * actual options; move other options back
+ * and clear it when none present.
+ */
+ if (m_trailingspace(m) < sizeof(struct in_addr))
+ return (EINVAL);
cnt = m->m_len;
+ m->m_len += sizeof(struct in_addr);
cp = mtod(m, u_char *) + sizeof(struct in_addr);
+ memmove((caddr_t)cp, mtod(m, caddr_t), (unsigned)cnt);
+ memset(mtod(m, caddr_t), 0, sizeof(struct in_addr));
- while (cnt > 0) {
+ for (; cnt > 0; cnt -= optlen, cp += optlen) {
opt = cp[IPOPT_OPTVAL];
-
- if (opt == IPOPT_NOP || opt == IPOPT_EOL)
+ if (opt == IPOPT_EOL)
+ break;
+ if (opt == IPOPT_NOP)
optlen = 1;
else {
if (cnt < IPOPT_OLEN + sizeof(*cp))
- goto bad;
+ return (EINVAL);
optlen = cp[IPOPT_OLEN];
if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt)
- goto bad;
+ return (EINVAL);
}
switch (opt) {
+
default:
- memcpy(p->ipopt_list + off, cp, optlen);
break;
case IPOPT_LSRR:
@@ -1293,46 +1293,33 @@ ip_pcbopts(struct mbuf **pcbopt, struct mbuf *m)
* actual IP option, but is stored before the options.
*/
if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
- goto bad;
-
- /*
- * Optlen is smaller because first address is popped.
- * Cnt and cp will be adjusted a bit later to reflect
- * this.
- */
+ return (EINVAL);
+ m->m_len -= sizeof(struct in_addr);
+ cnt -= sizeof(struct in_addr);
optlen -= sizeof(struct in_addr);
- p->ipopt_list[off + IPOPT_OPTVAL] = opt;
- p->ipopt_list[off + IPOPT_OLEN] = optlen;
-
+ cp[IPOPT_OLEN] = optlen;
/*
* Move first hop before start of options.
*/
- memcpy(&p->ipopt_dst, cp + IPOPT_OFFSET,
+ memcpy(mtod(m, caddr_t), &cp[IPOPT_OFFSET+1],
sizeof(struct in_addr));
- cp += sizeof(struct in_addr);
- cnt -= sizeof(struct in_addr);
/*
- * Then copy rest of options
+ * Then copy rest of options back
+ * to close up the deleted entry.
*/
- memcpy(p->ipopt_list + off + IPOPT_OFFSET,
- cp + IPOPT_OFFSET, optlen - IPOPT_OFFSET);
+ memmove((caddr_t)&cp[IPOPT_OFFSET+1],
+ (caddr_t)(&cp[IPOPT_OFFSET+1] +
+ sizeof(struct in_addr)),
+ (unsigned)cnt - (IPOPT_OFFSET+1));
break;
}
- off += optlen;
- cp += optlen;
- cnt -= optlen;
-
- if (opt == IPOPT_EOL)
- break;
}
- n->m_len += off;
- if (n->m_len > sizeof(*p)) {
- bad:
- m_freem(n);
+ if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
return (EINVAL);
- }
+ *pcbopt = m_copym(m, 0, M_COPYALL, M_NOWAIT);
+ if (*pcbopt == NULL)
+ return (ENOBUFS);
- *pcbopt = n;
return (0);
}