Factor out ip6_fragment() function, to be used in IPv6 stack and pf(4).

Submitted by:		Kristof Provost
Differential Revision:	D1766
This commit is contained in:
Gleb Smirnoff 2015-02-16 06:30:27 +00:00
parent 2cd617a883
commit 6c269f6912
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=278842
2 changed files with 64 additions and 48 deletions

View File

@ -212,6 +212,65 @@ in6_delayed_cksum(struct mbuf *m, uint32_t plen, u_short offset)
*(u_short *)(m->m_data + offset) = csum;
}
int
ip6_fragment(struct ifnet *ifp, struct mbuf *m0, int hlen, u_char nextproto,
int mtu)
{
struct mbuf *m, **mnext, *m_frgpart;
struct ip6_hdr *ip6, *mhip6;
struct ip6_frag *ip6f;
int off;
int error;
int tlen = m0->m_pkthdr.len;
uint32_t id = htonl(ip6_randomid());
m = m0;
ip6 = mtod(m, struct ip6_hdr *);
mnext = &m->m_nextpkt;
for (off = hlen; off < tlen; off += mtu) {
m = m_gethdr(M_NOWAIT, MT_DATA);
if (!m) {
IP6STAT_INC(ip6s_odropped);
return (ENOBUFS);
}
m->m_flags = m0->m_flags & M_COPYFLAGS;
*mnext = m;
mnext = &m->m_nextpkt;
m->m_data += max_linkhdr;
mhip6 = mtod(m, struct ip6_hdr *);
*mhip6 = *ip6;
m->m_len = sizeof(*mhip6);
error = ip6_insertfraghdr(m0, m, hlen, &ip6f);
if (error) {
IP6STAT_INC(ip6s_odropped);
return (error);
}
ip6f->ip6f_offlg = htons((u_short)((off - hlen) & ~7));
if (off + mtu >= tlen)
mtu = tlen - off;
else
ip6f->ip6f_offlg |= IP6F_MORE_FRAG;
mhip6->ip6_plen = htons((u_short)(mtu + hlen +
sizeof(*ip6f) - sizeof(struct ip6_hdr)));
if ((m_frgpart = m_copy(m0, off, mtu)) == 0) {
IP6STAT_INC(ip6s_odropped);
return (ENOBUFS);
}
m_cat(m, m_frgpart);
m->m_pkthdr.len = mtu + hlen + sizeof(*ip6f);
m->m_pkthdr.fibnum = m0->m_pkthdr.fibnum;
m->m_pkthdr.rcvif = NULL;
ip6f->ip6f_reserved = 0;
ip6f->ip6f_ident = id;
ip6f->ip6f_nxt = nextproto;
IP6STAT_INC(ip6s_ofragments);
in6_ifstat_inc(ifp, ifs6_out_fragcreat);
}
return (0);
}
/*
* IP6 output. The packet in mbuf chain m contains a skeletal IP6
* header (with pri, len, nxt, hlim, src, dst).
@ -236,11 +295,11 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
struct route_in6 *ro, int flags, struct ip6_moptions *im6o,
struct ifnet **ifpp, struct inpcb *inp)
{
struct ip6_hdr *ip6, *mhip6;
struct ip6_hdr *ip6;
struct ifnet *ifp, *origifp;
struct mbuf *m = m0;
struct mbuf *mprev = NULL;
int hlen, tlen, len, off;
int hlen, tlen, len;
struct route_in6 ip6route;
struct rtentry *rt = NULL;
struct sockaddr_in6 *dst, src_sa, dst_sa;
@ -901,9 +960,6 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
in6_ifstat_inc(ifp, ifs6_out_fragfail);
goto bad;
} else {
struct mbuf **mnext, *m_frgpart;
struct ip6_frag *ip6f;
u_int32_t id = htonl(ip6_randomid());
u_char nextproto;
/*
@ -937,8 +993,6 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
m->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6;
}
#endif
mnext = &m->m_nextpkt;
/*
* Change the next header field of the last header in the
* unfragmentable part.
@ -963,47 +1017,8 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
* chain.
*/
m0 = m;
for (off = hlen; off < tlen; off += len) {
m = m_gethdr(M_NOWAIT, MT_DATA);
if (!m) {
error = ENOBUFS;
IP6STAT_INC(ip6s_odropped);
goto sendorfree;
}
m->m_flags = m0->m_flags & M_COPYFLAGS;
*mnext = m;
mnext = &m->m_nextpkt;
m->m_data += max_linkhdr;
mhip6 = mtod(m, struct ip6_hdr *);
*mhip6 = *ip6;
m->m_len = sizeof(*mhip6);
error = ip6_insertfraghdr(m0, m, hlen, &ip6f);
if (error) {
IP6STAT_INC(ip6s_odropped);
goto sendorfree;
}
ip6f->ip6f_offlg = htons((u_short)((off - hlen) & ~7));
if (off + len >= tlen)
len = tlen - off;
else
ip6f->ip6f_offlg |= IP6F_MORE_FRAG;
mhip6->ip6_plen = htons((u_short)(len + hlen +
sizeof(*ip6f) - sizeof(struct ip6_hdr)));
if ((m_frgpart = m_copy(m0, off, len)) == 0) {
error = ENOBUFS;
IP6STAT_INC(ip6s_odropped);
goto sendorfree;
}
m_cat(m, m_frgpart);
m->m_pkthdr.len = len + hlen + sizeof(*ip6f);
m->m_pkthdr.fibnum = m0->m_pkthdr.fibnum;
m->m_pkthdr.rcvif = NULL;
ip6f->ip6f_reserved = 0;
ip6f->ip6f_ident = id;
ip6f->ip6f_nxt = nextproto;
IP6STAT_INC(ip6s_ofragments);
in6_ifstat_inc(ifp, ifs6_out_fragcreat);
}
if ((error = ip6_fragment(ifp, m, hlen, nextproto, len)))
goto sendorfree;
in6_ifstat_inc(ifp, ifs6_out_fragok);
}

View File

@ -389,6 +389,7 @@ void ip6_clearpktopts(struct ip6_pktopts *, int);
struct ip6_pktopts *ip6_copypktopts(struct ip6_pktopts *, int);
int ip6_optlen(struct inpcb *);
int ip6_deletefraghdr(struct mbuf *, int, int);
int ip6_fragment(struct ifnet *, struct mbuf *, int, u_char, int);
int route6_input(struct mbuf **, int *, int);