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);

Reply via email to