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