Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/netinet Abstract IP reassembly into single generic routi...



details:   https://anonhg.NetBSD.org/src/rev/e544e920c948
branches:  trunk
changeset: 756475:e544e920c948
user:      rmind <rmind%NetBSD.org@localhost>
date:      Mon Jul 19 14:09:44 2010 +0000

description:
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@

diffstat:

 sys/netinet/in_var.h   |    3 +-
 sys/netinet/ip_input.c |   82 ++++++++++++----------------------
 sys/netinet/ip_reass.c |  113 +++++++++++++++++++++++++++++++++++-------------
 sys/netinet/ip_var.h   |   31 ++----------
 4 files changed, 119 insertions(+), 110 deletions(-)

diffs (truncated from 407 to 300 lines):

diff -r 1195cf135ce1 -r e544e920c948 sys/netinet/in_var.h
--- a/sys/netinet/in_var.h      Mon Jul 19 10:31:46 2010 +0000
+++ b/sys/netinet/in_var.h      Mon Jul 19 14:09:44 2010 +0000
@@ -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);
diff -r 1195cf135ce1 -r e544e920c948 sys/netinet/ip_input.c
--- a/sys/netinet/ip_input.c    Mon Jul 19 10:31:46 2010 +0000
+++ b/sys/netinet/ip_input.c    Mon Jul 19 14:09:44 2010 +0000
@@ -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;
-               }
+               /*
+                * Adjust total IP length to not reflect header and convert
+                * offset of this to bytes.  XXX: clobbers struct ip.
+                */
+               ip->ip_len = htons(flen);
+               ip->ip_off = htons(off);
 
                /*
-                * If datagram marked as having more fragments
-                * or if this is not the first fragment,
-                * attempt reassembly; if it succeeds, proceed.
+                * Pass to IP reassembly mechanism.
                 */
-               if (mff || ip->ip_off != htons(0)) {
-                       struct ipqent *ipqe;
+               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;
 
-                       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();
-               }
+               /* Updated local variable(s). */
+               ip = mtod(m, struct ip *);
+               hlen = ip->ip_hl << 2;
        }
 
 #if defined(IPSEC)
diff -r 1195cf135ce1 -r e544e920c948 sys/netinet/ip_reass.c
--- a/sys/netinet/ip_reass.c    Mon Jul 19 10:31:46 2010 +0000
+++ b/sys/netinet/ip_reass.c    Mon Jul 19 14:09:44 2010 +0000
@@ -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.
+ *



Home | Main Index | Thread Index | Old Index