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