diff options
Diffstat (limited to 'sys/netinet/ip_output.c')
-rw-r--r-- | sys/netinet/ip_output.c | 44 |
1 files changed, 37 insertions, 7 deletions
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 5a8680e8d0b..9cc42341943 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_output.c,v 1.159 2003/11/06 16:57:41 dhartmei Exp $ */ +/* $OpenBSD: ip_output.c,v 1.160 2004/02/10 20:20:01 itojun Exp $ */ /* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */ /* @@ -717,8 +717,10 @@ sendit: } error = ip_fragment(m, ifp, mtu); - if (error) + if (error) { + m = m0 = NULL; goto bad; + } for (; m; m = m0) { m0 = m->m_nextpkt; @@ -739,7 +741,7 @@ done: return (error); bad: #ifdef IPSEC - if (error == EMSGSIZE && ip_mtudisc && icmp_mtu != 0) + if (error == EMSGSIZE && ip_mtudisc && icmp_mtu != 0 && m != NULL) ipsec_adjust_mtu(m, icmp_mtu); #endif m_freem(m0); @@ -754,13 +756,18 @@ ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu) int len, hlen, off; int mhlen, firstlen; struct mbuf **mnext; + int fragments = 0; + int s; + int error = 0; ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; len = (mtu - hlen) &~ 7; - if (len < 8) + if (len < 8) { + m_freem(m); return (EMSGSIZE); + } /* * If we are doing fragmentation, we can't defer TCP/UDP @@ -784,7 +791,8 @@ ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu) MGETHDR(m, M_DONTWAIT, MT_HEADER); if (m == 0) { ipstat.ips_odropped++; - return (ENOBUFS); + error = ENOBUFS; + goto sendorfree; } *mnext = m; mnext = &m->m_nextpkt; @@ -810,7 +818,8 @@ ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu) m->m_next = m_copy(m0, off, len); if (m->m_next == 0) { ipstat.ips_odropped++; - return (ENOBUFS); /* ??? */ + error = ENOBUFS; + goto sendorfree; } m->m_pkthdr.len = mhlen + len; m->m_pkthdr.rcvif = (struct ifnet *)0; @@ -824,6 +833,7 @@ ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu) mhip->ip_sum = in_cksum(m, mhlen); } ipstat.ips_ofragments++; + fragments++; } /* * Update first fragment by trimming what's been copied out @@ -842,8 +852,28 @@ ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu) ip->ip_sum = 0; ip->ip_sum = in_cksum(m, hlen); } +sendorfree: + /* + * If there is no room for all the fragments, don't queue + * any of them. + */ + s = splnet(); + if (ifp->if_snd.ifq_maxlen - ifp->if_snd.ifq_len < fragments && + error == 0) { + error = ENOBUFS; + ipstat.ips_odropped++; + IFQ_INC_DROPS(&ifp->if_snd); + } + splx(s); + if (error) { + for (m = m0; m; m = m0) { + m0 = m->m_nextpkt; + m->m_nextpkt = NULL; + m_freem(m); + } + } - return (0); + return (error); } /* |