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