Module Name: src
Committed By: rmind
Date: Mon Jul 19 14:09:45 UTC 2010
Modified Files:
src/sys/netinet: in_var.h ip_input.c ip_reass.c ip_var.h
Log Message:
Abstract IP reassembly into single generic routine - ip_reass_packet().
Make struct ipq private and struct ipqent not visible to userland.
Push ip_len adjustment into reassembly layer.
OK matt@
To generate a diff of this commit:
cvs rdiff -u -r1.63 -r1.64 src/sys/netinet/in_var.h
cvs rdiff -u -r1.288 -r1.289 src/sys/netinet/ip_input.c
cvs rdiff -u -r1.1 -r1.2 src/sys/netinet/ip_reass.c
cvs rdiff -u -r1.92 -r1.93 src/sys/netinet/ip_var.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/netinet/in_var.h
diff -u src/sys/netinet/in_var.h:1.63 src/sys/netinet/in_var.h:1.64
--- src/sys/netinet/in_var.h:1.63 Tue Jul 13 22:16:10 2010
+++ src/sys/netinet/in_var.h Mon Jul 19 14:09:44 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: in_var.h,v 1.63 2010/07/13 22:16:10 rmind Exp $ */
+/* $NetBSD: in_var.h,v 1.64 2010/07/19 14:09:44 rmind Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -300,7 +300,6 @@
struct lwp *);
void in_purgeaddr(struct ifaddr *);
void in_purgeif(struct ifnet *);
-void ip_reass_init(void);
void ip_input(struct mbuf *);
int ipflow_fastforward(struct mbuf *);
void ip_initid(void);
Index: src/sys/netinet/ip_input.c
diff -u src/sys/netinet/ip_input.c:1.288 src/sys/netinet/ip_input.c:1.289
--- src/sys/netinet/ip_input.c:1.288 Tue Jul 13 22:16:10 2010
+++ src/sys/netinet/ip_input.c Mon Jul 19 14:09:45 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: ip_input.c,v 1.288 2010/07/13 22:16:10 rmind Exp $ */
+/* $NetBSD: ip_input.c,v 1.289 2010/07/19 14:09:45 rmind Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.288 2010/07/13 22:16:10 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.289 2010/07/19 14:09:45 rmind Exp $");
#include "opt_inet.h"
#include "opt_compat_netbsd.h"
@@ -412,14 +412,11 @@
struct m_tag *mtag;
struct tdb_ident *tdbi;
struct secpolicy *sp;
- int error;
+ int error, s;
#endif /* FAST_IPSEC */
MCLAIM(m, &ip_rx_mowner);
-#ifdef DIAGNOSTIC
- if ((m->m_flags & M_PKTHDR) == 0)
- panic("ipintr no HDR");
-#endif
+ KASSERT((m->m_flags & M_PKTHDR) != 0);
/*
* If no IP addresses have been set yet but the interfaces
@@ -809,8 +806,8 @@
* If offset or IP_MF are set, must reassemble.
*/
if (ip->ip_off & ~htons(IP_DF|IP_RF)) {
- struct ipq *fp;
- u_int off, hash;
+ struct mbuf *m_final;
+ u_int off, flen;
bool mff;
/*
@@ -825,65 +822,44 @@
goto bad;
}
- /*
- * Adjust total IP length to not reflect header. Set 'mff'
- * indicator, if more fragments are expected. Convert offset
- * of this to bytes.
- */
- ip->ip_len = htons(ntohs(ip->ip_len) - hlen);
+ /* Fragment length and MF flag. */
+ flen = ntohs(ip->ip_len) - hlen;
mff = (ip->ip_off & htons(IP_MF)) != 0;
if (mff) {
/*
* Make sure that fragments have a data length
* which is non-zero and multiple of 8 bytes.
*/
- if (ntohs(ip->ip_len) == 0 ||
- (ntohs(ip->ip_len) & 0x7) != 0) {
+ if (flen == 0 || (flen & 0x7) != 0) {
IP_STATINC(IP_STAT_BADFRAGS);
goto bad;
}
}
- ip->ip_off = htons((ntohs(ip->ip_off) & IP_OFFMASK) << 3);
-
- /* Look for queue of fragments of this datagram. */
- fp = ip_reass_lookup(ip, &hash);
-
- /* Make sure the TOS matches previous fragments. */
- if (fp && fp->ipq_tos != ip->ip_tos) {
- IP_STATINC(IP_STAT_BADFRAGS);
- ip_reass_unlock();
- goto bad;
- }
/*
- * If datagram marked as having more fragments
- * or if this is not the first fragment,
- * attempt reassembly; if it succeeds, proceed.
+ * Adjust total IP length to not reflect header and convert
+ * offset of this to bytes. XXX: clobbers struct ip.
*/
- if (mff || ip->ip_off != htons(0)) {
- struct ipqent *ipqe;
+ ip->ip_len = htons(flen);
+ ip->ip_off = htons(off);
- ipqe = ip_reass_getent();
- if (ipqe == NULL) {
- IP_STATINC(IP_STAT_RCVMEMDROP);
- ip_reass_unlock();
- goto bad;
- }
- ipqe->ipqe_mff = mff;
- ipqe->ipqe_m = m;
- ipqe->ipqe_ip = ip;
- m = ip_reass(ipqe, fp, hash);
- if (m == NULL) {
- return;
- }
- IP_STATINC(IP_STAT_REASSEMBLED);
- ip = mtod(m, struct ip *);
- hlen = ip->ip_hl << 2;
- ip->ip_len = htons(ntohs(ip->ip_len) + hlen);
- } else if (fp) {
- ip_freef(fp);
- ip_reass_unlock();
+ /*
+ * Pass to IP reassembly mechanism.
+ */
+ if (ip_reass_packet(m, ip, mff, &m_final) != 0) {
+ /* Failed; invalid fragment(s) or packet. */
+ goto bad;
}
+ if (m_final == NULL) {
+ /* More fragments should come; silently return. */
+ return;
+ }
+ /* Reassembly is done, we have the final packet. */
+ m = m_final;
+
+ /* Updated local variable(s). */
+ ip = mtod(m, struct ip *);
+ hlen = ip->ip_hl << 2;
}
#if defined(IPSEC)
Index: src/sys/netinet/ip_reass.c
diff -u src/sys/netinet/ip_reass.c:1.1 src/sys/netinet/ip_reass.c:1.2
--- src/sys/netinet/ip_reass.c:1.1 Tue Jul 13 22:16:10 2010
+++ src/sys/netinet/ip_reass.c Mon Jul 19 14:09:45 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: ip_reass.c,v 1.1 2010/07/13 22:16:10 rmind Exp $ */
+/* $NetBSD: ip_reass.c,v 1.2 2010/07/19 14:09:45 rmind Exp $ */
/*
* Copyright (c) 1982, 1986, 1988, 1993
@@ -46,17 +46,19 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_reass.c,v 1.1 2010/07/13 22:16:10 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_reass.c,v 1.2 2010/07/19 14:09:45 rmind Exp $");
#include <sys/param.h>
-#include <sys/systm.h>
+#include <sys/types.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/pool.h>
+#include <sys/queue.h>
#include <sys/sysctl.h>
+#include <sys/systm.h>
#include <net/if.h>
#include <net/route.h>
@@ -65,10 +67,10 @@
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
#include <netinet/in_proto.h>
#include <netinet/ip_private.h>
#include <netinet/in_var.h>
-#include <netinet/ip_var.h>
/*
* IP datagram reassembly hashed queues, pool, lock and counters.
@@ -90,6 +92,23 @@
static int ip_maxfrags; /* limit on fragments. XXX sysctl */
/*
+ * IP reassembly queue structure. Each fragment being reassembled is
+ * attached to one of these structures. They are timed out after ipq_ttl
+ * drops to 0, and may also be reclaimed if memory becomes tight.
+ */
+struct ipq {
+ LIST_ENTRY(ipq) ipq_q; /* to other reass headers */
+ uint8_t ipq_ttl; /* time for reass q to live */
+ uint8_t ipq_p; /* protocol of this fragment */
+ uint16_t ipq_id; /* sequence id for reassembly */
+ struct ipqehead ipq_fragq; /* to ip fragment queue */
+ struct in_addr ipq_src;
+ struct in_addr ipq_dst;
+ uint16_t ipq_nfrags; /* frags in this queue entry */
+ uint8_t ipq_tos; /* TOS of this fragment */
+};
+
+/*
* Cached copy of nmbclusters. If nbclusters is different,
* recalculate IP parameters derived from nmbclusters.
*/
@@ -102,8 +121,12 @@
void sysctl_ip_reass_setup(void);
static void ip_nmbclusters_changed(void);
-static u_int ip_reass_ttl_decr(u_int ticks);
-static void ip_reass_drophalf(void);
+
+static struct ipq * ip_reass_lookup(struct ip *, u_int *);
+static struct mbuf * ip_reass(struct ipqent *, struct ipq *, u_int);
+static u_int ip_reass_ttl_decr(u_int ticks);
+static void ip_reass_drophalf(void);
+static void ip_freef(struct ipq *);
/*
* ip_reass_init:
@@ -236,7 +259,7 @@
*
* Look for queue of fragments of this datagram.
*/
-struct ipq *
+static struct ipq *
ip_reass_lookup(struct ip *ip, u_int *hashp)
{
struct ipq *fp;
@@ -259,27 +282,6 @@
return fp;
}
-void
-ip_reass_unlock(void)
-{
-
- IPQ_UNLOCK();
-}
-
-struct ipqent *
-ip_reass_getent(void)
-{
- struct ipqent *ipqe;
- int s;
-
- IP_STATINC(IP_STAT_FRAGMENTS);
- s = splvm();
- ipqe = pool_get(&ipqent_pool, PR_NOWAIT);
- splx(s);
-
- return ipqe;
-}
-
/*
* ip_reass:
*
@@ -467,9 +469,10 @@
* packet. Dequeue and discard fragment reassembly header. Make
* header visible.
*/
- ip->ip_len = htons(next);
+ ip->ip_len = htons((ip->ip_hl << 2) + next);
ip->ip_src = fp->ipq_src;
ip->ip_dst = fp->ipq_dst;
+
LIST_REMOVE(fp, ipq_q);
free(fp, M_FTABLE);
ip_nfragpackets--;
@@ -506,7 +509,7 @@
*
* Free a fragment reassembly header and all associated datagrams.
*/
-void
+static void
ip_freef(struct ipq *fp)
{
struct ipqent *q, *p;
@@ -675,3 +678,53 @@
}
IPQ_UNLOCK();
}
+
+/*
+ * ip_reass_packet: generic routine to perform IP reassembly.
+ *
+ * => Passed fragment should have IP_MF flag and/or offset set.
+ * => Fragment should not have other than IP_MF flags set.
+ *
+ * => Returns 0 on success or error otherwise. When reassembly is complete,
+ * m_final representing a constructed final packet is set.
+ */
+int
+ip_reass_packet(struct mbuf *m, struct ip *ip, bool mff, struct mbuf **m_final)
+{
+ struct ipq *fp;
+ struct ipqent *ipqe;
+ u_int hash;
+
+ /* Look for queue of fragments of this datagram. */
+ fp = ip_reass_lookup(ip, &hash);
+
+ /* Make sure that TOS matches previous fragments. */
+ if (fp && fp->ipq_tos != ip->ip_tos) {
+ IP_STATINC(IP_STAT_BADFRAGS);
+ IPQ_UNLOCK();
+ return EINVAL;
+ }
+
+ /*
+ * Create new entry and attempt to reassembly.
+ */
+ IP_STATINC(IP_STAT_FRAGMENTS);
+ int s = splvm();
+ ipqe = pool_get(&ipqent_pool, PR_NOWAIT);
+ splx(s);
+ if (ipqe == NULL) {
+ IP_STATINC(IP_STAT_RCVMEMDROP);
+ IPQ_UNLOCK();
+ return ENOMEM;
+ }
+ ipqe->ipqe_mff = mff;
+ ipqe->ipqe_m = m;
+ ipqe->ipqe_ip = ip;
+
+ *m_final = ip_reass(ipqe, fp, hash);
+ if (*m_final) {
+ /* Note if finally reassembled. */
+ IP_STATINC(IP_STAT_REASSEMBLED);
+ }
+ return 0;
+}
Index: src/sys/netinet/ip_var.h
diff -u src/sys/netinet/ip_var.h:1.92 src/sys/netinet/ip_var.h:1.93
--- src/sys/netinet/ip_var.h:1.92 Tue Jul 13 22:16:10 2010
+++ src/sys/netinet/ip_var.h Mon Jul 19 14:09:45 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: ip_var.h,v 1.92 2010/07/13 22:16:10 rmind Exp $ */
+/* $NetBSD: ip_var.h,v 1.93 2010/07/19 14:09:45 rmind Exp $ */
/*
* Copyright (c) 1982, 1986, 1993
@@ -48,6 +48,8 @@
struct in_addr ih_dst; /* destination internet address */
} __packed;
+#ifdef _KERNEL
+
/*
* Ip (reassembly or sequence) queue structures.
*
@@ -80,22 +82,7 @@
#define ipqe_ip _ipqe_u1._ip
#define ipqe_tcp _ipqe_u1._tcp
-/*
- * Ip reassembly queue structure. Each fragment
- * being reassembled is attached to one of these structures.
- * They are timed out after ipq_ttl drops to 0, and may also
- * be reclaimed if memory becomes tight.
- */
-struct ipq {
- LIST_ENTRY(ipq) ipq_q; /* to other reass headers */
- u_int8_t ipq_ttl; /* time for reass q to live */
- u_int8_t ipq_p; /* protocol of this fragment */
- u_int16_t ipq_id; /* sequence id for reassembly */
- struct ipqehead ipq_fragq; /* to ip fragment queue */
- struct in_addr ipq_src, ipq_dst;
- u_int16_t ipq_nfrags; /* frags in this queue entry */
- u_int8_t ipq_tos; /* TOS of this fragment */
-};
+#endif /* _KERNEL */
/*
* Structure stored in mbuf in inpcb.ip_options
@@ -214,16 +201,10 @@
int ip_fragment(struct mbuf *, struct ifnet *, u_long);
int ip_pcbopts(struct mbuf **, const struct sockopt *);
-struct ipq *
- ip_reass_lookup(struct ip *, u_int *);
-void ip_reass_unlock(void);
-struct ipqent *
- ip_reass_getent(void);
-struct mbuf *
- ip_reass(struct ipqent *, struct ipq *, u_int);
+void ip_reass_init(void);
+int ip_reass_packet(struct mbuf *, struct ip *, bool, struct mbuf **);
void ip_reass_slowtimo(void);
void ip_reass_drain(void);
-void ip_freef(struct ipq *);
struct in_ifaddr *
ip_rtaddr(struct in_addr);