1006 lines
31 KiB
C
1006 lines
31 KiB
C
/* $NetBSD: ip_lookup.c,v 1.2 2012/07/22 14:27:35 darrenr Exp $ */
|
|
|
|
/*
|
|
* 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/param.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <sys/file.h>
|
|
#if __FreeBSD_version >= 220000 && defined(_KERNEL)
|
|
# include <sys/fcntl.h>
|
|
# include <sys/filio.h>
|
|
#else
|
|
# include <sys/ioctl.h>
|
|
#endif
|
|
#if !defined(_KERNEL)
|
|
# include <stdio.h>
|
|
# include <string.h>
|
|
# include <stdlib.h>
|
|
# define _KERNEL
|
|
# ifdef __OpenBSD__
|
|
struct file;
|
|
# endif
|
|
# include <sys/uio.h>
|
|
# undef _KERNEL
|
|
#endif
|
|
#include <sys/socket.h>
|
|
#include <net/if.h>
|
|
#if defined(__FreeBSD__)
|
|
# include <sys/cdefs.h>
|
|
# include <sys/proc.h>
|
|
#endif
|
|
#if defined(_KERNEL)
|
|
# include <sys/systm.h>
|
|
# if !defined(__SVR4) && !defined(__svr4__)
|
|
# include <sys/mbuf.h>
|
|
# endif
|
|
#else
|
|
# include "ipf.h"
|
|
#endif
|
|
#include <netinet/in.h>
|
|
|
|
#include "netinet/ip_compat.h"
|
|
#include "netinet/ip_fil.h"
|
|
#include "netinet/ip_lookup.h"
|
|
#include "netinet/ip_pool.h"
|
|
#include "netinet/ip_htable.h"
|
|
#include "netinet/ip_dstlist.h"
|
|
/* END OF INCLUDES */
|
|
|
|
#if !defined(lint)
|
|
static const char rcsid[] = "@(#)Id: ip_lookup.c,v 1.1.1.2 2012/07/22 13:44:18 darrenr Exp $";
|
|
#endif
|
|
|
|
/*
|
|
* In this file, ip_pool.c, ip_htable.c and ip_dstlist.c, you will find the
|
|
* range for unit is [-1,IPL_LOGMAX]. The -1 is considered to be a valid number
|
|
* and represents a "wildcard" or "all" units (IPL_LOGALL). The reason for not
|
|
* starting the numbering at 0 is because the numbers [0,IPL_LOGMAX] correspond
|
|
* to the minor device number for their respective device. Thus where there is
|
|
* array indexing on the unit, +1 is used to map [-1.IPL_LOGMAX] to
|
|
* [0.POOL_LOOKUP_MAX].
|
|
*/
|
|
static int ipf_lookup_addnode __P((ipf_main_softc_t *, caddr_t, int));
|
|
static int ipf_lookup_delnode __P((ipf_main_softc_t *, caddr_t, int));
|
|
static int ipf_lookup_addtable __P((ipf_main_softc_t *, caddr_t));
|
|
static int ipf_lookup_deltable __P((ipf_main_softc_t *, caddr_t));
|
|
static int ipf_lookup_stats __P((ipf_main_softc_t *, caddr_t));
|
|
static int ipf_lookup_flush __P((ipf_main_softc_t *, caddr_t));
|
|
static int ipf_lookup_iterate __P((ipf_main_softc_t *, void *, int, void *));
|
|
static int ipf_lookup_deltok __P((ipf_main_softc_t *, void *, int, void *));
|
|
|
|
#define MAX_BACKENDS 3
|
|
static ipf_lookup_t *backends[MAX_BACKENDS] = {
|
|
&ipf_pool_backend,
|
|
&ipf_htable_backend,
|
|
&ipf_dstlist_backend
|
|
};
|
|
|
|
|
|
typedef struct ipf_lookup_softc_s {
|
|
void *ipf_back[MAX_BACKENDS];
|
|
} ipf_lookup_softc_t;
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_init */
|
|
/* Returns: int - 0 = success, else error */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* */
|
|
/* Initialise all of the subcomponents of the lookup infrstructure. */
|
|
/* ------------------------------------------------------------------------ */
|
|
void *
|
|
ipf_lookup_soft_create(softc)
|
|
ipf_main_softc_t *softc;
|
|
{
|
|
ipf_lookup_softc_t *softl;
|
|
ipf_lookup_t **l;
|
|
int i;
|
|
|
|
KMALLOC(softl, ipf_lookup_softc_t *);
|
|
if (softl == NULL)
|
|
return NULL;
|
|
|
|
bzero((char *)softl, sizeof(*softl));
|
|
|
|
for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
|
|
softl->ipf_back[i] = (*(*l)->ipfl_create)(softc);
|
|
if (softl->ipf_back[i] == NULL) {
|
|
ipf_lookup_soft_destroy(softc, softl);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return softl;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_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 */
|
|
/* */
|
|
/* Initialise all of the subcomponents of the lookup infrstructure. */
|
|
/* ------------------------------------------------------------------------ */
|
|
int
|
|
ipf_lookup_soft_init(softc, arg)
|
|
ipf_main_softc_t *softc;
|
|
void *arg;
|
|
{
|
|
ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
|
|
int err = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_BACKENDS; i++) {
|
|
err = (*backends[i]->ipfl_init)(softc, softl->ipf_back[i]);
|
|
if (err != 0)
|
|
break;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_soft_fini */
|
|
/* Returns: int - 0 = success, else error */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* arg(I) - pointer to local context to use */
|
|
/* */
|
|
/* Call the fini function in each backend to cleanup all allocated data. */
|
|
/* ------------------------------------------------------------------------ */
|
|
int
|
|
ipf_lookup_soft_fini(softc, arg)
|
|
ipf_main_softc_t *softc;
|
|
void *arg;
|
|
{
|
|
ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_BACKENDS; i++) {
|
|
if (softl->ipf_back[i] != NULL)
|
|
(*backends[i]->ipfl_fini)(softc,
|
|
softl->ipf_back[i]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_expire */
|
|
/* Returns: Nil */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* */
|
|
/* Step through each of the backends and call their expire functions, */
|
|
/* allowing them to delete any lifetime limited data. */
|
|
/* ------------------------------------------------------------------------ */
|
|
void
|
|
ipf_lookup_expire(softc)
|
|
ipf_main_softc_t *softc;
|
|
{
|
|
ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
|
|
int i;
|
|
|
|
WRITE_ENTER(&softc->ipf_poolrw);
|
|
for (i = 0; i < MAX_BACKENDS; i++)
|
|
(*backends[i]->ipfl_expire)(softc, softl->ipf_back[i]);
|
|
RWLOCK_EXIT(&softc->ipf_poolrw);
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_softc_destroy */
|
|
/* Returns: int - 0 = success, else error */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* arg(I) - pointer to local context to use */
|
|
/* */
|
|
/* Free up all pool related memory that has been allocated whilst IPFilter */
|
|
/* has been running. Also, do any other deinitialisation required such */
|
|
/* ipf_lookup_init() can be called again, safely. */
|
|
/* ------------------------------------------------------------------------ */
|
|
void
|
|
ipf_lookup_soft_destroy(softc, arg)
|
|
ipf_main_softc_t *softc;
|
|
void *arg;
|
|
{
|
|
ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_BACKENDS; i++) {
|
|
if (softl->ipf_back[i] != NULL)
|
|
(*backends[i]->ipfl_destroy)(softc,
|
|
softl->ipf_back[i]);
|
|
}
|
|
|
|
KFREE(softl);
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_ioctl */
|
|
/* Returns: int - 0 = success, else error */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* arg(I) - pointer to local context to use */
|
|
/* data(IO) - pointer to ioctl data to be copied to/from user */
|
|
/* space. */
|
|
/* cmd(I) - ioctl command number */
|
|
/* mode(I) - file mode bits used with open */
|
|
/* uid(I) - uid of process doing ioctl */
|
|
/* ctx(I) - pointer that represents context for uid */
|
|
/* */
|
|
/* Handle ioctl commands sent to the ioctl device. For the most part, this */
|
|
/* involves just calling another function to handle the specifics of each */
|
|
/* command. */
|
|
/* ------------------------------------------------------------------------ */
|
|
int
|
|
ipf_lookup_ioctl(softc, data, cmd, mode, uid, ctx)
|
|
ipf_main_softc_t *softc;
|
|
caddr_t data;
|
|
ioctlcmd_t cmd;
|
|
int mode, uid;
|
|
void *ctx;
|
|
{
|
|
int err;
|
|
SPL_INT(s);
|
|
|
|
mode = mode; /* LINT */
|
|
|
|
SPL_NET(s);
|
|
|
|
switch (cmd)
|
|
{
|
|
case SIOCLOOKUPADDNODE :
|
|
case SIOCLOOKUPADDNODEW :
|
|
WRITE_ENTER(&softc->ipf_poolrw);
|
|
err = ipf_lookup_addnode(softc, data, uid);
|
|
RWLOCK_EXIT(&softc->ipf_poolrw);
|
|
break;
|
|
|
|
case SIOCLOOKUPDELNODE :
|
|
case SIOCLOOKUPDELNODEW :
|
|
WRITE_ENTER(&softc->ipf_poolrw);
|
|
err = ipf_lookup_delnode(softc, data, uid);
|
|
RWLOCK_EXIT(&softc->ipf_poolrw);
|
|
break;
|
|
|
|
case SIOCLOOKUPADDTABLE :
|
|
WRITE_ENTER(&softc->ipf_poolrw);
|
|
err = ipf_lookup_addtable(softc, data);
|
|
RWLOCK_EXIT(&softc->ipf_poolrw);
|
|
break;
|
|
|
|
case SIOCLOOKUPDELTABLE :
|
|
WRITE_ENTER(&softc->ipf_poolrw);
|
|
err = ipf_lookup_deltable(softc, data);
|
|
RWLOCK_EXIT(&softc->ipf_poolrw);
|
|
break;
|
|
|
|
case SIOCLOOKUPSTAT :
|
|
case SIOCLOOKUPSTATW :
|
|
WRITE_ENTER(&softc->ipf_poolrw);
|
|
err = ipf_lookup_stats(softc, data);
|
|
RWLOCK_EXIT(&softc->ipf_poolrw);
|
|
break;
|
|
|
|
case SIOCLOOKUPFLUSH :
|
|
WRITE_ENTER(&softc->ipf_poolrw);
|
|
err = ipf_lookup_flush(softc, data);
|
|
RWLOCK_EXIT(&softc->ipf_poolrw);
|
|
break;
|
|
|
|
case SIOCLOOKUPITER :
|
|
err = ipf_lookup_iterate(softc, data, uid, ctx);
|
|
break;
|
|
|
|
case SIOCIPFDELTOK :
|
|
err = ipf_lookup_deltok(softc, data, uid, ctx);
|
|
break;
|
|
|
|
default :
|
|
IPFERROR(50001);
|
|
err = EINVAL;
|
|
break;
|
|
}
|
|
SPL_X(s);
|
|
return err;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_addnode */
|
|
/* Returns: int - 0 = success, else error */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* data(I) - pointer to data from ioctl call */
|
|
/* */
|
|
/* Add a new data node to a lookup structure. First, check to see if the */
|
|
/* parent structure refered to by name exists and if it does, then go on to */
|
|
/* add a node to it. */
|
|
/* ------------------------------------------------------------------------ */
|
|
static int
|
|
ipf_lookup_addnode(softc, data, uid)
|
|
ipf_main_softc_t *softc;
|
|
caddr_t data;
|
|
int uid;
|
|
{
|
|
ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
|
|
iplookupop_t op;
|
|
ipf_lookup_t **l;
|
|
int err;
|
|
int i;
|
|
|
|
err = BCOPYIN(data, &op, sizeof(op));
|
|
if (err != 0) {
|
|
IPFERROR(50002);
|
|
return EFAULT;
|
|
}
|
|
|
|
if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
|
|
(op.iplo_unit != IPLT_ALL)) {
|
|
IPFERROR(50003);
|
|
return EINVAL;
|
|
}
|
|
|
|
op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
|
|
|
|
for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
|
|
if (op.iplo_type == (*l)->ipfl_type) {
|
|
err = (*(*l)->ipfl_node_add)(softc,
|
|
softl->ipf_back[i],
|
|
&op, uid);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == MAX_BACKENDS) {
|
|
IPFERROR(50012);
|
|
err = EINVAL;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_delnode */
|
|
/* Returns: int - 0 = success, else error */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* data(I) - pointer to data from ioctl call */
|
|
/* */
|
|
/* Delete a node from a lookup table by first looking for the table it is */
|
|
/* in and then deleting the entry that gets found. */
|
|
/* ------------------------------------------------------------------------ */
|
|
static int
|
|
ipf_lookup_delnode(softc, data, uid)
|
|
ipf_main_softc_t *softc;
|
|
caddr_t data;
|
|
int uid;
|
|
{
|
|
ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
|
|
iplookupop_t op;
|
|
ipf_lookup_t **l;
|
|
int err;
|
|
int i;
|
|
|
|
err = BCOPYIN(data, &op, sizeof(op));
|
|
if (err != 0) {
|
|
IPFERROR(50042);
|
|
return EFAULT;
|
|
}
|
|
|
|
if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
|
|
(op.iplo_unit != IPLT_ALL)) {
|
|
IPFERROR(50013);
|
|
return EINVAL;
|
|
}
|
|
|
|
op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
|
|
|
|
for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
|
|
if (op.iplo_type == (*l)->ipfl_type) {
|
|
err = (*(*l)->ipfl_node_del)(softc, softl->ipf_back[i],
|
|
&op, uid);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == MAX_BACKENDS) {
|
|
IPFERROR(50021);
|
|
err = EINVAL;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_addtable */
|
|
/* Returns: int - 0 = success, else error */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* data(I) - pointer to data from ioctl call */
|
|
/* */
|
|
/* Create a new lookup table, if one doesn't already exist using the name */
|
|
/* for this one. */
|
|
/* ------------------------------------------------------------------------ */
|
|
static int
|
|
ipf_lookup_addtable(softc, data)
|
|
ipf_main_softc_t *softc;
|
|
caddr_t data;
|
|
{
|
|
ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
|
|
iplookupop_t op;
|
|
ipf_lookup_t **l;
|
|
int err, i;
|
|
|
|
err = BCOPYIN(data, &op, sizeof(op));
|
|
if (err != 0) {
|
|
IPFERROR(50022);
|
|
return EFAULT;
|
|
}
|
|
|
|
if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
|
|
(op.iplo_unit != IPLT_ALL)) {
|
|
IPFERROR(50023);
|
|
return EINVAL;
|
|
}
|
|
|
|
op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
|
|
|
|
for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
|
|
if (op.iplo_type == (*l)->ipfl_type) {
|
|
err = (*(*l)->ipfl_table_add)(softc,
|
|
softl->ipf_back[i],
|
|
&op);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == MAX_BACKENDS) {
|
|
IPFERROR(50026);
|
|
err = EINVAL;
|
|
}
|
|
|
|
/*
|
|
* For anonymous pools, copy back the operation struct because in the
|
|
* case of success it will contain the new table's name.
|
|
*/
|
|
if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) {
|
|
err = BCOPYOUT(&op, data, sizeof(op));
|
|
if (err != 0) {
|
|
IPFERROR(50027);
|
|
err = EFAULT;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_deltable */
|
|
/* Returns: int - 0 = success, else error */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* data(I) - pointer to data from ioctl call */
|
|
/* */
|
|
/* Decodes ioctl request to remove a particular hash table or pool and */
|
|
/* calls the relevant function to do the cleanup. */
|
|
/* ------------------------------------------------------------------------ */
|
|
static int
|
|
ipf_lookup_deltable(softc, data)
|
|
ipf_main_softc_t *softc;
|
|
caddr_t data;
|
|
{
|
|
ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
|
|
iplookupop_t op;
|
|
ipf_lookup_t **l;
|
|
int err, i;
|
|
|
|
err = BCOPYIN(data, &op, sizeof(op));
|
|
if (err != 0) {
|
|
IPFERROR(50028);
|
|
return EFAULT;
|
|
}
|
|
|
|
if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
|
|
(op.iplo_unit != IPLT_ALL)) {
|
|
IPFERROR(50029);
|
|
return EINVAL;
|
|
}
|
|
|
|
op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
|
|
|
|
for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
|
|
if (op.iplo_type == (*l)->ipfl_type) {
|
|
err = (*(*l)->ipfl_table_del)(softc,
|
|
softl->ipf_back[i],
|
|
&op);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == MAX_BACKENDS) {
|
|
IPFERROR(50030);
|
|
err = EINVAL;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_stats */
|
|
/* Returns: int - 0 = success, else error */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* data(I) - pointer to data from ioctl call */
|
|
/* */
|
|
/* Copy statistical information from inside the kernel back to user space. */
|
|
/* ------------------------------------------------------------------------ */
|
|
static int
|
|
ipf_lookup_stats(softc, data)
|
|
ipf_main_softc_t *softc;
|
|
caddr_t data;
|
|
{
|
|
ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
|
|
iplookupop_t op;
|
|
ipf_lookup_t **l;
|
|
int err;
|
|
int i;
|
|
|
|
err = BCOPYIN(data, &op, sizeof(op));
|
|
if (err != 0) {
|
|
IPFERROR(50031);
|
|
return EFAULT;
|
|
}
|
|
|
|
if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
|
|
(op.iplo_unit != IPLT_ALL)) {
|
|
IPFERROR(50032);
|
|
return EINVAL;
|
|
}
|
|
|
|
for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
|
|
if (op.iplo_type == (*l)->ipfl_type) {
|
|
err = (*(*l)->ipfl_stats_get)(softc,
|
|
softl->ipf_back[i],
|
|
&op);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == MAX_BACKENDS) {
|
|
IPFERROR(50033);
|
|
err = EINVAL;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_flush */
|
|
/* Returns: int - 0 = success, else error */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* data(I) - pointer to data from ioctl call */
|
|
/* */
|
|
/* A flush is called when we want to flush all the nodes from a particular */
|
|
/* entry in the hash table/pool or want to remove all groups from those. */
|
|
/* ------------------------------------------------------------------------ */
|
|
static int
|
|
ipf_lookup_flush(softc, data)
|
|
ipf_main_softc_t *softc;
|
|
caddr_t data;
|
|
{
|
|
ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
|
|
int err, unit, num, type, i;
|
|
iplookupflush_t flush;
|
|
ipf_lookup_t **l;
|
|
|
|
err = BCOPYIN(data, &flush, sizeof(flush));
|
|
if (err != 0) {
|
|
IPFERROR(50034);
|
|
return EFAULT;
|
|
}
|
|
|
|
unit = flush.iplf_unit;
|
|
if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) {
|
|
IPFERROR(50035);
|
|
return EINVAL;
|
|
}
|
|
|
|
flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
|
|
|
|
type = flush.iplf_type;
|
|
IPFERROR(50036);
|
|
err = EINVAL;
|
|
num = 0;
|
|
|
|
for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
|
|
if (type == (*l)->ipfl_type || type == IPLT_ALL) {
|
|
err = 0;
|
|
num += (*(*l)->ipfl_flush)(softc,
|
|
softl->ipf_back[i],
|
|
&flush);
|
|
}
|
|
}
|
|
|
|
if (err == 0) {
|
|
flush.iplf_count = num;
|
|
err = BCOPYOUT(&flush, data, sizeof(flush));
|
|
if (err != 0) {
|
|
IPFERROR(50037);
|
|
err = EFAULT;
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_delref */
|
|
/* Returns: void */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* type(I) - table type to operate on */
|
|
/* ptr(I) - pointer to object to remove reference for */
|
|
/* */
|
|
/* This function organises calling the correct deref function for a given */
|
|
/* type of object being passed into it. */
|
|
/* ------------------------------------------------------------------------ */
|
|
void
|
|
ipf_lookup_deref(softc, type, ptr)
|
|
ipf_main_softc_t *softc;
|
|
int type;
|
|
void *ptr;
|
|
{
|
|
ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
|
|
int i;
|
|
|
|
if (ptr == NULL)
|
|
return;
|
|
|
|
for (i = 0; i < MAX_BACKENDS; i++) {
|
|
if (type == backends[i]->ipfl_type) {
|
|
WRITE_ENTER(&softc->ipf_poolrw);
|
|
(*backends[i]->ipfl_table_deref)(softc,
|
|
softl->ipf_back[i],
|
|
ptr);
|
|
RWLOCK_EXIT(&softc->ipf_poolrw);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_iterate */
|
|
/* Returns: int - 0 = success, else error */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* data(I) - pointer to data from ioctl call */
|
|
/* uid(I) - uid of caller */
|
|
/* ctx(I) - pointer to give the uid context */
|
|
/* */
|
|
/* Decodes ioctl request to step through either hash tables or pools. */
|
|
/* ------------------------------------------------------------------------ */
|
|
static int
|
|
ipf_lookup_iterate(softc, data, uid, ctx)
|
|
ipf_main_softc_t *softc;
|
|
void *data;
|
|
int uid;
|
|
void *ctx;
|
|
{
|
|
ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
|
|
ipflookupiter_t iter;
|
|
ipftoken_t *token;
|
|
int err, i;
|
|
SPL_INT(s);
|
|
|
|
err = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_LOOKUPITER);
|
|
if (err != 0)
|
|
return err;
|
|
|
|
if (iter.ili_unit < IPL_LOGALL && iter.ili_unit > IPL_LOGMAX) {
|
|
IPFERROR(50038);
|
|
return EINVAL;
|
|
}
|
|
|
|
if (iter.ili_ival != IPFGENITER_LOOKUP) {
|
|
IPFERROR(50039);
|
|
return EINVAL;
|
|
}
|
|
|
|
SPL_SCHED(s);
|
|
token = ipf_token_find(softc, iter.ili_key, uid, ctx);
|
|
if (token == NULL) {
|
|
SPL_X(s);
|
|
IPFERROR(50040);
|
|
return ESRCH;
|
|
}
|
|
|
|
for (i = 0; i < MAX_BACKENDS; i++) {
|
|
if (iter.ili_type == backends[i]->ipfl_type) {
|
|
err = (*backends[i]->ipfl_iter_next)(softc,
|
|
softl->ipf_back[i],
|
|
token, &iter);
|
|
break;
|
|
}
|
|
}
|
|
SPL_X(s);
|
|
|
|
if (i == MAX_BACKENDS) {
|
|
IPFERROR(50041);
|
|
err = EINVAL;
|
|
}
|
|
|
|
WRITE_ENTER(&softc->ipf_tokens);
|
|
ipf_token_deref(softc, token);
|
|
RWLOCK_EXIT(&softc->ipf_tokens);
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_iterderef */
|
|
/* Returns: void */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* type(I) - backend type to iterate through */
|
|
/* data(I) - pointer to data from ioctl call */
|
|
/* */
|
|
/* Decodes ioctl request to remove a particular hash table or pool and */
|
|
/* calls the relevant function to do the cleanup. */
|
|
/* Because each of the backend types has a different data structure, */
|
|
/* iteration is limited to one type at a time (i.e. it is not permitted to */
|
|
/* go on from pool types to hash types as part of the "get next".) */
|
|
/* ------------------------------------------------------------------------ */
|
|
void
|
|
ipf_lookup_iterderef(softc, type, data)
|
|
ipf_main_softc_t *softc;
|
|
u_32_t type;
|
|
void *data;
|
|
{
|
|
ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
|
|
struct iplookupiterkey *lkey;
|
|
iplookupiterkey_t key;
|
|
int i;
|
|
|
|
key.ilik_key = type;
|
|
lkey = &key.ilik_unstr;
|
|
|
|
if (lkey->ilik_ival != IPFGENITER_LOOKUP)
|
|
return;
|
|
|
|
WRITE_ENTER(&softc->ipf_poolrw);
|
|
|
|
for (i = 0; i < MAX_BACKENDS; i++) {
|
|
if (lkey->ilik_type == backends[i]->ipfl_type) {
|
|
(*backends[i]->ipfl_iter_deref)(softc,
|
|
softl->ipf_back[i],
|
|
lkey->ilik_otype,
|
|
lkey->ilik_unit,
|
|
data);
|
|
break;
|
|
}
|
|
}
|
|
RWLOCK_EXIT(&softc->ipf_poolrw);
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_deltok */
|
|
/* Returns: int - 0 = success, else error */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* data(I) - pointer to data from ioctl call */
|
|
/* uid(I) - uid of caller */
|
|
/* ctx(I) - pointer to give the uid context */
|
|
/* */
|
|
/* Deletes the token identified by the combination of (type,uid,ctx) */
|
|
/* "key" is a combination of the table type, iterator type and the unit for */
|
|
/* which the token was being used. */
|
|
/* ------------------------------------------------------------------------ */
|
|
int
|
|
ipf_lookup_deltok(softc, data, uid, ctx)
|
|
ipf_main_softc_t *softc;
|
|
void *data;
|
|
int uid;
|
|
void *ctx;
|
|
{
|
|
int error, key;
|
|
SPL_INT(s);
|
|
|
|
SPL_SCHED(s);
|
|
error = BCOPYIN(data, &key, sizeof(key));
|
|
if (error == 0)
|
|
error = ipf_token_del(softc, key, uid, ctx);
|
|
SPL_X(s);
|
|
return error;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_res_num */
|
|
/* Returns: void * - NULL = failure, else success. */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* unit(I) - device for which this is for */
|
|
/* type(I) - type of lookup these parameters are for. */
|
|
/* number(I) - table number to use when searching */
|
|
/* funcptr(IO) - pointer to pointer for storing IP address */
|
|
/* searching function. */
|
|
/* */
|
|
/* Search for the "table" number passed in amongst those configured for */
|
|
/* that particular type. If the type is recognised then the function to */
|
|
/* call to do the IP address search will be change, regardless of whether */
|
|
/* or not the "table" number exists. */
|
|
/* ------------------------------------------------------------------------ */
|
|
void *
|
|
ipf_lookup_res_num(softc, unit, type, number, funcptr)
|
|
ipf_main_softc_t *softc;
|
|
int unit;
|
|
u_int type;
|
|
u_int number;
|
|
lookupfunc_t *funcptr;
|
|
{
|
|
char name[FR_GROUPLEN];
|
|
|
|
#if defined(SNPRINTF) && defined(_KERNEL)
|
|
SNPRINTF(name, sizeof(name), "%u", number);
|
|
#else
|
|
(void) sprintf(name, "%u", number);
|
|
#endif
|
|
|
|
return ipf_lookup_res_name(softc, unit, type, name, funcptr);
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_res_name */
|
|
/* Returns: void * - NULL = failure, else success. */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* unit(I) - device for which this is for */
|
|
/* type(I) - type of lookup these parameters are for. */
|
|
/* name(I) - table name to use when searching */
|
|
/* funcptr(IO) - pointer to pointer for storing IP address */
|
|
/* searching function. */
|
|
/* */
|
|
/* Search for the "table" number passed in amongst those configured for */
|
|
/* that particular type. If the type is recognised then the function to */
|
|
/* call to do the IP address search will be changed, regardless of whether */
|
|
/* or not the "table" number exists. */
|
|
/* ------------------------------------------------------------------------ */
|
|
void *
|
|
ipf_lookup_res_name(softc, unit, type, name, funcptr)
|
|
ipf_main_softc_t *softc;
|
|
int unit;
|
|
u_int type;
|
|
char *name;
|
|
lookupfunc_t *funcptr;
|
|
{
|
|
ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
|
|
ipf_lookup_t **l;
|
|
void *ptr = NULL;
|
|
int i;
|
|
|
|
READ_ENTER(&softc->ipf_poolrw);
|
|
|
|
for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
|
|
if (type == (*l)->ipfl_type) {
|
|
ptr = (*(*l)->ipfl_select_add_ref)(softl->ipf_back[i],
|
|
unit, name);
|
|
if (ptr != NULL && funcptr != NULL) {
|
|
*funcptr = (*l)->ipfl_addr_find;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == MAX_BACKENDS) {
|
|
ptr = NULL;
|
|
if (funcptr != NULL)
|
|
*funcptr = NULL;
|
|
}
|
|
|
|
RWLOCK_EXIT(&softc->ipf_poolrw);
|
|
|
|
return ptr;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_find_htable */
|
|
/* Returns: void * - NULL = failure, else success. */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* unit(I) - device for which this is for */
|
|
/* name(I) - table name to use when searching */
|
|
/* */
|
|
/* To support the group-map feature, where a hash table maps address */
|
|
/* networks to rule group numbers, we need to expose a function that uses */
|
|
/* only the hash table backend. */
|
|
/* ------------------------------------------------------------------------ */
|
|
void *
|
|
ipf_lookup_find_htable(softc, unit, name)
|
|
ipf_main_softc_t *softc;
|
|
int unit;
|
|
char *name;
|
|
{
|
|
ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
|
|
ipf_lookup_t **l;
|
|
void *tab = NULL;
|
|
int i;
|
|
|
|
READ_ENTER(&softc->ipf_poolrw);
|
|
|
|
for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
|
|
if (IPLT_HASH == (*l)->ipfl_type) {
|
|
tab = ipf_htable_find(softl->ipf_back[i], unit, name);
|
|
break;
|
|
}
|
|
|
|
RWLOCK_EXIT(&softc->ipf_poolrw);
|
|
|
|
return tab;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Function: ipf_lookup_sync */
|
|
/* Returns: void */
|
|
/* Parameters: softc(I) - pointer to soft context main structure */
|
|
/* */
|
|
/* This function is the interface that the machine dependent sync functions */
|
|
/* call when a network interface name change occurs. It then calls the sync */
|
|
/* functions of the lookup implementations - if they have one. */
|
|
/* ------------------------------------------------------------------------ */
|
|
/*ARGSUSED*/
|
|
void
|
|
ipf_lookup_sync(softc, ifp)
|
|
ipf_main_softc_t *softc;
|
|
void *ifp;
|
|
{
|
|
ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
|
|
ipf_lookup_t **l;
|
|
int i;
|
|
|
|
READ_ENTER(&softc->ipf_poolrw);
|
|
|
|
for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
|
|
if ((*l)->ipfl_sync != NULL)
|
|
(*(*l)->ipfl_sync)(softc, softl->ipf_back[i]);
|
|
|
|
RWLOCK_EXIT(&softc->ipf_poolrw);
|
|
}
|
|
|
|
|
|
#ifndef _KERNEL
|
|
void
|
|
ipf_lookup_dump(softc, arg)
|
|
ipf_main_softc_t *softc;
|
|
void *arg;
|
|
{
|
|
ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
|
|
ipf_lookup_t **l;
|
|
int i;
|
|
|
|
for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
|
|
if (IPLT_POOL == (*l)->ipfl_type) {
|
|
ipf_pool_dump(softc, softl->ipf_back[i]);
|
|
break;
|
|
}
|
|
|
|
for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
|
|
if (IPLT_HASH == (*l)->ipfl_type) {
|
|
ipf_htable_dump(softc, softl->ipf_back[i]);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|