-/* $OpenBSD: ip_output.c,v 1.381 2022/05/25 19:48:46 mvs Exp $ */
+/* $OpenBSD: ip_output.c,v 1.382 2022/08/12 17:04:16 bluhm Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
#endif /* IPSEC */
int
-ip_fragment(struct mbuf *m, struct mbuf_list *fml, struct ifnet *ifp,
+ip_fragment(struct mbuf *m0, struct mbuf_list *fml, struct ifnet *ifp,
u_long mtu)
{
- struct ip *ip, *mhip;
- struct mbuf *m0;
- int len, hlen, off;
- int mhlen, firstlen;
+ struct mbuf *m;
+ struct ip *ip;
+ int firstlen, hlen, tlen, len, off;
int error;
ml_init(fml);
- ml_enqueue(fml, m);
+ ml_enqueue(fml, m0);
- ip = mtod(m, struct ip *);
+ ip = mtod(m0, struct ip *);
hlen = ip->ip_hl << 2;
+ tlen = m0->m_pkthdr.len;
len = (mtu - hlen) &~ 7;
if (len < 8) {
error = EMSGSIZE;
goto bad;
}
+ firstlen = len;
/*
* If we are doing fragmentation, we can't defer TCP/UDP
* checksumming; compute the checksum and clear the flag.
*/
- in_proto_cksum_out(m, NULL);
- firstlen = len;
+ in_proto_cksum_out(m0, NULL);
/*
* Loop through length of segment after first fragment,
* make new header and copy data of each part and link onto chain.
*/
- m0 = m;
- mhlen = sizeof (struct ip);
- for (off = hlen + len; off < ntohs(ip->ip_len); off += len) {
+ for (off = hlen + firstlen; off < tlen; off += len) {
+ struct ip *mhip;
+ int mhlen;
+
MGETHDR(m, M_DONTWAIT, MT_HEADER);
if (m == NULL) {
error = ENOBUFS;
goto bad;
}
ml_enqueue(fml, m);
+
if ((error = m_dup_pkthdr(m, m0, M_DONTWAIT)) != 0)
goto bad;
m->m_data += max_linkhdr;
mhip = mtod(m, struct ip *);
*mhip = *ip;
- 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;
- }
+ } else
+ mhlen = sizeof(struct ip);
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 |= IP_MF;
- if (off + len >= ntohs(ip->ip_len))
- len = ntohs(ip->ip_len) - off;
+ if (off + len >= tlen)
+ len = tlen - off;
else
mhip->ip_off |= IP_MF;
- mhip->ip_len = htons((u_int16_t)(len + mhlen));
+ mhip->ip_off = htons(mhip->ip_off);
+
+ m->m_pkthdr.len = mhlen + len;
+ mhip->ip_len = htons(m->m_pkthdr.len);
m->m_next = m_copym(m0, off, len, M_NOWAIT);
if (m->m_next == NULL) {
error = ENOBUFS;
goto bad;
}
- m->m_pkthdr.len = mhlen + len;
- m->m_pkthdr.ph_ifidx = 0;
- mhip->ip_off = htons((u_int16_t)mhip->ip_off);
+
mhip->ip_sum = 0;
if (in_ifcap_cksum(m, ifp, IFCAP_CSUM_IPv4))
m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
mhip->ip_sum = in_cksum(m, mhlen);
}
}
+
/*
* Update first fragment by trimming what's been copied out
* and updating header, then send each fragment (in order).
*/
m = m0;
- m_adj(m, hlen + firstlen - ntohs(ip->ip_len));
- m->m_pkthdr.len = hlen + firstlen;
- ip->ip_len = htons((u_int16_t)m->m_pkthdr.len);
+ m_adj(m, hlen + firstlen - tlen);
ip->ip_off |= htons(IP_MF);
+ ip->ip_len = htons(m->m_pkthdr.len);
+
ip->ip_sum = 0;
if (in_ifcap_cksum(m, ifp, IFCAP_CSUM_IPv4))
m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
-/* $OpenBSD: ip6_output.c,v 1.270 2022/08/08 23:00:51 bluhm Exp $ */
+/* $OpenBSD: ip6_output.c,v 1.271 2022/08/12 17:04:17 bluhm Exp $ */
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
/*
ip6_fragment(struct mbuf *m0, struct mbuf_list *fml, int hlen,
u_char nextproto, u_long mtu)
{
- struct mbuf *m, *m_frgpart;
- struct ip6_hdr *mhip6;
- struct ip6_frag *ip6f;
- u_int32_t id;
- int tlen, len, off;
- int error;
+ struct mbuf *m;
+ struct ip6_hdr *ip6;
+ u_int32_t id;
+ int tlen, len, off;
+ int error;
ml_init(fml);
+ ip6 = mtod(m0, struct ip6_hdr *);
tlen = m0->m_pkthdr.len;
len = (mtu - hlen - sizeof(struct ip6_frag)) & ~7;
if (len < 8) {
error = EMSGSIZE;
goto bad;
}
-
id = htonl(ip6_randomid());
/*
- * Loop through length of segment after first fragment,
+ * Loop through length of segment,
* make new header and copy data of each part and link onto chain.
*/
for (off = hlen; off < tlen; off += len) {
struct mbuf *mlast;
+ struct ip6_hdr *mhip6;
+ struct ip6_frag *ip6f;
MGETHDR(m, M_DONTWAIT, MT_HEADER);
if (m == NULL) {
goto bad;
}
ml_enqueue(fml, m);
+
if ((error = m_dup_pkthdr(m, m0, M_DONTWAIT)) != 0)
goto bad;
m->m_data += max_linkhdr;
mhip6 = mtod(m, struct ip6_hdr *);
- *mhip6 = *mtod(m0, struct ip6_hdr *);
- m->m_len = sizeof(*mhip6);
+ *mhip6 = *ip6;
+ m->m_len = sizeof(struct ip6_hdr);
+
if ((error = ip6_insertfraghdr(m0, m, hlen, &ip6f)) != 0)
goto bad;
- ip6f->ip6f_offlg = htons((u_int16_t)((off - hlen) & ~7));
+ ip6f->ip6f_offlg = htons((off - hlen) & ~7);
if (off + len >= tlen)
len = tlen - off;
else
ip6f->ip6f_offlg |= IP6F_MORE_FRAG;
- mhip6->ip6_plen = htons((u_int16_t)(len + hlen +
- sizeof(*ip6f) - sizeof(struct ip6_hdr)));
- if ((m_frgpart = m_copym(m0, off, len, M_DONTWAIT)) == NULL) {
+
+ m->m_pkthdr.len = hlen + sizeof(struct ip6_frag) + len;
+ mhip6->ip6_plen = htons(m->m_pkthdr.len -
+ sizeof(struct ip6_hdr));
+ for (mlast = m; mlast->m_next; mlast = mlast->m_next)
+ ;
+ mlast->m_next = m_copym(m0, off, len, M_DONTWAIT);
+ if (mlast->m_next == NULL) {
error = ENOBUFS;
goto bad;
}
- for (mlast = m; mlast->m_next; mlast = mlast->m_next)
- ;
- mlast->m_next = m_frgpart;
- m->m_pkthdr.len = len + hlen + sizeof(*ip6f);
+
ip6f->ip6f_reserved = 0;
ip6f->ip6f_ident = id;
ip6f->ip6f_nxt = nextproto;