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.
10 #if defined(KERNEL) || defined(_KERNEL)
16 #include <sys/param.h>
17 #include <sys/types.h>
18 #include <sys/errno.h>
31 #include <sys/socket.h>
32 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
33 # include <sys/malloc.h>
35 #if defined(__FreeBSD__)
36 # include <sys/cdefs.h>
37 # include <sys/proc.h>
39 #if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \
41 # include <sys/mbuf.h>
44 # include <sys/systm.h>
48 #include <netinet/in.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"
58 static const char rcsid
[] = "@(#)Id: ip_htable.c,v 2.34.2.13 2009/05/13 19:13:36 darrenr Exp";
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()
75 fop
.iplf_unit
= IPL_LOGALL
;
76 (void)fr_flushhtable(&fop
);
80 int fr_gethtablestat(op
)
85 if (op
->iplo_size
!= sizeof(stats
))
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.
104 iphtable_t
*iph
, *oiph
;
105 char name
[FR_GROUPLEN
];
108 unit
= op
->iplo_unit
;
109 if ((op
->iplo_arg
& IPHASH_ANON
) == 0) {
110 iph
= fr_existshtable(unit
, op
->iplo_name
);
112 if ((iph
->iph_flags
& IPHASH_DELETE
) == 0)
114 iph
->iph_flags
&= ~IPHASH_DELETE
;
119 KMALLOC(iph
, iphtable_t
*);
121 ipht_nomem
[op
->iplo_unit
]++;
124 err
= COPYIN(op
->iplo_struct
, iph
, sizeof(*iph
));
130 if (iph
->iph_unit
!= unit
) {
135 if ((op
->iplo_arg
& IPHASH_ANON
) != 0) {
139 #if defined(SNPRINTF) && defined(_KERNEL)
140 SNPRINTF(name
, sizeof(name
), "%u", i
);
142 (void)sprintf(name
, "%u", i
);
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)
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
) {
164 bzero((char *)iph
->iph_table
, iph
->iph_size
* sizeof(*iph
->iph_table
));
166 iph
->iph_list
= NULL
;
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
]++;
182 int fr_removehtable(unit
, name
)
188 iph
= fr_findhtable(unit
, name
);
192 if (iph
->iph_unit
!= unit
) {
196 if (iph
->iph_ref
!= 0) {
197 (void) fr_clearhtable(iph
);
198 iph
->iph_flags
|= IPHASH_DELETE
;
208 int fr_clearhtable(iph
)
213 while ((ipe
= iph
->iph_list
) != NULL
)
214 if (fr_delhtent(iph
, ipe
) != 0)
220 int fr_delhtable(iph
)
224 if (fr_clearhtable(iph
) != 0)
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
)
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
);
269 return fr_derefhtent(ipe
);
273 int fr_derefhtable(iph
)
281 if (iph
->iph_ref
== 0) {
282 KFREES(iph
->iph_table
, iph
->iph_size
* sizeof(*iph
->iph_table
));
290 int fr_derefhtent(ipe
)
295 if (ipe
->ipe_ref
== 0) {
296 ipf_nhtnodes
[ipe
->ipe_unit
]--;
307 iphtable_t
*fr_existshtable(unit
, name
)
313 for (iph
= ipf_htables
[unit
]; iph
!= NULL
; iph
= iph
->iph_next
)
314 if (strncmp(iph
->iph_name
, name
, sizeof(iph
->iph_name
)) == 0)
320 iphtable_t
*fr_findhtable(unit
, name
)
326 iph
= fr_existshtable(unit
, name
);
327 if ((iph
!= NULL
) && (iph
->iph_flags
& IPHASH_DELETE
) == 0)
334 size_t fr_flushhtable(op
)
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) {
349 iph
->iph_flags
|= IPHASH_DELETE
;
360 * Add an entry to a hash table.
362 int fr_addhtent(iph
, ipeo
)
370 KMALLOC(ipe
, iphtent_t
*);
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
,
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
;
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
,
413 ipe
->ipe_unit
= iph
->iph_unit
;
414 ipf_nhtnodes
[ipe
->ipe_unit
]++;
420 void *fr_iphmfindgroup(tptr
, aptr
)
423 struct in_addr
*addr
;
428 READ_ENTER(&ip_poolrw
);
432 ipe
= fr_iphmfind(iph
, addr
);
437 RWLOCK_EXIT(&ip_poolrw
);
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 */
449 /* Search the hash table for a given address and return a search result. */
450 /* ------------------------------------------------------------------------ */
451 int fr_iphmfindip(tptr
, ipversion
, aptr
)
455 struct in_addr
*addr
;
463 if (tptr
== NULL
|| aptr
== NULL
)
469 READ_ENTER(&ip_poolrw
);
470 ipe
= fr_iphmfind(iph
, addr
);
475 RWLOCK_EXIT(&ip_poolrw
);
480 /* Locks: ip_poolrw */
481 static iphtent_t
*fr_iphmfind(iph
, addr
)
483 struct in_addr
*addr
;
485 u_32_t hmsk
, msk
, ips
;
489 hmsk
= iph
->iph_masks
;
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
) {
502 if ((ipe
== NULL
) && (hmsk
!= 0)) {
505 if (hmsk
& 0x80000000)
518 int fr_htable_getnext(token
, ilp
)
520 ipflookupiter_t
*ilp
;
522 iphtent_t
*node
, zn
, *nextnode
;
523 iphtable_t
*iph
, zp
, *nextiph
;
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
;
545 nextiph
= ipf_htables
[(int)ilp
->ili_unit
];
547 nextiph
= iph
->iph_next
;
550 if (nextiph
!= NULL
) {
551 ATOMIC_INC(nextiph
->iph_ref
);
552 token
->ipt_data
= nextiph
;
554 bzero((char *)&zp
, sizeof(zp
));
556 token
->ipt_data
= NULL
;
560 case IPFLOOKUPITER_NODE
:
561 node
= token
->ipt_data
;
563 iph
= fr_findhtable(ilp
->ili_unit
, ilp
->ili_name
);
567 nextnode
= iph
->iph_list
;
570 nextnode
= node
->ipe_next
;
573 if (nextnode
!= NULL
) {
574 ATOMIC_INC(nextnode
->ipe_ref
);
575 token
->ipt_data
= nextnode
;
577 bzero((char *)&zn
, sizeof(zn
));
579 token
->ipt_data
= NULL
;
589 * Now that we have ref, it's save to give up lock.
591 RWLOCK_EXIT(&ip_poolrw
);
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
));
604 if (token
->ipt_data
!= NULL
) {
606 WRITE_ENTER(&ip_poolrw
);
608 RWLOCK_EXIT(&ip_poolrw
);
610 if (nextiph
->iph_next
== NULL
)
611 token
->ipt_data
= NULL
;
615 case IPFLOOKUPITER_NODE
:
616 err
= COPYOUT(nextnode
, ilp
->ili_data
, sizeof(*nextnode
));
619 if (token
->ipt_data
!= NULL
) {
621 WRITE_ENTER(&ip_poolrw
);
623 RWLOCK_EXIT(&ip_poolrw
);
625 if (nextnode
->ipe_next
== NULL
)
626 token
->ipt_data
= NULL
;
635 void fr_htable_iterderef(otype
, unit
, data
)
644 if (unit
< 0 || unit
> IPL_LOGMAX
)
649 case IPFLOOKUPITER_LIST
:
650 WRITE_ENTER(&ip_poolrw
);
651 fr_derefhtable((iphtable_t
*)data
);
652 RWLOCK_EXIT(&ip_poolrw
);
655 case IPFLOOKUPITER_NODE
:
656 WRITE_ENTER(&ip_poolrw
);
657 fr_derefhtent((iphtent_t
*)data
);
658 RWLOCK_EXIT(&ip_poolrw
);
665 #endif /* IPFILTER_LOOKUP */