Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ipf / ip_htable.c
blob978c13f213bda93daa74e123aeea2f86f0422ae2
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 1993-2001, 2003 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
8 * Copyright 2008 Sun Microsystems, Inc.
9 */
10 #if defined(KERNEL) || defined(_KERNEL)
11 # undef KERNEL
12 # undef _KERNEL
13 # define KERNEL 1
14 # define _KERNEL 1
15 #endif
16 #include <sys/param.h>
17 #include <sys/types.h>
18 #include <sys/errno.h>
19 #include <sys/time.h>
20 #include <sys/file.h>
21 #if !defined(_KERNEL)
22 # include <stdlib.h>
23 # include <string.h>
24 # define _KERNEL
25 # ifdef __OpenBSD__
26 struct file;
27 # endif
28 # include <sys/uio.h>
29 # undef _KERNEL
30 #endif
31 #include <sys/socket.h>
32 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
33 # include <sys/malloc.h>
34 #endif
35 #if defined(__FreeBSD__)
36 # include <sys/cdefs.h>
37 # include <sys/proc.h>
38 #endif
39 #if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \
40 !defined(linux)
41 # include <sys/mbuf.h>
42 #endif
43 #if defined(_KERNEL)
44 # include <sys/systm.h>
45 #else
46 # include <stdio.h>
47 #endif
48 #include <netinet/in.h>
49 #include <net/if.h>
51 #include "netinet/ip_compat.h"
52 #include "netinet/ip_fil.h"
53 #include "netinet/ip_lookup.h"
54 #include "netinet/ip_htable.h"
55 /* END OF INCLUDES */
57 #if !defined(lint)
58 static const char rcsid[] = "@(#)Id: ip_htable.c,v 2.34.2.13 2009/05/13 19:13:36 darrenr Exp";
59 #endif
61 #ifdef IPFILTER_LOOKUP
62 static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *));
63 static u_long ipht_nomem[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };
64 static u_long ipf_nhtables[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };
65 static u_long ipf_nhtnodes[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };
67 iphtable_t *ipf_htables[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
68 NULL, NULL, NULL, NULL };
71 void fr_htable_unload()
73 iplookupflush_t fop;
75 fop.iplf_unit = IPL_LOGALL;
76 (void)fr_flushhtable(&fop);
80 int fr_gethtablestat(op)
81 iplookupop_t *op;
83 iphtstat_t stats;
85 if (op->iplo_size != sizeof(stats))
86 return EINVAL;
88 stats.iphs_tables = ipf_htables[op->iplo_unit];
89 stats.iphs_numtables = ipf_nhtables[op->iplo_unit];
90 stats.iphs_numnodes = ipf_nhtnodes[op->iplo_unit];
91 stats.iphs_nomem = ipht_nomem[op->iplo_unit];
93 return COPYOUT(&stats, op->iplo_struct, sizeof(stats));
99 * Create a new hash table using the template passed.
101 int fr_newhtable(op)
102 iplookupop_t *op;
104 iphtable_t *iph, *oiph;
105 char name[FR_GROUPLEN];
106 int err, i, unit;
108 unit = op->iplo_unit;
109 if ((op->iplo_arg & IPHASH_ANON) == 0) {
110 iph = fr_existshtable(unit, op->iplo_name);
111 if (iph != NULL) {
112 if ((iph->iph_flags & IPHASH_DELETE) == 0)
113 return EEXIST;
114 iph->iph_flags &= ~IPHASH_DELETE;
115 return 0;
119 KMALLOC(iph, iphtable_t *);
120 if (iph == NULL) {
121 ipht_nomem[op->iplo_unit]++;
122 return ENOMEM;
124 err = COPYIN(op->iplo_struct, iph, sizeof(*iph));
125 if (err != 0) {
126 KFREE(iph);
127 return EFAULT;
130 if (iph->iph_unit != unit) {
131 KFREE(iph);
132 return EINVAL;
135 if ((op->iplo_arg & IPHASH_ANON) != 0) {
136 i = IPHASH_ANON;
137 do {
138 i++;
139 #if defined(SNPRINTF) && defined(_KERNEL)
140 SNPRINTF(name, sizeof(name), "%u", i);
141 #else
142 (void)sprintf(name, "%u", i);
143 #endif
144 for (oiph = ipf_htables[unit]; oiph != NULL;
145 oiph = oiph->iph_next)
146 if (strncmp(oiph->iph_name, name,
147 sizeof(oiph->iph_name)) == 0)
148 break;
149 } while (oiph != NULL);
151 (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
152 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
153 iph->iph_type |= IPHASH_ANON;
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 ipht_nomem[unit]++;
161 return ENOMEM;
164 bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
165 iph->iph_masks = 0;
166 iph->iph_list = NULL;
168 iph->iph_ref = 1;
169 iph->iph_next = ipf_htables[unit];
170 iph->iph_pnext = &ipf_htables[unit];
171 if (ipf_htables[unit] != NULL)
172 ipf_htables[unit]->iph_pnext = &iph->iph_next;
173 ipf_htables[unit] = iph;
174 ipf_nhtables[unit]++;
176 return 0;
182 int fr_removehtable(unit, name)
183 int unit;
184 char *name;
186 iphtable_t *iph;
188 iph = fr_findhtable(unit, name);
189 if (iph == NULL)
190 return ESRCH;
192 if (iph->iph_unit != unit) {
193 return EINVAL;
196 if (iph->iph_ref != 0) {
197 (void) fr_clearhtable(iph);
198 iph->iph_flags |= IPHASH_DELETE;
199 return 0;
202 fr_delhtable(iph);
204 return 0;
208 int fr_clearhtable(iph)
209 iphtable_t *iph;
211 iphtent_t *ipe;
213 while ((ipe = iph->iph_list) != NULL)
214 if (fr_delhtent(iph, ipe) != 0)
215 return 1;
216 return 0;
220 int fr_delhtable(iph)
221 iphtable_t *iph;
224 if (fr_clearhtable(iph) != 0)
225 return 1;
227 if (iph->iph_pnext != NULL)
228 *iph->iph_pnext = iph->iph_next;
229 if (iph->iph_next != NULL)
230 iph->iph_next->iph_pnext = iph->iph_pnext;
232 ipf_nhtables[iph->iph_unit]--;
234 return fr_derefhtable(iph);
239 * Delete an entry from a hash table.
241 int fr_delhtent(iph, ipe)
242 iphtable_t *iph;
243 iphtent_t *ipe;
246 if (ipe->ipe_phnext != NULL)
247 *ipe->ipe_phnext = ipe->ipe_hnext;
248 if (ipe->ipe_hnext != NULL)
249 ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext;
251 if (ipe->ipe_pnext != NULL)
252 *ipe->ipe_pnext = ipe->ipe_next;
253 if (ipe->ipe_next != NULL)
254 ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
256 switch (iph->iph_type & ~IPHASH_ANON)
258 case IPHASH_GROUPMAP :
259 if (ipe->ipe_group != NULL)
260 fr_delgroup(ipe->ipe_group, IPL_LOGIPF, fr_active);
261 break;
263 default :
264 ipe->ipe_ptr = NULL;
265 ipe->ipe_value = 0;
266 break;
269 return fr_derefhtent(ipe);
273 int fr_derefhtable(iph)
274 iphtable_t *iph;
276 int refs;
278 iph->iph_ref--;
279 refs = iph->iph_ref;
281 if (iph->iph_ref == 0) {
282 KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
283 KFREE(iph);
286 return refs;
290 int fr_derefhtent(ipe)
291 iphtent_t *ipe;
294 ipe->ipe_ref--;
295 if (ipe->ipe_ref == 0) {
296 ipf_nhtnodes[ipe->ipe_unit]--;
298 KFREE(ipe);
300 return 0;
303 return ipe->ipe_ref;
307 iphtable_t *fr_existshtable(unit, name)
308 int unit;
309 char *name;
311 iphtable_t *iph;
313 for (iph = ipf_htables[unit]; iph != NULL; iph = iph->iph_next)
314 if (strncmp(iph->iph_name, name, sizeof(iph->iph_name)) == 0)
315 break;
316 return iph;
320 iphtable_t *fr_findhtable(unit, name)
321 int unit;
322 char *name;
324 iphtable_t *iph;
326 iph = fr_existshtable(unit, name);
327 if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0)
328 return iph;
330 return NULL;
334 size_t fr_flushhtable(op)
335 iplookupflush_t *op;
337 iphtable_t *iph;
338 size_t freed;
339 int i;
341 freed = 0;
343 for (i = 0; i <= IPL_LOGMAX; i++) {
344 if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
345 while ((iph = ipf_htables[i]) != NULL) {
346 if (fr_delhtable(iph) == 0) {
347 freed++;
348 } else {
349 iph->iph_flags |= IPHASH_DELETE;
355 return freed;
360 * Add an entry to a hash table.
362 int fr_addhtent(iph, ipeo)
363 iphtable_t *iph;
364 iphtent_t *ipeo;
366 iphtent_t *ipe;
367 u_int hv;
368 int bits;
370 KMALLOC(ipe, iphtent_t *);
371 if (ipe == NULL)
372 return -1;
374 bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
375 ipe->ipe_addr.in4_addr &= ipe->ipe_mask.in4_addr;
376 ipe->ipe_addr.in4_addr = ntohl(ipe->ipe_addr.in4_addr);
377 bits = count4bits(ipe->ipe_mask.in4_addr);
378 ipe->ipe_mask.in4_addr = ntohl(ipe->ipe_mask.in4_addr);
380 hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr,
381 iph->iph_size);
382 ipe->ipe_ref = 1;
383 ipe->ipe_hnext = iph->iph_table[hv];
384 ipe->ipe_phnext = iph->iph_table + hv;
386 if (iph->iph_table[hv] != NULL)
387 iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext;
388 iph->iph_table[hv] = ipe;
390 ipe->ipe_next = iph->iph_list;
391 ipe->ipe_pnext = &iph->iph_list;
392 if (ipe->ipe_next != NULL)
393 ipe->ipe_next->ipe_pnext = &ipe->ipe_next;
394 iph->iph_list = ipe;
396 if ((bits >= 0) && (bits != 32))
397 iph->iph_masks |= 1 << bits;
399 switch (iph->iph_type & ~IPHASH_ANON)
401 case IPHASH_GROUPMAP :
402 ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL,
403 iph->iph_flags, IPL_LOGIPF,
404 fr_active);
405 break;
407 default :
408 ipe->ipe_ptr = NULL;
409 ipe->ipe_value = 0;
410 break;
413 ipe->ipe_unit = iph->iph_unit;
414 ipf_nhtnodes[ipe->ipe_unit]++;
416 return 0;
420 void *fr_iphmfindgroup(tptr, aptr)
421 void *tptr, *aptr;
423 struct in_addr *addr;
424 iphtable_t *iph;
425 iphtent_t *ipe;
426 void *rval;
428 READ_ENTER(&ip_poolrw);
429 iph = tptr;
430 addr = aptr;
432 ipe = fr_iphmfind(iph, addr);
433 if (ipe != NULL)
434 rval = ipe->ipe_ptr;
435 else
436 rval = NULL;
437 RWLOCK_EXIT(&ip_poolrw);
438 return rval;
442 /* ------------------------------------------------------------------------ */
443 /* Function: fr_iphmfindip */
444 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
445 /* Parameters: tptr(I) - pointer to the pool to search */
446 /* ipversion(I) - IP protocol version (4 or 6) */
447 /* aptr(I) - pointer to address information */
448 /* */
449 /* Search the hash table for a given address and return a search result. */
450 /* ------------------------------------------------------------------------ */
451 int fr_iphmfindip(tptr, ipversion, aptr)
452 void *tptr, *aptr;
453 int ipversion;
455 struct in_addr *addr;
456 iphtable_t *iph;
457 iphtent_t *ipe;
458 int rval;
460 if (ipversion != 4)
461 return -1;
463 if (tptr == NULL || aptr == NULL)
464 return -1;
466 iph = tptr;
467 addr = aptr;
469 READ_ENTER(&ip_poolrw);
470 ipe = fr_iphmfind(iph, addr);
471 if (ipe != NULL)
472 rval = 0;
473 else
474 rval = 1;
475 RWLOCK_EXIT(&ip_poolrw);
476 return rval;
480 /* Locks: ip_poolrw */
481 static iphtent_t *fr_iphmfind(iph, addr)
482 iphtable_t *iph;
483 struct in_addr *addr;
485 u_32_t hmsk, msk, ips;
486 iphtent_t *ipe;
487 u_int hv;
489 hmsk = iph->iph_masks;
490 msk = 0xffffffff;
491 maskloop:
492 ips = ntohl(addr->s_addr) & msk;
493 hv = IPE_HASH_FN(ips, msk, iph->iph_size);
494 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) {
495 if (ipe->ipe_mask.in4_addr != msk ||
496 ipe->ipe_addr.in4_addr != ips) {
497 continue;
499 break;
502 if ((ipe == NULL) && (hmsk != 0)) {
503 while (hmsk != 0) {
504 msk <<= 1;
505 if (hmsk & 0x80000000)
506 break;
507 hmsk <<= 1;
509 if (hmsk != 0) {
510 hmsk <<= 1;
511 goto maskloop;
514 return ipe;
518 int fr_htable_getnext(token, ilp)
519 ipftoken_t *token;
520 ipflookupiter_t *ilp;
522 iphtent_t *node, zn, *nextnode;
523 iphtable_t *iph, zp, *nextiph;
524 int err;
526 err = 0;
527 iph = NULL;
528 node = NULL;
529 nextiph = NULL;
530 nextnode = NULL;
532 READ_ENTER(&ip_poolrw);
535 * Get "previous" entry from the token and find the next entry.
537 * If we found an entry, add a reference to it and update the token.
538 * Otherwise, zero out data to be returned and NULL out token.
540 switch (ilp->ili_otype)
542 case IPFLOOKUPITER_LIST :
543 iph = token->ipt_data;
544 if (iph == NULL) {
545 nextiph = ipf_htables[(int)ilp->ili_unit];
546 } else {
547 nextiph = iph->iph_next;
550 if (nextiph != NULL) {
551 ATOMIC_INC(nextiph->iph_ref);
552 token->ipt_data = nextiph;
553 } else {
554 bzero((char *)&zp, sizeof(zp));
555 nextiph = &zp;
556 token->ipt_data = NULL;
558 break;
560 case IPFLOOKUPITER_NODE :
561 node = token->ipt_data;
562 if (node == NULL) {
563 iph = fr_findhtable(ilp->ili_unit, ilp->ili_name);
564 if (iph == NULL)
565 err = ESRCH;
566 else {
567 nextnode = iph->iph_list;
569 } else {
570 nextnode = node->ipe_next;
573 if (nextnode != NULL) {
574 ATOMIC_INC(nextnode->ipe_ref);
575 token->ipt_data = nextnode;
576 } else {
577 bzero((char *)&zn, sizeof(zn));
578 nextnode = &zn;
579 token->ipt_data = NULL;
581 break;
583 default :
584 err = EINVAL;
585 break;
589 * Now that we have ref, it's save to give up lock.
591 RWLOCK_EXIT(&ip_poolrw);
592 if (err != 0)
593 return err;
596 * Copy out data and clean up references and token as needed.
598 switch (ilp->ili_otype)
600 case IPFLOOKUPITER_LIST :
601 err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
602 if (err != 0)
603 err = EFAULT;
604 if (token->ipt_data != NULL) {
605 if (iph != NULL) {
606 WRITE_ENTER(&ip_poolrw);
607 fr_derefhtable(iph);
608 RWLOCK_EXIT(&ip_poolrw);
610 if (nextiph->iph_next == NULL)
611 token->ipt_data = NULL;
613 break;
615 case IPFLOOKUPITER_NODE :
616 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
617 if (err != 0)
618 err = EFAULT;
619 if (token->ipt_data != NULL) {
620 if (node != NULL) {
621 WRITE_ENTER(&ip_poolrw);
622 fr_derefhtent(node);
623 RWLOCK_EXIT(&ip_poolrw);
625 if (nextnode->ipe_next == NULL)
626 token->ipt_data = NULL;
628 break;
631 return err;
635 void fr_htable_iterderef(otype, unit, data)
636 u_int otype;
637 int unit;
638 void *data;
641 if (data == NULL)
642 return;
644 if (unit < 0 || unit > IPL_LOGMAX)
645 return;
647 switch (otype)
649 case IPFLOOKUPITER_LIST :
650 WRITE_ENTER(&ip_poolrw);
651 fr_derefhtable((iphtable_t *)data);
652 RWLOCK_EXIT(&ip_poolrw);
653 break;
655 case IPFLOOKUPITER_NODE :
656 WRITE_ENTER(&ip_poolrw);
657 fr_derefhtent((iphtent_t *)data);
658 RWLOCK_EXIT(&ip_poolrw);
659 break;
660 default :
661 break;
665 #endif /* IPFILTER_LOOKUP */