Several changes, mostly cosmetic:

* Add a KASSERT in ip_output(), we expect (at least) the IP header to be
   here.

 * In ip_fragment(), declare two variables instead of recomputing the
   values each time. Add an XXX for ipoff, it seems to me we should also
   remove IP_RF.

 * Rename the arguments of ip_optcopy().

 * Style: use NULL for pointers, remove ()s for return statements, and
   add whitespaces for clarity.

No real functional change.
This commit is contained in:
maxv 2018-02-06 17:08:18 +00:00
parent 64a90adb69
commit ca56b5b05a
1 changed files with 61 additions and 39 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_output.c,v 1.292 2018/01/10 18:51:31 christos Exp $ */
/* $NetBSD: ip_output.c,v 1.293 2018/02/06 17:08:18 maxv Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -29,7 +29,7 @@
* SUCH DAMAGE.
*/
/*-
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
@ -91,7 +91,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.292 2018/01/10 18:51:31 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.293 2018/02/06 17:08:18 maxv Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -156,7 +156,7 @@ static int ip_ifaddrvalid(const struct in_ifaddr *);
extern pfil_head_t *inet_pfil_hook; /* XXX */
int ip_do_loopback_cksum = 0;
int ip_do_loopback_cksum = 0;
static int
ip_mark_mpls(struct ifnet * const ifp, struct mbuf * const m,
@ -232,8 +232,7 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro, int flags,
struct ip *ip;
struct ifnet *ifp, *mifp = NULL;
struct mbuf *m = m0;
int hlen = sizeof (struct ip);
int len, error = 0;
int len, hlen, error = 0;
struct route iproute;
const struct sockaddr_in *dst;
struct in_ifaddr *ia = NULL;
@ -262,11 +261,12 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro, int flags,
KASSERT((m->m_pkthdr.csum_flags & (M_CSUM_TCPv6|M_CSUM_UDPv6)) == 0);
KASSERT((m->m_pkthdr.csum_flags & (M_CSUM_TCPv4|M_CSUM_UDPv4)) !=
(M_CSUM_TCPv4|M_CSUM_UDPv4));
KASSERT(m->m_len >= sizeof(struct ip));
hlen = sizeof(struct ip);
if (opt) {
m = ip_insertoptions(m, opt, &len);
if (len >= sizeof(struct ip))
hlen = len;
hlen = len;
}
ip = mtod(m, struct ip *);
@ -538,8 +538,8 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro, int flags,
}
/*
* packets with Class-D address as source are not valid per
* RFC 1112
* Packets with Class-D address as source are not valid per
* RFC1112.
*/
if (IN_MULTICAST(ip->ip_src.s_addr)) {
IP_STATINC(IP_STAT_ODROPPED);
@ -576,7 +576,6 @@ sendit:
} else if ((m->m_pkthdr.csum_flags & M_CSUM_TSOv4) == 0) {
ip->ip_id = ip_newid(ia);
} else {
/*
* TSO capable interfaces (typically?) increment
* ip_id for each segment.
@ -673,6 +672,7 @@ sendit:
m->m_pkthdr.csum_flags |= M_CSUM_IPv4;
}
sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_csum_flags_tx;
/*
* If small enough for mtu of path, or if using TCP segmentation
* offload, can just send directly.
@ -726,8 +726,7 @@ sendit:
}
/*
* We can't use HW checksumming if we're about to
* fragment the packet.
* We can't use HW checksumming if we're about to fragment the packet.
*
* XXX Some hardware can do this.
*/
@ -791,6 +790,7 @@ sendit:
if (error == 0) {
IP_STATINC(IP_STAT_FRAGMENTED);
}
done:
ia4_release(ia, &psref_ia);
rtcache_unref(rt, ro);
@ -803,6 +803,7 @@ done:
if (bind_need_restore)
curlwp_bindx(bound);
return error;
bad:
m_freem(m);
goto done;
@ -819,16 +820,24 @@ ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu)
int sw_csum = m->m_pkthdr.csum_flags;
int fragments = 0;
int error = 0;
int ipoff;
bool mff;
ip = mtod(m, struct ip *);
hlen = ip->ip_hl << 2;
/* XXX: Why don't we remove IP_RF? */
ipoff = ntohs(ip->ip_off) & ~IP_MF;
mff = (ip->ip_off & htons(IP_MF)) != 0;
if (ifp != NULL)
sw_csum &= ~ifp->if_csum_flags_tx;
len = (mtu - hlen) &~ 7;
if (len < 8) {
m_freem(m);
return (EMSGSIZE);
return EMSGSIZE;
}
firstlen = len;
@ -839,45 +848,52 @@ ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu)
* make new header and copy data of each part and link onto chain.
*/
m0 = m;
mhlen = sizeof (struct ip);
mhlen = sizeof(struct ip);
for (off = hlen + len; off < ntohs(ip->ip_len); off += len) {
MGETHDR(m, M_DONTWAIT, MT_HEADER);
if (m == 0) {
if (m == NULL) {
error = ENOBUFS;
IP_STATINC(IP_STAT_ODROPPED);
goto sendorfree;
}
MCLAIM(m, m0->m_owner);
*mnext = m;
mnext = &m->m_nextpkt;
m->m_data += max_linkhdr;
mhip = mtod(m, struct ip *);
*mhip = *ip;
/* we must inherit MCAST and BCAST flags */
m->m_flags |= m0->m_flags & (M_MCAST|M_BCAST);
if (hlen > sizeof (struct ip)) {
mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
if (hlen > sizeof(struct ip)) {
mhlen = ip_optcopy(ip, mhip) + sizeof(struct ip);
mhip->ip_hl = mhlen >> 2;
}
m->m_len = mhlen;
mhip->ip_off = ((off - hlen) >> 3) +
(ntohs(ip->ip_off) & ~IP_MF);
if (ip->ip_off & htons(IP_MF))
mhip->ip_off = ((off - hlen) >> 3) + ipoff;
if (mff)
mhip->ip_off |= IP_MF;
if (off + len >= ntohs(ip->ip_len))
len = ntohs(ip->ip_len) - off;
else
mhip->ip_off |= IP_MF;
HTONS(mhip->ip_off);
mhip->ip_len = htons((u_int16_t)(len + mhlen));
m->m_next = m_copym(m0, off, len, M_DONTWAIT);
if (m->m_next == 0) {
error = ENOBUFS; /* ??? */
if (m->m_next == NULL) {
error = ENOBUFS;
IP_STATINC(IP_STAT_ODROPPED);
goto sendorfree;
}
m->m_pkthdr.len = mhlen + len;
m_reset_rcvif(m);
mhip->ip_sum = 0;
KASSERT((m->m_pkthdr.csum_flags & M_CSUM_IPv4) == 0);
if (sw_csum & M_CSUM_IPv4) {
@ -896,6 +912,7 @@ ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu)
IP_STATINC(IP_STAT_OFRAGMENTS);
fragments++;
}
/*
* Update first fragment by trimming what's been copied out
* and updating header, then send each fragment (in order).
@ -918,6 +935,7 @@ ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu)
KASSERT(M_CSUM_DATA_IPv4_IPHL(m->m_pkthdr.csum_data) >=
sizeof(struct ip));
}
sendorfree:
/*
* If there is no room for all the fragments, don't queue
@ -940,7 +958,8 @@ sendorfree:
m_freem(m);
}
}
return (error);
return error;
}
/*
@ -974,7 +993,6 @@ in_delayed_cksum(struct mbuf *m)
* Determine the maximum length of the options to be inserted;
* we would far rather allocate too much space rather than too little.
*/
u_int
ip_optlen(struct inpcb *inp)
{
@ -1001,13 +1019,13 @@ ip_insertoptions(struct mbuf *m, struct mbuf *opt, int *phlen)
optlen = opt->m_len - sizeof(p->ipopt_dst);
if (optlen + ntohs(ip->ip_len) > IP_MAXPACKET)
return (m); /* XXX should fail */
return m; /* XXX should fail */
if (!in_nullhost(p->ipopt_dst))
ip->ip_dst = p->ipopt_dst;
if (M_READONLY(m) || M_LEADINGSPACE(m) < optlen) {
MGETHDR(n, M_DONTWAIT, MT_HEADER);
if (n == 0)
return (m);
if (n == NULL)
return m;
MCLAIM(n, m->m_owner);
M_MOVE_PKTHDR(n, m);
m->m_len -= sizeof(struct ip);
@ -1027,22 +1045,22 @@ ip_insertoptions(struct mbuf *m, struct mbuf *opt, int *phlen)
bcopy((void *)p->ipopt_list, (void *)(ip + 1), (unsigned)optlen);
*phlen = sizeof(struct ip) + optlen;
ip->ip_len = htons(ntohs(ip->ip_len) + optlen);
return (m);
return m;
}
/*
* Copy options from ip to jp,
* omitting those not copied during fragmentation.
* Copy options from ipsrc to ipdst, omitting those not copied during
* fragmentation.
*/
int
ip_optcopy(struct ip *ip, struct ip *jp)
ip_optcopy(struct ip *ipsrc, struct ip *ipdst)
{
u_char *cp, *dp;
int opt, optlen, cnt;
cp = (u_char *)(ip + 1);
dp = (u_char *)(jp + 1);
cnt = (ip->ip_hl << 2) - sizeof (struct ip);
cp = (u_char *)(ipsrc + 1);
dp = (u_char *)(ipdst + 1);
cnt = (ipsrc->ip_hl << 2) - sizeof(struct ip);
for (; cnt > 0; cnt -= optlen, cp += optlen) {
opt = cp[0];
if (opt == IPOPT_EOL)
@ -1066,9 +1084,12 @@ ip_optcopy(struct ip *ip, struct ip *jp)
dp += optlen;
}
}
for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
for (optlen = dp - (u_char *)(ipdst+1); optlen & 0x3; optlen++) {
*dp++ = IPOPT_EOL;
return (optlen);
}
return optlen;
}
/*
@ -1560,12 +1581,12 @@ ip_pcbopts(struct inpcb *inp, const struct sockopt *sopt)
#ifndef __vax__
if (cnt % sizeof(int32_t))
return (EINVAL);
return EINVAL;
#endif
m = m_get(M_DONTWAIT, MT_SOOPTS);
if (m == NULL)
return (ENOBUFS);
return ENOBUFS;
dp = mtod(m, u_char *);
memset(dp, 0, sizeof(struct in_addr));
@ -1645,6 +1666,7 @@ ip_pcbopts(struct inpcb *inp, const struct sockopt *sopt)
inp->inp_options = m;
return 0;
bad:
(void)m_free(m);
return EINVAL;