summaryrefslogtreecommitdiff
path: root/sys/netinet/ip_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/ip_output.c')
-rw-r--r--sys/netinet/ip_output.c44
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);
}
/*