Home | History | Annotate | Line # | Download | only in netinet
ip_dstlist.c revision 1.1
      1 /*	$NetBSD: ip_dstlist.c,v 1.1 2012/03/23 20:36:53 christos 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/errno.h>
     18 #include <sys/types.h>
     19 #include <sys/param.h>
     20 #include <sys/file.h>
     21 #if !defined(_KERNEL) && !defined(__KERNEL__)
     22 # include <stdio.h>
     23 # include <stdlib.h>
     24 # include <string.h>
     25 # define _KERNEL
     26 # ifdef __OpenBSD__
     27 struct file;
     28 # endif
     29 # include <sys/uio.h>
     30 # undef _KERNEL
     31 #else
     32 # include <sys/systm.h>
     33 # if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
     34 #  include <sys/proc.h>
     35 # endif
     36 #endif
     37 #include <sys/time.h>
     38 #if !defined(linux)
     39 # include <sys/protosw.h>
     40 #endif
     41 #include <sys/socket.h>
     42 #if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
     43 # include <sys/mbuf.h>
     44 #endif
     45 #if defined(__SVR4) || defined(__svr4__)
     46 # include <sys/filio.h>
     47 # include <sys/byteorder.h>
     48 # ifdef _KERNEL
     49 #  include <sys/dditypes.h>
     50 # endif
     51 # include <sys/stream.h>
     52 # include <sys/kmem.h>
     53 #endif
     54 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
     55 # include <sys/malloc.h>
     56 #endif
     57 
     58 #include <net/if.h>
     59 #include <netinet/in.h>
     60 
     61 #include "netinet/ip_compat.h"
     62 #include "netinet/ip_fil.h"
     63 #include "netinet/ip_nat.h"
     64 #include "netinet/ip_lookup.h"
     65 #include "netinet/ip_dstlist.h"
     66 
     67 /* END OF INCLUDES */
     68 
     69 #ifdef HAS_SYS_MD5_H
     70 # include <sys/md5.h>
     71 #else
     72 # include "md5.h"
     73 #endif
     74 
     75 #if !defined(lint)
     76 static const char rcsid[] = "@(#)Id: ip_dstlist.c,v 1.13.2.7 2012/01/29 05:30:35 darren_r Exp ";
     77 #endif
     78 
     79 typedef struct ipf_dstl_softc_s {
     80 	ippool_dst_t	*dstlist[LOOKUP_POOL_SZ];
     81 	ipf_dstl_stat_t	stats;
     82 } ipf_dstl_softc_t;
     83 
     84 
     85 static void *ipf_dstlist_soft_create __P((ipf_main_softc_t *));
     86 static void ipf_dstlist_soft_destroy __P((ipf_main_softc_t *, void *));
     87 static int ipf_dstlist_soft_init __P((ipf_main_softc_t *, void *));
     88 static void ipf_dstlist_soft_fini __P((ipf_main_softc_t *, void *));
     89 static int ipf_dstlist_addr_find __P((ipf_main_softc_t *, void *, int,
     90 				      void *, u_int));
     91 static size_t ipf_dstlist_flush __P((ipf_main_softc_t *, void *,
     92 				     iplookupflush_t *));
     93 static int ipf_dstlist_iter_deref __P((ipf_main_softc_t *, void *, int, int,
     94 				       void *));
     95 static int ipf_dstlist_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *,
     96 				      ipflookupiter_t *));
     97 static int ipf_dstlist_node_add __P((ipf_main_softc_t *, void *,
     98 				     iplookupop_t *, int));
     99 static int ipf_dstlist_node_del __P((ipf_main_softc_t *, void *,
    100 				     iplookupop_t *, int));
    101 static int ipf_dstlist_stats_get __P((ipf_main_softc_t *, void *,
    102 				      iplookupop_t *));
    103 static int ipf_dstlist_table_add __P((ipf_main_softc_t *, void *,
    104 				      iplookupop_t *));
    105 static int ipf_dstlist_table_del __P((ipf_main_softc_t *, void *,
    106 				      iplookupop_t *));
    107 static int ipf_dstlist_table_deref __P((ipf_main_softc_t *, void *, void *));
    108 static void *ipf_dstlist_table_find __P((void *, int, char *));
    109 static void ipf_dstlist_table_remove __P((ipf_main_softc_t *,
    110 					  ipf_dstl_softc_t *, ippool_dst_t *));
    111 static void ipf_dstlist_table_clearnodes __P((ipf_dstl_softc_t *,
    112 					      ippool_dst_t *));
    113 static ipf_dstnode_t *ipf_dstlist_select __P((fr_info_t *, ippool_dst_t *));
    114 static void *ipf_dstlist_select_ref __P((void *, int, char *));
    115 static void ipf_dstlist_node_free __P((ipf_dstl_softc_t *, ippool_dst_t *, ipf_dstnode_t *));
    116 static int ipf_dstlist_node_deref __P((void *, ipf_dstnode_t *));
    117 static void ipf_dstlist_expire __P((ipf_main_softc_t *, void *));
    118 static void ipf_dstlist_sync __P((ipf_main_softc_t *, void *));
    119 
    120 ipf_lookup_t ipf_dstlist_backend = {
    121 	IPLT_DSTLIST,
    122 	ipf_dstlist_soft_create,
    123 	ipf_dstlist_soft_destroy,
    124 	ipf_dstlist_soft_init,
    125 	ipf_dstlist_soft_fini,
    126 	ipf_dstlist_addr_find,
    127 	ipf_dstlist_flush,
    128 	ipf_dstlist_iter_deref,
    129 	ipf_dstlist_iter_next,
    130 	ipf_dstlist_node_add,
    131 	ipf_dstlist_node_del,
    132 	ipf_dstlist_stats_get,
    133 	ipf_dstlist_table_add,
    134 	ipf_dstlist_table_del,
    135 	ipf_dstlist_table_deref,
    136 	ipf_dstlist_table_find,
    137 	ipf_dstlist_select_ref,
    138 	ipf_dstlist_select_node,
    139 	ipf_dstlist_expire,
    140 	ipf_dstlist_sync
    141 };
    142 
    143 
    144 /* ------------------------------------------------------------------------ */
    145 /* Function:    ipf_dstlist_soft_create                                     */
    146 /* Returns:     int - 0 = success, else error                               */
    147 /* Parameters:  softc(I) - pointer to soft context main structure           */
    148 /*                                                                          */
    149 /* Allocating a chunk of memory filled with 0's is enough for the current   */
    150 /* soft context used with destination lists.                                */
    151 /* ------------------------------------------------------------------------ */
    152 static void *
    153 ipf_dstlist_soft_create(softc)
    154 	ipf_main_softc_t *softc;
    155 {
    156 	ipf_dstl_softc_t *softd;
    157 
    158 	KMALLOC(softd, ipf_dstl_softc_t *);
    159 	if (softd == NULL)
    160 		return NULL;
    161 
    162 	bzero((char *)softd, sizeof(*softd));
    163 
    164 	return softd;
    165 }
    166 
    167 
    168 /* ------------------------------------------------------------------------ */
    169 /* Function:    ipf_dstlist_soft_destroy                                    */
    170 /* Returns:     Nil                                                         */
    171 /* Parameters:  softc(I) - pointer to soft context main structure           */
    172 /*              arg(I)   - pointer to local context to use                  */
    173 /*                                                                          */
    174 /* For destination lists, the only thing we have to do when destroying the  */
    175 /* soft context is free it!                                                 */
    176 /* ------------------------------------------------------------------------ */
    177 static void
    178 ipf_dstlist_soft_destroy(softc, arg)
    179 	ipf_main_softc_t *softc;
    180 	void *arg;
    181 {
    182 	ipf_dstl_softc_t *softd = arg;
    183 
    184 	KFREE(softd);
    185 }
    186 
    187 
    188 /* ------------------------------------------------------------------------ */
    189 /* Function:    ipf_dstlist_soft_init                                       */
    190 /* Returns:     int - 0 = success, else error                               */
    191 /* Parameters:  softc(I) - pointer to soft context main structure           */
    192 /*              arg(I)   - pointer to local context to use                  */
    193 /*                                                                          */
    194 /* There is currently no soft context for destination list management.      */
    195 /* ------------------------------------------------------------------------ */
    196 static int
    197 ipf_dstlist_soft_init(softc, arg)
    198 	ipf_main_softc_t *softc;
    199 	void *arg;
    200 {
    201 	return 0;
    202 }
    203 
    204 
    205 /* ------------------------------------------------------------------------ */
    206 /* Function:    ipf_dstlist_soft_fini                                       */
    207 /* Returns:     Nil                                                         */
    208 /* Parameters:  softc(I) - pointer to soft context main structure           */
    209 /*              arg(I)   - pointer to local context to use                  */
    210 /*                                                                          */
    211 /* There is currently no soft context for destination list management.      */
    212 /* ------------------------------------------------------------------------ */
    213 static void
    214 ipf_dstlist_soft_fini(softc, arg)
    215 	ipf_main_softc_t *softc;
    216 	void *arg;
    217 {
    218 	ipf_dstl_softc_t *softd = arg;
    219 	int i;
    220 
    221 	for (i = -1; i <= IPL_LOGMAX; i++)
    222 		while (softd->dstlist[i + 1] != NULL)
    223 			ipf_dstlist_table_remove(softc, softd,
    224 						 softd->dstlist[i + 1]);
    225 
    226 	ASSERT(softd->stats.ipls_numderefnodes == 0);
    227 }
    228 
    229 
    230 /* ------------------------------------------------------------------------ */
    231 /* Function:    ipf_dstlist_addr_find                                       */
    232 /* Returns:     int - 0 = success, else error                               */
    233 /* Parameters:  softc(I) - pointer to soft context main structure           */
    234 /*              arg1(I)  - pointer to local context to use                  */
    235 /*              arg2(I)  - pointer to local context to use                  */
    236 /*              arg3(I)  - pointer to local context to use                  */
    237 /*              arg4(I)  - pointer to local context to use                  */
    238 /*                                                                          */
    239 /* There is currently no such thing as searching a destination list for an  */
    240 /* address so this function becomes a no-op.                                */
    241 /* ------------------------------------------------------------------------ */
    242 /*ARGSUSED*/
    243 static int
    244 ipf_dstlist_addr_find(softc, arg1, arg2, arg3, arg4)
    245 	ipf_main_softc_t *softc;
    246 	void *arg1, *arg3;
    247 	int arg2;
    248 	u_int arg4;
    249 {
    250 	return -1;
    251 }
    252 
    253 
    254 /* ------------------------------------------------------------------------ */
    255 /* Function:    ipf_dstlist_flush                                           */
    256 /* Returns:     int      - number of objects deleted                        */
    257 /* Parameters:  softc(I) - pointer to soft context main structure           */
    258 /*              arg(I)   - pointer to local context to use                  */
    259 /*              fop(I)   - pointer to lookup flush operation data           */
    260 /*                                                                          */
    261 /* Flush all of the destination tables that match the data passed in with   */
    262 /* the iplookupflush_t. There are two ways to match objects: the device for */
    263 /* which they are to be used with and their name.                           */
    264 /* ------------------------------------------------------------------------ */
    265 static size_t
    266 ipf_dstlist_flush(softc, arg, fop)
    267 	ipf_main_softc_t *softc;
    268 	void *arg;
    269 	iplookupflush_t *fop;
    270 {
    271 	ipf_dstl_softc_t *softd = arg;
    272 	ippool_dst_t *node, *next;
    273 	int n, i;
    274 
    275 	for (n = 0, i = -1; i <= IPL_LOGMAX; i++) {
    276 		if (fop->iplf_unit != IPLT_ALL && fop->iplf_unit != i)
    277 			continue;
    278 		for (node = softd->dstlist[i + 1]; node != NULL; node = next) {
    279 			next = node->ipld_next;
    280 
    281 			if ((*fop->iplf_name != '\0') &&
    282 			    strncmp(fop->iplf_name, node->ipld_name,
    283 				    FR_GROUPLEN))
    284 				continue;
    285 
    286 			ipf_dstlist_table_remove(softc, softd, node);
    287 			n++;
    288 		}
    289 	}
    290 	return n;
    291 }
    292 
    293 
    294 /* ------------------------------------------------------------------------ */
    295 /* Function:    ipf_dstlist_iter_deref                                      */
    296 /* Returns:     int      - 0 = success, else error                          */
    297 /* Parameters:  softc(I) - pointer to soft context main structure           */
    298 /*              arg(I)   - pointer to local context to use                  */
    299 /*              otype(I) - type of data structure to iterate through        */
    300 /*              unit(I)  - device we are working with                       */
    301 /*              data(I)  - address of object in kernel space                */
    302 /*                                                                          */
    303 /* ------------------------------------------------------------------------ */
    304 static int
    305 ipf_dstlist_iter_deref(softc, arg, otype, unit, data)
    306 	ipf_main_softc_t *softc;
    307 	void *arg;
    308 	int otype, unit;
    309 	void *data;
    310 {
    311 	if (data == NULL) {
    312 		IPFERROR(120001);
    313 		return EINVAL;
    314 	}
    315 
    316 	if (unit < -1 || unit > IPL_LOGMAX) {
    317 		IPFERROR(120002);
    318 		return EINVAL;
    319 	}
    320 
    321 	switch (otype)
    322 	{
    323 	case IPFLOOKUPITER_LIST :
    324 		ipf_dstlist_table_deref(softc, arg, (ippool_dst_t *)data);
    325 		break;
    326 
    327 	case IPFLOOKUPITER_NODE :
    328 		ipf_dstlist_node_deref(arg, (ipf_dstnode_t *)data);
    329 		break;
    330 	}
    331 
    332 	return 0;
    333 }
    334 
    335 
    336 /* ------------------------------------------------------------------------ */
    337 /* Function:    ipf_dstlist_iter_next                                       */
    338 /* Returns:     int - 0 = success, else error                               */
    339 /* Parameters:  softc(I) - pointer to soft context main structure           */
    340 /*              arg(I)   - pointer to local context to use                  */
    341 /*              op(I)    - pointer to lookup operation data                 */
    342 /*              uid(I)   - uid of process doing the ioctl                   */
    343 /*                                                                          */
    344 /* ------------------------------------------------------------------------ */
    345 static int
    346 ipf_dstlist_iter_next(softc, arg, token, iter)
    347 	ipf_main_softc_t *softc;
    348 	void *arg;
    349 	ipftoken_t *token;
    350 	ipflookupiter_t *iter;
    351 {
    352 	ipf_dstnode_t zn, *nextnode = NULL, *node = NULL;
    353 	ippool_dst_t zero, *next = NULL, *list = NULL;
    354 	ipf_dstl_softc_t *softd = arg;
    355 	int err = 0;
    356 
    357 	switch (iter->ili_otype)
    358 	{
    359 	case IPFLOOKUPITER_LIST :
    360 		list = token->ipt_data;
    361 		if (list == NULL) {
    362 			next = softd->dstlist[(int)iter->ili_unit + 1];
    363 		} else {
    364 			next = list->ipld_next;
    365 		}
    366 
    367 		if (next != NULL) {
    368 			ATOMIC_INC32(list->ipld_ref);
    369 			token->ipt_data = next;
    370 		} else {
    371 			bzero((char *)&zero, sizeof(zero));
    372 			next = &zero;
    373 			token->ipt_data = NULL;
    374 		}
    375 		break;
    376 
    377 	case IPFLOOKUPITER_NODE :
    378 		node = token->ipt_data;
    379 		if (node == NULL) {
    380 			list = ipf_dstlist_table_find(arg, iter->ili_unit,
    381 						      iter->ili_name);
    382 			if (list == NULL) {
    383 				IPFERROR(120004);
    384 				err = ESRCH;
    385 				nextnode = NULL;
    386 			} else {
    387 				nextnode = *list->ipld_dests;
    388 				list = NULL;
    389 			}
    390 		} else {
    391 			nextnode = node->ipfd_next;
    392 		}
    393 
    394 		if (nextnode != NULL) {
    395 			ATOMIC_INC32(nextnode->ipfd_ref);
    396 			token->ipt_data = nextnode;
    397 		} else {
    398 			bzero((char *)&zn, sizeof(zn));
    399 			nextnode = &zn;
    400 			token->ipt_data = NULL;
    401 		}
    402 		break;
    403 	default :
    404 		IPFERROR(120003);
    405 		err = EINVAL;
    406 		break;
    407 	}
    408 
    409 	if (err != 0)
    410 		return err;
    411 
    412 	switch (iter->ili_otype)
    413 	{
    414 	case IPFLOOKUPITER_LIST :
    415 		if (node != NULL) {
    416 			ipf_dstlist_table_deref(softc, arg, node);
    417 		}
    418 		token->ipt_data = next;
    419 		err = COPYOUT(next, iter->ili_data, sizeof(*next));
    420 		if (err != 0) {
    421 			IPFERROR(120005);
    422 			err = EFAULT;
    423 		}
    424 		break;
    425 
    426 	case IPFLOOKUPITER_NODE :
    427 		if (node != NULL) {
    428 			ipf_dstlist_node_deref(arg, node);
    429 		}
    430 		token->ipt_data = nextnode;
    431 		err = COPYOUT(nextnode, iter->ili_data, sizeof(*nextnode));
    432 		if (err != 0) {
    433 			IPFERROR(120006);
    434 			err = EFAULT;
    435 		}
    436 		break;
    437 	}
    438 
    439 	return err;
    440 }
    441 
    442 
    443 /* ------------------------------------------------------------------------ */
    444 /* Function:    ipf_dstlist_node_add                                        */
    445 /* Returns:     int - 0 = success, else error                               */
    446 /* Parameters:  softc(I) - pointer to soft context main structure           */
    447 /*              arg(I)   - pointer to local context to use                  */
    448 /*              op(I)    - pointer to lookup operation data                 */
    449 /*              uid(I)   - uid of process doing the ioctl                   */
    450 /* Locks:       WRITE(ipf_poolrw)                                           */
    451 /*                                                                          */
    452 /* Add a new node to a destination list. To do this, we only copy in the    */
    453 /* frdest_t structure because that contains the only data required from the */
    454 /* application to create a new node. The frdest_t doesn't contain the name  */
    455 /* itself. When loading filter rules, fd_name is a 'pointer' to the name.   */
    456 /* In this case, the 'pointer' does not work, instead it is the length of   */
    457 /* the name and the name is immediately following the frdest_t structure.   */
    458 /* fd_name must include the trailing \0, so it should be strlen(str) + 1.   */
    459 /* For simple sanity checking, an upper bound on the size of fd_name is     */
    460 /* imposed - 128.                                                          */
    461 /* ------------------------------------------------------------------------ */
    462 static int
    463 ipf_dstlist_node_add(softc, arg, op, uid)
    464 	ipf_main_softc_t *softc;
    465 	void *arg;
    466 	iplookupop_t *op;
    467 	int uid;
    468 {
    469 	ipf_dstl_softc_t *softd = arg;
    470 	ipf_dstnode_t *node, **nodes;
    471 	ippool_dst_t *d;
    472 	frdest_t dest;
    473 	int err;
    474 
    475 	if (op->iplo_size < sizeof(frdest_t)) {
    476 		IPFERROR(120007);
    477 		return EINVAL;
    478 	}
    479 
    480 	err = COPYIN(op->iplo_struct, &dest, sizeof(dest));
    481 	if (err != 0) {
    482 		IPFERROR(120009);
    483 		return EFAULT;
    484 	}
    485 
    486 	d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
    487 	if (d == NULL) {
    488 		IPFERROR(120010);
    489 		return ESRCH;
    490 	}
    491 
    492 	switch (dest.fd_addr.adf_family)
    493 	{
    494 	case AF_INET :
    495 	case AF_INET6 :
    496 		break;
    497 	default :
    498 		IPFERROR(120019);
    499 		return EINVAL;
    500 	}
    501 
    502 	if (dest.fd_name < -1 || dest.fd_name > 128) {
    503 		IPFERROR(120018);
    504 		return EINVAL;
    505 	}
    506 
    507 	KMALLOCS(node, ipf_dstnode_t *, sizeof(*node) + dest.fd_name);
    508 	if (node == NULL) {
    509 		softd->stats.ipls_nomem++;
    510 		IPFERROR(120008);
    511 		return ENOMEM;
    512 	}
    513 
    514 	bcopy(&dest, &node->ipfd_dest, sizeof(dest));
    515 	node->ipfd_size = sizeof(*node) + dest.fd_name;
    516 
    517 	err = COPYIN((char *)op->iplo_struct + sizeof(dest), node->ipfd_names,
    518 		     dest.fd_name);
    519 	if (err != 0) {
    520 		IPFERROR(120017);
    521 		KFREES(node, node->ipfd_size);
    522 		return EFAULT;
    523 	}
    524 	if (d->ipld_nodes == d->ipld_maxnodes) {
    525 		KMALLOCS(nodes, ipf_dstnode_t **,
    526 			 sizeof(*nodes) * (d->ipld_maxnodes + 1));
    527 		if (nodes == NULL) {
    528 			softd->stats.ipls_nomem++;
    529 			IPFERROR(120022);
    530 			KFREES(node, node->ipfd_size);
    531 			return ENOMEM;
    532 		}
    533 		if (d->ipld_dests != NULL) {
    534 			bcopy(d->ipld_dests, nodes,
    535 			      sizeof(*nodes) * d->ipld_maxnodes);
    536 			KFREES(d->ipld_dests, sizeof(*nodes) * d->ipld_nodes);
    537 			nodes[0]->ipfd_pnext = nodes;
    538 		}
    539 		d->ipld_dests = nodes;
    540 		d->ipld_maxnodes++;
    541 	}
    542 	d->ipld_dests[d->ipld_nodes] = node;
    543 	d->ipld_nodes++;
    544 
    545 	if (d->ipld_nodes == 1) {
    546 		node->ipfd_pnext = d->ipld_dests;
    547 	} else if (d->ipld_nodes > 1) {
    548 		node->ipfd_pnext = &d->ipld_dests[d->ipld_nodes - 2]->ipfd_next;
    549 	}
    550 	*node->ipfd_pnext = node;
    551 
    552 	MUTEX_INIT(&node->ipfd_lock, "ipf dst node lock");
    553 	node->ipfd_plock = &d->ipld_lock;
    554 	node->ipfd_next = NULL;
    555 	node->ipfd_uid = uid;
    556 	node->ipfd_states = 0;
    557 	node->ipfd_ref = 1;
    558 	node->ipfd_syncat = 0;
    559 	node->ipfd_dest.fd_name = 0;
    560 	(void) ipf_resolvedest(softc, node->ipfd_names, &node->ipfd_dest,
    561 			       AF_INET);
    562 #ifdef USE_INET6
    563 	if (node->ipfd_dest.fd_ptr == (void *)-1)
    564 		(void) ipf_resolvedest(softc, node->ipfd_names,
    565 				       &node->ipfd_dest, AF_INET6);
    566 #endif
    567 
    568 	softd->stats.ipls_numnodes++;
    569 
    570 	return 0;
    571 }
    572 
    573 
    574 /* ------------------------------------------------------------------------ */
    575 /* Function:    ipf_dstlist_node_deref                                      */
    576 /* Returns:     int - 0 = success, else error                               */
    577 /* Parameters:  softc(I) - pointer to soft context main structure           */
    578 /*              arg(I)   - pointer to local context to use                  */
    579 /*              op(I)    - pointer to lookup operation data                 */
    580 /*              uid(I)   - uid of process doing the ioctl                   */
    581 /*                                                                          */
    582 /* Dereference the use count by one. If it drops to zero then we can assume */
    583 /* that it has been removed from any lists/tables and is ripe for freeing.  */
    584 /* ------------------------------------------------------------------------ */
    585 static int
    586 ipf_dstlist_node_deref(arg, node)
    587 	void *arg;
    588 	ipf_dstnode_t *node;
    589 {
    590 	ipf_dstl_softc_t *softd = arg;
    591 	int ref;
    592 
    593 	/*
    594 	 * ipfd_plock points back to the lock in the ippool_dst_t that is
    595 	 * used to synchronise additions/deletions from its node list.
    596 	 */
    597 	MUTEX_ENTER(node->ipfd_plock);
    598 	ref = --node->ipfd_ref;
    599 	MUTEX_EXIT(node->ipfd_plock);
    600 
    601 	if (ref > 0)
    602 		return 0;
    603 
    604 	MUTEX_DESTROY(&node->ipfd_lock);
    605 
    606 	KFREES(node, node->ipfd_size);
    607 
    608 	if ((node->ipfd_flags & IPDST_DELETE) != 0)
    609 		softd->stats.ipls_numderefnodes--;
    610 
    611 	return 0;
    612 }
    613 
    614 
    615 /* ------------------------------------------------------------------------ */
    616 /* Function:    ipf_dstlist_node_del                                        */
    617 /* Returns:     int      - 0 = success, else error                          */
    618 /* Parameters:  softc(I) - pointer to soft context main structure           */
    619 /*              arg(I)   - pointer to local context to use                  */
    620 /*              op(I)    - pointer to lookup operation data                 */
    621 /*              uid(I)   - uid of process doing the ioctl                   */
    622 /*                                                                          */
    623 /* Look for a matching destination node on the named table and free it if   */
    624 /* found. Because the name embedded in the frdest_t is variable in length,  */
    625 /* it is necessary to allocate some memory locally, to complete this op.    */
    626 /* ------------------------------------------------------------------------ */
    627 static int
    628 ipf_dstlist_node_del(softc, arg, op, uid)
    629 	ipf_main_softc_t *softc;
    630 	void *arg;
    631 	iplookupop_t *op;
    632 	int uid;
    633 {
    634 	ipf_dstl_softc_t *softd = arg;
    635 	ipf_dstnode_t *node;
    636 	frdest_t frd, *temp;
    637 	ippool_dst_t *d;
    638 	size_t size;
    639 	int err;
    640 
    641 	d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
    642 	if (d == NULL) {
    643 		IPFERROR(120012);
    644 		return ESRCH;
    645 	}
    646 
    647 	err = COPYIN(op->iplo_struct, &frd, sizeof(frd));
    648 	if (err != 0) {
    649 		IPFERROR(120011);
    650 		return EFAULT;
    651 	}
    652 
    653 	size = sizeof(*temp) + frd.fd_name;
    654 	KMALLOCS(temp, frdest_t *, size);
    655 	if (temp == NULL) {
    656 		softd->stats.ipls_nomem++;
    657 		IPFERROR(120026);
    658 		return ENOMEM;
    659 	}
    660 
    661 	err = COPYIN(op->iplo_struct, temp, size);
    662 	if (err != 0) {
    663 		IPFERROR(120027);
    664 		return EFAULT;
    665 	}
    666 
    667 	MUTEX_ENTER(&d->ipld_lock);
    668 	for (node = *d->ipld_dests; node != NULL; node = node->ipfd_next) {
    669 		if ((uid != 0) && (node->ipfd_uid != uid))
    670 			continue;
    671 		if (node->ipfd_size != size)
    672 			continue;
    673 		if (!bcmp(&node->ipfd_dest.fd_ip6, &frd.fd_ip6,
    674 			  size - offsetof(frdest_t, fd_ip6))) {
    675 			MUTEX_ENTER(&node->ipfd_lock);
    676 			ipf_dstlist_node_free(softd, d, node);
    677 			MUTEX_EXIT(&d->ipld_lock);
    678 			KFREES(temp, size);
    679 			return 0;
    680 		}
    681 	}
    682 	MUTEX_EXIT(&d->ipld_lock);
    683 	KFREES(temp, size);
    684 
    685 	return ESRCH;
    686 }
    687 
    688 
    689 /* ------------------------------------------------------------------------ */
    690 /* Function:    ipf_dstlist_node_free                                       */
    691 /* Returns:     Nil                                                         */
    692 /* Parameters:  node(I) - pointer to node to free                           */
    693 /* Locks:       MUTEX(ipld_lock) or WRITE(ipf_poolrw)                       */
    694 /*                                                                          */
    695 /* Free the destination node by first removing it from any lists and then   */
    696 /* checking if this was the last reference held to the object. While the    */
    697 /* array of pointers to nodes is compacted, its size isn't reduced (by way  */
    698 /* of allocating a new smaller one and copying) because the belief is that  */
    699 /* it is likely the array will again reach that size.                       */
    700 /* ------------------------------------------------------------------------ */
    701 static void
    702 ipf_dstlist_node_free(softd, d, node)
    703 	ipf_dstl_softc_t *softd;
    704 	ippool_dst_t *d;
    705 	ipf_dstnode_t *node;
    706 {
    707 	int ref;
    708 	int i;
    709 
    710 	/*
    711 	 * Compact the array of pointers to nodes.
    712 	 */
    713 	for (i = 0; i < d->ipld_nodes; i++)
    714 		if (d->ipld_dests[i] == node)
    715 			break;
    716 	if (d->ipld_nodes - i > 1) {
    717 		bcopy(&d->ipld_dests[i + 1], &d->ipld_dests[i],
    718 		      sizeof(*d->ipld_dests) * (d->ipld_nodes - i - 1));
    719 	}
    720 	d->ipld_nodes--;
    721 	/*
    722 	 * ipfd_plock points back to the lock in the ippool_dst_t that is
    723 	 * used to synchronise additions/deletions from its node list.
    724 	 */
    725 	MUTEX_ENTER(node->ipfd_plock);
    726 
    727 	ref = --node->ipfd_ref;
    728 
    729 	if (node->ipfd_pnext != NULL)
    730 		*node->ipfd_pnext = node->ipfd_next;
    731 	if (node->ipfd_next != NULL)
    732 		node->ipfd_next->ipfd_pnext = node->ipfd_pnext;
    733 	node->ipfd_pnext = NULL;
    734 	node->ipfd_next = NULL;
    735 
    736 	MUTEX_EXIT(node->ipfd_plock);
    737 
    738 	if (ref == 0) {
    739 		MUTEX_DESTROY(&node->ipfd_lock);
    740 		KFREES(node, node->ipfd_size);
    741 		softd->stats.ipls_numnodes--;
    742 	} else if ((node->ipfd_flags & IPDST_DELETE) == 0) {
    743 		softd->stats.ipls_numderefnodes++;
    744 		node->ipfd_flags |= IPDST_DELETE;
    745 	}
    746 }
    747 
    748 
    749 /* ------------------------------------------------------------------------ */
    750 /* Function:    ipf_dstlist_stats_get                                       */
    751 /* Returns:     int - 0 = success, else error                               */
    752 /* Parameters:  softc(I) - pointer to soft context main structure           */
    753 /*              arg(I)   - pointer to local context to use                  */
    754 /*              op(I)    - pointer to lookup operation data                 */
    755 /*                                                                          */
    756 /* Return the current statistics for destination lists. This may be for all */
    757 /* of them or just information pertaining to a particular table.            */
    758 /* ------------------------------------------------------------------------ */
    759 /*ARGSUSED*/
    760 static int
    761 ipf_dstlist_stats_get(softc, arg, op)
    762 	ipf_main_softc_t *softc;
    763 	void *arg;
    764 	iplookupop_t *op;
    765 {
    766 	ipf_dstl_softc_t *softd = arg;
    767 	ipf_dstl_stat_t stats;
    768 	int unit, i, err = 0;
    769 
    770 	if (op->iplo_size != sizeof(ipf_dstl_stat_t)) {
    771 		IPFERROR(120023);
    772 		return EINVAL;
    773 	}
    774 
    775 	stats = softd->stats;
    776 	unit = op->iplo_unit;
    777 	if (unit == IPL_LOGALL) {
    778 		for (i = 0; i <= IPL_LOGMAX; i++)
    779 			stats.ipls_list[i] = softd->dstlist[i];
    780 	} else if (unit >= 0 && unit <= IPL_LOGMAX) {
    781 		void *ptr;
    782 
    783 		if (op->iplo_name[0] != '\0')
    784 			ptr = ipf_dstlist_table_find(softd, unit,
    785 						     op->iplo_name);
    786 		else
    787 			ptr = softd->dstlist[unit + 1];
    788 		stats.ipls_list[unit + 1] = ptr;
    789 	} else {
    790 		IPFERROR(120024);
    791 		err = EINVAL;
    792 	}
    793 
    794 	if (err == 0) {
    795 		err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
    796 		if (err != 0) {
    797 			IPFERROR(120025);
    798 			return EFAULT;
    799 		}
    800 	}
    801 	return 0;
    802 }
    803 
    804 
    805 /* ------------------------------------------------------------------------ */
    806 /* Function:    ipf_dstlist_table_add                                       */
    807 /* Returns:     int      - 0 = success, else error                          */
    808 /* Parameters:  softc(I) - pointer to soft context main structure           */
    809 /*              arg(I)   - pointer to local context to use                  */
    810 /*              op(I)    - pointer to lookup operation data                 */
    811 /*                                                                          */
    812 /* Add a new destination table to the list of those available for the given */
    813 /* device. Because we seldom operate on these objects (find/add/delete),    */
    814 /* they are just kept in a simple linked list.                              */
    815 /* ------------------------------------------------------------------------ */
    816 static int
    817 ipf_dstlist_table_add(softc, arg, op)
    818 	ipf_main_softc_t *softc;
    819 	void *arg;
    820 	iplookupop_t *op;
    821 {
    822 	ipf_dstl_softc_t *softd = arg;
    823 	ippool_dst_t user, *d, *new;
    824 	int unit, err;
    825 
    826 	KMALLOC(new, ippool_dst_t *);
    827 	if (new == NULL) {
    828 		softd->stats.ipls_nomem++;
    829 		IPFERROR(120014);
    830 		return ENOMEM;
    831 	}
    832 
    833 	d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
    834 	if (d != NULL) {
    835 		IPFERROR(120013);
    836 		KFREE(new);
    837 		return EEXIST;
    838 	}
    839 
    840 	err = COPYIN(op->iplo_struct, &user, sizeof(user));
    841 	if (err != 0) {
    842 		IPFERROR(120021);
    843 		KFREE(new);
    844 		return EFAULT;
    845 	}
    846 
    847 	MUTEX_INIT(&new->ipld_lock, "ipf dst table lock");
    848 
    849 	strncpy(new->ipld_name, op->iplo_name, FR_GROUPLEN);
    850 	unit = op->iplo_unit;
    851 	new->ipld_unit = unit;
    852 	new->ipld_policy = user.ipld_policy;
    853 	new->ipld_seed = ipf_random();
    854 	new->ipld_dests = NULL;
    855 	new->ipld_nodes = 0;
    856 	new->ipld_maxnodes = 0;
    857 	new->ipld_selected = NULL;
    858 	new->ipld_ref = 0;
    859 	new->ipld_flags = 0;
    860 
    861 	new->ipld_pnext = &softd->dstlist[unit + 1];
    862 	new->ipld_next = softd->dstlist[unit + 1];
    863 	if (softd->dstlist[unit + 1] != NULL)
    864 		softd->dstlist[unit + 1]->ipld_pnext = &new->ipld_next;
    865 	softd->dstlist[unit + 1] = new;
    866 	softd->stats.ipls_numlists++;
    867 
    868 	return 0;
    869 }
    870 
    871 
    872 /* ------------------------------------------------------------------------ */
    873 /* Function:    ipf_dstlist_table_del                                       */
    874 /* Returns:     int - 0 = success, else error                               */
    875 /* Parameters:  softc(I) - pointer to soft context main structure           */
    876 /*              arg(I)   - pointer to local context to use                  */
    877 /*              op(I)    - pointer to lookup operation data                 */
    878 /*                                                                          */
    879 /* Find a named destinstion list table and delete it. If there are other    */
    880 /* references to it, the caller isn't told.                                 */
    881 /* ------------------------------------------------------------------------ */
    882 static int
    883 ipf_dstlist_table_del(softc, arg, op)
    884 	ipf_main_softc_t *softc;
    885 	void *arg;
    886 	iplookupop_t *op;
    887 {
    888 	ippool_dst_t *d;
    889 
    890 	d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
    891 	if (d == NULL) {
    892 		IPFERROR(120015);
    893 		return ESRCH;
    894 	}
    895 
    896 	if (d->ipld_dests != NULL) {
    897 		IPFERROR(120016);
    898 		return EBUSY;
    899 	}
    900 
    901 	ipf_dstlist_table_remove(softc, arg, d);
    902 
    903 	return 0;
    904 }
    905 
    906 
    907 /* ------------------------------------------------------------------------ */
    908 /* Function:    ipf_dstlist_table_remove                                    */
    909 /* Returns:     Nil                                                         */
    910 /* Parameters:  softc(I) - pointer to soft context main structure           */
    911 /*              arg(I)   - pointer to local context to use                  */
    912 /*              op(I)    - pointer to lookup operation data                 */
    913 /*                                                                          */
    914 /* Remove a given destination list from existance. While the IPDST_DELETE   */
    915 /* flag is set every time we call this function and the reference count is  */
    916 /* non-zero, the "numdereflists" counter is only incremented when the entry */
    917 /* is removed from the list as it only becomes dereferenced once.           */
    918 /* ------------------------------------------------------------------------ */
    919 static void
    920 ipf_dstlist_table_remove(softc, softd, d)
    921 	ipf_main_softc_t *softc;
    922 	ipf_dstl_softc_t *softd;
    923 	ippool_dst_t *d;
    924 {
    925 
    926 	if (d->ipld_pnext != NULL) {
    927 		*d->ipld_pnext = d->ipld_next;
    928 		if (d->ipld_ref > 1)
    929 			softd->stats.ipls_numdereflists++;
    930 	}
    931 	if (d->ipld_next != NULL)
    932 		d->ipld_next->ipld_pnext = d->ipld_pnext;
    933 	d->ipld_pnext = NULL;
    934 	d->ipld_next = NULL;
    935 
    936 	ipf_dstlist_table_clearnodes(softd, d);
    937 
    938 	if (d->ipld_ref > 0) {
    939 		d->ipld_flags |= IPDST_DELETE;
    940 		return;
    941 	}
    942 
    943 	MUTEX_DESTROY(&d->ipld_lock);
    944 
    945 	if ((d->ipld_flags & IPDST_DELETE) != 0)
    946 		softd->stats.ipls_numdereflists--;
    947 	softd->stats.ipls_numlists--;
    948 
    949 	if (d->ipld_dests != NULL) {
    950 		KFREES(d->ipld_dests,
    951 		       d->ipld_maxnodes * sizeof(*d->ipld_dests));
    952 	}
    953 
    954 	KFREE(d);
    955 }
    956 
    957 
    958 /* ------------------------------------------------------------------------ */
    959 /* Function:    ipf_dstlist_table_deref                                     */
    960 /* Returns:     int - 0 = success, else error                               */
    961 /* Parameters:  softc(I) - pointer to soft context main structure           */
    962 /*              arg(I)   - pointer to local context to use                  */
    963 /*              op(I)    - pointer to lookup operation data                 */
    964 /*                                                                          */
    965 /* Drops the reference count on a destination list table object and free's  */
    966 /* it if 0 has been reached.                                                */
    967 /* ------------------------------------------------------------------------ */
    968 static int
    969 ipf_dstlist_table_deref(softc, arg, table)
    970 	ipf_main_softc_t *softc;
    971 	void *arg;
    972 	void *table;
    973 {
    974 	ippool_dst_t *d = table;
    975 
    976 	d->ipld_ref--;
    977 	if (d->ipld_ref > 0)
    978 		return d->ipld_ref;
    979 
    980 	ipf_dstlist_table_remove(softc, arg, table);
    981 
    982 	return 0;
    983 }
    984 
    985 
    986 /* ------------------------------------------------------------------------ */
    987 /* Function:    ipf_dstlist_table_clearnodes                                */
    988 /* Returns:     Nil                                                         */
    989 /* Parameters:  dst(I) - pointer to soft context main structure             */
    990 /*                                                                          */
    991 /* Free all of the destination nodes attached to the given table.           */
    992 /* ------------------------------------------------------------------------ */
    993 static void
    994 ipf_dstlist_table_clearnodes(softd, dst)
    995 	ipf_dstl_softc_t *softd;
    996 	ippool_dst_t *dst;
    997 {
    998 	ipf_dstnode_t *node;
    999 
   1000 	while ((node = *dst->ipld_dests) != NULL) {
   1001 		ipf_dstlist_node_free(softd, dst, node);
   1002 	}
   1003 }
   1004 
   1005 
   1006 /* ------------------------------------------------------------------------ */
   1007 /* Function:    ipf_dstlist_table_find                                      */
   1008 /* Returns:     int      - 0 = success, else error                          */
   1009 /* Parameters:  arg(I)   - pointer to local context to use                  */
   1010 /*              unit(I)  - device we are working with                       */
   1011 /*              name(I)  - destination table name to find                   */
   1012 /*                                                                          */
   1013 /* Return a pointer to a destination table that matches the unit+name that  */
   1014 /* is passed in.                                                            */
   1015 /* ------------------------------------------------------------------------ */
   1016 static void *
   1017 ipf_dstlist_table_find(arg, unit, name)
   1018 	void *arg;
   1019 	int unit;
   1020 	char *name;
   1021 {
   1022 	ipf_dstl_softc_t *softd = arg;
   1023 	ippool_dst_t *d;
   1024 
   1025 	for (d = softd->dstlist[unit + 1]; d != NULL; d = d->ipld_next) {
   1026 		if ((d->ipld_unit == unit) &&
   1027 		    !strncmp(d->ipld_name, name, FR_GROUPLEN)) {
   1028 			return d;
   1029 		}
   1030 	}
   1031 
   1032 	return NULL;
   1033 }
   1034 
   1035 
   1036 /* ------------------------------------------------------------------------ */
   1037 /* Function:    ipf_dstlist_select_ref                                      */
   1038 /* Returns:     void *   - NULL = failure, else pointer to table            */
   1039 /* Parameters:  arg(I)   - pointer to local context to use                  */
   1040 /*              unit(I)  - device we are working with                       */
   1041 /*              name(I)  - destination table name to find                   */
   1042 /*                                                                          */
   1043 /* Attempt to find a destination table that matches the name passed in and  */
   1044 /* if successful, bump up the reference count on it because we intend to    */
   1045 /* store the pointer to it somewhere else.                                  */
   1046 /* ------------------------------------------------------------------------ */
   1047 static void *
   1048 ipf_dstlist_select_ref(arg, unit, name)
   1049 	void *arg;
   1050 	int unit;
   1051 	char *name;
   1052 {
   1053 	ippool_dst_t *d;
   1054 
   1055 	d = ipf_dstlist_table_find(arg, unit, name);
   1056 	if (d != NULL) {
   1057 		MUTEX_ENTER(&d->ipld_lock);
   1058 		d->ipld_ref++;
   1059 		MUTEX_EXIT(&d->ipld_lock);
   1060 	}
   1061 	return d;
   1062 }
   1063 
   1064 
   1065 /* ------------------------------------------------------------------------ */
   1066 /* Function:    ipf_dstlist_select                                          */
   1067 /* Returns:     void * - NULL = failure, else pointer to table              */
   1068 /* Parameters:  d(I)   - pointer to destination list                        */
   1069 /*                                                                          */
   1070 /* Find the next node in the destination list to be used according to the   */
   1071 /* defined policy. Of these, "connection" is the most expensive policy to   */
   1072 /* implement as it always looks for the node with the least number of       */
   1073 /* connections associated with it.                                          */
   1074 /*                                                                          */
   1075 /* The hashes exclude the port numbers so that all protocols map to the     */
   1076 /* same destination. Otherwise, someone doing a ping would target a         */
   1077 /* different server than their TCP connection, etc. MD-5 is used to         */
   1078 /* transform the addressese into something random that the other end could  */
   1079 /* not easily guess and use in an attack. ipld_seed introduces an unknown   */
   1080 /* into the hash calculation to increase the difficult of an attacker       */
   1081 /* guessing the bucket.                                                     */
   1082 /*                                                                          */
   1083 /* One final comment: mixing different address families in a single pool    */
   1084 /* will currently result in failures as the address family of the node is   */
   1085 /* only matched up with that in the packet as the last step. While this can */
   1086 /* be coded around for the weighted connection and round-robin models, it   */
   1087 /* cannot be supported for the hash/random models as they do not search and */
   1088 /* nor is the algorithm conducive to searching.                             */
   1089 /* ------------------------------------------------------------------------ */
   1090 static ipf_dstnode_t *
   1091 ipf_dstlist_select(fin, d)
   1092 	fr_info_t *fin;
   1093 	ippool_dst_t *d;
   1094 {
   1095 	ipf_dstnode_t *node, *sel;
   1096 	int connects;
   1097 	u_32_t hash[4];
   1098 	MD5_CTX ctx;
   1099 	int family;
   1100 	int x;
   1101 
   1102 	if (d->ipld_dests == NULL || *d->ipld_dests == NULL)
   1103 		return NULL;
   1104 
   1105 	family = fin->fin_family;
   1106 
   1107 	MUTEX_ENTER(&d->ipld_lock);
   1108 
   1109 	switch (d->ipld_policy)
   1110 	{
   1111 	case IPLDP_ROUNDROBIN:
   1112 		sel = d->ipld_selected;
   1113 		if (sel == NULL) {
   1114 			sel = *d->ipld_dests;
   1115 		} else {
   1116 			sel = sel->ipfd_next;
   1117 			if (sel == NULL)
   1118 				sel = *d->ipld_dests;
   1119 		}
   1120 		break;
   1121 
   1122 	case IPLDP_CONNECTION:
   1123 		if (d->ipld_selected == NULL) {
   1124 			sel = *d->ipld_dests;
   1125 			break;
   1126 		}
   1127 
   1128 		sel = d->ipld_selected;
   1129 		connects = 0x7fffffff;
   1130 		node = sel->ipfd_next;
   1131 		if (node == NULL)
   1132 			node = *d->ipld_dests;
   1133 		while (node != d->ipld_selected) {
   1134 			if (node->ipfd_states == 0) {
   1135 				sel = node;
   1136 				break;
   1137 			}
   1138 			if (node->ipfd_states < connects) {
   1139 				sel = node;
   1140 				connects = node->ipfd_states;
   1141 			}
   1142 			node = node->ipfd_next;
   1143 			if (node == NULL)
   1144 				node = *d->ipld_dests;
   1145 		}
   1146 		break;
   1147 
   1148 	case IPLDP_RANDOM :
   1149 		x = ipf_random() % d->ipld_nodes;
   1150 		sel = d->ipld_dests[x];
   1151 		break;
   1152 
   1153 	case IPLDP_HASHED :
   1154 		MD5Init(&ctx);
   1155 		MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed));
   1156 		MD5Update(&ctx, (u_char *)&fin->fin_src6,
   1157 			  sizeof(fin->fin_src6));
   1158 		MD5Update(&ctx, (u_char *)&fin->fin_dst6,
   1159 			  sizeof(fin->fin_dst6));
   1160 		MD5Final((u_char *)hash, &ctx);
   1161 		x = hash[0] % d->ipld_nodes;
   1162 		sel = d->ipld_dests[x];
   1163 		break;
   1164 
   1165 	case IPLDP_SRCHASH :
   1166 		MD5Init(&ctx);
   1167 		MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed));
   1168 		MD5Update(&ctx, (u_char *)&fin->fin_src6,
   1169 			  sizeof(fin->fin_src6));
   1170 		MD5Final((u_char *)hash, &ctx);
   1171 		x = hash[0] % d->ipld_nodes;
   1172 		sel = d->ipld_dests[x];
   1173 		break;
   1174 
   1175 	case IPLDP_DSTHASH :
   1176 		MD5Init(&ctx);
   1177 		MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed));
   1178 		MD5Update(&ctx, (u_char *)&fin->fin_dst6,
   1179 			  sizeof(fin->fin_dst6));
   1180 		MD5Final((u_char *)hash, &ctx);
   1181 		x = hash[0] % d->ipld_nodes;
   1182 		sel = d->ipld_dests[x];
   1183 		break;
   1184 
   1185 	default :
   1186 		sel = NULL;
   1187 		break;
   1188 	}
   1189 
   1190 	if (sel->ipfd_dest.fd_addr.adf_family != family)
   1191 		sel = NULL;
   1192 	d->ipld_selected = sel;
   1193 
   1194 	MUTEX_EXIT(&d->ipld_lock);
   1195 
   1196 	return sel;
   1197 }
   1198 
   1199 
   1200 /* ------------------------------------------------------------------------ */
   1201 /* Function:    ipf_dstlist_select_node                                     */
   1202 /* Returns:     int      - -1 == failure, 0 == success                      */
   1203 /* Parameters:  fin(I)   - pointer to packet information                    */
   1204 /*              group(I) - destination pool to search                       */
   1205 /*              addr(I)  - pointer to store selected address                */
   1206 /*                                                                          */
   1207 /* This function is only responsible for obtaining the next IP address for  */
   1208 /* use and storing it in the caller's address space (addr). No permanent    */
   1209 /* reference is currently kept on the node.                                 */
   1210 /* ------------------------------------------------------------------------ */
   1211 int
   1212 ipf_dstlist_select_node(fin, group, addr, pfdp)
   1213 	fr_info_t *fin;
   1214 	void *group;
   1215 	u_32_t *addr;
   1216 	frdest_t *pfdp;
   1217 {
   1218 #ifdef USE_MUTEXES
   1219 	ipf_main_softc_t *softc = fin->fin_main_soft;
   1220 #endif
   1221 	ippool_dst_t *d = group;
   1222 	ipf_dstnode_t *node;
   1223 	frdest_t *fdp;
   1224 
   1225 	READ_ENTER(&softc->ipf_poolrw);
   1226 
   1227 	node = ipf_dstlist_select(fin, d);
   1228 	if (node == NULL) {
   1229 		RWLOCK_EXIT(&softc->ipf_poolrw);
   1230 		return -1;
   1231 	}
   1232 
   1233 	if (pfdp != NULL) {
   1234 		bcopy(&node->ipfd_dest, pfdp, sizeof(*pfdp));
   1235 	} else {
   1236 		if (fin->fin_family == AF_INET) {
   1237 			addr[0] = node->ipfd_dest.fd_addr.adf_addr.i6[0];
   1238 		} else if (fin->fin_family == AF_INET6) {
   1239 			addr[0] = node->ipfd_dest.fd_addr.adf_addr.i6[0];
   1240 			addr[1] = node->ipfd_dest.fd_addr.adf_addr.i6[1];
   1241 			addr[2] = node->ipfd_dest.fd_addr.adf_addr.i6[2];
   1242 			addr[3] = node->ipfd_dest.fd_addr.adf_addr.i6[3];
   1243 		}
   1244 	}
   1245 
   1246 	fdp = &node->ipfd_dest;
   1247 	if (fdp->fd_ptr == NULL)
   1248 		fdp->fd_ptr = fin->fin_ifp;
   1249 
   1250 	MUTEX_ENTER(&node->ipfd_lock);
   1251 	node->ipfd_states++;
   1252 	MUTEX_EXIT(&node->ipfd_lock);
   1253 
   1254 	RWLOCK_EXIT(&softc->ipf_poolrw);
   1255 
   1256 	return 0;
   1257 }
   1258 
   1259 
   1260 /* ------------------------------------------------------------------------ */
   1261 /* Function:    ipf_dstlist_expire                                          */
   1262 /* Returns:     Nil                                                         */
   1263 /* Parameters:  softc(I) - pointer to soft context main structure           */
   1264 /*              arg(I)   - pointer to local context to use                  */
   1265 /*                                                                          */
   1266 /* There are currently no objects to expire in destination lists.           */
   1267 /* ------------------------------------------------------------------------ */
   1268 static void
   1269 ipf_dstlist_expire(softc, arg)
   1270 	ipf_main_softc_t *softc;
   1271 	void *arg;
   1272 {
   1273 	return;
   1274 }
   1275 
   1276 
   1277 /* ------------------------------------------------------------------------ */
   1278 /* Function:    ipf_dstlist_sync                                            */
   1279 /* Returns:     Nil                                                         */
   1280 /* Parameters:  softc(I) - pointer to soft context main structure           */
   1281 /*              arg(I)   - pointer to local context to use                  */
   1282 /*                                                                          */
   1283 /* When a network interface appears or disappears, we need to revalidate    */
   1284 /* all of the network interface names that have been configured as a target */
   1285 /* in a destination list.                                                   */
   1286 /* ------------------------------------------------------------------------ */
   1287 void
   1288 ipf_dstlist_sync(softc, arg)
   1289 	ipf_main_softc_t *softc;
   1290 	void *arg;
   1291 {
   1292 	ipf_dstl_softc_t *softd = arg;
   1293 	ipf_dstnode_t *node;
   1294 	ippool_dst_t *list;
   1295 	int i;
   1296 	int j;
   1297 
   1298 	for (i = 0; i < IPL_LOGMAX; i++) {
   1299 		for (list = softd->dstlist[i]; list != NULL;
   1300 		     list = list->ipld_next) {
   1301 			for (j = 0; j < list->ipld_maxnodes; j++) {
   1302 				node = list->ipld_dests[j];
   1303 				if (node == NULL)
   1304 					continue;
   1305 				if (node->ipfd_dest.fd_name == -1)
   1306 					continue;
   1307 				(void) ipf_resolvedest(softc,
   1308 						       node->ipfd_names,
   1309 						       &node->ipfd_dest,
   1310 						       AF_INET);
   1311 			}
   1312 		}
   1313 	}
   1314 }
   1315