Home | History | Annotate | Line # | Download | only in netinet
      1 /*	$NetBSD: ip_lookup.c,v 1.5 2016/06/09 04:43:46 pgoyette Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2012 by Darren Reed.
      5  *
      6  * See the IPFILTER.LICENCE file for details on licencing.
      7  */
      8 #if defined(KERNEL) || defined(_KERNEL)
      9 # undef KERNEL
     10 # undef _KERNEL
     11 # define        KERNEL	1
     12 # define        _KERNEL	1
     13 #endif
     14 #if defined(__osf__)
     15 # define _PROTO_NET_H_
     16 #endif
     17 #include <sys/param.h>
     18 #if defined(__NetBSD__)
     19 # if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
     20 #  if (__NetBSD_Version__ >= 799003000)
     21 #   if defined(_KERNEL_OPT)
     22 #    include "opt_ipfilter.h"
     23 #   endif
     24 #  else
     25 #   include "opt_ipfilter.h"
     26 #  endif
     27 # endif
     28 #endif
     29 #include <sys/errno.h>
     30 #include <sys/types.h>
     31 #include <sys/time.h>
     32 #include <sys/file.h>
     33 #if __FreeBSD_version >= 220000 && defined(_KERNEL)
     34 # include <sys/fcntl.h>
     35 # include <sys/filio.h>
     36 #else
     37 # include <sys/ioctl.h>
     38 #endif
     39 #if !defined(_KERNEL)
     40 # include <stdio.h>
     41 # include <string.h>
     42 # include <stdlib.h>
     43 # define _KERNEL
     44 # ifdef __OpenBSD__
     45 struct file;
     46 # endif
     47 # include <sys/uio.h>
     48 # undef _KERNEL
     49 #endif
     50 #include <sys/socket.h>
     51 #include <net/if.h>
     52 #if defined(__FreeBSD__)
     53 # include <sys/cdefs.h>
     54 # include <sys/proc.h>
     55 #endif
     56 #if defined(_KERNEL)
     57 # include <sys/systm.h>
     58 # if !defined(__SVR4) && !defined(__svr4__)
     59 #  include <sys/mbuf.h>
     60 # endif
     61 #else
     62 # include "ipf.h"
     63 #endif
     64 #include <netinet/in.h>
     65 
     66 #include "netinet/ip_compat.h"
     67 #include "netinet/ip_fil.h"
     68 #include "netinet/ip_lookup.h"
     69 #include "netinet/ip_pool.h"
     70 #include "netinet/ip_htable.h"
     71 #include "netinet/ip_dstlist.h"
     72 /* END OF INCLUDES */
     73 
     74 #if !defined(lint)
     75 #if defined(__NetBSD__)
     76 #include <sys/cdefs.h>
     77 __KERNEL_RCSID(0, "$NetBSD: ip_lookup.c,v 1.5 2016/06/09 04:43:46 pgoyette Exp $");
     78 #else
     79 static const char rcsid[] = "@(#)Id: ip_lookup.c,v 1.1.1.2 2012/07/22 13:45:21 darrenr Exp";
     80 #endif
     81 #endif
     82 
     83 /*
     84  * In this file, ip_pool.c, ip_htable.c and ip_dstlist.c, you will find the
     85  * range for unit is [-1,IPL_LOGMAX]. The -1 is considered to be a valid number
     86  * and represents a "wildcard" or "all" units (IPL_LOGALL). The reason for not
     87  * starting the numbering at 0 is because the numbers [0,IPL_LOGMAX] correspond
     88  * to the minor device number for their respective device. Thus where there is
     89  * array indexing on the unit, +1 is used to map [-1.IPL_LOGMAX] to
     90  * [0.POOL_LOOKUP_MAX].
     91  */
     92 static int ipf_lookup_addnode(ipf_main_softc_t *, void *, int);
     93 static int ipf_lookup_delnode(ipf_main_softc_t *, void *, int);
     94 static int ipf_lookup_addtable(ipf_main_softc_t *, void *);
     95 static int ipf_lookup_deltable(ipf_main_softc_t *, void *);
     96 static int ipf_lookup_stats(ipf_main_softc_t *, void *);
     97 static int ipf_lookup_flush(ipf_main_softc_t *, void *);
     98 static int ipf_lookup_iterate(ipf_main_softc_t *, void *, int, void *);
     99 static int ipf_lookup_deltok(ipf_main_softc_t *, void *, int, void *);
    100 
    101 #define	MAX_BACKENDS	3
    102 static ipf_lookup_t *backends[MAX_BACKENDS] = {
    103 	&ipf_pool_backend,
    104 	&ipf_htable_backend,
    105 	&ipf_dstlist_backend
    106 };
    107 
    108 
    109 typedef struct ipf_lookup_softc_s {
    110 	void		*ipf_back[MAX_BACKENDS];
    111 } ipf_lookup_softc_t;
    112 
    113 
    114 /* ------------------------------------------------------------------------ */
    115 /* Function:    ipf_lookup_init                                             */
    116 /* Returns:     int      - 0 = success, else error                          */
    117 /* Parameters:  softc(I) - pointer to soft context main structure           */
    118 /*                                                                          */
    119 /* Initialise all of the subcomponents of the lookup infrstructure.         */
    120 /* ------------------------------------------------------------------------ */
    121 void *
    122 ipf_lookup_soft_create(ipf_main_softc_t *softc)
    123 {
    124 	ipf_lookup_softc_t *softl;
    125 	ipf_lookup_t **l;
    126 	int i;
    127 
    128 	KMALLOC(softl, ipf_lookup_softc_t *);
    129 	if (softl == NULL)
    130 		return NULL;
    131 
    132 	bzero((char *)softl, sizeof(*softl));
    133 
    134 	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
    135 		softl->ipf_back[i] = (*(*l)->ipfl_create)(softc);
    136 		if (softl->ipf_back[i] == NULL) {
    137 			ipf_lookup_soft_destroy(softc, softl);
    138 			return NULL;
    139 		}
    140 	}
    141 
    142 	return softl;
    143 }
    144 
    145 
    146 /* ------------------------------------------------------------------------ */
    147 /* Function:    ipf_lookup_soft_init                                        */
    148 /* Returns:     int      - 0 = success, else error                          */
    149 /* Parameters:  softc(I) - pointer to soft context main structure           */
    150 /*              arg(I)   - pointer to local context to use                  */
    151 /*                                                                          */
    152 /* Initialise all of the subcomponents of the lookup infrstructure.         */
    153 /* ------------------------------------------------------------------------ */
    154 int
    155 ipf_lookup_soft_init(ipf_main_softc_t *softc, void *arg)
    156 {
    157 	ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
    158 	int err = 0;
    159 	int i;
    160 
    161 	for (i = 0; i < MAX_BACKENDS; i++) {
    162 		err = (*backends[i]->ipfl_init)(softc, softl->ipf_back[i]);
    163 		if (err != 0)
    164 			break;
    165 	}
    166 
    167 	return err;
    168 }
    169 
    170 
    171 /* ------------------------------------------------------------------------ */
    172 /* Function:    ipf_lookup_soft_fini                                        */
    173 /* Returns:     int      - 0 = success, else error                          */
    174 /* Parameters:  softc(I) - pointer to soft context main structure           */
    175 /*              arg(I)   - pointer to local context to use                  */
    176 /*                                                                          */
    177 /* Call the fini function in each backend to cleanup all allocated data.    */
    178 /* ------------------------------------------------------------------------ */
    179 int
    180 ipf_lookup_soft_fini(ipf_main_softc_t *softc, void *arg)
    181 {
    182 	ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
    183 	int i;
    184 
    185 	for (i = 0; i < MAX_BACKENDS; i++) {
    186 		if (softl->ipf_back[i] != NULL)
    187 			(*backends[i]->ipfl_fini)(softc,
    188 						  softl->ipf_back[i]);
    189 	}
    190 
    191 	return 0;
    192 }
    193 
    194 
    195 /* ------------------------------------------------------------------------ */
    196 /* Function:    ipf_lookup_expire                                           */
    197 /* Returns:     Nil                                                         */
    198 /* Parameters:  softc(I) - pointer to soft context main structure           */
    199 /*                                                                          */
    200 /* Step through each of the backends and call their expire functions,       */
    201 /* allowing them to delete any lifetime limited data.                       */
    202 /* ------------------------------------------------------------------------ */
    203 void
    204 ipf_lookup_expire(ipf_main_softc_t *softc)
    205 {
    206 	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
    207 	int i;
    208 
    209 	WRITE_ENTER(&softc->ipf_poolrw);
    210 	for (i = 0; i < MAX_BACKENDS; i++)
    211 		(*backends[i]->ipfl_expire)(softc, softl->ipf_back[i]);
    212 	RWLOCK_EXIT(&softc->ipf_poolrw);
    213 }
    214 
    215 
    216 /* ------------------------------------------------------------------------ */
    217 /* Function:    ipf_lookup_softc_destroy                                    */
    218 /* Returns:     int     - 0 = success, else error                           */
    219 /* Parameters:  softc(I) - pointer to soft context main structure           */
    220 /*              arg(I)   - pointer to local context to use                  */
    221 /*                                                                          */
    222 /* Free up all pool related memory that has been allocated whilst IPFilter  */
    223 /* has been running.  Also, do any other deinitialisation required such     */
    224 /* ipf_lookup_init() can be called again, safely.                           */
    225 /* ------------------------------------------------------------------------ */
    226 void
    227 ipf_lookup_soft_destroy(ipf_main_softc_t *softc, void *arg)
    228 {
    229 	ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
    230 	int i;
    231 
    232 	for (i = 0; i < MAX_BACKENDS; i++) {
    233 		if (softl->ipf_back[i] != NULL)
    234 			(*backends[i]->ipfl_destroy)(softc,
    235 						     softl->ipf_back[i]);
    236 	}
    237 
    238 	KFREE(softl);
    239 }
    240 
    241 
    242 /* ------------------------------------------------------------------------ */
    243 /* Function:    ipf_lookup_ioctl                                            */
    244 /* Returns:     int      - 0 = success, else error                          */
    245 /* Parameters:  softc(I) - pointer to soft context main structure           */
    246 /*              arg(I)   - pointer to local context to use                  */
    247 /*              data(IO) - pointer to ioctl data to be copied to/from user  */
    248 /*                         space.                                           */
    249 /*              cmd(I)   - ioctl command number                             */
    250 /*              mode(I)  - file mode bits used with open                    */
    251 /*              uid(I)   - uid of process doing ioctl                       */
    252 /*              ctx(I)   - pointer that represents context for uid          */
    253 /*                                                                          */
    254 /* Handle ioctl commands sent to the ioctl device.  For the most part, this */
    255 /* involves just calling another function to handle the specifics of each   */
    256 /* command.                                                                 */
    257 /* ------------------------------------------------------------------------ */
    258 int
    259 ipf_lookup_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd,
    260     int mode, int uid, void *ctx)
    261 {
    262 	int err;
    263 	SPL_INT(s);
    264 
    265 	mode = mode;	/* LINT */
    266 
    267 	SPL_NET(s);
    268 
    269 	switch (cmd)
    270 	{
    271 	case SIOCLOOKUPADDNODE :
    272 	case SIOCLOOKUPADDNODEW :
    273 		WRITE_ENTER(&softc->ipf_poolrw);
    274 		err = ipf_lookup_addnode(softc, data, uid);
    275 		RWLOCK_EXIT(&softc->ipf_poolrw);
    276 		break;
    277 
    278 	case SIOCLOOKUPDELNODE :
    279 	case SIOCLOOKUPDELNODEW :
    280 		WRITE_ENTER(&softc->ipf_poolrw);
    281 		err = ipf_lookup_delnode(softc, data, uid);
    282 		RWLOCK_EXIT(&softc->ipf_poolrw);
    283 		break;
    284 
    285 	case SIOCLOOKUPADDTABLE :
    286 		WRITE_ENTER(&softc->ipf_poolrw);
    287 		err = ipf_lookup_addtable(softc, data);
    288 		RWLOCK_EXIT(&softc->ipf_poolrw);
    289 		break;
    290 
    291 	case SIOCLOOKUPDELTABLE :
    292 		WRITE_ENTER(&softc->ipf_poolrw);
    293 		err = ipf_lookup_deltable(softc, data);
    294 		RWLOCK_EXIT(&softc->ipf_poolrw);
    295 		break;
    296 
    297 	case SIOCLOOKUPSTAT :
    298 	case SIOCLOOKUPSTATW :
    299 		WRITE_ENTER(&softc->ipf_poolrw);
    300 		err = ipf_lookup_stats(softc, data);
    301 		RWLOCK_EXIT(&softc->ipf_poolrw);
    302 		break;
    303 
    304 	case SIOCLOOKUPFLUSH :
    305 		WRITE_ENTER(&softc->ipf_poolrw);
    306 		err = ipf_lookup_flush(softc, data);
    307 		RWLOCK_EXIT(&softc->ipf_poolrw);
    308 		break;
    309 
    310 	case SIOCLOOKUPITER :
    311 		err = ipf_lookup_iterate(softc, data, uid, ctx);
    312 		break;
    313 
    314 	case SIOCIPFDELTOK :
    315 		err = ipf_lookup_deltok(softc, data, uid, ctx);
    316 		break;
    317 
    318 	default :
    319 		IPFERROR(50001);
    320 		err = EINVAL;
    321 		break;
    322 	}
    323 	SPL_X(s);
    324 	return err;
    325 }
    326 
    327 
    328 /* ------------------------------------------------------------------------ */
    329 /* Function:    ipf_lookup_addnode                                          */
    330 /* Returns:     int     - 0 = success, else error                           */
    331 /* Parameters:  softc(I) - pointer to soft context main structure           */
    332 /*              data(I) - pointer to data from ioctl call                   */
    333 /*                                                                          */
    334 /* Add a new data node to a lookup structure.  First, check to see if the   */
    335 /* parent structure refered to by name exists and if it does, then go on to */
    336 /* add a node to it.                                                        */
    337 /* ------------------------------------------------------------------------ */
    338 static int
    339 ipf_lookup_addnode(ipf_main_softc_t *softc, void *data, int uid)
    340 {
    341 	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
    342 	iplookupop_t op;
    343 	ipf_lookup_t **l;
    344 	int err;
    345 	int i;
    346 
    347 	err = BCOPYIN(data, &op, sizeof(op));
    348 	if (err != 0) {
    349 		IPFERROR(50002);
    350 		return EFAULT;
    351 	}
    352 
    353 	if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
    354 	    (op.iplo_unit != IPLT_ALL)) {
    355 		IPFERROR(50003);
    356 		return EINVAL;
    357 	}
    358 
    359 	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
    360 
    361 	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
    362 		if (op.iplo_type == (*l)->ipfl_type) {
    363 			err = (*(*l)->ipfl_node_add)(softc,
    364 						     softl->ipf_back[i],
    365 						     &op, uid);
    366 			break;
    367 		}
    368 	}
    369 
    370 	if (i == MAX_BACKENDS) {
    371 		IPFERROR(50012);
    372 		err = EINVAL;
    373 	}
    374 
    375 	return err;
    376 }
    377 
    378 
    379 /* ------------------------------------------------------------------------ */
    380 /* Function:    ipf_lookup_delnode                                          */
    381 /* Returns:     int     - 0 = success, else error                           */
    382 /* Parameters:  softc(I) - pointer to soft context main structure           */
    383 /*              data(I) - pointer to data from ioctl call                   */
    384 /*                                                                          */
    385 /* Delete a node from a lookup table by first looking for the table it is   */
    386 /* in and then deleting the entry that gets found.                          */
    387 /* ------------------------------------------------------------------------ */
    388 static int
    389 ipf_lookup_delnode(ipf_main_softc_t *softc, void *data, int uid)
    390 {
    391 	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
    392 	iplookupop_t op;
    393 	ipf_lookup_t **l;
    394 	int err;
    395 	int i;
    396 
    397 	err = BCOPYIN(data, &op, sizeof(op));
    398 	if (err != 0) {
    399 		IPFERROR(50042);
    400 		return EFAULT;
    401 	}
    402 
    403 	if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
    404 	    (op.iplo_unit != IPLT_ALL)) {
    405 		IPFERROR(50013);
    406 		return EINVAL;
    407 	}
    408 
    409 	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
    410 
    411 	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
    412 		if (op.iplo_type == (*l)->ipfl_type) {
    413 			err = (*(*l)->ipfl_node_del)(softc, softl->ipf_back[i],
    414 						     &op, uid);
    415 			break;
    416 		}
    417 	}
    418 
    419 	if (i == MAX_BACKENDS) {
    420 		IPFERROR(50021);
    421 		err = EINVAL;
    422 	}
    423 	return err;
    424 }
    425 
    426 
    427 /* ------------------------------------------------------------------------ */
    428 /* Function:    ipf_lookup_addtable                                         */
    429 /* Returns:     int     - 0 = success, else error                           */
    430 /* Parameters:  softc(I) - pointer to soft context main structure           */
    431 /*              data(I) - pointer to data from ioctl call                   */
    432 /*                                                                          */
    433 /* Create a new lookup table, if one doesn't already exist using the name   */
    434 /* for this one.                                                            */
    435 /* ------------------------------------------------------------------------ */
    436 static int
    437 ipf_lookup_addtable(ipf_main_softc_t *softc, void *data)
    438 {
    439 	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
    440 	iplookupop_t op;
    441 	ipf_lookup_t **l;
    442 	int err, i;
    443 
    444 	err = BCOPYIN(data, &op, sizeof(op));
    445 	if (err != 0) {
    446 		IPFERROR(50022);
    447 		return EFAULT;
    448 	}
    449 
    450 	if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
    451 	    (op.iplo_unit != IPLT_ALL)) {
    452 		IPFERROR(50023);
    453 		return EINVAL;
    454 	}
    455 
    456 	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
    457 
    458 	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
    459 		if (op.iplo_type == (*l)->ipfl_type) {
    460 			err = (*(*l)->ipfl_table_add)(softc,
    461 						      softl->ipf_back[i],
    462 						      &op);
    463 			break;
    464 		}
    465 	}
    466 
    467 	if (i == MAX_BACKENDS) {
    468 		IPFERROR(50026);
    469 		err = EINVAL;
    470 	}
    471 
    472 	/*
    473 	 * For anonymous pools, copy back the operation struct because in the
    474 	 * case of success it will contain the new table's name.
    475 	 */
    476 	if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) {
    477 		err = BCOPYOUT(&op, data, sizeof(op));
    478 		if (err != 0) {
    479 			IPFERROR(50027);
    480 			err = EFAULT;
    481 		}
    482 	}
    483 
    484 	return err;
    485 }
    486 
    487 
    488 /* ------------------------------------------------------------------------ */
    489 /* Function:    ipf_lookup_deltable                                         */
    490 /* Returns:     int     - 0 = success, else error                           */
    491 /* Parameters:  softc(I) - pointer to soft context main structure           */
    492 /*              data(I) - pointer to data from ioctl call                   */
    493 /*                                                                          */
    494 /* Decodes ioctl request to remove a particular hash table or pool and      */
    495 /* calls the relevant function to do the cleanup.                           */
    496 /* ------------------------------------------------------------------------ */
    497 static int
    498 ipf_lookup_deltable(ipf_main_softc_t *softc, void *data)
    499 {
    500 	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
    501 	iplookupop_t op;
    502 	ipf_lookup_t **l;
    503 	int err, i;
    504 
    505 	err = BCOPYIN(data, &op, sizeof(op));
    506 	if (err != 0) {
    507 		IPFERROR(50028);
    508 		return EFAULT;
    509 	}
    510 
    511 	if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
    512 	    (op.iplo_unit != IPLT_ALL)) {
    513 		IPFERROR(50029);
    514 		return EINVAL;
    515 	}
    516 
    517 	op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
    518 
    519 	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
    520 		if (op.iplo_type == (*l)->ipfl_type) {
    521 			err = (*(*l)->ipfl_table_del)(softc,
    522 						      softl->ipf_back[i],
    523 						      &op);
    524 			break;
    525 		}
    526 	}
    527 
    528 	if (i == MAX_BACKENDS) {
    529 		IPFERROR(50030);
    530 		err = EINVAL;
    531 	}
    532 	return err;
    533 }
    534 
    535 
    536 /* ------------------------------------------------------------------------ */
    537 /* Function:    ipf_lookup_stats                                            */
    538 /* Returns:     int     - 0 = success, else error                           */
    539 /* Parameters:  softc(I) - pointer to soft context main structure           */
    540 /*              data(I) - pointer to data from ioctl call                   */
    541 /*                                                                          */
    542 /* Copy statistical information from inside the kernel back to user space.  */
    543 /* ------------------------------------------------------------------------ */
    544 static int
    545 ipf_lookup_stats(ipf_main_softc_t *softc, void *data)
    546 {
    547 	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
    548 	iplookupop_t op;
    549 	ipf_lookup_t **l;
    550 	int err;
    551 	int i;
    552 
    553 	err = BCOPYIN(data, &op, sizeof(op));
    554 	if (err != 0) {
    555 		IPFERROR(50031);
    556 		return EFAULT;
    557 	}
    558 
    559 	if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
    560 	    (op.iplo_unit != IPLT_ALL)) {
    561 		IPFERROR(50032);
    562 		return EINVAL;
    563 	}
    564 
    565 	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
    566 		if (op.iplo_type == (*l)->ipfl_type) {
    567 			err = (*(*l)->ipfl_stats_get)(softc,
    568 						      softl->ipf_back[i],
    569 						      &op);
    570 			break;
    571 		}
    572 	}
    573 
    574 	if (i == MAX_BACKENDS) {
    575 		IPFERROR(50033);
    576 		err = EINVAL;
    577 	}
    578 
    579 	return err;
    580 }
    581 
    582 
    583 /* ------------------------------------------------------------------------ */
    584 /* Function:    ipf_lookup_flush                                            */
    585 /* Returns:     int     - 0 = success, else error                           */
    586 /* Parameters:  softc(I) - pointer to soft context main structure           */
    587 /*              data(I) - pointer to data from ioctl call                   */
    588 /*                                                                          */
    589 /* A flush is called when we want to flush all the nodes from a particular  */
    590 /* entry in the hash table/pool or want to remove all groups from those.    */
    591 /* ------------------------------------------------------------------------ */
    592 static int
    593 ipf_lookup_flush(ipf_main_softc_t *softc, void *data)
    594 {
    595 	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
    596 	int err, unit, num, type, i;
    597 	iplookupflush_t flush;
    598 	ipf_lookup_t **l;
    599 
    600 	err = BCOPYIN(data, &flush, sizeof(flush));
    601 	if (err != 0) {
    602 		IPFERROR(50034);
    603 		return EFAULT;
    604 	}
    605 
    606 	unit = flush.iplf_unit;
    607 	if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) {
    608 		IPFERROR(50035);
    609 		return EINVAL;
    610 	}
    611 
    612 	flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
    613 
    614 	type = flush.iplf_type;
    615 	IPFERROR(50036);
    616 	err = EINVAL;
    617 	num = 0;
    618 
    619 	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
    620 		if (type == (*l)->ipfl_type || type == IPLT_ALL) {
    621 			err = 0;
    622 			num += (*(*l)->ipfl_flush)(softc,
    623 						   softl->ipf_back[i],
    624 						   &flush);
    625 		}
    626 	}
    627 
    628 	if (err == 0) {
    629 		flush.iplf_count = num;
    630 		err = BCOPYOUT(&flush, data, sizeof(flush));
    631 		if (err != 0) {
    632 			IPFERROR(50037);
    633 			err = EFAULT;
    634 		}
    635 	}
    636 	return err;
    637 }
    638 
    639 
    640 /* ------------------------------------------------------------------------ */
    641 /* Function:    ipf_lookup_delref                                           */
    642 /* Returns:     void                                                        */
    643 /* Parameters:  softc(I) - pointer to soft context main structure           */
    644 /*              type(I) - table type to operate on                          */
    645 /*              ptr(I)  - pointer to object to remove reference for         */
    646 /*                                                                          */
    647 /* This function organises calling the correct deref function for a given   */
    648 /* type of object being passed into it.                                     */
    649 /* ------------------------------------------------------------------------ */
    650 void
    651 ipf_lookup_deref(ipf_main_softc_t *softc, int type, void *ptr)
    652 {
    653 	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
    654 	int i;
    655 
    656 	if (ptr == NULL)
    657 		return;
    658 
    659 	for (i = 0; i < MAX_BACKENDS; i++) {
    660 		if (type == backends[i]->ipfl_type) {
    661 			WRITE_ENTER(&softc->ipf_poolrw);
    662 			(*backends[i]->ipfl_table_deref)(softc,
    663 							 softl->ipf_back[i],
    664 							 ptr);
    665 			RWLOCK_EXIT(&softc->ipf_poolrw);
    666 			break;
    667 		}
    668 	}
    669 }
    670 
    671 
    672 /* ------------------------------------------------------------------------ */
    673 /* Function:    ipf_lookup_iterate                                          */
    674 /* Returns:     int     - 0 = success, else error                           */
    675 /* Parameters:  softc(I) - pointer to soft context main structure           */
    676 /*              data(I) - pointer to data from ioctl call                   */
    677 /*              uid(I)  - uid of caller                                     */
    678 /*              ctx(I)  - pointer to give the uid context                   */
    679 /*                                                                          */
    680 /* Decodes ioctl request to step through either hash tables or pools.       */
    681 /* ------------------------------------------------------------------------ */
    682 static int
    683 ipf_lookup_iterate(ipf_main_softc_t *softc, void *data, int uid, void *ctx)
    684 {
    685 	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
    686 	ipflookupiter_t iter;
    687 	ipftoken_t *token;
    688 	int err, i;
    689 	SPL_INT(s);
    690 
    691 	err = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_LOOKUPITER);
    692 	if (err != 0)
    693 		return err;
    694 
    695 	if (iter.ili_unit < IPL_LOGALL && iter.ili_unit > IPL_LOGMAX) {
    696 		IPFERROR(50038);
    697 		return EINVAL;
    698 	}
    699 
    700 	if (iter.ili_ival != IPFGENITER_LOOKUP) {
    701 		IPFERROR(50039);
    702 		return EINVAL;
    703 	}
    704 
    705 	SPL_SCHED(s);
    706 	token = ipf_token_find(softc, iter.ili_key, uid, ctx);
    707 	if (token == NULL) {
    708 		SPL_X(s);
    709 		IPFERROR(50040);
    710 		return ESRCH;
    711 	}
    712 
    713 	for (i = 0; i < MAX_BACKENDS; i++) {
    714 		if (iter.ili_type == backends[i]->ipfl_type) {
    715 			err = (*backends[i]->ipfl_iter_next)(softc,
    716 							     softl->ipf_back[i],
    717 							     token, &iter);
    718 			break;
    719 		}
    720 	}
    721 	SPL_X(s);
    722 
    723 	if (i == MAX_BACKENDS) {
    724 		IPFERROR(50041);
    725 		err = EINVAL;
    726 	}
    727 
    728 	WRITE_ENTER(&softc->ipf_tokens);
    729 	ipf_token_deref(softc, token);
    730 	RWLOCK_EXIT(&softc->ipf_tokens);
    731 
    732 	return err;
    733 }
    734 
    735 
    736 /* ------------------------------------------------------------------------ */
    737 /* Function:    ipf_lookup_iterderef                                        */
    738 /* Returns:     void                                                        */
    739 /* Parameters:  softc(I) - pointer to soft context main structure           */
    740 /*              type(I)  - backend type to iterate through                  */
    741 /*              data(I)  - pointer to data from ioctl call                  */
    742 /*                                                                          */
    743 /* Decodes ioctl request to remove a particular hash table or pool and      */
    744 /* calls the relevant function to do the cleanup.                           */
    745 /* Because each of the backend types has a different data structure,        */
    746 /* iteration is limited to one type at a time (i.e. it is not permitted to  */
    747 /* go on from pool types to hash types as part of the "get next".)          */
    748 /* ------------------------------------------------------------------------ */
    749 void
    750 ipf_lookup_iterderef(ipf_main_softc_t *softc, u_32_t type, void *data)
    751 {
    752 	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
    753 	struct iplookupiterkey *lkey;
    754 	iplookupiterkey_t key;
    755 	int i;
    756 
    757 	key.ilik_key = type;
    758 	lkey = &key.ilik_unstr;
    759 
    760 	if (lkey->ilik_ival != IPFGENITER_LOOKUP)
    761 		return;
    762 
    763 	WRITE_ENTER(&softc->ipf_poolrw);
    764 
    765 	for (i = 0; i < MAX_BACKENDS; i++) {
    766 		if (lkey->ilik_type == backends[i]->ipfl_type) {
    767 			(*backends[i]->ipfl_iter_deref)(softc,
    768 							softl->ipf_back[i],
    769 							lkey->ilik_otype,
    770 							lkey->ilik_unit,
    771 							data);
    772 			break;
    773 		}
    774 	}
    775 	RWLOCK_EXIT(&softc->ipf_poolrw);
    776 }
    777 
    778 
    779 /* ------------------------------------------------------------------------ */
    780 /* Function:    ipf_lookup_deltok                                           */
    781 /* Returns:     int     - 0 = success, else error                           */
    782 /* Parameters:  softc(I) - pointer to soft context main structure           */
    783 /*              data(I) - pointer to data from ioctl call                   */
    784 /*              uid(I)  - uid of caller                                     */
    785 /*              ctx(I)  - pointer to give the uid context                   */
    786 /*                                                                          */
    787 /* Deletes the token identified by the combination of (type,uid,ctx)        */
    788 /* "key" is a combination of the table type, iterator type and the unit for */
    789 /* which the token was being used.                                          */
    790 /* ------------------------------------------------------------------------ */
    791 int
    792 ipf_lookup_deltok(ipf_main_softc_t *softc, void *data, int uid, void *ctx)
    793 {
    794 	int error, key;
    795 	SPL_INT(s);
    796 
    797 	SPL_SCHED(s);
    798 	error = BCOPYIN(data, &key, sizeof(key));
    799 	if (error == 0)
    800 		error = ipf_token_del(softc, key, uid, ctx);
    801 	SPL_X(s);
    802 	return error;
    803 }
    804 
    805 
    806 /* ------------------------------------------------------------------------ */
    807 /* Function:    ipf_lookup_res_num                                          */
    808 /* Returns:     void * - NULL = failure, else success.                      */
    809 /* Parameters:  softc(I) - pointer to soft context main structure           */
    810 /*              unit(I)     - device for which this is for                  */
    811 /*              type(I)     - type of lookup these parameters are for.      */
    812 /*              number(I)   - table number to use when searching            */
    813 /*              funcptr(IO) - pointer to pointer for storing IP address     */
    814 /*                            searching function.                           */
    815 /*                                                                          */
    816 /* Search for the "table" number passed in amongst those configured for     */
    817 /* that particular type.  If the type is recognised then the function to    */
    818 /* call to do the IP address search will be change, regardless of whether   */
    819 /* or not the "table" number exists.                                        */
    820 /* ------------------------------------------------------------------------ */
    821 void *
    822 ipf_lookup_res_num(ipf_main_softc_t *softc, int unit, u_int type, u_int number,
    823     lookupfunc_t *funcptr)
    824 {
    825 	char name[FR_GROUPLEN];
    826 
    827 	snprintf(name, sizeof(name), "%u", number);
    828 
    829 	return ipf_lookup_res_name(softc, unit, type, name, funcptr);
    830 }
    831 
    832 
    833 /* ------------------------------------------------------------------------ */
    834 /* Function:    ipf_lookup_res_name                                         */
    835 /* Returns:     void * - NULL = failure, else success.                      */
    836 /* Parameters:  softc(I) - pointer to soft context main structure           */
    837 /*              unit(I)     - device for which this is for                  */
    838 /*              type(I)     - type of lookup these parameters are for.      */
    839 /*              name(I)     - table name to use when searching              */
    840 /*              funcptr(IO) - pointer to pointer for storing IP address     */
    841 /*                            searching function.                           */
    842 /*                                                                          */
    843 /* Search for the "table" number passed in amongst those configured for     */
    844 /* that particular type.  If the type is recognised then the function to    */
    845 /* call to do the IP address search will be changed, regardless of whether  */
    846 /* or not the "table" number exists.                                        */
    847 /* ------------------------------------------------------------------------ */
    848 void *
    849 ipf_lookup_res_name(ipf_main_softc_t *softc, int unit, u_int type, char *name,
    850     lookupfunc_t *funcptr)
    851 {
    852 	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
    853 	ipf_lookup_t **l;
    854 	void *ptr = NULL;
    855 	int i;
    856 
    857 	READ_ENTER(&softc->ipf_poolrw);
    858 
    859 	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
    860 		if (type == (*l)->ipfl_type) {
    861 			ptr = (*(*l)->ipfl_select_add_ref)(softl->ipf_back[i],
    862 							   unit, name);
    863 			if (ptr != NULL && funcptr != NULL) {
    864 				*funcptr = (*l)->ipfl_addr_find;
    865 			}
    866 			break;
    867 		}
    868 	}
    869 
    870 	if (i == MAX_BACKENDS) {
    871 		ptr = NULL;
    872 		if (funcptr != NULL)
    873 			*funcptr = NULL;
    874 	}
    875 
    876 	RWLOCK_EXIT(&softc->ipf_poolrw);
    877 
    878 	return ptr;
    879 }
    880 
    881 
    882 /* ------------------------------------------------------------------------ */
    883 /* Function:    ipf_lookup_find_htable                                      */
    884 /* Returns:     void * - NULL = failure, else success.                      */
    885 /* Parameters:  softc(I) - pointer to soft context main structure           */
    886 /*              unit(I)     - device for which this is for                  */
    887 /*              name(I)     - table name to use when searching              */
    888 /*                                                                          */
    889 /* To support the group-map feature, where a hash table maps address        */
    890 /* networks to rule group numbers, we need to expose a function that uses   */
    891 /* only the hash table backend.                                             */
    892 /* ------------------------------------------------------------------------ */
    893 void *
    894 ipf_lookup_find_htable(ipf_main_softc_t *softc, int unit, char *name)
    895 {
    896 	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
    897 	ipf_lookup_t **l;
    898 	void *tab = NULL;
    899 	int i;
    900 
    901 	READ_ENTER(&softc->ipf_poolrw);
    902 
    903 	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
    904 		if (IPLT_HASH == (*l)->ipfl_type) {
    905 			tab = ipf_htable_find(softl->ipf_back[i], unit, name);
    906 			break;
    907 		}
    908 
    909 	RWLOCK_EXIT(&softc->ipf_poolrw);
    910 
    911 	return tab;
    912 }
    913 
    914 
    915 /* ------------------------------------------------------------------------ */
    916 /* Function:    ipf_lookup_sync                                             */
    917 /* Returns:     void                                                        */
    918 /* Parameters:  softc(I) - pointer to soft context main structure           */
    919 /*                                                                          */
    920 /* This function is the interface that the machine dependent sync functions */
    921 /* call when a network interface name change occurs. It then calls the sync */
    922 /* functions of the lookup implementations - if they have one.              */
    923 /* ------------------------------------------------------------------------ */
    924 /*ARGSUSED*/
    925 void
    926 ipf_lookup_sync(ipf_main_softc_t *softc, void *ifp)
    927 {
    928 	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
    929 	ipf_lookup_t **l;
    930 	int i;
    931 
    932 	READ_ENTER(&softc->ipf_poolrw);
    933 
    934 	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
    935 		if ((*l)->ipfl_sync != NULL)
    936 			(*(*l)->ipfl_sync)(softc, softl->ipf_back[i]);
    937 
    938 	RWLOCK_EXIT(&softc->ipf_poolrw);
    939 }
    940 
    941 
    942 #ifndef _KERNEL
    943 void
    944 ipf_lookup_dump(softc, arg)
    945 	ipf_main_softc_t *softc;
    946 	void *arg;
    947 {
    948 	ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
    949 	ipf_lookup_t **l;
    950 	int i;
    951 
    952 	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
    953 		if (IPLT_POOL == (*l)->ipfl_type) {
    954 			ipf_pool_dump(softc, softl->ipf_back[i]);
    955 			break;
    956 		}
    957 
    958 	for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
    959 		if (IPLT_HASH == (*l)->ipfl_type) {
    960 			ipf_htable_dump(softc, softl->ipf_back[i]);
    961 			break;
    962 		}
    963 }
    964 #endif
    965