Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 20 Aug 2013 13:24:44 +0000 (UTC)
From:      Cy Schubert <cy@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org
Subject:   svn commit: r254562 - vendor-sys/ipfilter/dist/netinet
Message-ID:  <201308201324.r7KDOiOr025410@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: cy
Date: Tue Aug 20 13:24:44 2013
New Revision: 254562
URL: http://svnweb.freebsd.org/changeset/base/254562

Log:
  Add kernel sources from IP-Filter 5.1.2 to vendor-sys/ branch.
  
  Approved by:	glebius (mentor)

Added:
  vendor-sys/ipfilter/dist/netinet/ip_dstlist.c   (contents, props changed)
  vendor-sys/ipfilter/dist/netinet/ip_dstlist.h
  vendor-sys/ipfilter/dist/netinet/ipf_rb.h
  vendor-sys/ipfilter/dist/netinet/radix_ipf.c   (contents, props changed)
  vendor-sys/ipfilter/dist/netinet/radix_ipf.h

Added: vendor-sys/ipfilter/dist/netinet/ip_dstlist.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor-sys/ipfilter/dist/netinet/ip_dstlist.c	Tue Aug 20 13:24:44 2013	(r254562)
@@ -0,0 +1,1351 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if defined(KERNEL) || defined(_KERNEL)
+# undef KERNEL
+# undef _KERNEL
+# define        KERNEL	1
+# define        _KERNEL	1
+#endif
+#if defined(__osf__)
+# define _PROTO_NET_H_
+#endif
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#if !defined(_KERNEL) && !defined(__KERNEL__)
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# define _KERNEL
+# ifdef __OpenBSD__
+struct file;
+# endif
+# include <sys/uio.h>
+# undef _KERNEL
+#else
+# include <sys/systm.h>
+# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
+#  include <sys/proc.h>
+# endif
+#endif
+#include <sys/time.h>
+#if !defined(linux)
+# include <sys/protosw.h>
+#endif
+#include <sys/socket.h>
+#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
+# include <sys/mbuf.h>
+#endif
+#if defined(__SVR4) || defined(__svr4__)
+# include <sys/filio.h>
+# include <sys/byteorder.h>
+# ifdef _KERNEL
+#  include <sys/dditypes.h>
+# endif
+# include <sys/stream.h>
+# include <sys/kmem.h>
+#endif
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
+# include <sys/malloc.h>
+#endif
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_dstlist.h"
+
+/* END OF INCLUDES */
+
+#ifdef HAS_SYS_MD5_H
+# include <sys/md5.h>
+#else
+# include "md5.h"
+#endif
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id: ip_dstlist.c,v 1.13.2.12 2012/07/20 08:40:19 darren_r Exp $";
+#endif
+
+typedef struct ipf_dstl_softc_s {
+	ippool_dst_t	*dstlist[LOOKUP_POOL_SZ];
+	ippool_dst_t	**tails[LOOKUP_POOL_SZ];
+	ipf_dstl_stat_t	stats;
+} ipf_dstl_softc_t;
+
+
+static void *ipf_dstlist_soft_create __P((ipf_main_softc_t *));
+static void ipf_dstlist_soft_destroy __P((ipf_main_softc_t *, void *));
+static int ipf_dstlist_soft_init __P((ipf_main_softc_t *, void *));
+static void ipf_dstlist_soft_fini __P((ipf_main_softc_t *, void *));
+static int ipf_dstlist_addr_find __P((ipf_main_softc_t *, void *, int,
+				      void *, u_int));
+static size_t ipf_dstlist_flush __P((ipf_main_softc_t *, void *,
+				     iplookupflush_t *));
+static int ipf_dstlist_iter_deref __P((ipf_main_softc_t *, void *, int, int,
+				       void *));
+static int ipf_dstlist_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *,
+				      ipflookupiter_t *));
+static int ipf_dstlist_node_add __P((ipf_main_softc_t *, void *,
+				     iplookupop_t *, int));
+static int ipf_dstlist_node_del __P((ipf_main_softc_t *, void *,
+				     iplookupop_t *, int));
+static int ipf_dstlist_stats_get __P((ipf_main_softc_t *, void *,
+				      iplookupop_t *));
+static int ipf_dstlist_table_add __P((ipf_main_softc_t *, void *,
+				      iplookupop_t *));
+static int ipf_dstlist_table_del __P((ipf_main_softc_t *, void *,
+				      iplookupop_t *));
+static int ipf_dstlist_table_deref __P((ipf_main_softc_t *, void *, void *));
+static void *ipf_dstlist_table_find __P((void *, int, char *));
+static void ipf_dstlist_table_free __P((ipf_dstl_softc_t *, ippool_dst_t *));
+static void ipf_dstlist_table_remove __P((ipf_main_softc_t *,
+					  ipf_dstl_softc_t *, ippool_dst_t *));
+static void ipf_dstlist_table_clearnodes __P((ipf_dstl_softc_t *,
+					      ippool_dst_t *));
+static ipf_dstnode_t *ipf_dstlist_select __P((fr_info_t *, ippool_dst_t *));
+static void *ipf_dstlist_select_ref __P((void *, int, char *));
+static void ipf_dstlist_node_free __P((ipf_dstl_softc_t *, ippool_dst_t *, ipf_dstnode_t *));
+static int ipf_dstlist_node_deref __P((void *, ipf_dstnode_t *));
+static void ipf_dstlist_expire __P((ipf_main_softc_t *, void *));
+static void ipf_dstlist_sync __P((ipf_main_softc_t *, void *));
+
+ipf_lookup_t ipf_dstlist_backend = {
+	IPLT_DSTLIST,
+	ipf_dstlist_soft_create,
+	ipf_dstlist_soft_destroy,
+	ipf_dstlist_soft_init,
+	ipf_dstlist_soft_fini,
+	ipf_dstlist_addr_find,
+	ipf_dstlist_flush,
+	ipf_dstlist_iter_deref,
+	ipf_dstlist_iter_next,
+	ipf_dstlist_node_add,
+	ipf_dstlist_node_del,
+	ipf_dstlist_stats_get,
+	ipf_dstlist_table_add,
+	ipf_dstlist_table_del,
+	ipf_dstlist_table_deref,
+	ipf_dstlist_table_find,
+	ipf_dstlist_select_ref,
+	ipf_dstlist_select_node,
+	ipf_dstlist_expire,
+	ipf_dstlist_sync
+};
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_soft_create                                     */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*                                                                          */
+/* Allocating a chunk of memory filled with 0's is enough for the current   */
+/* soft context used with destination lists.                                */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_dstlist_soft_create(softc)
+	ipf_main_softc_t *softc;
+{
+	ipf_dstl_softc_t *softd;
+	int i;
+
+	KMALLOC(softd, ipf_dstl_softc_t *);
+	if (softd == NULL) {
+		IPFERROR(120028);
+		return NULL;
+	}
+
+	bzero((char *)softd, sizeof(*softd));
+	for (i = 0; i <= IPL_LOGMAX; i++)
+		softd->tails[i] = &softd->dstlist[i];
+
+	return softd;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_soft_destroy                                    */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* For destination lists, the only thing we have to do when destroying the  */
+/* soft context is free it!                                                 */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_soft_destroy(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_dstl_softc_t *softd = arg;
+
+	KFREE(softd);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_soft_init                                       */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* There is currently no soft context for destination list management.      */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_soft_init(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_soft_fini                                       */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*                                                                          */
+/* There is currently no soft context for destination list management.      */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_soft_fini(softc, arg)
+	ipf_main_softc_t *softc;
+	void *arg;
+{
+	ipf_dstl_softc_t *softd = arg;
+	int i;
+
+	for (i = -1; i <= IPL_LOGMAX; i++) {
+		while (softd->dstlist[i + 1] != NULL) {
+			ipf_dstlist_table_remove(softc, softd,
+						 softd->dstlist[i + 1]);
+		}
+	}
+
+	ASSERT(softd->stats.ipls_numderefnodes == 0);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_addr_find                                       */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg1(I)  - pointer to local context to use                  */
+/*              arg2(I)  - pointer to local context to use                  */
+/*              arg3(I)  - pointer to local context to use                  */
+/*              arg4(I)  - pointer to local context to use                  */
+/*                                                                          */
+/* There is currently no such thing as searching a destination list for an  */
+/* address so this function becomes a no-op. Its presence is required as    */
+/* ipf_lookup_res_name() stores the "addr_find" function pointer in the     */
+/* pointer passed in to it as funcptr, although it could be a generic null- */
+/* op function rather than a specific one.                                  */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+static int
+ipf_dstlist_addr_find(softc, arg1, arg2, arg3, arg4)
+	ipf_main_softc_t *softc;
+	void *arg1, *arg3;
+	int arg2;
+	u_int arg4;
+{
+	return -1;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_flush                                           */
+/* Returns:     int      - number of objects deleted                        */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              fop(I)   - pointer to lookup flush operation data           */
+/*                                                                          */
+/* Flush all of the destination tables that match the data passed in with   */
+/* the iplookupflush_t. There are two ways to match objects: the device for */
+/* which they are to be used with and their name.                           */
+/* ------------------------------------------------------------------------ */
+static size_t
+ipf_dstlist_flush(softc, arg, fop)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupflush_t *fop;
+{
+	ipf_dstl_softc_t *softd = arg;
+	ippool_dst_t *node, *next;
+	int n, i;
+
+	for (n = 0, i = -1; i <= IPL_LOGMAX; i++) {
+		if (fop->iplf_unit != IPLT_ALL && fop->iplf_unit != i)
+			continue;
+		for (node = softd->dstlist[i + 1]; node != NULL; node = next) {
+			next = node->ipld_next;
+
+			if ((*fop->iplf_name != '\0') &&
+			    strncmp(fop->iplf_name, node->ipld_name,
+				    FR_GROUPLEN))
+				continue;
+
+			ipf_dstlist_table_remove(softc, softd, node);
+			n++;
+		}
+	}
+	return n;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_iter_deref                                      */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              otype(I) - type of data structure to iterate through        */
+/*              unit(I)  - device we are working with                       */
+/*              data(I)  - address of object in kernel space                */
+/*                                                                          */
+/* This function is called when the iteration token is being free'd and is  */
+/* responsible for dropping the reference count of the structure it points  */
+/* to.                                                                      */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_iter_deref(softc, arg, otype, unit, data)
+	ipf_main_softc_t *softc;
+	void *arg;
+	int otype, unit;
+	void *data;
+{
+	if (data == NULL) {
+		IPFERROR(120001);
+		return EINVAL;
+	}
+
+	if (unit < -1 || unit > IPL_LOGMAX) {
+		IPFERROR(120002);
+		return EINVAL;
+	}
+
+	switch (otype)
+	{
+	case IPFLOOKUPITER_LIST :
+		ipf_dstlist_table_deref(softc, arg, (ippool_dst_t *)data);
+		break;
+
+	case IPFLOOKUPITER_NODE :
+		ipf_dstlist_node_deref(arg, (ipf_dstnode_t *)data);
+		break;
+	}
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_iter_next                                       */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*              uid(I)   - uid of process doing the ioctl                   */
+/*                                                                          */
+/* This function is responsible for either selecting the next destination   */
+/* list or node on a destination list to be returned as a user process      */
+/* iterates through the list of destination lists or nodes.                 */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_iter_next(softc, arg, token, iter)
+	ipf_main_softc_t *softc;
+	void *arg;
+	ipftoken_t *token;
+	ipflookupiter_t *iter;
+{
+	ipf_dstnode_t zn, *nextnode = NULL, *node = NULL;
+	ippool_dst_t zero, *next = NULL, *dsttab = NULL;
+	ipf_dstl_softc_t *softd = arg;
+	int err = 0;
+	void *hint;
+
+	switch (iter->ili_otype)
+	{
+	case IPFLOOKUPITER_LIST :
+		dsttab = token->ipt_data;
+		if (dsttab == NULL) {
+			next = softd->dstlist[(int)iter->ili_unit + 1];
+		} else {
+			next = dsttab->ipld_next;
+		}
+
+		if (next != NULL) {
+			ATOMIC_INC32(next->ipld_ref);
+			token->ipt_data = next;
+			hint = next->ipld_next;
+		} else {
+			bzero((char *)&zero, sizeof(zero));
+			next = &zero;
+			token->ipt_data = NULL;
+			hint = NULL;
+		}
+		break;
+
+	case IPFLOOKUPITER_NODE :
+		node = token->ipt_data;
+		if (node == NULL) {
+			dsttab = ipf_dstlist_table_find(arg, iter->ili_unit,
+							iter->ili_name);
+			if (dsttab == NULL) {
+				IPFERROR(120004);
+				err = ESRCH;
+				nextnode = NULL;
+			} else {
+				if (dsttab->ipld_dests == NULL)
+					nextnode = NULL;
+				else
+					nextnode = *dsttab->ipld_dests;
+				dsttab = NULL;
+			}
+		} else {
+			nextnode = node->ipfd_next;
+		}
+
+		if (nextnode != NULL) {
+			MUTEX_ENTER(&nextnode->ipfd_lock);
+			nextnode->ipfd_ref++;
+			MUTEX_EXIT(&nextnode->ipfd_lock);
+			token->ipt_data = nextnode;
+			hint = nextnode->ipfd_next;
+		} else {
+			bzero((char *)&zn, sizeof(zn));
+			nextnode = &zn;
+			token->ipt_data = NULL;
+			hint = NULL;
+		}
+		break;
+	default :
+		IPFERROR(120003);
+		err = EINVAL;
+		break;
+	}
+
+	if (err != 0)
+		return err;
+
+	switch (iter->ili_otype)
+	{
+	case IPFLOOKUPITER_LIST :
+		if (dsttab != NULL)
+			ipf_dstlist_table_deref(softc, arg, dsttab);
+		err = COPYOUT(next, iter->ili_data, sizeof(*next));
+		if (err != 0) {
+			IPFERROR(120005);
+			err = EFAULT;
+		}
+		break;
+
+	case IPFLOOKUPITER_NODE :
+		if (node != NULL)
+			ipf_dstlist_node_deref(arg, node);
+		err = COPYOUT(nextnode, iter->ili_data, sizeof(*nextnode));
+		if (err != 0) {
+			IPFERROR(120006);
+			err = EFAULT;
+		}
+		break;
+	}
+
+	if (hint == NULL)
+		ipf_token_mark_complete(token);
+
+	return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_node_add                                        */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*              uid(I)   - uid of process doing the ioctl                   */
+/* Locks:       WRITE(ipf_poolrw)                                           */
+/*                                                                          */
+/* Add a new node to a destination list. To do this, we only copy in the    */
+/* frdest_t structure because that contains the only data required from the */
+/* application to create a new node. The frdest_t doesn't contain the name  */
+/* itself. When loading filter rules, fd_name is a 'pointer' to the name.   */
+/* In this case, the 'pointer' does not work, instead it is the length of   */
+/* the name and the name is immediately following the frdest_t structure.   */
+/* fd_name must include the trailing \0, so it should be strlen(str) + 1.   */
+/* For simple sanity checking, an upper bound on the size of fd_name is     */
+/* imposed - 128.                                                          */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_node_add(softc, arg, op, uid)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+	int uid;
+{
+	ipf_dstl_softc_t *softd = arg;
+	ipf_dstnode_t *node, **nodes;
+	ippool_dst_t *d;
+	frdest_t dest;
+	int err;
+
+	if (op->iplo_size < sizeof(frdest_t)) {
+		IPFERROR(120007);
+		return EINVAL;
+	}
+
+	err = COPYIN(op->iplo_struct, &dest, sizeof(dest));
+	if (err != 0) {
+		IPFERROR(120009);
+		return EFAULT;
+	}
+
+	d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+	if (d == NULL) {
+		IPFERROR(120010);
+		return ESRCH;
+	}
+
+	switch (dest.fd_addr.adf_family)
+	{
+	case AF_INET :
+	case AF_INET6 :
+		break;
+	default :
+		IPFERROR(120019);
+		return EINVAL;
+	}
+
+	if (dest.fd_name < -1 || dest.fd_name > 128) {
+		IPFERROR(120018);
+		return EINVAL;
+	}
+
+	KMALLOCS(node, ipf_dstnode_t *, sizeof(*node) + dest.fd_name);
+	if (node == NULL) {
+		softd->stats.ipls_nomem++;
+		IPFERROR(120008);
+		return ENOMEM;
+	}
+	bzero((char *)node, sizeof(*node) + dest.fd_name);
+
+	bcopy(&dest, &node->ipfd_dest, sizeof(dest));
+	node->ipfd_size = sizeof(*node) + dest.fd_name;
+
+	if (dest.fd_name > 0) {
+		/*
+		 * fd_name starts out as the length of the string to copy
+		 * in (including \0) and ends up being the offset from
+		 * fd_names (0).
+		 */
+		err = COPYIN((char *)op->iplo_struct + sizeof(dest),
+			     node->ipfd_names, dest.fd_name);
+		if (err != 0) {
+			IPFERROR(120017);
+			KFREES(node, node->ipfd_size);
+			return EFAULT;
+		}
+		node->ipfd_dest.fd_name = 0;
+	} else {
+		node->ipfd_dest.fd_name = -1;
+	}
+
+	if (d->ipld_nodes == d->ipld_maxnodes) {
+		KMALLOCS(nodes, ipf_dstnode_t **,
+			 sizeof(*nodes) * (d->ipld_maxnodes + 1));
+		if (nodes == NULL) {
+			softd->stats.ipls_nomem++;
+			IPFERROR(120022);
+			KFREES(node, node->ipfd_size);
+			return ENOMEM;
+		}
+		if (d->ipld_dests != NULL) {
+			bcopy(d->ipld_dests, nodes,
+			      sizeof(*nodes) * d->ipld_maxnodes);
+			KFREES(d->ipld_dests, sizeof(*nodes) * d->ipld_nodes);
+			nodes[0]->ipfd_pnext = nodes;
+		}
+		d->ipld_dests = nodes;
+		d->ipld_maxnodes++;
+	}
+	d->ipld_dests[d->ipld_nodes] = node;
+	d->ipld_nodes++;
+
+	if (d->ipld_nodes == 1) {
+		node->ipfd_pnext = d->ipld_dests;
+	} else if (d->ipld_nodes > 1) {
+		node->ipfd_pnext = &d->ipld_dests[d->ipld_nodes - 2]->ipfd_next;
+	}
+	*node->ipfd_pnext = node;
+
+	MUTEX_INIT(&node->ipfd_lock, "ipf dst node lock");
+	node->ipfd_uid = uid;
+	node->ipfd_ref = 1;
+	if (node->ipfd_dest.fd_name == 0)
+		(void) ipf_resolvedest(softc, node->ipfd_names,
+				       &node->ipfd_dest, AF_INET);
+#ifdef USE_INET6
+	if (node->ipfd_dest.fd_name == 0 &&
+	    node->ipfd_dest.fd_ptr == (void *)-1)
+		(void) ipf_resolvedest(softc, node->ipfd_names,
+				       &node->ipfd_dest, AF_INET6);
+#endif
+
+	softd->stats.ipls_numnodes++;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_node_deref                                      */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  arg(I)  - pointer to local context to use                   */
+/*              node(I) - pointer to destionation node to free              */
+/*                                                                          */
+/* Dereference the use count by one. If it drops to zero then we can assume */
+/* that it has been removed from any lists/tables and is ripe for freeing.  */
+/* The pointer to context is required for the purpose of maintaining        */
+/* statistics.                                                              */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_node_deref(arg, node)
+	void *arg;
+	ipf_dstnode_t *node;
+{
+	ipf_dstl_softc_t *softd = arg;
+	int ref;
+
+	MUTEX_ENTER(&node->ipfd_lock);
+	ref = --node->ipfd_ref;
+	MUTEX_EXIT(&node->ipfd_lock);
+
+	if (ref > 0)
+		return 0;
+
+	if ((node->ipfd_flags & IPDST_DELETE) != 0)
+		softd->stats.ipls_numderefnodes--;
+	MUTEX_DESTROY(&node->ipfd_lock);
+	KFREES(node, node->ipfd_size);
+	softd->stats.ipls_numnodes--;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_node_del                                        */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*              uid(I)   - uid of process doing the ioctl                   */
+/*                                                                          */
+/* Look for a matching destination node on the named table and free it if   */
+/* found. Because the name embedded in the frdest_t is variable in length,  */
+/* it is necessary to allocate some memory locally, to complete this op.    */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_node_del(softc, arg, op, uid)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+	int uid;
+{
+	ipf_dstl_softc_t *softd = arg;
+	ipf_dstnode_t *node;
+	frdest_t frd, *temp;
+	ippool_dst_t *d;
+	size_t size;
+	int err;
+
+	d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+	if (d == NULL) {
+		IPFERROR(120012);
+		return ESRCH;
+	}
+
+	err = COPYIN(op->iplo_struct, &frd, sizeof(frd));
+	if (err != 0) {
+		IPFERROR(120011);
+		return EFAULT;
+	}
+
+	size = sizeof(*temp) + frd.fd_name;
+	KMALLOCS(temp, frdest_t *, size);
+	if (temp == NULL) {
+		softd->stats.ipls_nomem++;
+		IPFERROR(120026);
+		return ENOMEM;
+	}
+
+	err = COPYIN(op->iplo_struct, temp, size);
+	if (err != 0) {
+		IPFERROR(120027);
+		return EFAULT;
+	}
+
+	MUTEX_ENTER(&d->ipld_lock);
+	for (node = *d->ipld_dests; node != NULL; node = node->ipfd_next) {
+		if ((uid != 0) && (node->ipfd_uid != uid))
+			continue;
+		if (node->ipfd_size != size)
+			continue;
+		if (!bcmp(&node->ipfd_dest.fd_ip6, &frd.fd_ip6,
+			  size - offsetof(frdest_t, fd_ip6))) {
+			ipf_dstlist_node_free(softd, d, node);
+			MUTEX_EXIT(&d->ipld_lock);
+			KFREES(temp, size);
+			return 0;
+		}
+	}
+	MUTEX_EXIT(&d->ipld_lock);
+	KFREES(temp, size);
+
+	return ESRCH;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_node_free                                       */
+/* Returns:     Nil                                                         */
+/* Parameters:  softd(I) - pointer to the destination list context          */
+/*              d(I)     - pointer to destination list                      */
+/*              node(I)  - pointer to node to free                          */
+/* Locks:       MUTEX(ipld_lock) or WRITE(ipf_poolrw)                       */
+/*                                                                          */
+/* Free the destination node by first removing it from any lists and then   */
+/* checking if this was the last reference held to the object. While the    */
+/* array of pointers to nodes is compacted, its size isn't reduced (by way  */
+/* of allocating a new smaller one and copying) because the belief is that  */
+/* it is likely the array will again reach that size.                       */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_node_free(softd, d, node)
+	ipf_dstl_softc_t *softd;
+	ippool_dst_t *d;
+	ipf_dstnode_t *node;
+{
+	int i;
+
+	/*
+	 * Compact the array of pointers to nodes.
+	 */
+	for (i = 0; i < d->ipld_nodes; i++)
+		if (d->ipld_dests[i] == node)
+			break;
+	if (d->ipld_nodes - i > 1) {
+		bcopy(&d->ipld_dests[i + 1], &d->ipld_dests[i],
+		      sizeof(*d->ipld_dests) * (d->ipld_nodes - i - 1));
+	}
+	d->ipld_nodes--;
+
+	if (node->ipfd_pnext != NULL)
+		*node->ipfd_pnext = node->ipfd_next;
+	if (node->ipfd_next != NULL)
+		node->ipfd_next->ipfd_pnext = node->ipfd_pnext;
+	node->ipfd_pnext = NULL;
+	node->ipfd_next = NULL;
+
+	if ((node->ipfd_flags & IPDST_DELETE) == 0) {
+		softd->stats.ipls_numderefnodes++;
+		node->ipfd_flags |= IPDST_DELETE;
+	}
+
+	ipf_dstlist_node_deref(softd, node);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_stats_get                                       */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*                                                                          */
+/* Return the current statistics for destination lists. This may be for all */
+/* of them or just information pertaining to a particular table.            */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+static int
+ipf_dstlist_stats_get(softc, arg, op)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+{
+	ipf_dstl_softc_t *softd = arg;
+	ipf_dstl_stat_t stats;
+	int unit, i, err = 0;
+
+	if (op->iplo_size != sizeof(ipf_dstl_stat_t)) {
+		IPFERROR(120023);
+		return EINVAL;
+	}
+
+	stats = softd->stats;
+	unit = op->iplo_unit;
+	if (unit == IPL_LOGALL) {
+		for (i = 0; i <= IPL_LOGMAX; i++)
+			stats.ipls_list[i] = softd->dstlist[i];
+	} else if (unit >= 0 && unit <= IPL_LOGMAX) {
+		void *ptr;
+
+		if (op->iplo_name[0] != '\0')
+			ptr = ipf_dstlist_table_find(softd, unit,
+						     op->iplo_name);
+		else
+			ptr = softd->dstlist[unit + 1];
+		stats.ipls_list[unit] = ptr;
+	} else {
+		IPFERROR(120024);
+		err = EINVAL;
+	}
+
+	if (err == 0) {
+		err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
+		if (err != 0) {
+			IPFERROR(120025);
+			return EFAULT;
+		}
+	}
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_table_add                                       */
+/* Returns:     int      - 0 = success, else error                          */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*                                                                          */
+/* Add a new destination table to the list of those available for the given */
+/* device. Because we seldom operate on these objects (find/add/delete),    */
+/* they are just kept in a simple linked list.                              */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_table_add(softc, arg, op)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+{
+	ipf_dstl_softc_t *softd = arg;
+	ippool_dst_t user, *d, *new;
+	int unit, err;
+
+	d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+	if (d != NULL) {
+		IPFERROR(120013);
+		return EEXIST;
+	}
+
+	err = COPYIN(op->iplo_struct, &user, sizeof(user));
+	if (err != 0) {
+		IPFERROR(120021);
+		return EFAULT;
+	}
+
+	KMALLOC(new, ippool_dst_t *);
+	if (new == NULL) {
+		softd->stats.ipls_nomem++;
+		IPFERROR(120014);
+		return ENOMEM;
+	}
+	bzero((char *)new, sizeof(*new));
+
+	MUTEX_INIT(&new->ipld_lock, "ipf dst table lock");
+
+	strncpy(new->ipld_name, op->iplo_name, FR_GROUPLEN);
+	unit = op->iplo_unit;
+	new->ipld_unit = unit;
+	new->ipld_policy = user.ipld_policy;
+	new->ipld_seed = ipf_random();
+	new->ipld_ref = 1;
+
+	new->ipld_pnext = softd->tails[unit + 1];
+	*softd->tails[unit + 1] = new;
+	softd->tails[unit + 1] = &new->ipld_next;
+	softd->stats.ipls_numlists++;
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_table_del                                       */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*                                                                          */
+/* Find a named destinstion list table and delete it. If there are other    */
+/* references to it, the caller isn't told.                                 */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_table_del(softc, arg, op)
+	ipf_main_softc_t *softc;
+	void *arg;
+	iplookupop_t *op;
+{
+	ippool_dst_t *d;
+
+	d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+	if (d == NULL) {
+		IPFERROR(120015);
+		return ESRCH;
+	}
+
+	if (d->ipld_dests != NULL) {
+		IPFERROR(120016);
+		return EBUSY;
+	}
+
+	ipf_dstlist_table_remove(softc, arg, d);
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_table_remove                                    */
+/* Returns:     Nil                                                         */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              softd(I) - pointer to the destination list context          */
+/*              d(I)     - pointer to destination list                      */
+/*                                                                          */
+/* Remove a given destination list from existance. While the IPDST_DELETE   */
+/* flag is set every time we call this function and the reference count is  */
+/* non-zero, the "numdereflists" counter is always incremented because the  */
+/* decision about whether it will be freed or not is not made here. This    */
+/* means that the only action the code can take here is to treat it as if   */
+/* it will become a detached.                                               */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_table_remove(softc, softd, d)
+	ipf_main_softc_t *softc;
+	ipf_dstl_softc_t *softd;
+	ippool_dst_t *d;
+{
+
+	if (softd->tails[d->ipld_unit + 1] == &d->ipld_next)
+		softd->tails[d->ipld_unit + 1] = d->ipld_pnext;
+
+	if (d->ipld_pnext != NULL)
+		*d->ipld_pnext = d->ipld_next;
+	if (d->ipld_next != NULL)
+		d->ipld_next->ipld_pnext = d->ipld_pnext;
+	d->ipld_pnext = NULL;
+	d->ipld_next = NULL;
+
+	ipf_dstlist_table_clearnodes(softd, d);
+
+	softd->stats.ipls_numdereflists++;
+	d->ipld_flags |= IPDST_DELETE;
+
+	ipf_dstlist_table_deref(softc, softd, d);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_table_free                                      */
+/* Returns:     Nil                                                         */
+/* Parameters:  softd(I) - pointer to the destination list context          */
+/*              d(I)   - pointer to destination list                        */
+/*                                                                          */
+/* Free up a destination list data structure and any other memory that was  */
+/* directly allocated as part of creating it. Individual destination list   */
+/* nodes are not freed. It is assumed the caller will have already emptied  */
+/* the destination list.                                                    */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_table_free(softd, d)
+	ipf_dstl_softc_t *softd;
+	ippool_dst_t *d;
+{
+	MUTEX_DESTROY(&d->ipld_lock);
+
+	if ((d->ipld_flags & IPDST_DELETE) != 0)
+		softd->stats.ipls_numdereflists--;
+	softd->stats.ipls_numlists--;
+
+	if (d->ipld_dests != NULL) {
+		KFREES(d->ipld_dests,
+		       d->ipld_maxnodes * sizeof(*d->ipld_dests));
+	}
+
+	KFREE(d);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function:    ipf_dstlist_table_deref                                     */
+/* Returns:     int - 0 = success, else error                               */
+/* Parameters:  softc(I) - pointer to soft context main structure           */
+/*              arg(I)   - pointer to local context to use                  */
+/*              op(I)    - pointer to lookup operation data                 */
+/*                                                                          */
+/* Drops the reference count on a destination list table object and free's  */
+/* it if 0 has been reached.                                                */
+/* ------------------------------------------------------------------------ */

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201308201324.r7KDOiOr025410>