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