diff options
-rw-r--r-- | sys/netinet/ip_output.c | 89 | ||||
-rw-r--r-- | sys/netinet/ip_var.h | 3 |
2 files changed, 54 insertions, 38 deletions
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index be3c4403aca..a3116b1aa61 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_output.c,v 1.143 2002/03/15 18:19:52 millert Exp $ */ +/* $OpenBSD: ip_output.c,v 1.144 2002/05/28 15:44:28 jasoni Exp $ */ /* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */ /* @@ -99,11 +99,11 @@ static void ip_mloopback(struct ifnet *, struct mbuf *, struct sockaddr_in *); int ip_output(struct mbuf *m0, ...) { - register struct ip *ip, *mhip; + register struct ip *ip; register struct ifnet *ifp; struct mbuf *m = m0; register int hlen = sizeof (struct ip); - int len, off, error = 0; + int len, error = 0; struct route iproute; struct sockaddr_in *dst; struct in_ifaddr *ia; @@ -705,12 +705,53 @@ sendit: ipstat.ips_cantfrag++; goto bad; } - len = (ifp->if_mtu - hlen) &~ 7; - if (len < 8) { - error = EMSGSIZE; + + error = ip_fragment(m, ifp); + if (error == EMSGSIZE) goto bad; + + for (m = m0; m; m = m0) { + m0 = m->m_nextpkt; + m->m_nextpkt = 0; + if (error == 0) + error = (*ifp->if_output)(ifp, m, sintosa(dst), + ro->ro_rt); + else + m_freem(m); } + if (error == 0) + ipstat.ips_fragmented++; + +done: + if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) + RTFREE(ro->ro_rt); + return (error); +bad: +#ifdef IPSEC + if (error == EMSGSIZE && ip_mtudisc && icmp_mtu != 0) + ipsec_adjust_mtu(m, icmp_mtu); +#endif + m_freem(m0); + goto done; +} + +int +ip_fragment(struct mbuf *m, struct ifnet *ifp) +{ + struct ip *ip, *mhip; + struct mbuf *m0; + int len, hlen, off; + int mhlen, firstlen; + struct mbuf **mnext; + + ip = mtod(m, struct ip *); + hlen = ip->ip_hl << 2; + + len = (ifp->if_mtu - hlen) &~ 7; + if (len < 8) + return (EMSGSIZE); + /* * If we are doing fragmentation, we can't defer TCP/UDP * checksumming; compute the checksum and clear the flag. @@ -720,9 +761,8 @@ sendit: m->m_pkthdr.csum &= ~(M_UDPV4_CSUM_OUT | M_TCPV4_CSUM_OUT); } - { - int mhlen, firstlen = len; - struct mbuf **mnext = &m->m_nextpkt; + firstlen = len; + mnext = &m->m_nextpkt; /* * Loop through length of segment after first fragment, @@ -733,9 +773,8 @@ sendit: for (off = hlen + len; off < (u_int16_t)ip->ip_len; off += len) { MGETHDR(m, M_DONTWAIT, MT_HEADER); if (m == 0) { - error = ENOBUFS; ipstat.ips_odropped++; - goto sendorfree; + return (ENOBUFS); } *mnext = m; mnext = &m->m_nextpkt; @@ -759,9 +798,8 @@ sendit: mhip->ip_len = htons((u_int16_t)(len + mhlen)); m->m_next = m_copy(m0, off, len); if (m->m_next == 0) { - error = ENOBUFS; /* ??? */ ipstat.ips_odropped++; - goto sendorfree; + return (ENOBUFS); /* ??? */ } m->m_pkthdr.len = mhlen + len; m->m_pkthdr.rcvif = (struct ifnet *)0; @@ -793,31 +831,8 @@ sendit: ip->ip_sum = 0; ip->ip_sum = in_cksum(m, hlen); } -sendorfree: - for (m = m0; m; m = m0) { - m0 = m->m_nextpkt; - m->m_nextpkt = 0; - if (error == 0) - error = (*ifp->if_output)(ifp, m, sintosa(dst), - ro->ro_rt); - else - m_freem(m); - } - if (error == 0) - ipstat.ips_fragmented++; - } -done: - if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) - RTFREE(ro->ro_rt); - return (error); -bad: -#ifdef IPSEC - if (error == EMSGSIZE && ip_mtudisc && icmp_mtu != 0) - ipsec_adjust_mtu(m, icmp_mtu); -#endif - m_freem(m0); - goto done; + return (0); } /* diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index c20fd9ed9fd..b914636cb45 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_var.h,v 1.22 2002/03/14 01:27:11 millert Exp $ */ +/* $OpenBSD: ip_var.h,v 1.23 2002/05/28 15:44:28 jasoni Exp $ */ /* $NetBSD: ip_var.h,v 1.16 1996/02/13 23:43:20 christos Exp $ */ /* @@ -172,6 +172,7 @@ int ip_dooptions(struct mbuf *); void ip_drain(void); void ip_flush(void); void ip_forward(struct mbuf *, int); +int ip_fragment(struct mbuf *, struct ifnet *); void ip_freef(struct ipq *); void ip_freemoptions(struct ip_moptions *); int ip_getmoptions(int, struct ip_moptions *, struct mbuf **); |