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