1 /*
2 * Copyright (C) 1993-2001, 2003 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 *
6 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
7 */
8
9 #if defined(KERNEL) || defined(_KERNEL)
10 # undef KERNEL
11 # undef _KERNEL
12 # define KERNEL 1
13 # define _KERNEL 1
14 #endif
15 #include <sys/param.h>
16 #include <sys/types.h>
17 #include <sys/errno.h>
18 #include <sys/time.h>
19 #include <sys/file.h>
20 #if !defined(_KERNEL)
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 #endif
30 #include <sys/socket.h>
31 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
32 # include <sys/malloc.h>
33 #endif
34 #if defined(__FreeBSD__)
35 # include <sys/cdefs.h>
36 # include <sys/proc.h>
37 #endif
38 #if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \
39 !defined(linux)
40 # include <sys/mbuf.h>
41 #endif
42 #if defined(_KERNEL)
43 # include <sys/systm.h>
44 #else
45 # include <stdio.h>
46 #endif
47 #include <netinet/in.h>
48 #include <net/if.h>
49
50 #include "netinet/ip_compat.h"
51 #include "netinet/ip_fil.h"
52 #include "netinet/ip_lookup.h"
53 #include "netinet/ip_htable.h"
54 #include "netinet/ipf_stack.h"
55 /* END OF INCLUDES */
56
57 #if !defined(lint)
58 static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.34.2.3 2005/05/14 05:11:38 darrenr Exp $";
59 #endif
60
61 #ifdef IPFILTER_LOOKUP
62 static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *));
63 #ifdef USE_INET6
64 static iphtent_t *fr_iphmfind6 __P((iphtable_t *, struct in6_addr *));
65 static uint32_t sum4(uint32_t *);
66 static void left_shift_ipv6 __P((char *));
67 #endif
68
fr_htable_unload(ifs)69 void fr_htable_unload(ifs)
70 ipf_stack_t *ifs;
71 {
72 iplookupflush_t fop;
73
74 fop.iplf_unit = IPL_LOGALL;
75 (void)fr_flushhtable(&fop, ifs);
76 }
77
78
fr_gethtablestat(op,ifs)79 int fr_gethtablestat(op, ifs)
80 iplookupop_t *op;
81 ipf_stack_t *ifs;
82 {
83 iphtstat_t stats;
84
85 if (op->iplo_size != sizeof(stats))
86 return EINVAL;
87
88 stats.iphs_tables = ifs->ifs_ipf_htables[op->iplo_unit];
89 stats.iphs_numtables = ifs->ifs_ipf_nhtables[op->iplo_unit];
90 stats.iphs_numnodes = ifs->ifs_ipf_nhtnodes[op->iplo_unit];
91 stats.iphs_nomem = ifs->ifs_ipht_nomem[op->iplo_unit];
92
93 return COPYOUT(&stats, op->iplo_struct, sizeof(stats));
94
95 }
96
97
98 /*
99 * Create a new hash table using the template passed.
100 */
fr_newhtable(op,ifs)101 int fr_newhtable(op, ifs)
102 iplookupop_t *op;
103 ipf_stack_t *ifs;
104 {
105 iphtable_t *iph, *oiph;
106 char name[FR_GROUPLEN];
107 int err, i, unit;
108
109 KMALLOC(iph, iphtable_t *);
110 if (iph == NULL) {
111 ifs->ifs_ipht_nomem[op->iplo_unit]++;
112 return ENOMEM;
113 }
114
115 err = COPYIN(op->iplo_struct, iph, sizeof(*iph));
116 if (err != 0) {
117 KFREE(iph);
118 return EFAULT;
119 }
120
121 unit = op->iplo_unit;
122 if (iph->iph_unit != unit) {
123 KFREE(iph);
124 return EINVAL;
125 }
126
127 if ((op->iplo_arg & IPHASH_ANON) == 0) {
128 if (fr_findhtable(op->iplo_unit, op->iplo_name, ifs) != NULL) {
129 KFREE(iph);
130 return EEXIST;
131 }
132 } else {
133 i = IPHASH_ANON;
134 do {
135 i++;
136 #if defined(SNPRINTF) && defined(_KERNEL)
137 (void)SNPRINTF(name, sizeof(name), "%u", i);
138 #else
139 (void)sprintf(name, "%u", i);
140 #endif
141 for (oiph = ifs->ifs_ipf_htables[unit]; oiph != NULL;
142 oiph = oiph->iph_next)
143 if (strncmp(oiph->iph_name, name,
144 sizeof(oiph->iph_name)) == 0)
145 break;
146 } while (oiph != NULL);
147 (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
148 err = COPYOUT(iph, op->iplo_struct, sizeof(*iph));
149 if (err != 0) {
150 KFREE(iph);
151 return EFAULT;
152 }
153 iph->iph_type |= IPHASH_ANON;
154 }
155
156 KMALLOCS(iph->iph_table, iphtent_t **,
157 iph->iph_size * sizeof(*iph->iph_table));
158 if (iph->iph_table == NULL) {
159 KFREE(iph);
160 ifs->ifs_ipht_nomem[unit]++;
161 return ENOMEM;
162 }
163
164 bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
165 iph->iph_masks[0] = 0;
166 iph->iph_masks[1] = 0;
167 iph->iph_masks[2] = 0;
168 iph->iph_masks[3] = 0;
169 iph->iph_list = NULL;
170
171 iph->iph_ref = 1;
172 iph->iph_next = ifs->ifs_ipf_htables[unit];
173 iph->iph_pnext = &ifs->ifs_ipf_htables[unit];
174 if (ifs->ifs_ipf_htables[unit] != NULL)
175 ifs->ifs_ipf_htables[unit]->iph_pnext = &iph->iph_next;
176 ifs->ifs_ipf_htables[unit] = iph;
177
178 ifs->ifs_ipf_nhtables[unit]++;
179
180 return 0;
181 }
182
183
184 /*
185 */
fr_removehtable(op,ifs)186 int fr_removehtable(op, ifs)
187 iplookupop_t *op;
188 ipf_stack_t *ifs;
189 {
190 iphtable_t *iph;
191
192
193 iph = fr_findhtable(op->iplo_unit, op->iplo_name, ifs);
194 if (iph == NULL)
195 return ESRCH;
196
197 if (iph->iph_unit != op->iplo_unit) {
198 return EINVAL;
199 }
200
201 if (iph->iph_ref != 1) {
202 return EBUSY;
203 }
204
205 fr_delhtable(iph, ifs);
206
207 return 0;
208 }
209
210
fr_delhtable(iph,ifs)211 void fr_delhtable(iph, ifs)
212 iphtable_t *iph;
213 ipf_stack_t *ifs;
214 {
215 iphtent_t *ipe;
216 int i;
217
218 for (i = 0; i < iph->iph_size; i++)
219 while ((ipe = iph->iph_table[i]) != NULL)
220 if (fr_delhtent(iph, ipe, ifs) != 0)
221 return;
222
223 *iph->iph_pnext = iph->iph_next;
224 if (iph->iph_next != NULL)
225 iph->iph_next->iph_pnext = iph->iph_pnext;
226
227 ifs->ifs_ipf_nhtables[iph->iph_unit]--;
228
229 if (iph->iph_ref == 1) {
230 KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
231 KFREE(iph);
232 }
233 }
234
235
fr_derefhtable(iph,ifs)236 void fr_derefhtable(iph, ifs)
237 iphtable_t *iph;
238 ipf_stack_t *ifs;
239 {
240 iph->iph_ref--;
241 if (iph->iph_ref == 0)
242 fr_delhtable(iph, ifs);
243 }
244
245
fr_derefhtent(ipe)246 void fr_derefhtent(ipe)
247 iphtent_t *ipe;
248 {
249 ipe->ipe_ref--;
250 if (ipe->ipe_ref == 0) {
251 KFREE(ipe);
252 }
253 }
254
255
fr_findhtable(unit,name,ifs)256 iphtable_t *fr_findhtable(unit, name, ifs)
257 int unit;
258 char *name;
259 ipf_stack_t *ifs;
260 {
261 iphtable_t *iph;
262
263 for (iph = ifs->ifs_ipf_htables[unit]; iph != NULL; iph = iph->iph_next)
264 if (strncmp(iph->iph_name, name, sizeof(iph->iph_name)) == 0)
265 break;
266 return iph;
267 }
268
269
fr_flushhtable(op,ifs)270 size_t fr_flushhtable(op, ifs)
271 iplookupflush_t *op;
272 ipf_stack_t *ifs;
273 {
274 iphtable_t *iph;
275 size_t freed;
276 int i;
277
278 freed = 0;
279
280 for (i = 0; i <= IPL_LOGMAX; i++) {
281 if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
282 while ((iph = ifs->ifs_ipf_htables[i]) != NULL) {
283 fr_delhtable(iph, ifs);
284 freed++;
285 }
286 }
287 }
288
289 return freed;
290 }
291
292
293 /*
294 * Add an entry to a hash table.
295 */
fr_addhtent(iph,ipeo,ifs)296 int fr_addhtent(iph, ipeo, ifs)
297 iphtable_t *iph;
298 iphtent_t *ipeo;
299 ipf_stack_t *ifs;
300 {
301 iphtent_t *ipe;
302 u_int hv;
303 int bits;
304
305 KMALLOC(ipe, iphtent_t *);
306 if (ipe == NULL)
307 return -1;
308
309 bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
310 #ifdef USE_INET6
311 if (ipe->ipe_family == AF_INET6) {
312 bits = count6bits((u_32_t *)ipe->ipe_mask.in6_addr8);
313 hv = IPE_HASH_FN(sum4((uint32_t *)ipe->ipe_addr.in6_addr8),
314 sum4((uint32_t *)ipe->ipe_mask.in6_addr8),
315 iph->iph_size);
316 } else
317 #endif
318 if (ipe->ipe_family == AF_INET)
319 {
320 ipe->ipe_addr.in4_addr &= ipe->ipe_mask.in4_addr;
321 ipe->ipe_addr.in4_addr = ntohl(ipe->ipe_addr.in4_addr);
322 bits = count4bits(ipe->ipe_mask.in4_addr);
323 ipe->ipe_mask.in4_addr = ntohl(ipe->ipe_mask.in4_addr);
324
325 hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr,
326 iph->iph_size);
327 } else
328 return -1;
329
330 ipe->ipe_ref = 1;
331 ipe->ipe_next = iph->iph_table[hv];
332 ipe->ipe_pnext = iph->iph_table + hv;
333
334 if (iph->iph_table[hv] != NULL)
335 iph->iph_table[hv]->ipe_pnext = &ipe->ipe_next;
336 iph->iph_table[hv] = ipe;
337
338 ipe->ipe_snext = iph->iph_list;
339 ipe->ipe_psnext = &iph->iph_list;
340 if (ipe->ipe_next != NULL)
341 ipe->ipe_next->ipe_psnext = &ipe->ipe_snext;
342 iph->iph_list = ipe;
343
344 #ifdef USE_INET6
345 if (ipe->ipe_family == AF_INET6) {
346 if ((bits >= 0) && (bits != 128))
347 if (bits >= 96)
348 iph->iph_masks[0] |= 1 << (bits - 96);
349 else if (bits >= 64)
350 iph->iph_masks[1] |= 1 << (bits - 64);
351 else if (bits >= 32)
352 iph->iph_masks[2] |= 1 << (bits - 32);
353 else
354 iph->iph_masks[3] |= 1 << bits;
355
356 } else
357 #endif
358 {
359 if ((bits >= 0) && (bits != 32))
360 iph->iph_masks[3] |= 1 << bits;
361 }
362
363 switch (iph->iph_type & ~IPHASH_ANON)
364 {
365 case IPHASH_GROUPMAP :
366 ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL,
367 iph->iph_flags, IPL_LOGIPF,
368 ifs->ifs_fr_active, ifs);
369 break;
370
371 default :
372 ipe->ipe_ptr = NULL;
373 ipe->ipe_value = 0;
374 break;
375 }
376
377 ifs->ifs_ipf_nhtnodes[iph->iph_unit]++;
378
379 return 0;
380 }
381
382
383 /*
384 * Delete an entry from a hash table.
385 */
fr_delhtent(iph,ipe,ifs)386 int fr_delhtent(iph, ipe, ifs)
387 iphtable_t *iph;
388 iphtent_t *ipe;
389 ipf_stack_t *ifs;
390 {
391 if (ipe->ipe_ref != 1)
392 return EBUSY;
393
394
395 *ipe->ipe_pnext = ipe->ipe_next;
396 if (ipe->ipe_next != NULL)
397 ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
398
399 switch (iph->iph_type & ~IPHASH_ANON)
400 {
401 case IPHASH_GROUPMAP :
402 if (ipe->ipe_group != NULL)
403 fr_delgroup(ipe->ipe_group, IPL_LOGIPF,
404 ifs->ifs_fr_active, ifs);
405 break;
406
407 default :
408 ipe->ipe_ptr = NULL;
409 ipe->ipe_value = 0;
410 break;
411 }
412
413 KFREE(ipe);
414
415 ifs->ifs_ipf_nhtnodes[iph->iph_unit]--;
416
417 return 0;
418 }
419
420
fr_iphmfindgroup(tptr,version,aptr,ifs)421 void *fr_iphmfindgroup(tptr, version, aptr, ifs)
422 void *tptr;
423 int version;
424 void *aptr;
425 ipf_stack_t *ifs;
426 {
427 i6addr_t *addr;
428 iphtable_t *iph;
429 iphtent_t *ipe;
430 void *rval;
431
432 if ((version != 4)
433 #ifdef USE_INET6
434 && (version != 6)
435 #endif
436 )
437 return NULL;
438
439 READ_ENTER(&ifs->ifs_ip_poolrw);
440 iph = tptr;
441 addr = aptr;
442
443 #ifdef USE_INET6
444 if (version == 6)
445 ipe = fr_iphmfind6(iph, &addr->in6);
446 else
447 #endif
448 if (version == 4)
449 ipe = fr_iphmfind(iph, &addr->in4);
450 else
451 ipe = NULL;
452 if (ipe != NULL)
453 rval = ipe->ipe_ptr;
454 else
455 rval = NULL;
456 RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
457 return rval;
458 }
459
460
461 /* ------------------------------------------------------------------------ */
462 /* Function: fr_iphmfindip */
463 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
464 /* Parameters: tptr(I) - pointer to the pool to search */
465 /* version(I) - IP protocol version (4 or 6) */
466 /* aptr(I) - pointer to address information */
467 /* fin - pointer to packet information */
468 /* ifs - ipf stack instance */
469 /* */
470 /* Search the hash table for a given address and return a search result. */
471 /* ------------------------------------------------------------------------ */
fr_iphmfindip(tptr,version,aptr,fin,ifs)472 int fr_iphmfindip(tptr, version, aptr, fin, ifs)
473 void *tptr, *aptr;
474 int version;
475 fr_info_t *fin;
476 ipf_stack_t *ifs;
477 {
478 i6addr_t *addr;
479 iphtable_t *iph;
480 iphtent_t *ipe;
481 int rval;
482
483 if ((version != 4)
484 #ifdef USE_INET6
485 && (version != 6)
486 #endif
487 )
488 return -1;
489
490 if (tptr == NULL || aptr == NULL)
491 return -1;
492
493 iph = tptr;
494 addr = aptr;
495
496 READ_ENTER(&ifs->ifs_ip_poolrw);
497 #ifdef USE_INET6
498 if (version == 6)
499 ipe = fr_iphmfind6(iph, &addr->in6);
500 else
501 #endif
502 if (version == 4)
503 ipe = fr_iphmfind(iph, &addr->in4);
504 else
505 ipe = NULL;
506 if (ipe != NULL) {
507 ipe->ipe_hits++;
508 ipe->ipe_bytes += fin->fin_plen;
509 rval = 0;
510 } else {
511 rval = 1;
512 }
513 RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
514 return rval;
515 }
516
517
518 /* Locks: ip_poolrw */
fr_iphmfind(iph,addr)519 static iphtent_t *fr_iphmfind(iph, addr)
520 iphtable_t *iph;
521 struct in_addr *addr;
522 {
523 u_32_t hmsk, msk, ips;
524 iphtent_t *ipe;
525 u_int hv;
526
527 hmsk = iph->iph_masks[3];
528 msk = 0xffffffff;
529 maskloop:
530 ips = ntohl(addr->s_addr) & msk;
531 hv = IPE_HASH_FN(ips, msk, iph->iph_size);
532 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
533 if (ipe->ipe_mask.in4_addr != msk ||
534 ipe->ipe_addr.in4_addr != ips) {
535 continue;
536 }
537 break;
538 }
539
540 if ((ipe == NULL) && (hmsk != 0)) {
541 while (hmsk != 0) {
542 msk <<= 1;
543 if (hmsk & 0x80000000)
544 break;
545 hmsk <<= 1;
546 }
547 if (hmsk != 0) {
548 hmsk <<= 1;
549 goto maskloop;
550 }
551 }
552 return ipe;
553 }
554
555
556 #ifdef USE_INET6
557 /* Locks: ip_poolrw */
fr_iphmfind6(iph,addr)558 static iphtent_t *fr_iphmfind6(iph, addr)
559 iphtable_t *iph;
560 struct in6_addr *addr;
561 {
562 u_32_t hmsk[4], msk[4], ips[4], *and;
563 iphtent_t *ipe;
564 u_int hv;
565
566 hmsk[0] = iph->iph_masks[0];
567 hmsk[1] = iph->iph_masks[1];
568 hmsk[2] = iph->iph_masks[2];
569 hmsk[3] = iph->iph_masks[3];
570
571 msk[0] = 0xffffffff;
572 msk[1] = 0xffffffff;
573 msk[2] = 0xffffffff;
574 msk[3] = 0xffffffff;
575 maskloop:
576 and = (u_32_t *)addr->s6_addr;
577 ips[0] = *and & msk[0];
578 ips[1] = *(and + 1) & msk[1];
579 ips[2] = *(and + 2) & msk[2];
580 ips[3] = *(and + 3) & msk[3];
581
582 hv = IPE_HASH_FN(sum4((uint32_t *)addr), sum4((uint32_t *)msk),
583 iph->iph_size);
584 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
585 if (bcmp((void *)&ipe->ipe_mask.in6, (void *)msk, 16) ||
586 bcmp((void *)&ipe->ipe_addr.in6, (void *)ips, 16))
587 continue;
588 break;
589 }
590
591 if ((ipe == NULL) && ((hmsk[0] != 0) ||
592 (hmsk[1] != 0) ||
593 (hmsk[2] != 0) ||
594 (hmsk[3] != 0) )) {
595 while ((hmsk[0] != 0) && (hmsk[1] != 0) &&
596 (hmsk[2] != 0) && (hmsk[3] != 0)) {
597 left_shift_ipv6((char *)msk);
598 if (hmsk[0] & 0x80000000)
599 break;
600 left_shift_ipv6((char *)hmsk);
601 }
602 if ((hmsk[0] != 0) && (hmsk[1] != 0) &&
603 (hmsk[2] != 0) && (hmsk[3] != 0)) {
604 left_shift_ipv6((char *)hmsk);
605 goto maskloop;
606 }
607 }
608 return ipe;
609 }
610
611
612 /*
613 * sum4: ipv6 add -> 4 bytes values
614 */
sum4(add)615 static uint32_t sum4(add)
616 uint32_t *add;
617 {
618 return (*add + *(add + 1) + *(add + 2) + *(add + 3));
619 }
620
621 /*
622 * left shift on 128 bits
623 */
left_shift_ipv6(data)624 static void left_shift_ipv6(data)
625 char *data;
626 {
627 u_32_t *sd;
628
629 sd = (u_32_t *)data;
630 sd[0] <<= 1;
631 if (sd[1] >= 0x80000000)
632 sd[0] += 1;
633
634 sd[1] <<= 1;
635 if (sd[2] >= 0x80000000)
636 sd[1] += 1;
637
638 sd[2] <<= 1;
639 if (sd[3] >= 0x80000000)
640 sd[2] += 1;
641
642 sd[3] <<= 1;
643 }
644 #endif
645
fr_htable_getnext(token,ilp,ifs)646 int fr_htable_getnext(token, ilp, ifs)
647 ipftoken_t *token;
648 ipflookupiter_t *ilp;
649 ipf_stack_t *ifs;
650 {
651 iphtent_t *node, zn, *nextnode;
652 iphtable_t *iph, zp, *nextiph;
653 int err;
654
655 err = 0;
656 iph = NULL;
657 node = NULL;
658 nextiph = NULL;
659 nextnode = NULL;
660
661 READ_ENTER(&ifs->ifs_ip_poolrw);
662
663 /*
664 * Get "previous" entry from the token and find the next entry.
665 *
666 * If we found an entry, add a reference to it and update the token.
667 * Otherwise, zero out data to be returned and NULL out token.
668 */
669 switch (ilp->ili_otype)
670 {
671 case IPFLOOKUPITER_LIST :
672 iph = token->ipt_data;
673 if (iph == NULL) {
674 nextiph = ifs->ifs_ipf_htables[(int)ilp->ili_unit];
675 } else {
676 nextiph = iph->iph_next;
677 }
678 if (nextiph != NULL) {
679 ATOMIC_INC(nextiph->iph_ref);
680 token->ipt_data = nextiph;
681 } else {
682 bzero((char *)&zp, sizeof(zp));
683 nextiph = &zp;
684 token->ipt_data = NULL;
685 }
686 break;
687
688 case IPFLOOKUPITER_NODE :
689 node = token->ipt_data;
690 if (node == NULL) {
691 iph = fr_findhtable(ilp->ili_unit, ilp->ili_name, ifs);
692 if (iph == NULL)
693 err = ESRCH;
694 else {
695 nextnode = iph->iph_list;
696 }
697 } else {
698 nextnode = node->ipe_snext;
699 }
700 if (nextnode != NULL) {
701 ATOMIC_INC(nextnode->ipe_ref);
702 token->ipt_data = nextnode;
703 } else {
704 bzero((char *)&zn, sizeof(zn));
705 nextnode = &zn;
706 token->ipt_data = NULL;
707 }
708 break;
709
710 default :
711 err = EINVAL;
712 break;
713 }
714
715 /*
716 * Now that we have ref, it's save to give up lock.
717 */
718 RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
719 if (err != 0)
720 return err;
721
722 /*
723 * Copy out data and clean up references and token as needed.
724 */
725 switch (ilp->ili_otype)
726 {
727 case IPFLOOKUPITER_LIST :
728 err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
729 if (err != 0)
730 err = EFAULT;
731 if (token->ipt_data == NULL) {
732 ipf_freetoken(token, ifs);
733 } else {
734 if (iph != NULL) {
735 WRITE_ENTER(&ifs->ifs_ip_poolrw);
736 fr_derefhtable(iph, ifs);
737 RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
738 }
739 if (nextiph->iph_next == NULL)
740 ipf_freetoken(token, ifs);
741 }
742 break;
743
744 case IPFLOOKUPITER_NODE :
745 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
746 if (err != 0)
747 err = EFAULT;
748 if (token->ipt_data == NULL) {
749 ipf_freetoken(token, ifs);
750 } else {
751 if (node != NULL) {
752 WRITE_ENTER(&ifs->ifs_ip_poolrw);
753 fr_derefhtent(node);
754 RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
755 }
756 if (nextnode->ipe_snext == NULL)
757 ipf_freetoken(token, ifs);
758 }
759 break;
760 }
761
762 return err;
763 }
764
765
fr_htable_iterderef(otype,unit,data,ifs)766 void fr_htable_iterderef(otype, unit, data, ifs)
767 u_int otype;
768 int unit;
769 void *data;
770 ipf_stack_t *ifs;
771 {
772
773 if (data == NULL)
774 return;
775
776 if (unit < 0 || unit > IPL_LOGMAX)
777 return;
778
779 switch (otype)
780 {
781 case IPFLOOKUPITER_LIST :
782 WRITE_ENTER(&ifs->ifs_ip_poolrw);
783 fr_derefhtable((iphtable_t *)data, ifs);
784 RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
785 break;
786
787 case IPFLOOKUPITER_NODE :
788 WRITE_ENTER(&ifs->ifs_ip_poolrw);
789 fr_derefhtent((iphtent_t *)data);
790 RWLOCK_EXIT(&ifs->ifs_ip_poolrw);
791 break;
792 default :
793 break;
794 }
795 }
796 #endif /* IPFILTER_LOOKUP */
797