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