1 /*        $NetBSD: ip_htable.c,v 1.2 2012/07/22 14:27:35 darrenr Exp $          */
2 
3 /*
4  * Copyright (C) 2012 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 #if defined(KERNEL) || defined(_KERNEL)
9 # undef KERNEL
10 # undef _KERNEL
11 # define        KERNEL        1
12 # define        _KERNEL       1
13 #endif
14 #include <sys/param.h>
15 #include <sys/types.h>
16 #include <sys/errno.h>
17 #include <sys/time.h>
18 #include <sys/file.h>
19 #if !defined(_KERNEL)
20 # include <stdlib.h>
21 # include <string.h>
22 # define _KERNEL
23 # ifdef __OpenBSD__
24 struct file;
25 # endif
26 # include <sys/uio.h>
27 # undef _KERNEL
28 #endif
29 #include <sys/socket.h>
30 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
31 # include <sys/malloc.h>
32 #endif
33 #if defined(__FreeBSD__)
34 #  include <sys/cdefs.h>
35 #  include <sys/proc.h>
36 #endif
37 #if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \
38     !defined(linux)
39 # include <sys/mbuf.h>
40 #endif
41 #if defined(_KERNEL)
42 # include <sys/systm.h>
43 #else
44 # include "ipf.h"
45 #endif
46 #include <netinet/in.h>
47 #include <net/if.h>
48 
49 #include "netinet/ip_compat.h"
50 #include "netinet/ip_fil.h"
51 #include "netinet/ip_lookup.h"
52 #include "netinet/ip_htable.h"
53 /* END OF INCLUDES */
54 
55 #if !defined(lint)
56 static const char rcsid[] = "@(#)Id: ip_htable.c,v 1.1.1.2 2012/07/22 13:44:17 darrenr Exp";
57 #endif
58 
59 # ifdef USE_INET6
60 static iphtent_t *ipf_iphmfind6 __P((iphtable_t *, i6addr_t *));
61 # endif
62 static iphtent_t *ipf_iphmfind __P((iphtable_t *, struct in_addr *));
63 static int ipf_iphmfindip __P((ipf_main_softc_t *, void *, int, void *, u_int));
64 static int ipf_htable_clear __P((ipf_main_softc_t *, void *, iphtable_t *));
65 static int ipf_htable_create __P((ipf_main_softc_t *, void *, iplookupop_t *));
66 static int ipf_htable_deref __P((ipf_main_softc_t *, void *, void *));
67 static int ipf_htable_destroy __P((ipf_main_softc_t *, void *, int, char *));
68 static void *ipf_htable_exists __P((void *, int, char *));
69 static size_t ipf_htable_flush __P((ipf_main_softc_t *, void *,
70                                             iplookupflush_t *));
71 static void ipf_htable_free __P((void *, iphtable_t *));
72 static int ipf_htable_iter_deref __P((ipf_main_softc_t *, void *, int,
73                                               int, void *));
74 static int ipf_htable_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *,
75                                              ipflookupiter_t *));
76 static int ipf_htable_node_add __P((ipf_main_softc_t *, void *,
77                                             iplookupop_t *, int));
78 static int ipf_htable_node_del __P((ipf_main_softc_t *, void *,
79                                             iplookupop_t *, int));
80 static int ipf_htable_remove __P((ipf_main_softc_t *, void *, iphtable_t *));
81 static void *ipf_htable_soft_create __P((ipf_main_softc_t *));
82 static void ipf_htable_soft_destroy __P((ipf_main_softc_t *, void *));
83 static int ipf_htable_soft_init __P((ipf_main_softc_t *, void *));
84 static void ipf_htable_soft_fini __P((ipf_main_softc_t *, void *));
85 static int ipf_htable_stats_get __P((ipf_main_softc_t *, void *,
86                                              iplookupop_t *));
87 static int ipf_htable_table_add __P((ipf_main_softc_t *, void *,
88                                              iplookupop_t *));
89 static int ipf_htable_table_del __P((ipf_main_softc_t *, void *,
90                                              iplookupop_t *));
91 static int ipf_htent_deref __P((void *, iphtent_t *));
92 static iphtent_t *ipf_htent_find __P((iphtable_t *, iphtent_t *));
93 static int ipf_htent_insert __P((ipf_main_softc_t *, void *, iphtable_t *,
94                                          iphtent_t *));
95 static int ipf_htent_remove __P((ipf_main_softc_t *, void *, iphtable_t *,
96                                          iphtent_t *));
97 static void *ipf_htable_select_add_ref __P((void *, int, char *));
98 static void ipf_htable_expire __P((ipf_main_softc_t *, void *));
99 
100 
101 typedef struct ipf_htable_softc_s {
102           u_long              ipht_nomem[LOOKUP_POOL_SZ];
103           u_long              ipf_nhtables[LOOKUP_POOL_SZ];
104           u_long              ipf_nhtnodes[LOOKUP_POOL_SZ];
105           iphtable_t          *ipf_htables[LOOKUP_POOL_SZ];
106           iphtent_t *ipf_node_explist;
107 } ipf_htable_softc_t;
108 
109 ipf_lookup_t ipf_htable_backend = {
110           IPLT_HASH,
111           ipf_htable_soft_create,
112           ipf_htable_soft_destroy,
113           ipf_htable_soft_init,
114           ipf_htable_soft_fini,
115           ipf_iphmfindip,
116           ipf_htable_flush,
117           ipf_htable_iter_deref,
118           ipf_htable_iter_next,
119           ipf_htable_node_add,
120           ipf_htable_node_del,
121           ipf_htable_stats_get,
122           ipf_htable_table_add,
123           ipf_htable_table_del,
124           ipf_htable_deref,
125           ipf_htable_exists,
126           ipf_htable_select_add_ref,
127           NULL,
128           ipf_htable_expire,
129           NULL
130 };
131 
132 
133 /* ------------------------------------------------------------------------ */
134 /* Function:    ipf_htable_soft_create                                      */
135 /* Returns:     void *   - NULL = failure, else pointer to local context    */
136 /* Parameters:  softc(I) - pointer to soft context main structure           */
137 /*                                                                          */
138 /* Initialise the routing table data structures where required.             */
139 /* ------------------------------------------------------------------------ */
140 static void *
ipf_htable_soft_create(softc)141 ipf_htable_soft_create(softc)
142           ipf_main_softc_t *softc;
143 {
144           ipf_htable_softc_t *softh;
145 
146           KMALLOC(softh, ipf_htable_softc_t *);
147           if (softh == NULL) {
148                     IPFERROR(30026);
149                     return NULL;
150           }
151 
152           bzero((char *)softh, sizeof(*softh));
153 
154           return softh;
155 }
156 
157 
158 /* ------------------------------------------------------------------------ */
159 /* Function:    ipf_htable_soft_destroy                                     */
160 /* Returns:     Nil                                                         */
161 /* Parameters:  softc(I) - pointer to soft context main structure           */
162 /*              arg(I)   - pointer to local context to use                  */
163 /*                                                                          */
164 /* Clean up the pool by free'ing the radix tree associated with it and free */
165 /* up the pool context too.                                                 */
166 /* ------------------------------------------------------------------------ */
167 static void
ipf_htable_soft_destroy(softc,arg)168 ipf_htable_soft_destroy(softc, arg)
169           ipf_main_softc_t *softc;
170           void *arg;
171 {
172           ipf_htable_softc_t *softh = arg;
173 
174           KFREE(softh);
175 }
176 
177 
178 /* ------------------------------------------------------------------------ */
179 /* Function:    ipf_htable_soft_init                                        */
180 /* Returns:     int     - 0 = success, else error                           */
181 /* Parameters:  softc(I) - pointer to soft context main structure           */
182 /*              arg(I)   - pointer to local context to use                  */
183 /*                                                                          */
184 /* Initialise the hash table ready for use.                                 */
185 /* ------------------------------------------------------------------------ */
186 static int
ipf_htable_soft_init(softc,arg)187 ipf_htable_soft_init(softc, arg)
188           ipf_main_softc_t *softc;
189           void *arg;
190 {
191           ipf_htable_softc_t *softh = arg;
192 
193           bzero((char *)softh, sizeof(*softh));
194 
195           return 0;
196 }
197 
198 
199 /* ------------------------------------------------------------------------ */
200 /* Function:    ipf_htable_soft_fini                                        */
201 /* Returns:     Nil                                                         */
202 /* Parameters:  softc(I) - pointer to soft context main structure           */
203 /*              arg(I)   - pointer to local context to use                  */
204 /* Locks:       WRITE(ipf_global)                                           */
205 /*                                                                          */
206 /* Clean up all the pool data structures allocated and call the cleanup     */
207 /* function for the radix tree that supports the pools. ipf_pool_destroy is */
208 /* used to delete the pools one by one to ensure they're properly freed up. */
209 /* ------------------------------------------------------------------------ */
210 static void
ipf_htable_soft_fini(softc,arg)211 ipf_htable_soft_fini(softc, arg)
212           ipf_main_softc_t *softc;
213           void *arg;
214 {
215           iplookupflush_t fop;
216 
217           fop.iplf_type = IPLT_HASH;
218           fop.iplf_unit = IPL_LOGALL;
219           fop.iplf_arg = 0;
220           fop.iplf_count = 0;
221           *fop.iplf_name = '\0';
222           ipf_htable_flush(softc, arg, &fop);
223 }
224 
225 
226 /* ------------------------------------------------------------------------ */
227 /* Function:    ipf_htable_stats_get                                        */
228 /* Returns:     int - 0 = success, else error                               */
229 /* Parameters:  softc(I) - pointer to soft context main structure           */
230 /*              arg(I)   - pointer to local context to use                  */
231 /*              op(I)    - pointer to lookup operation data                 */
232 /*                                                                          */
233 /* Copy the relevant statistics out of internal structures and into the     */
234 /* structure used to export statistics.                                     */
235 /* ------------------------------------------------------------------------ */
236 static int
ipf_htable_stats_get(softc,arg,op)237 ipf_htable_stats_get(softc, arg, op)
238           ipf_main_softc_t *softc;
239           void *arg;
240           iplookupop_t *op;
241 {
242           ipf_htable_softc_t *softh = arg;
243           iphtstat_t stats;
244           int err;
245 
246           if (op->iplo_size != sizeof(stats)) {
247                     IPFERROR(30001);
248                     return EINVAL;
249           }
250 
251           stats.iphs_tables = softh->ipf_htables[op->iplo_unit + 1];
252           stats.iphs_numtables = softh->ipf_nhtables[op->iplo_unit + 1];
253           stats.iphs_numnodes = softh->ipf_nhtnodes[op->iplo_unit + 1];
254           stats.iphs_nomem = softh->ipht_nomem[op->iplo_unit + 1];
255 
256           err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
257           if (err != 0) {
258                     IPFERROR(30013);
259                     return EFAULT;
260           }
261           return 0;
262 
263 }
264 
265 
266 /* ------------------------------------------------------------------------ */
267 /* Function:    ipf_htable_create                                           */
268 /* Returns:     int - 0 = success, else error                               */
269 /* Parameters:  softc(I) - pointer to soft context main structure           */
270 /*              arg(I)   - pointer to local context to use                  */
271 /*              op(I)    - pointer to lookup operation data                 */
272 /*                                                                          */
273 /* Create a new hash table using the template passed.                       */
274 /* ------------------------------------------------------------------------ */
275 static int
ipf_htable_create(softc,arg,op)276 ipf_htable_create(softc, arg, op)
277           ipf_main_softc_t *softc;
278           void *arg;
279           iplookupop_t *op;
280 {
281           ipf_htable_softc_t *softh = arg;
282           iphtable_t htab, *iph, *oiph;
283           char name[FR_GROUPLEN];
284           int err, i, unit;
285 
286           if (op->iplo_size != sizeof(htab)) {
287                     IPFERROR(30024);
288                     return EINVAL;
289           }
290           err = COPYIN(op->iplo_struct, &htab, sizeof(htab));
291           if (err != 0) {
292                     IPFERROR(30003);
293                     return EFAULT;
294           }
295 
296           unit = op->iplo_unit;
297           if (htab.iph_unit != unit) {
298                     IPFERROR(30005);
299                     return EINVAL;
300           }
301           if (htab.iph_size < 1) {
302                     IPFERROR(30025);
303                     return EINVAL;
304           }
305 
306 
307           if ((op->iplo_arg & IPHASH_ANON) == 0) {
308                     iph = ipf_htable_exists(softh, unit, op->iplo_name);
309                     if (iph != NULL) {
310                               if ((iph->iph_flags & IPHASH_DELETE) == 0) {
311                                         IPFERROR(30004);
312                                         return EEXIST;
313                               }
314                               iph->iph_flags &= ~IPHASH_DELETE;
315                               iph->iph_ref++;
316                               return 0;
317                     }
318           }
319 
320           KMALLOC(iph, iphtable_t *);
321           if (iph == NULL) {
322                     softh->ipht_nomem[op->iplo_unit + 1]++;
323                     IPFERROR(30002);
324                     return ENOMEM;
325           }
326           *iph = htab;
327 
328           if ((op->iplo_arg & IPHASH_ANON) != 0) {
329                     i = IPHASH_ANON;
330                     do {
331                               i++;
332 #if defined(SNPRINTF) && defined(_KERNEL)
333                               SNPRINTF(name, sizeof(name), "%u", i);
334 #else
335                               (void)sprintf(name, "%u", i);
336 #endif
337                               for (oiph = softh->ipf_htables[unit + 1]; oiph != NULL;
338                                    oiph = oiph->iph_next)
339                                         if (strncmp(oiph->iph_name, name,
340                                                       sizeof(oiph->iph_name)) == 0)
341                                                   break;
342                     } while (oiph != NULL);
343 
344                     (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
345                     (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
346                     iph->iph_type |= IPHASH_ANON;
347           } else {
348                     (void)strncpy(iph->iph_name, op->iplo_name,
349                                     sizeof(iph->iph_name));
350                     iph->iph_name[sizeof(iph->iph_name) - 1] = '\0';
351           }
352 
353           KMALLOCS(iph->iph_table, iphtent_t **,
354                      iph->iph_size * sizeof(*iph->iph_table));
355           if (iph->iph_table == NULL) {
356                     KFREE(iph);
357                     softh->ipht_nomem[unit + 1]++;
358                     IPFERROR(30006);
359                     return ENOMEM;
360           }
361 
362           bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
363           iph->iph_maskset[0] = 0;
364           iph->iph_maskset[1] = 0;
365           iph->iph_maskset[2] = 0;
366           iph->iph_maskset[3] = 0;
367 
368           iph->iph_ref = 1;
369           iph->iph_list = NULL;
370           iph->iph_tail = &iph->iph_list;
371           iph->iph_next = softh->ipf_htables[unit + 1];
372           iph->iph_pnext = &softh->ipf_htables[unit + 1];
373           if (softh->ipf_htables[unit + 1] != NULL)
374                     softh->ipf_htables[unit + 1]->iph_pnext = &iph->iph_next;
375           softh->ipf_htables[unit + 1] = iph;
376 
377           softh->ipf_nhtables[unit + 1]++;
378 
379           return 0;
380 }
381 
382 
383 /* ------------------------------------------------------------------------ */
384 /* Function:    ipf_htable_table_del                                        */
385 /* Returns:     int      - 0 = success, else error                          */
386 /* Parameters:  softc(I) - pointer to soft context main structure           */
387 /*              arg(I)   - pointer to local context to use                  */
388 /*              op(I)    - pointer to lookup operation data                 */
389 /*                                                                          */
390 /* ------------------------------------------------------------------------ */
391 static int
ipf_htable_table_del(softc,arg,op)392 ipf_htable_table_del(softc, arg, op)
393           ipf_main_softc_t *softc;
394           void *arg;
395           iplookupop_t *op;
396 {
397           return ipf_htable_destroy(softc, arg, op->iplo_unit, op->iplo_name);
398 }
399 
400 
401 /* ------------------------------------------------------------------------ */
402 /* Function:    ipf_htable_destroy                                          */
403 /* Returns:     int      - 0 = success, else error                          */
404 /* Parameters:  softc(I) - pointer to soft context main structure           */
405 /*              arg(I)   - pointer to local context to use                  */
406 /*              op(I)    - pointer to lookup operation data                 */
407 /*                                                                          */
408 /* Find the hash table that belongs to the relevant part of ipfilter with a */
409 /* matching name and attempt to destroy it.  If it is in use, empty it out  */
410 /* and mark it for deletion so that when all the references disappear, it   */
411 /* can be removed.                                                          */
412 /* ------------------------------------------------------------------------ */
413 static int
ipf_htable_destroy(softc,arg,unit,name)414 ipf_htable_destroy(softc, arg, unit, name)
415           ipf_main_softc_t *softc;
416           void *arg;
417           int unit;
418           char *name;
419 {
420           iphtable_t *iph;
421 
422           iph = ipf_htable_find(arg, unit, name);
423           if (iph == NULL) {
424                     IPFERROR(30007);
425                     return ESRCH;
426           }
427 
428           if (iph->iph_unit != unit) {
429                     IPFERROR(30008);
430                     return EINVAL;
431           }
432 
433           if (iph->iph_ref != 0) {
434                     ipf_htable_clear(softc, arg, iph);
435                     iph->iph_flags |= IPHASH_DELETE;
436                     return 0;
437           }
438 
439           ipf_htable_remove(softc, arg, iph);
440 
441           return 0;
442 }
443 
444 
445 /* ------------------------------------------------------------------------ */
446 /* Function:    ipf_htable_clear                                            */
447 /* Returns:     int      - 0 = success, else error                          */
448 /* Parameters:  softc(I) - pointer to soft context main structure           */
449 /*              arg(I)   - pointer to local context to use                  */
450 /*              iph(I)   - pointer to hash table to destroy                 */
451 /*                                                                          */
452 /* Clean out the hash table by walking the list of entries and removing     */
453 /* each one, one by one.                                                    */
454 /* ------------------------------------------------------------------------ */
455 static int
ipf_htable_clear(softc,arg,iph)456 ipf_htable_clear(softc, arg, iph)
457           ipf_main_softc_t *softc;
458           void *arg;
459           iphtable_t *iph;
460 {
461           iphtent_t *ipe;
462 
463           while ((ipe = iph->iph_list) != NULL)
464                     if (ipf_htent_remove(softc, arg, iph, ipe) != 0)
465                               return 1;
466           return 0;
467 }
468 
469 
470 /* ------------------------------------------------------------------------ */
471 /* Function:    ipf_htable_free                                             */
472 /* Returns:     Nil                                                         */
473 /* Parameters:  arg(I) - pointer to local context to use                    */
474 /*              iph(I) - pointer to hash table to destroy                   */
475 /*                                                                          */
476 /* ------------------------------------------------------------------------ */
477 static void
ipf_htable_free(arg,iph)478 ipf_htable_free(arg, iph)
479           void *arg;
480           iphtable_t *iph;
481 {
482           ipf_htable_softc_t *softh = arg;
483 
484           if (iph->iph_next != NULL)
485                     iph->iph_next->iph_pnext = iph->iph_pnext;
486           if (iph->iph_pnext != NULL)
487                     *iph->iph_pnext = iph->iph_next;
488           iph->iph_pnext = NULL;
489           iph->iph_next = NULL;
490 
491           softh->ipf_nhtables[iph->iph_unit + 1]--;
492 
493           KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
494           KFREE(iph);
495 }
496 
497 
498 /* ------------------------------------------------------------------------ */
499 /* Function:    ipf_htable_remove                                           */
500 /* Returns:     int      - 0 = success, else error                          */
501 /* Parameters:  softc(I) - pointer to soft context main structure           */
502 /*              arg(I)   - pointer to local context to use                  */
503 /*              iph(I)   - pointer to hash table to destroy                 */
504 /*                                                                          */
505 /* It is necessary to unlink here as well as free (called by deref) so that */
506 /* the while loop in ipf_htable_flush() functions properly.                 */
507 /* ------------------------------------------------------------------------ */
508 static int
ipf_htable_remove(softc,arg,iph)509 ipf_htable_remove(softc, arg, iph)
510           ipf_main_softc_t *softc;
511           void *arg;
512           iphtable_t *iph;
513 {
514 
515           if (ipf_htable_clear(softc, arg, iph) != 0)
516                     return 1;
517 
518           if (iph->iph_pnext != NULL)
519                     *iph->iph_pnext = iph->iph_next;
520           if (iph->iph_next != NULL)
521                     iph->iph_next->iph_pnext = iph->iph_pnext;
522           iph->iph_pnext = NULL;
523           iph->iph_next = NULL;
524 
525           return ipf_htable_deref(softc, arg, iph);
526 }
527 
528 
529 /* ------------------------------------------------------------------------ */
530 /* Function:    ipf_htable_node_del                                         */
531 /* Returns:     int      - 0 = success, else error                          */
532 /* Parameters:  softc(I) - pointer to soft context main structure           */
533 /*              arg(I)   - pointer to local context to use                  */
534 /*              op(I)    - pointer to lookup operation data                 */
535 /*              uid(I)   - real uid of process doing operation              */
536 /*                                                                          */
537 /* ------------------------------------------------------------------------ */
538 static int
ipf_htable_node_del(softc,arg,op,uid)539 ipf_htable_node_del(softc, arg, op, uid)
540           ipf_main_softc_t *softc;
541           void *arg;
542           iplookupop_t *op;
543           int uid;
544 {
545         iphtable_t *iph;
546         iphtent_t hte, *ent;
547           int err;
548 
549           if (op->iplo_size != sizeof(hte)) {
550                     IPFERROR(30014);
551                     return EINVAL;
552           }
553 
554           err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
555           if (err != 0) {
556                     IPFERROR(30015);
557                     return EFAULT;
558           }
559 
560           iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
561           if (iph == NULL) {
562                     IPFERROR(30016);
563                     return ESRCH;
564           }
565 
566           ent = ipf_htent_find(iph, &hte);
567           if (ent == NULL) {
568                     IPFERROR(30022);
569                     return ESRCH;
570           }
571 
572           if ((uid != 0) && (ent->ipe_uid != uid)) {
573                     IPFERROR(30023);
574                     return EACCES;
575           }
576 
577           err = ipf_htent_remove(softc, arg, iph, ent);
578 
579           return err;
580 }
581 
582 
583 /* ------------------------------------------------------------------------ */
584 /* Function:    ipf_htable_node_del                                         */
585 /* Returns:     int      - 0 = success, else error                          */
586 /* Parameters:  softc(I) - pointer to soft context main structure           */
587 /*              arg(I)   - pointer to local context to use                  */
588 /*              op(I)    - pointer to lookup operation data                 */
589 /*                                                                          */
590 /* ------------------------------------------------------------------------ */
591 static int
ipf_htable_table_add(softc,arg,op)592 ipf_htable_table_add(softc, arg, op)
593           ipf_main_softc_t *softc;
594           void *arg;
595         iplookupop_t *op;
596 {
597           int err;
598 
599           if (ipf_htable_find(arg, op->iplo_unit, op->iplo_name) != NULL) {
600                     IPFERROR(30017);
601                     err = EEXIST;
602           } else {
603                     err = ipf_htable_create(softc, arg, op);
604           }
605 
606           return err;
607 }
608 
609 
610 /* ------------------------------------------------------------------------ */
611 /* Function:    ipf_htent_remove                                            */
612 /* Returns:     int      - 0 = success, else error                          */
613 /* Parameters:  softc(I) - pointer to soft context main structure           */
614 /*              arg(I)   - pointer to local context to use                  */
615 /*              iph(I)   - pointer to hash table                            */
616 /*              ipe(I)   - pointer to hash table entry to remove            */
617 /*                                                                          */
618 /* Delete an entry from a hash table.                                       */
619 /* ------------------------------------------------------------------------ */
620 static int
ipf_htent_remove(softc,arg,iph,ipe)621 ipf_htent_remove(softc, arg, iph, ipe)
622           ipf_main_softc_t *softc;
623           void *arg;
624           iphtable_t *iph;
625           iphtent_t *ipe;
626 {
627 
628           if (iph->iph_tail == &ipe->ipe_next)
629                     iph->iph_tail = ipe->ipe_pnext;
630 
631           if (ipe->ipe_hnext != NULL)
632                     ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext;
633           if (ipe->ipe_phnext != NULL)
634                     *ipe->ipe_phnext = ipe->ipe_hnext;
635           ipe->ipe_phnext = NULL;
636           ipe->ipe_hnext = NULL;
637 
638           if (ipe->ipe_dnext != NULL)
639                     ipe->ipe_dnext->ipe_pdnext = ipe->ipe_pdnext;
640           if (ipe->ipe_pdnext != NULL)
641                     *ipe->ipe_pdnext = ipe->ipe_dnext;
642           ipe->ipe_pdnext = NULL;
643           ipe->ipe_dnext = NULL;
644 
645           if (ipe->ipe_next != NULL)
646                     ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
647           if (ipe->ipe_pnext != NULL)
648                     *ipe->ipe_pnext = ipe->ipe_next;
649           ipe->ipe_pnext = NULL;
650           ipe->ipe_next = NULL;
651 
652           switch (iph->iph_type & ~IPHASH_ANON)
653           {
654           case IPHASH_GROUPMAP :
655                     if (ipe->ipe_group != NULL)
656                               ipf_group_del(softc, ipe->ipe_ptr, NULL);
657                     break;
658 
659           default :
660                     ipe->ipe_ptr = NULL;
661                     ipe->ipe_value = 0;
662                     break;
663           }
664 
665           return ipf_htent_deref(arg, ipe);
666 }
667 
668 
669 /* ------------------------------------------------------------------------ */
670 /* Function:    ipf_htable_deref                                            */
671 /* Returns:     int       - 0 = success, else error                         */
672 /* Parameters:  softc(I)  - pointer to soft context main structure          */
673 /*              arg(I)    - pointer to local context to use                 */
674 /*              object(I) - pointer to hash table                           */
675 /*                                                                          */
676 /* ------------------------------------------------------------------------ */
677 static int
ipf_htable_deref(softc,arg,object)678 ipf_htable_deref(softc, arg, object)
679           ipf_main_softc_t *softc;
680           void *arg, *object;
681 {
682           ipf_htable_softc_t *softh = arg;
683           iphtable_t *iph = object;
684           int refs;
685 
686           iph->iph_ref--;
687           refs = iph->iph_ref;
688 
689           if (iph->iph_ref == 0) {
690                     ipf_htable_free(softh, iph);
691           }
692 
693           return refs;
694 }
695 
696 
697 /* ------------------------------------------------------------------------ */
698 /* Function:    ipf_htent_deref                                             */
699 /* Parameters:  arg(I) - pointer to local context to use                    */
700 /*              ipe(I) -                                                    */
701 /*                                                                          */
702 /* ------------------------------------------------------------------------ */
703 static int
ipf_htent_deref(arg,ipe)704 ipf_htent_deref(arg, ipe)
705           void *arg;
706           iphtent_t *ipe;
707 {
708           ipf_htable_softc_t *softh = arg;
709 
710           ipe->ipe_ref--;
711           if (ipe->ipe_ref == 0) {
712                     softh->ipf_nhtnodes[ipe->ipe_unit + 1]--;
713                     KFREE(ipe);
714 
715                     return 0;
716           }
717 
718           return ipe->ipe_ref;
719 }
720 
721 
722 /* ------------------------------------------------------------------------ */
723 /* Function:    ipf_htable_exists                                           */
724 /* Parameters:  arg(I) - pointer to local context to use                    */
725 /*                                                                          */
726 /* ------------------------------------------------------------------------ */
727 static void *
ipf_htable_exists(arg,unit,name)728 ipf_htable_exists(arg, unit, name)
729           void *arg;
730           int unit;
731           char *name;
732 {
733           ipf_htable_softc_t *softh = arg;
734           iphtable_t *iph;
735 
736           if (unit == IPL_LOGALL) {
737                     int i;
738 
739                     for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
740                               for (iph = softh->ipf_htables[i]; iph != NULL;
741                                    iph = iph->iph_next) {
742                                         if (strncmp(iph->iph_name, name,
743                                                       sizeof(iph->iph_name)) == 0)
744                                                   break;
745                               }
746                               if (iph != NULL)
747                                         break;
748                     }
749           } else {
750                     for (iph = softh->ipf_htables[unit + 1]; iph != NULL;
751                          iph = iph->iph_next) {
752                               if (strncmp(iph->iph_name, name,
753                                             sizeof(iph->iph_name)) == 0)
754                                         break;
755                     }
756           }
757           return iph;
758 }
759 
760 
761 /* ------------------------------------------------------------------------ */
762 /* Function:    ipf_htable_select_add_ref                                   */
763 /* Returns:     void *  - NULL = failure, else pointer to the hash table    */
764 /* Parameters:  arg(I)  - pointer to local context to use                   */
765 /*              unit(I) - ipfilter device to which we are working on        */
766 /*              name(I) - name of the hash table                            */
767 /*                                                                          */
768 /* ------------------------------------------------------------------------ */
769 static void *
ipf_htable_select_add_ref(arg,unit,name)770 ipf_htable_select_add_ref(arg, unit, name)
771           void *arg;
772           int unit;
773           char *name;
774 {
775           iphtable_t *iph;
776 
777           iph = ipf_htable_exists(arg, unit, name);
778           if (iph != NULL) {
779                     ATOMIC_INC32(iph->iph_ref);
780           }
781           return iph;
782 }
783 
784 
785 /* ------------------------------------------------------------------------ */
786 /* Function:    ipf_htable_find                                             */
787 /* Returns:     void *  - NULL = failure, else pointer to the hash table    */
788 /* Parameters:  arg(I)  - pointer to local context to use                   */
789 /*              unit(I) - ipfilter device to which we are working on        */
790 /*              name(I) - name of the hash table                            */
791 /*                                                                          */
792 /* This function is exposed becaues it is used in the group-map feature.    */
793 /* ------------------------------------------------------------------------ */
794 iphtable_t *
ipf_htable_find(arg,unit,name)795 ipf_htable_find(arg, unit, name)
796           void *arg;
797           int unit;
798           char *name;
799 {
800           iphtable_t *iph;
801 
802           iph = ipf_htable_exists(arg, unit, name);
803           if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0)
804                     return iph;
805 
806           return NULL;
807 }
808 
809 
810 /* ------------------------------------------------------------------------ */
811 /* Function:    ipf_htable_flush                                            */
812 /* Returns:     size_t   - number of entries flushed                        */
813 /* Parameters:  softc(I) - pointer to soft context main structure           */
814 /*              arg(I)   - pointer to local context to use                  */
815 /*              op(I)    - pointer to lookup operation data                 */
816 /*                                                                          */
817 /* ------------------------------------------------------------------------ */
818 static size_t
ipf_htable_flush(softc,arg,op)819 ipf_htable_flush(softc, arg, op)
820           ipf_main_softc_t *softc;
821           void *arg;
822           iplookupflush_t *op;
823 {
824           ipf_htable_softc_t *softh = arg;
825           iphtable_t *iph;
826           size_t freed;
827           int i;
828 
829           freed = 0;
830 
831           for (i = -1; i <= IPL_LOGMAX; i++) {
832                     if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
833                               while ((iph = softh->ipf_htables[i + 1]) != NULL) {
834                                         if (ipf_htable_remove(softc, arg, iph) == 0) {
835                                                   freed++;
836                                         } else {
837                                                   iph->iph_flags |= IPHASH_DELETE;
838                                         }
839                               }
840                     }
841           }
842 
843           return freed;
844 }
845 
846 
847 /* ------------------------------------------------------------------------ */
848 /* Function:    ipf_htable_node_add                                         */
849 /* Returns:     int      - 0 = success, else error                          */
850 /* Parameters:  softc(I) - pointer to soft context main structure           */
851 /*              arg(I)   - pointer to local context to use                  */
852 /*              op(I)    - pointer to lookup operation data                 */
853 /*              uid(I)   - real uid of process doing operation              */
854 /*                                                                          */
855 /* ------------------------------------------------------------------------ */
856 static int
ipf_htable_node_add(softc,arg,op,uid)857 ipf_htable_node_add(softc, arg, op, uid)
858           ipf_main_softc_t *softc;
859           void *arg;
860           iplookupop_t *op;
861           int uid;
862 {
863           iphtable_t *iph;
864           iphtent_t hte;
865           int err;
866 
867           if (op->iplo_size != sizeof(hte)) {
868                     IPFERROR(30018);
869                     return EINVAL;
870           }
871 
872           err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
873           if (err != 0) {
874                     IPFERROR(30019);
875                     return EFAULT;
876           }
877           hte.ipe_uid = uid;
878 
879           iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
880           if (iph == NULL) {
881                     IPFERROR(30020);
882                     return ESRCH;
883           }
884 
885           if (ipf_htent_find(iph, &hte) != NULL) {
886                     IPFERROR(30021);
887                     return EEXIST;
888           }
889 
890           err = ipf_htent_insert(softc, arg, iph, &hte);
891 
892           return err;
893 }
894 
895 
896 /* ------------------------------------------------------------------------ */
897 /* Function:    ipf_htent_insert                                            */
898 /* Returns:     int      - 0 = success, -1 =  error                         */
899 /* Parameters:  softc(I) - pointer to soft context main structure           */
900 /*              arg(I)   - pointer to local context to use                  */
901 /*              op(I)    - pointer to lookup operation data                 */
902 /*              ipeo(I)  -                                                  */
903 /*                                                                          */
904 /* Add an entry to a hash table.                                            */
905 /* ------------------------------------------------------------------------ */
906 static int
ipf_htent_insert(softc,arg,iph,ipeo)907 ipf_htent_insert(softc, arg, iph, ipeo)
908           ipf_main_softc_t *softc;
909           void *arg;
910           iphtable_t *iph;
911           iphtent_t *ipeo;
912 {
913           ipf_htable_softc_t *softh = arg;
914           iphtent_t *ipe;
915           u_int hv;
916           int bits;
917 
918           KMALLOC(ipe, iphtent_t *);
919           if (ipe == NULL)
920                     return -1;
921 
922           bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
923           ipe->ipe_addr.i6[0] &= ipe->ipe_mask.i6[0];
924           if (ipe->ipe_family == AF_INET) {
925                     bits = count4bits(ipe->ipe_mask.in4_addr);
926                     ipe->ipe_addr.i6[1] = 0;
927                     ipe->ipe_addr.i6[2] = 0;
928                     ipe->ipe_addr.i6[3] = 0;
929                     ipe->ipe_mask.i6[1] = 0;
930                     ipe->ipe_mask.i6[2] = 0;
931                     ipe->ipe_mask.i6[3] = 0;
932                     hv = IPE_V4_HASH_FN(ipe->ipe_addr.in4_addr,
933                                             ipe->ipe_mask.in4_addr, iph->iph_size);
934           } else
935 #ifdef USE_INET6
936           if (ipe->ipe_family == AF_INET6) {
937                     ipe->ipe_addr.i6[1] &= ipe->ipe_mask.i6[1];
938                     ipe->ipe_addr.i6[2] &= ipe->ipe_mask.i6[2];
939                     ipe->ipe_addr.i6[3] &= ipe->ipe_mask.i6[3];
940 
941                     bits = count6bits(ipe->ipe_mask.i6);
942                     hv = IPE_V6_HASH_FN(ipe->ipe_addr.i6,
943                                             ipe->ipe_mask.i6, iph->iph_size);
944           } else
945 #endif
946           {
947                     KFREE(ipe);
948                     return -1;
949           }
950 
951           ipe->ipe_owner = iph;
952           ipe->ipe_ref = 1;
953           ipe->ipe_hnext = iph->iph_table[hv];
954           ipe->ipe_phnext = iph->iph_table + hv;
955 
956           if (iph->iph_table[hv] != NULL)
957                     iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext;
958           iph->iph_table[hv] = ipe;
959 
960           ipe->ipe_pnext = iph->iph_tail;
961           *iph->iph_tail = ipe;
962           iph->iph_tail = &ipe->ipe_next;
963           ipe->ipe_next = NULL;
964 
965           if (ipe->ipe_die != 0) {
966                     /*
967                      * If the new node has a given expiration time, insert it
968                      * into the list of expiring nodes with the ones to be
969                      * removed first added to the front of the list. The
970                      * insertion is O(n) but it is kept sorted for quick scans
971                      * at expiration interval checks.
972                      */
973                     iphtent_t *n;
974 
975                     ipe->ipe_die = softc->ipf_ticks + IPF_TTLVAL(ipe->ipe_die);
976                     for (n = softh->ipf_node_explist; n != NULL; n = n->ipe_dnext) {
977                               if (ipe->ipe_die < n->ipe_die)
978                                         break;
979                               if (n->ipe_dnext == NULL) {
980                                         /*
981                                          * We've got to the last node and everything
982                                          * wanted to be expired before this new node,
983                                          * so we have to tack it on the end...
984                                          */
985                                         n->ipe_dnext = ipe;
986                                         ipe->ipe_pdnext = &n->ipe_dnext;
987                                         n = NULL;
988                                         break;
989                               }
990                     }
991 
992                     if (softh->ipf_node_explist == NULL) {
993                               softh->ipf_node_explist = ipe;
994                               ipe->ipe_pdnext = &softh->ipf_node_explist;
995                     } else if (n != NULL) {
996                               ipe->ipe_dnext = n;
997                               ipe->ipe_pdnext = n->ipe_pdnext;
998                               n->ipe_pdnext = &ipe->ipe_dnext;
999                     }
1000           }
1001 
1002           if (ipe->ipe_family == AF_INET) {
1003                     ipf_inet_mask_add(bits, &iph->iph_v4_masks);
1004           }
1005 #ifdef USE_INET6
1006           else if (ipe->ipe_family == AF_INET6) {
1007                     ipf_inet6_mask_add(bits, &ipe->ipe_mask, &iph->iph_v6_masks);
1008           }
1009 #endif
1010 
1011           switch (iph->iph_type & ~IPHASH_ANON)
1012           {
1013           case IPHASH_GROUPMAP :
1014                     ipe->ipe_ptr = ipf_group_add(softc, ipe->ipe_group, NULL,
1015                                                      iph->iph_flags, IPL_LOGIPF,
1016                                                      softc->ipf_active);
1017                     break;
1018 
1019           default :
1020                     ipe->ipe_ptr = NULL;
1021                     ipe->ipe_value = 0;
1022                     break;
1023           }
1024 
1025           ipe->ipe_unit = iph->iph_unit;
1026           softh->ipf_nhtnodes[ipe->ipe_unit + 1]++;
1027 
1028           return 0;
1029 }
1030 
1031 
1032 /* ------------------------------------------------------------------------ */
1033 /* Function:    ipf_htent_find                                              */
1034 /* Returns:     int     - 0 = success, else error                           */
1035 /* Parameters:  iph(I)  - pointer to table to search                        */
1036 /*              ipeo(I) - pointer to entry to find                          */
1037 /*                                                                          */
1038 /* While it isn't absolutely necessary to for the address and mask to be    */
1039 /* passed in through an iphtent_t structure, one is always present when it  */
1040 /* is time to call this function, so it is just more convenient.            */
1041 /* ------------------------------------------------------------------------ */
1042 static iphtent_t *
ipf_htent_find(iph,ipeo)1043 ipf_htent_find(iph, ipeo)
1044           iphtable_t *iph;
1045           iphtent_t *ipeo;
1046 {
1047           iphtent_t ipe, *ent;
1048           u_int hv;
1049           int bits;
1050 
1051           bcopy((char *)ipeo, (char *)&ipe, sizeof(ipe));
1052           ipe.ipe_addr.i6[0] &= ipe.ipe_mask.i6[0];
1053           ipe.ipe_addr.i6[1] &= ipe.ipe_mask.i6[1];
1054           ipe.ipe_addr.i6[2] &= ipe.ipe_mask.i6[2];
1055           ipe.ipe_addr.i6[3] &= ipe.ipe_mask.i6[3];
1056           if (ipe.ipe_family == AF_INET) {
1057                     bits = count4bits(ipe.ipe_mask.in4_addr);
1058                     ipe.ipe_addr.i6[1] = 0;
1059                     ipe.ipe_addr.i6[2] = 0;
1060                     ipe.ipe_addr.i6[3] = 0;
1061                     ipe.ipe_mask.i6[1] = 0;
1062                     ipe.ipe_mask.i6[2] = 0;
1063                     ipe.ipe_mask.i6[3] = 0;
1064                     hv = IPE_V4_HASH_FN(ipe.ipe_addr.in4_addr,
1065                                             ipe.ipe_mask.in4_addr, iph->iph_size);
1066           } else
1067 #ifdef USE_INET6
1068           if (ipe.ipe_family == AF_INET6) {
1069                     bits = count6bits(ipe.ipe_mask.i6);
1070                     hv = IPE_V6_HASH_FN(ipe.ipe_addr.i6,
1071                                             ipe.ipe_mask.i6, iph->iph_size);
1072           } else
1073 #endif
1074                     return NULL;
1075 
1076           for (ent = iph->iph_table[hv]; ent != NULL; ent = ent->ipe_hnext) {
1077                     if (ent->ipe_family != ipe.ipe_family)
1078                               continue;
1079                     if (IP6_NEQ(&ipe.ipe_addr, &ent->ipe_addr))
1080                               continue;
1081                     if (IP6_NEQ(&ipe.ipe_mask, &ent->ipe_mask))
1082                               continue;
1083                     break;
1084           }
1085 
1086           return ent;
1087 }
1088 
1089 
1090 /* ------------------------------------------------------------------------ */
1091 /* Function:    ipf_iphmfindgroup                                           */
1092 /* Returns:     int      - 0 = success, else error                          */
1093 /* Parameters:  softc(I) - pointer to soft context main structure           */
1094 /*              tptr(I)  -                                                  */
1095 /*              aptr(I)  -                                                  */
1096 /*                                                                          */
1097 /* Search a hash table for a matching entry and return the pointer stored   */
1098 /* in it for use as the next group of rules to search.                      */
1099 /*                                                                          */
1100 /* This function is exposed becaues it is used in the group-map feature.    */
1101 /* ------------------------------------------------------------------------ */
1102 void *
ipf_iphmfindgroup(softc,tptr,aptr)1103 ipf_iphmfindgroup(softc, tptr, aptr)
1104           ipf_main_softc_t *softc;
1105           void *tptr, *aptr;
1106 {
1107           struct in_addr *addr;
1108           iphtable_t *iph;
1109           iphtent_t *ipe;
1110           void *rval;
1111 
1112           READ_ENTER(&softc->ipf_poolrw);
1113           iph = tptr;
1114           addr = aptr;
1115 
1116           ipe = ipf_iphmfind(iph, addr);
1117           if (ipe != NULL)
1118                     rval = ipe->ipe_ptr;
1119           else
1120                     rval = NULL;
1121           RWLOCK_EXIT(&softc->ipf_poolrw);
1122           return rval;
1123 }
1124 
1125 
1126 /* ------------------------------------------------------------------------ */
1127 /* Function:    ipf_iphmfindip                                              */
1128 /* Returns:     int     - 0 == +ve match, -1 == error, 1 == -ve/no match    */
1129 /* Parameters:  softc(I)     - pointer to soft context main structure       */
1130 /*              tptr(I)      - pointer to the pool to search                */
1131 /*              ipversion(I) - IP protocol version (4 or 6)                 */
1132 /*              aptr(I)      - pointer to address information               */
1133 /*              bytes(I)     - packet length                                */
1134 /*                                                                          */
1135 /* Search the hash table for a given address and return a search result.    */
1136 /* ------------------------------------------------------------------------ */
1137 static int
ipf_iphmfindip(softc,tptr,ipversion,aptr,bytes)1138 ipf_iphmfindip(softc, tptr, ipversion, aptr, bytes)
1139           ipf_main_softc_t *softc;
1140           void *tptr, *aptr;
1141           int ipversion;
1142           u_int bytes;
1143 {
1144           struct in_addr *addr;
1145           iphtable_t *iph;
1146           iphtent_t *ipe;
1147           int rval;
1148 
1149           if (tptr == NULL || aptr == NULL)
1150                     return -1;
1151 
1152           iph = tptr;
1153           addr = aptr;
1154 
1155           READ_ENTER(&softc->ipf_poolrw);
1156           if (ipversion == 4) {
1157                     ipe = ipf_iphmfind(iph, addr);
1158 #ifdef USE_INET6
1159           } else if (ipversion == 6) {
1160                     ipe = ipf_iphmfind6(iph, (i6addr_t *)addr);
1161 #endif
1162           } else {
1163                     ipe = NULL;
1164           }
1165 
1166           if (ipe != NULL) {
1167                     rval = 0;
1168                     ipe->ipe_hits++;
1169                     ipe->ipe_bytes += bytes;
1170           } else {
1171                     rval = 1;
1172           }
1173           RWLOCK_EXIT(&softc->ipf_poolrw);
1174           return rval;
1175 }
1176 
1177 
1178 /* ------------------------------------------------------------------------ */
1179 /* Function:    ipf_iphmfindip                                              */
1180 /* Parameters:  iph(I)  - pointer to hash table                             */
1181 /*              addr(I) - pointer to IPv4 address                           */
1182 /* Locks:  ipf_poolrw                                                       */
1183 /*                                                                          */
1184 /* ------------------------------------------------------------------------ */
1185 static iphtent_t *
ipf_iphmfind(iph,addr)1186 ipf_iphmfind(iph, addr)
1187           iphtable_t *iph;
1188           struct in_addr *addr;
1189 {
1190           u_32_t msk, ips;
1191           iphtent_t *ipe;
1192           u_int hv;
1193           int i;
1194 
1195           i = 0;
1196 maskloop:
1197           msk = iph->iph_v4_masks.imt4_active[i];
1198           ips = addr->s_addr & msk;
1199           hv = IPE_V4_HASH_FN(ips, msk, iph->iph_size);
1200           for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) {
1201                     if ((ipe->ipe_family != AF_INET) ||
1202                         (ipe->ipe_mask.in4_addr != msk) ||
1203                         (ipe->ipe_addr.in4_addr != ips)) {
1204                               continue;
1205                     }
1206                     break;
1207           }
1208 
1209           if (ipe == NULL) {
1210                     i++;
1211                     if (i < iph->iph_v4_masks.imt4_max)
1212                               goto maskloop;
1213           }
1214           return ipe;
1215 }
1216 
1217 
1218 /* ------------------------------------------------------------------------ */
1219 /* Function:    ipf_htable_iter_next                                        */
1220 /* Returns:     int      - 0 = success, else error                          */
1221 /* Parameters:  softc(I) - pointer to soft context main structure           */
1222 /*              arg(I)   - pointer to local context to use                  */
1223 /*              token(I) -                                                  */
1224 /*              ilp(I)   -                                                  */
1225 /*                                                                          */
1226 /* ------------------------------------------------------------------------ */
1227 static int
ipf_htable_iter_next(softc,arg,token,ilp)1228 ipf_htable_iter_next(softc, arg, token, ilp)
1229           ipf_main_softc_t *softc;
1230           void *arg;
1231           ipftoken_t *token;
1232           ipflookupiter_t *ilp;
1233 {
1234           ipf_htable_softc_t *softh = arg;
1235           iphtent_t *node, zn, *nextnode;
1236           iphtable_t *iph, zp, *nextiph;
1237           void *hnext;
1238           int err;
1239 
1240           err = 0;
1241           iph = NULL;
1242           node = NULL;
1243           nextiph = NULL;
1244           nextnode = NULL;
1245 
1246           READ_ENTER(&softc->ipf_poolrw);
1247 
1248           switch (ilp->ili_otype)
1249           {
1250           case IPFLOOKUPITER_LIST :
1251                     iph = token->ipt_data;
1252                     if (iph == NULL) {
1253                               nextiph = softh->ipf_htables[(int)ilp->ili_unit + 1];
1254                     } else {
1255                               nextiph = iph->iph_next;
1256                     }
1257 
1258                     if (nextiph != NULL) {
1259                               ATOMIC_INC(nextiph->iph_ref);
1260                               token->ipt_data = nextiph;
1261                     } else {
1262                               bzero((char *)&zp, sizeof(zp));
1263                               nextiph = &zp;
1264                               token->ipt_data = NULL;
1265                     }
1266                     hnext = nextiph->iph_next;
1267                     break;
1268 
1269           case IPFLOOKUPITER_NODE :
1270                     node = token->ipt_data;
1271                     if (node == NULL) {
1272                               iph = ipf_htable_find(arg, ilp->ili_unit,
1273                                                         ilp->ili_name);
1274                               if (iph == NULL) {
1275                                         IPFERROR(30009);
1276                                         err = ESRCH;
1277                               } else {
1278                                         nextnode = iph->iph_list;
1279                               }
1280                     } else {
1281                               nextnode = node->ipe_next;
1282                     }
1283 
1284                     if (nextnode != NULL) {
1285                               ATOMIC_INC(nextnode->ipe_ref);
1286                               token->ipt_data = nextnode;
1287                     } else {
1288                               bzero((char *)&zn, sizeof(zn));
1289                               nextnode = &zn;
1290                               token->ipt_data = NULL;
1291                     }
1292                     hnext = nextnode->ipe_next;
1293                     break;
1294 
1295           default :
1296                     IPFERROR(30010);
1297                     err = EINVAL;
1298                     hnext = NULL;
1299                     break;
1300           }
1301 
1302           RWLOCK_EXIT(&softc->ipf_poolrw);
1303           if (err != 0)
1304                     return err;
1305 
1306           switch (ilp->ili_otype)
1307           {
1308           case IPFLOOKUPITER_LIST :
1309                     err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
1310                     if (err != 0) {
1311                               IPFERROR(30011);
1312                               err = EFAULT;
1313                     }
1314                     if (iph != NULL) {
1315                               WRITE_ENTER(&softc->ipf_poolrw);
1316                               ipf_htable_deref(softc, softh, iph);
1317                               RWLOCK_EXIT(&softc->ipf_poolrw);
1318                     }
1319                     break;
1320 
1321           case IPFLOOKUPITER_NODE :
1322                     err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
1323                     if (err != 0) {
1324                               IPFERROR(30012);
1325                               err = EFAULT;
1326                     }
1327                     if (node != NULL) {
1328                               WRITE_ENTER(&softc->ipf_poolrw);
1329                               ipf_htent_deref(softc, node);
1330                               RWLOCK_EXIT(&softc->ipf_poolrw);
1331                     }
1332                     break;
1333           }
1334 
1335           if (hnext == NULL)
1336                     ipf_token_mark_complete(token);
1337 
1338           return err;
1339 }
1340 
1341 
1342 /* ------------------------------------------------------------------------ */
1343 /* Function:    ipf_htable_iter_deref                                       */
1344 /* Returns:     int      - 0 = success, else  error                         */
1345 /* Parameters:  softc(I) - pointer to soft context main structure           */
1346 /*              arg(I)   - pointer to local context to use                  */
1347 /*              otype(I) - which data structure type is being walked        */
1348 /*              unit(I)  - ipfilter device to which we are working on       */
1349 /*              data(I)  - pointer to old data structure                    */
1350 /*                                                                          */
1351 /* ------------------------------------------------------------------------ */
1352 static int
ipf_htable_iter_deref(softc,arg,otype,unit,data)1353 ipf_htable_iter_deref(softc, arg, otype, unit, data)
1354           ipf_main_softc_t *softc;
1355           void *arg;
1356           int otype;
1357           int unit;
1358           void *data;
1359 {
1360 
1361           if (data == NULL)
1362                     return EFAULT;
1363 
1364           if (unit < -1 || unit > IPL_LOGMAX)
1365                     return EINVAL;
1366 
1367           switch (otype)
1368           {
1369           case IPFLOOKUPITER_LIST :
1370                     ipf_htable_deref(softc, arg, (iphtable_t *)data);
1371                     break;
1372 
1373           case IPFLOOKUPITER_NODE :
1374                     ipf_htent_deref(arg, (iphtent_t *)data);
1375                     break;
1376           default :
1377                     break;
1378           }
1379 
1380           return 0;
1381 }
1382 
1383 
1384 #ifdef USE_INET6
1385 /* ------------------------------------------------------------------------ */
1386 /* Function:    ipf_iphmfind6                                               */
1387 /* Parameters:  iph(I)  - pointer to hash table                             */
1388 /*              addr(I) - pointer to IPv6 address                           */
1389 /* Locks:  ipf_poolrw                                                       */
1390 /*                                                                          */
1391 /* ------------------------------------------------------------------------ */
1392 static iphtent_t *
ipf_iphmfind6(iph,addr)1393 ipf_iphmfind6(iph, addr)
1394           iphtable_t *iph;
1395           i6addr_t *addr;
1396 {
1397           i6addr_t *msk, ips;
1398           iphtent_t *ipe;
1399           u_int hv;
1400           int i;
1401 
1402           i = 0;
1403 maskloop:
1404           msk = iph->iph_v6_masks.imt6_active + i;
1405           ips.i6[0] = addr->i6[0] & msk->i6[0];
1406           ips.i6[1] = addr->i6[1] & msk->i6[1];
1407           ips.i6[2] = addr->i6[2] & msk->i6[2];
1408           ips.i6[3] = addr->i6[3] & msk->i6[3];
1409           hv = IPE_V6_HASH_FN(ips.i6, msk->i6, iph->iph_size);
1410           for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
1411                     if ((ipe->ipe_family != AF_INET6) ||
1412                         IP6_NEQ(&ipe->ipe_mask, msk) ||
1413                         IP6_NEQ(&ipe->ipe_addr, &ips)) {
1414                               continue;
1415                     }
1416                     break;
1417           }
1418 
1419           if (ipe == NULL) {
1420                     i++;
1421                     if (i < iph->iph_v6_masks.imt6_max)
1422                               goto maskloop;
1423           }
1424           return ipe;
1425 }
1426 #endif
1427 
1428 
1429 static void
ipf_htable_expire(softc,arg)1430 ipf_htable_expire(softc, arg)
1431           ipf_main_softc_t *softc;
1432           void *arg;
1433 {
1434           ipf_htable_softc_t *softh = arg;
1435           iphtent_t *n;
1436 
1437           while ((n = softh->ipf_node_explist) != NULL) {
1438                     if (n->ipe_die > softc->ipf_ticks)
1439                               break;
1440 
1441                     ipf_htent_remove(softc, softh, n->ipe_owner, n);
1442           }
1443 }
1444 
1445 
1446 #ifndef _KERNEL
1447 
1448 /* ------------------------------------------------------------------------ */
1449 /*                                                                          */
1450 /* ------------------------------------------------------------------------ */
1451 void
ipf_htable_dump(softc,arg)1452 ipf_htable_dump(softc, arg)
1453           ipf_main_softc_t *softc;
1454           void *arg;
1455 {
1456           ipf_htable_softc_t *softh = arg;
1457           iphtable_t *iph;
1458           int i;
1459 
1460           printf("List of configured hash tables\n");
1461           for (i = 0; i < IPL_LOGSIZE; i++)
1462                     for (iph = softh->ipf_htables[i]; iph != NULL;
1463                          iph = iph->iph_next)
1464                               printhash(iph, bcopywrap, NULL, opts, NULL);
1465 
1466 }
1467 #endif
1468