1 /*
2 * Copyright (C) 2012 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 */
6 #if defined(KERNEL) || defined(_KERNEL)
7 # undef KERNEL
8 # undef _KERNEL
9 # define KERNEL 1
10 # define _KERNEL 1
11 #endif
12 #include <sys/param.h>
13 #include <sys/errno.h>
14 #include <sys/types.h>
15 #include <sys/time.h>
16 #include <sys/file.h>
17 #if defined(__FreeBSD__) && defined(_KERNEL)
18 # include <sys/fcntl.h>
19 # include <sys/filio.h>
20 #else
21 # include <sys/ioctl.h>
22 #endif
23 #if !defined(_KERNEL)
24 # include <stdio.h>
25 # include <string.h>
26 # include <stdlib.h>
27 # define _KERNEL
28 # include <sys/uio.h>
29 # undef _KERNEL
30 #endif
31 #include <sys/socket.h>
32 #include <net/if.h>
33 #if defined(__FreeBSD__)
34 # include <sys/cdefs.h>
35 # include <sys/proc.h>
36 #endif
37 #if defined(_KERNEL)
38 # include <sys/systm.h>
39 # if !defined(__SVR4)
40 # include <sys/mbuf.h>
41 # endif
42 #else
43 # include "ipf.h"
44 #endif
45 #include <netinet/in.h>
46
47 #include "netinet/ip_compat.h"
48 #include "netinet/ip_fil.h"
49 #include "netinet/ip_lookup.h"
50 #include "netinet/ip_pool.h"
51 #include "netinet/ip_htable.h"
52 #include "netinet/ip_dstlist.h"
53 /* END OF INCLUDES */
54
55 #if !defined(lint)
56 static const char rcsid[] = "@(#)$Id$";
57 #endif
58
59 /*
60 * In this file, ip_pool.c, ip_htable.c and ip_dstlist.c, you will find the
61 * range for unit is [-1,IPL_LOGMAX]. The -1 is considered to be a valid number
62 * and represents a "wildcard" or "all" units (IPL_LOGALL). The reason for not
63 * starting the numbering at 0 is because the numbers [0,IPL_LOGMAX] correspond
64 * to the minor device number for their respective device. Thus where there is
65 * array indexing on the unit, +1 is used to map [-1.IPL_LOGMAX] to
66 * [0.POOL_LOOKUP_MAX].
67 */
68 static int ipf_lookup_addnode(ipf_main_softc_t *, caddr_t, int);
69 static int ipf_lookup_delnode(ipf_main_softc_t *, caddr_t, int);
70 static int ipf_lookup_addtable(ipf_main_softc_t *, caddr_t);
71 static int ipf_lookup_deltable(ipf_main_softc_t *, caddr_t);
72 static int ipf_lookup_stats(ipf_main_softc_t *, caddr_t);
73 static int ipf_lookup_flush(ipf_main_softc_t *, caddr_t);
74 static int ipf_lookup_iterate(ipf_main_softc_t *, void *, int, void *);
75 static int ipf_lookup_deltok(ipf_main_softc_t *, void *, int, void *);
76
77 #define MAX_BACKENDS 3
78 static ipf_lookup_t *backends[MAX_BACKENDS] = {
79 &ipf_pool_backend,
80 &ipf_htable_backend,
81 &ipf_dstlist_backend
82 };
83
84
85 typedef struct ipf_lookup_softc_s {
86 void *ipf_back[MAX_BACKENDS];
87 } ipf_lookup_softc_t;
88
89
90 /* ------------------------------------------------------------------------ */
91 /* Function: ipf_lookup_init */
92 /* Returns: int - 0 = success, else error */
93 /* Parameters: softc(I) - pointer to soft context main structure */
94 /* */
95 /* Initialise all of the subcomponents of the lookup infrstructure. */
96 /* ------------------------------------------------------------------------ */
97 void *
ipf_lookup_soft_create(ipf_main_softc_t * softc)98 ipf_lookup_soft_create(ipf_main_softc_t *softc)
99 {
100 ipf_lookup_softc_t *softl;
101 ipf_lookup_t **l;
102 int i;
103
104 KMALLOC(softl, ipf_lookup_softc_t *);
105 if (softl == NULL)
106 return (NULL);
107
108 bzero((char *)softl, sizeof(*softl));
109
110 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
111 softl->ipf_back[i] = (*(*l)->ipfl_create)(softc);
112 if (softl->ipf_back[i] == NULL) {
113 ipf_lookup_soft_destroy(softc, softl);
114 return (NULL);
115 }
116 }
117
118 return (softl);
119 }
120
121
122 /* ------------------------------------------------------------------------ */
123 /* Function: ipf_lookup_soft_init */
124 /* Returns: int - 0 = success, else error */
125 /* Parameters: softc(I) - pointer to soft context main structure */
126 /* arg(I) - pointer to local context to use */
127 /* */
128 /* Initialise all of the subcomponents of the lookup infrstructure. */
129 /* ------------------------------------------------------------------------ */
130 int
ipf_lookup_soft_init(ipf_main_softc_t * softc,void * arg)131 ipf_lookup_soft_init(ipf_main_softc_t *softc, void *arg)
132 {
133 ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
134 int err = 0;
135 int i;
136
137 for (i = 0; i < MAX_BACKENDS; i++) {
138 err = (*backends[i]->ipfl_init)(softc, softl->ipf_back[i]);
139 if (err != 0)
140 break;
141 }
142
143 return (err);
144 }
145
146
147 /* ------------------------------------------------------------------------ */
148 /* Function: ipf_lookup_soft_fini */
149 /* Returns: int - 0 = success, else error */
150 /* Parameters: softc(I) - pointer to soft context main structure */
151 /* arg(I) - pointer to local context to use */
152 /* */
153 /* Call the fini function in each backend to cleanup all allocated data. */
154 /* ------------------------------------------------------------------------ */
155 int
ipf_lookup_soft_fini(ipf_main_softc_t * softc,void * arg)156 ipf_lookup_soft_fini(ipf_main_softc_t *softc, void *arg)
157 {
158 ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
159 int i;
160
161 for (i = 0; i < MAX_BACKENDS; i++) {
162 if (softl->ipf_back[i] != NULL)
163 (*backends[i]->ipfl_fini)(softc,
164 softl->ipf_back[i]);
165 }
166
167 return (0);
168 }
169
170
171 /* ------------------------------------------------------------------------ */
172 /* Function: ipf_lookup_expire */
173 /* Returns: Nil */
174 /* Parameters: softc(I) - pointer to soft context main structure */
175 /* */
176 /* Step through each of the backends and call their expire functions, */
177 /* allowing them to delete any lifetime limited data. */
178 /* ------------------------------------------------------------------------ */
179 void
ipf_lookup_expire(ipf_main_softc_t * softc)180 ipf_lookup_expire(ipf_main_softc_t *softc)
181 {
182 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
183 int i;
184
185 WRITE_ENTER(&softc->ipf_poolrw);
186 for (i = 0; i < MAX_BACKENDS; i++)
187 (*backends[i]->ipfl_expire)(softc, softl->ipf_back[i]);
188 RWLOCK_EXIT(&softc->ipf_poolrw);
189 }
190
191
192 /* ------------------------------------------------------------------------ */
193 /* Function: ipf_lookup_softc_destroy */
194 /* Returns: int - 0 = success, else error */
195 /* Parameters: softc(I) - pointer to soft context main structure */
196 /* arg(I) - pointer to local context to use */
197 /* */
198 /* Free up all pool related memory that has been allocated whilst IPFilter */
199 /* has been running. Also, do any other deinitialisation required such */
200 /* ipf_lookup_init() can be called again, safely. */
201 /* ------------------------------------------------------------------------ */
202 void
ipf_lookup_soft_destroy(ipf_main_softc_t * softc,void * arg)203 ipf_lookup_soft_destroy(ipf_main_softc_t *softc, void *arg)
204 {
205 ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
206 int i;
207
208 for (i = 0; i < MAX_BACKENDS; i++) {
209 if (softl->ipf_back[i] != NULL)
210 (*backends[i]->ipfl_destroy)(softc,
211 softl->ipf_back[i]);
212 }
213
214 KFREE(softl);
215 }
216
217
218 /* ------------------------------------------------------------------------ */
219 /* Function: ipf_lookup_ioctl */
220 /* Returns: int - 0 = success, else error */
221 /* Parameters: softc(I) - pointer to soft context main structure */
222 /* arg(I) - pointer to local context to use */
223 /* data(IO) - pointer to ioctl data to be copied to/from user */
224 /* space. */
225 /* cmd(I) - ioctl command number */
226 /* mode(I) - file mode bits used with open */
227 /* uid(I) - uid of process doing ioctl */
228 /* ctx(I) - pointer that represents context for uid */
229 /* */
230 /* Handle ioctl commands sent to the ioctl device. For the most part, this */
231 /* involves just calling another function to handle the specifics of each */
232 /* command. */
233 /* ------------------------------------------------------------------------ */
234 int
ipf_lookup_ioctl(ipf_main_softc_t * softc,caddr_t data,ioctlcmd_t cmd,int mode,int uid,void * ctx)235 ipf_lookup_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd,
236 int mode, int uid, void *ctx)
237 {
238 int err;
239 SPL_INT(s);
240
241 mode = mode; /* LINT */
242
243 SPL_NET(s);
244
245 switch (cmd)
246 {
247 case SIOCLOOKUPADDNODE :
248 case SIOCLOOKUPADDNODEW :
249 WRITE_ENTER(&softc->ipf_poolrw);
250 err = ipf_lookup_addnode(softc, data, uid);
251 RWLOCK_EXIT(&softc->ipf_poolrw);
252 break;
253
254 case SIOCLOOKUPDELNODE :
255 case SIOCLOOKUPDELNODEW :
256 WRITE_ENTER(&softc->ipf_poolrw);
257 err = ipf_lookup_delnode(softc, data, uid);
258 RWLOCK_EXIT(&softc->ipf_poolrw);
259 break;
260
261 case SIOCLOOKUPADDTABLE :
262 WRITE_ENTER(&softc->ipf_poolrw);
263 err = ipf_lookup_addtable(softc, data);
264 RWLOCK_EXIT(&softc->ipf_poolrw);
265 break;
266
267 case SIOCLOOKUPDELTABLE :
268 WRITE_ENTER(&softc->ipf_poolrw);
269 err = ipf_lookup_deltable(softc, data);
270 RWLOCK_EXIT(&softc->ipf_poolrw);
271 break;
272
273 case SIOCLOOKUPSTAT :
274 case SIOCLOOKUPSTATW :
275 WRITE_ENTER(&softc->ipf_poolrw);
276 err = ipf_lookup_stats(softc, data);
277 RWLOCK_EXIT(&softc->ipf_poolrw);
278 break;
279
280 case SIOCLOOKUPFLUSH :
281 WRITE_ENTER(&softc->ipf_poolrw);
282 err = ipf_lookup_flush(softc, data);
283 RWLOCK_EXIT(&softc->ipf_poolrw);
284 break;
285
286 case SIOCLOOKUPITER :
287 err = ipf_lookup_iterate(softc, data, uid, ctx);
288 break;
289
290 case SIOCIPFDELTOK :
291 err = ipf_lookup_deltok(softc, data, uid, ctx);
292 break;
293
294 default :
295 IPFERROR(50001);
296 err = EINVAL;
297 break;
298 }
299 SPL_X(s);
300 return (err);
301 }
302
303
304 /* ------------------------------------------------------------------------ */
305 /* Function: ipf_lookup_addnode */
306 /* Returns: int - 0 = success, else error */
307 /* Parameters: softc(I) - pointer to soft context main structure */
308 /* data(I) - pointer to data from ioctl call */
309 /* */
310 /* Add a new data node to a lookup structure. First, check to see if the */
311 /* parent structure refered to by name exists and if it does, then go on to */
312 /* add a node to it. */
313 /* ------------------------------------------------------------------------ */
314 static int
ipf_lookup_addnode(ipf_main_softc_t * softc,caddr_t data,int uid)315 ipf_lookup_addnode(ipf_main_softc_t *softc, caddr_t data, int uid)
316 {
317 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
318 iplookupop_t op;
319 ipf_lookup_t **l;
320 int err;
321 int i;
322
323 err = BCOPYIN(data, &op, sizeof(op));
324 if (err != 0) {
325 IPFERROR(50002);
326 return (EFAULT);
327 }
328
329 if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
330 (op.iplo_unit != IPLT_ALL)) {
331 IPFERROR(50003);
332 return (EINVAL);
333 }
334
335 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
336
337 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
338 if (op.iplo_type == (*l)->ipfl_type) {
339 err = (*(*l)->ipfl_node_add)(softc,
340 softl->ipf_back[i],
341 &op, uid);
342 break;
343 }
344 }
345
346 if (i == MAX_BACKENDS) {
347 IPFERROR(50012);
348 err = EINVAL;
349 }
350
351 return (err);
352 }
353
354
355 /* ------------------------------------------------------------------------ */
356 /* Function: ipf_lookup_delnode */
357 /* Returns: int - 0 = success, else error */
358 /* Parameters: softc(I) - pointer to soft context main structure */
359 /* data(I) - pointer to data from ioctl call */
360 /* */
361 /* Delete a node from a lookup table by first looking for the table it is */
362 /* in and then deleting the entry that gets found. */
363 /* ------------------------------------------------------------------------ */
364 static int
ipf_lookup_delnode(ipf_main_softc_t * softc,caddr_t data,int uid)365 ipf_lookup_delnode(ipf_main_softc_t *softc, caddr_t data, int uid)
366 {
367 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
368 iplookupop_t op;
369 ipf_lookup_t **l;
370 int err;
371 int i;
372
373 err = BCOPYIN(data, &op, sizeof(op));
374 if (err != 0) {
375 IPFERROR(50042);
376 return (EFAULT);
377 }
378
379 if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
380 (op.iplo_unit != IPLT_ALL)) {
381 IPFERROR(50013);
382 return (EINVAL);
383 }
384
385 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
386
387 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
388 if (op.iplo_type == (*l)->ipfl_type) {
389 err = (*(*l)->ipfl_node_del)(softc, softl->ipf_back[i],
390 &op, uid);
391 break;
392 }
393 }
394
395 if (i == MAX_BACKENDS) {
396 IPFERROR(50021);
397 err = EINVAL;
398 }
399 return (err);
400 }
401
402
403 /* ------------------------------------------------------------------------ */
404 /* Function: ipf_lookup_addtable */
405 /* Returns: int - 0 = success, else error */
406 /* Parameters: softc(I) - pointer to soft context main structure */
407 /* data(I) - pointer to data from ioctl call */
408 /* */
409 /* Create a new lookup table, if one doesn't already exist using the name */
410 /* for this one. */
411 /* ------------------------------------------------------------------------ */
412 static int
ipf_lookup_addtable(ipf_main_softc_t * softc,caddr_t data)413 ipf_lookup_addtable(ipf_main_softc_t *softc, caddr_t data)
414 {
415 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
416 iplookupop_t op;
417 ipf_lookup_t **l;
418 int err, i;
419
420 err = BCOPYIN(data, &op, sizeof(op));
421 if (err != 0) {
422 IPFERROR(50022);
423 return (EFAULT);
424 }
425
426 if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
427 (op.iplo_unit != IPLT_ALL)) {
428 IPFERROR(50023);
429 return (EINVAL);
430 }
431
432 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
433
434 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
435 if (op.iplo_type == (*l)->ipfl_type) {
436 err = (*(*l)->ipfl_table_add)(softc,
437 softl->ipf_back[i],
438 &op);
439 break;
440 }
441 }
442
443 if (i == MAX_BACKENDS) {
444 IPFERROR(50026);
445 err = EINVAL;
446 }
447
448 /*
449 * For anonymous pools, copy back the operation struct because in the
450 * case of success it will contain the new table's name.
451 */
452 if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) {
453 err = BCOPYOUT(&op, data, sizeof(op));
454 if (err != 0) {
455 IPFERROR(50027);
456 err = EFAULT;
457 }
458 }
459
460 return (err);
461 }
462
463
464 /* ------------------------------------------------------------------------ */
465 /* Function: ipf_lookup_deltable */
466 /* Returns: int - 0 = success, else error */
467 /* Parameters: softc(I) - pointer to soft context main structure */
468 /* data(I) - pointer to data from ioctl call */
469 /* */
470 /* Decodes ioctl request to remove a particular hash table or pool and */
471 /* calls the relevant function to do the cleanup. */
472 /* ------------------------------------------------------------------------ */
473 static int
ipf_lookup_deltable(ipf_main_softc_t * softc,caddr_t data)474 ipf_lookup_deltable(ipf_main_softc_t *softc, caddr_t data)
475 {
476 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
477 iplookupop_t op;
478 ipf_lookup_t **l;
479 int err, i;
480
481 err = BCOPYIN(data, &op, sizeof(op));
482 if (err != 0) {
483 IPFERROR(50028);
484 return (EFAULT);
485 }
486
487 if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
488 (op.iplo_unit != IPLT_ALL)) {
489 IPFERROR(50029);
490 return (EINVAL);
491 }
492
493 op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
494
495 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
496 if (op.iplo_type == (*l)->ipfl_type) {
497 err = (*(*l)->ipfl_table_del)(softc,
498 softl->ipf_back[i],
499 &op);
500 break;
501 }
502 }
503
504 if (i == MAX_BACKENDS) {
505 IPFERROR(50030);
506 err = EINVAL;
507 }
508 return (err);
509 }
510
511
512 /* ------------------------------------------------------------------------ */
513 /* Function: ipf_lookup_stats */
514 /* Returns: int - 0 = success, else error */
515 /* Parameters: softc(I) - pointer to soft context main structure */
516 /* data(I) - pointer to data from ioctl call */
517 /* */
518 /* Copy statistical information from inside the kernel back to user space. */
519 /* ------------------------------------------------------------------------ */
520 static int
ipf_lookup_stats(ipf_main_softc_t * softc,caddr_t data)521 ipf_lookup_stats(ipf_main_softc_t *softc, caddr_t data)
522 {
523 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
524 iplookupop_t op;
525 ipf_lookup_t **l;
526 int err;
527 int i;
528
529 err = BCOPYIN(data, &op, sizeof(op));
530 if (err != 0) {
531 IPFERROR(50031);
532 return (EFAULT);
533 }
534
535 if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
536 (op.iplo_unit != IPLT_ALL)) {
537 IPFERROR(50032);
538 return (EINVAL);
539 }
540
541 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
542 if (op.iplo_type == (*l)->ipfl_type) {
543 err = (*(*l)->ipfl_stats_get)(softc,
544 softl->ipf_back[i],
545 &op);
546 break;
547 }
548 }
549
550 if (i == MAX_BACKENDS) {
551 IPFERROR(50033);
552 err = EINVAL;
553 }
554
555 return (err);
556 }
557
558
559 /* ------------------------------------------------------------------------ */
560 /* Function: ipf_lookup_flush */
561 /* Returns: int - 0 = success, else error */
562 /* Parameters: softc(I) - pointer to soft context main structure */
563 /* data(I) - pointer to data from ioctl call */
564 /* */
565 /* A flush is called when we want to flush all the nodes from a particular */
566 /* entry in the hash table/pool or want to remove all groups from those. */
567 /* ------------------------------------------------------------------------ */
568 static int
ipf_lookup_flush(ipf_main_softc_t * softc,caddr_t data)569 ipf_lookup_flush(ipf_main_softc_t *softc, caddr_t data)
570 {
571 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
572 int err, unit, num, type, i;
573 iplookupflush_t flush;
574 ipf_lookup_t **l;
575
576 err = BCOPYIN(data, &flush, sizeof(flush));
577 if (err != 0) {
578 IPFERROR(50034);
579 return (EFAULT);
580 }
581
582 unit = flush.iplf_unit;
583 if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) {
584 IPFERROR(50035);
585 return (EINVAL);
586 }
587
588 flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
589
590 type = flush.iplf_type;
591 IPFERROR(50036);
592 err = EINVAL;
593 num = 0;
594
595 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
596 if (type == (*l)->ipfl_type || type == IPLT_ALL) {
597 err = 0;
598 num += (*(*l)->ipfl_flush)(softc,
599 softl->ipf_back[i],
600 &flush);
601 }
602 }
603
604 if (err == 0) {
605 flush.iplf_count = num;
606 err = BCOPYOUT(&flush, data, sizeof(flush));
607 if (err != 0) {
608 IPFERROR(50037);
609 err = EFAULT;
610 }
611 }
612 return (err);
613 }
614
615
616 /* ------------------------------------------------------------------------ */
617 /* Function: ipf_lookup_delref */
618 /* Returns: void */
619 /* Parameters: softc(I) - pointer to soft context main structure */
620 /* type(I) - table type to operate on */
621 /* ptr(I) - pointer to object to remove reference for */
622 /* */
623 /* This function organises calling the correct deref function for a given */
624 /* type of object being passed into it. */
625 /* ------------------------------------------------------------------------ */
626 void
ipf_lookup_deref(ipf_main_softc_t * softc,int type,void * ptr)627 ipf_lookup_deref(ipf_main_softc_t *softc, int type, void *ptr)
628 {
629 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
630 int i;
631
632 if (ptr == NULL)
633 return;
634
635 for (i = 0; i < MAX_BACKENDS; i++) {
636 if (type == backends[i]->ipfl_type) {
637 WRITE_ENTER(&softc->ipf_poolrw);
638 (*backends[i]->ipfl_table_deref)(softc,
639 softl->ipf_back[i],
640 ptr);
641 RWLOCK_EXIT(&softc->ipf_poolrw);
642 break;
643 }
644 }
645 }
646
647
648 /* ------------------------------------------------------------------------ */
649 /* Function: ipf_lookup_iterate */
650 /* Returns: int - 0 = success, else error */
651 /* Parameters: softc(I) - pointer to soft context main structure */
652 /* data(I) - pointer to data from ioctl call */
653 /* uid(I) - uid of caller */
654 /* ctx(I) - pointer to give the uid context */
655 /* */
656 /* Decodes ioctl request to step through either hash tables or pools. */
657 /* ------------------------------------------------------------------------ */
658 static int
ipf_lookup_iterate(ipf_main_softc_t * softc,void * data,int uid,void * ctx)659 ipf_lookup_iterate(ipf_main_softc_t *softc, void *data, int uid, void *ctx)
660 {
661 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
662 ipflookupiter_t iter;
663 ipftoken_t *token;
664 int err, i;
665 SPL_INT(s);
666
667 err = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_LOOKUPITER);
668 if (err != 0)
669 return (err);
670
671 if (iter.ili_unit < IPL_LOGALL && iter.ili_unit > IPL_LOGMAX) {
672 IPFERROR(50038);
673 return (EINVAL);
674 }
675
676 if (iter.ili_ival != IPFGENITER_LOOKUP) {
677 IPFERROR(50039);
678 return (EINVAL);
679 }
680
681 SPL_SCHED(s);
682 token = ipf_token_find(softc, iter.ili_key, uid, ctx);
683 if (token == NULL) {
684 SPL_X(s);
685 IPFERROR(50040);
686 return (ESRCH);
687 }
688
689 for (i = 0; i < MAX_BACKENDS; i++) {
690 if (iter.ili_type == backends[i]->ipfl_type) {
691 err = (*backends[i]->ipfl_iter_next)(softc,
692 softl->ipf_back[i],
693 token, &iter);
694 break;
695 }
696 }
697 SPL_X(s);
698
699 if (i == MAX_BACKENDS) {
700 IPFERROR(50041);
701 err = EINVAL;
702 }
703
704 WRITE_ENTER(&softc->ipf_tokens);
705 ipf_token_deref(softc, token);
706 RWLOCK_EXIT(&softc->ipf_tokens);
707
708 return (err);
709 }
710
711
712 /* ------------------------------------------------------------------------ */
713 /* Function: ipf_lookup_iterderef */
714 /* Returns: void */
715 /* Parameters: softc(I) - pointer to soft context main structure */
716 /* type(I) - backend type to iterate through */
717 /* data(I) - pointer to data from ioctl call */
718 /* */
719 /* Decodes ioctl request to remove a particular hash table or pool and */
720 /* calls the relevant function to do the cleanup. */
721 /* Because each of the backend types has a different data structure, */
722 /* iteration is limited to one type at a time (i.e. it is not permitted to */
723 /* go on from pool types to hash types as part of the "get next".) */
724 /* ------------------------------------------------------------------------ */
725 void
ipf_lookup_iterderef(ipf_main_softc_t * softc,u_32_t type,void * data)726 ipf_lookup_iterderef(ipf_main_softc_t *softc, u_32_t type, void *data)
727 {
728 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
729 struct iplookupiterkey *lkey;
730 iplookupiterkey_t key;
731 int i;
732
733 key.ilik_key = type;
734 lkey = &key.ilik_unstr;
735
736 if (lkey->ilik_ival != IPFGENITER_LOOKUP)
737 return;
738
739 WRITE_ENTER(&softc->ipf_poolrw);
740
741 for (i = 0; i < MAX_BACKENDS; i++) {
742 if (lkey->ilik_type == backends[i]->ipfl_type) {
743 (*backends[i]->ipfl_iter_deref)(softc,
744 softl->ipf_back[i],
745 lkey->ilik_otype,
746 lkey->ilik_unit,
747 data);
748 break;
749 }
750 }
751 RWLOCK_EXIT(&softc->ipf_poolrw);
752 }
753
754
755 /* ------------------------------------------------------------------------ */
756 /* Function: ipf_lookup_deltok */
757 /* Returns: int - 0 = success, else error */
758 /* Parameters: softc(I) - pointer to soft context main structure */
759 /* data(I) - pointer to data from ioctl call */
760 /* uid(I) - uid of caller */
761 /* ctx(I) - pointer to give the uid context */
762 /* */
763 /* Deletes the token identified by the combination of (type,uid,ctx) */
764 /* "key" is a combination of the table type, iterator type and the unit for */
765 /* which the token was being used. */
766 /* ------------------------------------------------------------------------ */
767 int
ipf_lookup_deltok(ipf_main_softc_t * softc,void * data,int uid,void * ctx)768 ipf_lookup_deltok(ipf_main_softc_t *softc, void *data, int uid, void *ctx)
769 {
770 int error, key;
771 SPL_INT(s);
772
773 SPL_SCHED(s);
774 error = BCOPYIN(data, &key, sizeof(key));
775 if (error == 0)
776 error = ipf_token_del(softc, key, uid, ctx);
777 SPL_X(s);
778 return (error);
779 }
780
781
782 /* ------------------------------------------------------------------------ */
783 /* Function: ipf_lookup_res_num */
784 /* Returns: void * - NULL = failure, else success. */
785 /* Parameters: softc(I) - pointer to soft context main structure */
786 /* unit(I) - device for which this is for */
787 /* type(I) - type of lookup these parameters are for. */
788 /* number(I) - table number to use when searching */
789 /* funcptr(IO) - pointer to pointer for storing IP address */
790 /* searching function. */
791 /* */
792 /* Search for the "table" number passed in amongst those configured for */
793 /* that particular type. If the type is recognised then the function to */
794 /* call to do the IP address search will be change, regardless of whether */
795 /* or not the "table" number exists. */
796 /* ------------------------------------------------------------------------ */
797 void *
ipf_lookup_res_num(ipf_main_softc_t * softc,int unit,u_int type,u_int number,lookupfunc_t * funcptr)798 ipf_lookup_res_num(ipf_main_softc_t *softc, int unit, u_int type, u_int number,
799 lookupfunc_t *funcptr)
800 {
801 char name[FR_GROUPLEN];
802
803 (void) snprintf(name, sizeof(name), "%u", number);
804
805 return (ipf_lookup_res_name(softc, unit, type, name, funcptr));
806 }
807
808
809 /* ------------------------------------------------------------------------ */
810 /* Function: ipf_lookup_res_name */
811 /* Returns: void * - NULL = failure, else success. */
812 /* Parameters: softc(I) - pointer to soft context main structure */
813 /* unit(I) - device for which this is for */
814 /* type(I) - type of lookup these parameters are for. */
815 /* name(I) - table name to use when searching */
816 /* funcptr(IO) - pointer to pointer for storing IP address */
817 /* searching function. */
818 /* */
819 /* Search for the "table" number passed in amongst those configured for */
820 /* that particular type. If the type is recognised then the function to */
821 /* call to do the IP address search will be changed, regardless of whether */
822 /* or not the "table" number exists. */
823 /* ------------------------------------------------------------------------ */
824 void *
ipf_lookup_res_name(ipf_main_softc_t * softc,int unit,u_int type,char * name,lookupfunc_t * funcptr)825 ipf_lookup_res_name(ipf_main_softc_t *softc, int unit, u_int type, char *name,
826 lookupfunc_t *funcptr)
827 {
828 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
829 ipf_lookup_t **l;
830 void *ptr = NULL;
831 int i;
832
833 READ_ENTER(&softc->ipf_poolrw);
834
835 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
836 if (type == (*l)->ipfl_type) {
837 ptr = (*(*l)->ipfl_select_add_ref)(softl->ipf_back[i],
838 unit, name);
839 if (ptr != NULL && funcptr != NULL) {
840 *funcptr = (*l)->ipfl_addr_find;
841 }
842 break;
843 }
844 }
845
846 if (i == MAX_BACKENDS) {
847 ptr = NULL;
848 if (funcptr != NULL)
849 *funcptr = NULL;
850 }
851
852 RWLOCK_EXIT(&softc->ipf_poolrw);
853
854 return (ptr);
855 }
856
857
858 /* ------------------------------------------------------------------------ */
859 /* Function: ipf_lookup_find_htable */
860 /* Returns: void * - NULL = failure, else success. */
861 /* Parameters: softc(I) - pointer to soft context main structure */
862 /* unit(I) - device for which this is for */
863 /* name(I) - table name to use when searching */
864 /* */
865 /* To support the group-map feature, where a hash table maps address */
866 /* networks to rule group numbers, we need to expose a function that uses */
867 /* only the hash table backend. */
868 /* ------------------------------------------------------------------------ */
869 void *
ipf_lookup_find_htable(ipf_main_softc_t * softc,int unit,char * name)870 ipf_lookup_find_htable(ipf_main_softc_t *softc, int unit, char *name)
871 {
872 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
873 ipf_lookup_t **l;
874 void *tab = NULL;
875 int i;
876
877 READ_ENTER(&softc->ipf_poolrw);
878
879 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
880 if (IPLT_HASH == (*l)->ipfl_type) {
881 tab = ipf_htable_find(softl->ipf_back[i], unit, name);
882 break;
883 }
884
885 RWLOCK_EXIT(&softc->ipf_poolrw);
886
887 return (tab);
888 }
889
890
891 /* ------------------------------------------------------------------------ */
892 /* Function: ipf_lookup_sync */
893 /* Returns: void */
894 /* Parameters: softc(I) - pointer to soft context main structure */
895 /* */
896 /* This function is the interface that the machine dependent sync functions */
897 /* call when a network interface name change occurs. It then calls the sync */
898 /* functions of the lookup implementations - if they have one. */
899 /* ------------------------------------------------------------------------ */
900 /*ARGSUSED*/
901 void
ipf_lookup_sync(ipf_main_softc_t * softc,void * ifp)902 ipf_lookup_sync(ipf_main_softc_t *softc, void *ifp)
903 {
904 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
905 ipf_lookup_t **l;
906 int i;
907
908 READ_ENTER(&softc->ipf_poolrw);
909
910 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
911 if ((*l)->ipfl_sync != NULL)
912 (*(*l)->ipfl_sync)(softc, softl->ipf_back[i]);
913
914 RWLOCK_EXIT(&softc->ipf_poolrw);
915 }
916
917
918 #ifndef _KERNEL
919 void
ipf_lookup_dump(ipf_main_softc_t * softc,void * arg)920 ipf_lookup_dump(ipf_main_softc_t *softc, void *arg)
921 {
922 ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
923 ipf_lookup_t **l;
924 int i;
925
926 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
927 if (IPLT_POOL == (*l)->ipfl_type) {
928 ipf_pool_dump(softc, softl->ipf_back[i]);
929 break;
930 }
931
932 for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
933 if (IPLT_HASH == (*l)->ipfl_type) {
934 ipf_htable_dump(softc, softl->ipf_back[i]);
935 break;
936 }
937 }
938 #endif
939