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