1145516Sdarrenr/* $FreeBSD$ */ 2145516Sdarrenr 3145516Sdarrenr/* 4255332Scy * Copyright (C) 2012 by Darren Reed. 5145516Sdarrenr * 6145516Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 7145516Sdarrenr */ 8145516Sdarrenr#if defined(KERNEL) || defined(_KERNEL) 9145516Sdarrenr# undef KERNEL 10145516Sdarrenr# undef _KERNEL 11145516Sdarrenr# define KERNEL 1 12145516Sdarrenr# define _KERNEL 1 13145516Sdarrenr#endif 14145516Sdarrenr#include <sys/param.h> 15145516Sdarrenr#include <sys/types.h> 16145516Sdarrenr#include <sys/errno.h> 17145516Sdarrenr#include <sys/time.h> 18145516Sdarrenr#include <sys/file.h> 19145516Sdarrenr#if !defined(_KERNEL) 20145516Sdarrenr# include <stdlib.h> 21145516Sdarrenr# include <string.h> 22145516Sdarrenr# define _KERNEL 23145516Sdarrenr# ifdef __OpenBSD__ 24145516Sdarrenrstruct file; 25145516Sdarrenr# endif 26145516Sdarrenr# include <sys/uio.h> 27145516Sdarrenr# undef _KERNEL 28145516Sdarrenr#endif 29145516Sdarrenr#include <sys/socket.h> 30145516Sdarrenr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 31145516Sdarrenr# include <sys/malloc.h> 32145516Sdarrenr#endif 33145516Sdarrenr#if defined(__FreeBSD__) 34145516Sdarrenr# include <sys/cdefs.h> 35145516Sdarrenr# include <sys/proc.h> 36145516Sdarrenr#endif 37145516Sdarrenr#if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \ 38145516Sdarrenr !defined(linux) 39145516Sdarrenr# include <sys/mbuf.h> 40145516Sdarrenr#endif 41145516Sdarrenr#if defined(_KERNEL) 42145516Sdarrenr# include <sys/systm.h> 43145516Sdarrenr#else 44255332Scy# include "ipf.h" 45145516Sdarrenr#endif 46145516Sdarrenr#include <netinet/in.h> 47145516Sdarrenr#include <net/if.h> 48145516Sdarrenr 49145516Sdarrenr#include "netinet/ip_compat.h" 50145516Sdarrenr#include "netinet/ip_fil.h" 51145516Sdarrenr#include "netinet/ip_lookup.h" 52145516Sdarrenr#include "netinet/ip_htable.h" 53145516Sdarrenr/* END OF INCLUDES */ 54145516Sdarrenr 55145516Sdarrenr#if !defined(lint) 56255332Scystatic const char rcsid[] = "@(#)$Id$"; 57145516Sdarrenr#endif 58145516Sdarrenr 59255332Scy# ifdef USE_INET6 60255332Scystatic iphtent_t *ipf_iphmfind6 __P((iphtable_t *, i6addr_t *)); 61255332Scy# endif 62255332Scystatic iphtent_t *ipf_iphmfind __P((iphtable_t *, struct in_addr *)); 63255332Scystatic int ipf_iphmfindip __P((ipf_main_softc_t *, void *, int, void *, u_int)); 64255332Scystatic int ipf_htable_clear __P((ipf_main_softc_t *, void *, iphtable_t *)); 65255332Scystatic int ipf_htable_create __P((ipf_main_softc_t *, void *, iplookupop_t *)); 66255332Scystatic int ipf_htable_deref __P((ipf_main_softc_t *, void *, void *)); 67255332Scystatic int ipf_htable_destroy __P((ipf_main_softc_t *, void *, int, char *)); 68255332Scystatic void *ipf_htable_exists __P((void *, int, char *)); 69255332Scystatic size_t ipf_htable_flush __P((ipf_main_softc_t *, void *, 70255332Scy iplookupflush_t *)); 71255332Scystatic void ipf_htable_free __P((void *, iphtable_t *)); 72255332Scystatic int ipf_htable_iter_deref __P((ipf_main_softc_t *, void *, int, 73255332Scy int, void *)); 74255332Scystatic int ipf_htable_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *, 75255332Scy ipflookupiter_t *)); 76255332Scystatic int ipf_htable_node_add __P((ipf_main_softc_t *, void *, 77255332Scy iplookupop_t *, int)); 78255332Scystatic int ipf_htable_node_del __P((ipf_main_softc_t *, void *, 79255332Scy iplookupop_t *, int)); 80255332Scystatic int ipf_htable_remove __P((ipf_main_softc_t *, void *, iphtable_t *)); 81255332Scystatic void *ipf_htable_soft_create __P((ipf_main_softc_t *)); 82255332Scystatic void ipf_htable_soft_destroy __P((ipf_main_softc_t *, void *)); 83255332Scystatic int ipf_htable_soft_init __P((ipf_main_softc_t *, void *)); 84255332Scystatic void ipf_htable_soft_fini __P((ipf_main_softc_t *, void *)); 85255332Scystatic int ipf_htable_stats_get __P((ipf_main_softc_t *, void *, 86255332Scy iplookupop_t *)); 87255332Scystatic int ipf_htable_table_add __P((ipf_main_softc_t *, void *, 88255332Scy iplookupop_t *)); 89255332Scystatic int ipf_htable_table_del __P((ipf_main_softc_t *, void *, 90255332Scy iplookupop_t *)); 91255332Scystatic int ipf_htent_deref __P((void *, iphtent_t *)); 92255332Scystatic iphtent_t *ipf_htent_find __P((iphtable_t *, iphtent_t *)); 93255332Scystatic int ipf_htent_insert __P((ipf_main_softc_t *, void *, iphtable_t *, 94255332Scy iphtent_t *)); 95255332Scystatic int ipf_htent_remove __P((ipf_main_softc_t *, void *, iphtable_t *, 96255332Scy iphtent_t *)); 97255332Scystatic void *ipf_htable_select_add_ref __P((void *, int, char *)); 98255332Scystatic void ipf_htable_expire __P((ipf_main_softc_t *, void *)); 99145516Sdarrenr 100145516Sdarrenr 101255332Scytypedef struct ipf_htable_softc_s { 102255332Scy u_long ipht_nomem[LOOKUP_POOL_SZ]; 103255332Scy u_long ipf_nhtables[LOOKUP_POOL_SZ]; 104255332Scy u_long ipf_nhtnodes[LOOKUP_POOL_SZ]; 105255332Scy iphtable_t *ipf_htables[LOOKUP_POOL_SZ]; 106255332Scy iphtent_t *ipf_node_explist; 107255332Scy} ipf_htable_softc_t; 108145516Sdarrenr 109255332Scyipf_lookup_t ipf_htable_backend = { 110255332Scy IPLT_HASH, 111255332Scy ipf_htable_soft_create, 112255332Scy ipf_htable_soft_destroy, 113255332Scy ipf_htable_soft_init, 114255332Scy ipf_htable_soft_fini, 115255332Scy ipf_iphmfindip, 116255332Scy ipf_htable_flush, 117255332Scy ipf_htable_iter_deref, 118255332Scy ipf_htable_iter_next, 119255332Scy ipf_htable_node_add, 120255332Scy ipf_htable_node_del, 121255332Scy ipf_htable_stats_get, 122255332Scy ipf_htable_table_add, 123255332Scy ipf_htable_table_del, 124255332Scy ipf_htable_deref, 125255332Scy ipf_htable_exists, 126255332Scy ipf_htable_select_add_ref, 127255332Scy NULL, 128255332Scy ipf_htable_expire, 129255332Scy NULL 130255332Scy}; 131255332Scy 132255332Scy 133255332Scy/* ------------------------------------------------------------------------ */ 134255332Scy/* Function: ipf_htable_soft_create */ 135255332Scy/* Returns: void * - NULL = failure, else pointer to local context */ 136255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 137255332Scy/* */ 138255332Scy/* Initialise the routing table data structures where required. */ 139255332Scy/* ------------------------------------------------------------------------ */ 140255332Scystatic void * 141255332Scyipf_htable_soft_create(softc) 142255332Scy ipf_main_softc_t *softc; 143145516Sdarrenr{ 144255332Scy ipf_htable_softc_t *softh; 145255332Scy 146255332Scy KMALLOC(softh, ipf_htable_softc_t *); 147255332Scy if (softh == NULL) { 148255332Scy IPFERROR(30026); 149255332Scy return NULL; 150255332Scy } 151255332Scy 152255332Scy bzero((char *)softh, sizeof(*softh)); 153255332Scy 154255332Scy return softh; 155255332Scy} 156255332Scy 157255332Scy 158255332Scy/* ------------------------------------------------------------------------ */ 159255332Scy/* Function: ipf_htable_soft_destroy */ 160255332Scy/* Returns: Nil */ 161255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 162255332Scy/* arg(I) - pointer to local context to use */ 163255332Scy/* */ 164255332Scy/* Clean up the pool by free'ing the radix tree associated with it and free */ 165255332Scy/* up the pool context too. */ 166255332Scy/* ------------------------------------------------------------------------ */ 167255332Scystatic void 168255332Scyipf_htable_soft_destroy(softc, arg) 169255332Scy ipf_main_softc_t *softc; 170255332Scy void *arg; 171255332Scy{ 172255332Scy ipf_htable_softc_t *softh = arg; 173255332Scy 174255332Scy KFREE(softh); 175255332Scy} 176255332Scy 177255332Scy 178255332Scy/* ------------------------------------------------------------------------ */ 179255332Scy/* Function: ipf_htable_soft_init */ 180255332Scy/* Returns: int - 0 = success, else error */ 181255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 182255332Scy/* arg(I) - pointer to local context to use */ 183255332Scy/* */ 184255332Scy/* Initialise the hash table ready for use. */ 185255332Scy/* ------------------------------------------------------------------------ */ 186255332Scystatic int 187255332Scyipf_htable_soft_init(softc, arg) 188255332Scy ipf_main_softc_t *softc; 189255332Scy void *arg; 190255332Scy{ 191255332Scy ipf_htable_softc_t *softh = arg; 192255332Scy 193255332Scy bzero((char *)softh, sizeof(*softh)); 194255332Scy 195255332Scy return 0; 196255332Scy} 197255332Scy 198255332Scy 199255332Scy/* ------------------------------------------------------------------------ */ 200255332Scy/* Function: ipf_htable_soft_fini */ 201255332Scy/* Returns: Nil */ 202255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 203255332Scy/* arg(I) - pointer to local context to use */ 204255332Scy/* Locks: WRITE(ipf_global) */ 205255332Scy/* */ 206255332Scy/* Clean up all the pool data structures allocated and call the cleanup */ 207255332Scy/* function for the radix tree that supports the pools. ipf_pool_destroy is */ 208255332Scy/* used to delete the pools one by one to ensure they're properly freed up. */ 209255332Scy/* ------------------------------------------------------------------------ */ 210255332Scystatic void 211255332Scyipf_htable_soft_fini(softc, arg) 212255332Scy ipf_main_softc_t *softc; 213255332Scy void *arg; 214255332Scy{ 215145516Sdarrenr iplookupflush_t fop; 216145516Sdarrenr 217255332Scy fop.iplf_type = IPLT_HASH; 218145516Sdarrenr fop.iplf_unit = IPL_LOGALL; 219255332Scy fop.iplf_arg = 0; 220255332Scy fop.iplf_count = 0; 221255332Scy *fop.iplf_name = '\0'; 222255332Scy ipf_htable_flush(softc, arg, &fop); 223145516Sdarrenr} 224145516Sdarrenr 225145516Sdarrenr 226255332Scy/* ------------------------------------------------------------------------ */ 227255332Scy/* Function: ipf_htable_stats_get */ 228255332Scy/* Returns: int - 0 = success, else error */ 229255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 230255332Scy/* arg(I) - pointer to local context to use */ 231255332Scy/* op(I) - pointer to lookup operation data */ 232255332Scy/* */ 233255332Scy/* Copy the relevant statistics out of internal structures and into the */ 234255332Scy/* structure used to export statistics. */ 235255332Scy/* ------------------------------------------------------------------------ */ 236255332Scystatic int 237255332Scyipf_htable_stats_get(softc, arg, op) 238255332Scy ipf_main_softc_t *softc; 239255332Scy void *arg; 240255332Scy iplookupop_t *op; 241145516Sdarrenr{ 242255332Scy ipf_htable_softc_t *softh = arg; 243145516Sdarrenr iphtstat_t stats; 244255332Scy int err; 245145516Sdarrenr 246255332Scy if (op->iplo_size != sizeof(stats)) { 247255332Scy IPFERROR(30001); 248145516Sdarrenr return EINVAL; 249255332Scy } 250145516Sdarrenr 251255332Scy stats.iphs_tables = softh->ipf_htables[op->iplo_unit + 1]; 252255332Scy stats.iphs_numtables = softh->ipf_nhtables[op->iplo_unit + 1]; 253255332Scy stats.iphs_numnodes = softh->ipf_nhtnodes[op->iplo_unit + 1]; 254255332Scy stats.iphs_nomem = softh->ipht_nomem[op->iplo_unit + 1]; 255145516Sdarrenr 256255332Scy err = COPYOUT(&stats, op->iplo_struct, sizeof(stats)); 257255332Scy if (err != 0) { 258255332Scy IPFERROR(30013); 259255332Scy return EFAULT; 260255332Scy } 261255332Scy return 0; 262145516Sdarrenr 263145516Sdarrenr} 264145516Sdarrenr 265145516Sdarrenr 266255332Scy/* ------------------------------------------------------------------------ */ 267255332Scy/* Function: ipf_htable_create */ 268255332Scy/* Returns: int - 0 = success, else error */ 269255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 270255332Scy/* arg(I) - pointer to local context to use */ 271255332Scy/* op(I) - pointer to lookup operation data */ 272255332Scy/* */ 273255332Scy/* Create a new hash table using the template passed. */ 274255332Scy/* ------------------------------------------------------------------------ */ 275255332Scystatic int 276255332Scyipf_htable_create(softc, arg, op) 277255332Scy ipf_main_softc_t *softc; 278255332Scy void *arg; 279255332Scy iplookupop_t *op; 280145516Sdarrenr{ 281255332Scy ipf_htable_softc_t *softh = arg; 282255332Scy iphtable_t htab, *iph, *oiph; 283145516Sdarrenr char name[FR_GROUPLEN]; 284145516Sdarrenr int err, i, unit; 285145516Sdarrenr 286255332Scy if (op->iplo_size != sizeof(htab)) { 287255332Scy IPFERROR(30024); 288255332Scy return EINVAL; 289255332Scy } 290255332Scy err = COPYIN(op->iplo_struct, &htab, sizeof(htab)); 291255332Scy if (err != 0) { 292255332Scy IPFERROR(30003); 293255332Scy return EFAULT; 294255332Scy } 295255332Scy 296170268Sdarrenr unit = op->iplo_unit; 297255332Scy if (htab.iph_unit != unit) { 298255332Scy IPFERROR(30005); 299255332Scy return EINVAL; 300255332Scy } 301255332Scy if (htab.iph_size < 1) { 302255332Scy IPFERROR(30025); 303255332Scy return EINVAL; 304255332Scy } 305255332Scy 306255332Scy 307172776Sdarrenr if ((op->iplo_arg & IPHASH_ANON) == 0) { 308255332Scy iph = ipf_htable_exists(softh, unit, op->iplo_name); 309172776Sdarrenr if (iph != NULL) { 310255332Scy if ((iph->iph_flags & IPHASH_DELETE) == 0) { 311255332Scy IPFERROR(30004); 312172776Sdarrenr return EEXIST; 313255332Scy } 314172776Sdarrenr iph->iph_flags &= ~IPHASH_DELETE; 315255332Scy iph->iph_ref++; 316172776Sdarrenr return 0; 317172776Sdarrenr } 318172776Sdarrenr } 319170268Sdarrenr 320172776Sdarrenr KMALLOC(iph, iphtable_t *); 321147547Sdarrenr if (iph == NULL) { 322255332Scy softh->ipht_nomem[op->iplo_unit + 1]++; 323255332Scy IPFERROR(30002); 324172776Sdarrenr return ENOMEM; 325147547Sdarrenr } 326255332Scy *iph = htab; 327145516Sdarrenr 328170268Sdarrenr if ((op->iplo_arg & IPHASH_ANON) != 0) { 329145516Sdarrenr i = IPHASH_ANON; 330145516Sdarrenr do { 331145516Sdarrenr i++; 332145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL) 333145516Sdarrenr SNPRINTF(name, sizeof(name), "%u", i); 334145516Sdarrenr#else 335145516Sdarrenr (void)sprintf(name, "%u", i); 336145516Sdarrenr#endif 337255332Scy for (oiph = softh->ipf_htables[unit + 1]; oiph != NULL; 338145516Sdarrenr oiph = oiph->iph_next) 339145516Sdarrenr if (strncmp(oiph->iph_name, name, 340145516Sdarrenr sizeof(oiph->iph_name)) == 0) 341145516Sdarrenr break; 342145516Sdarrenr } while (oiph != NULL); 343153876Sguido 344145516Sdarrenr (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name)); 345153876Sguido (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name)); 346145516Sdarrenr iph->iph_type |= IPHASH_ANON; 347255332Scy } else { 348255332Scy (void)strncpy(iph->iph_name, op->iplo_name, 349255332Scy sizeof(iph->iph_name)); 350255332Scy iph->iph_name[sizeof(iph->iph_name) - 1] = '\0'; 351145516Sdarrenr } 352145516Sdarrenr 353172776Sdarrenr KMALLOCS(iph->iph_table, iphtent_t **, 354172776Sdarrenr iph->iph_size * sizeof(*iph->iph_table)); 355172776Sdarrenr if (iph->iph_table == NULL) { 356172776Sdarrenr KFREE(iph); 357255332Scy softh->ipht_nomem[unit + 1]++; 358255332Scy IPFERROR(30006); 359172776Sdarrenr return ENOMEM; 360172776Sdarrenr } 361145516Sdarrenr 362172776Sdarrenr bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); 363255332Scy iph->iph_maskset[0] = 0; 364255332Scy iph->iph_maskset[1] = 0; 365255332Scy iph->iph_maskset[2] = 0; 366255332Scy iph->iph_maskset[3] = 0; 367145516Sdarrenr 368172776Sdarrenr iph->iph_ref = 1; 369255332Scy iph->iph_list = NULL; 370255332Scy iph->iph_tail = &iph->iph_list; 371255332Scy iph->iph_next = softh->ipf_htables[unit + 1]; 372255332Scy iph->iph_pnext = &softh->ipf_htables[unit + 1]; 373255332Scy if (softh->ipf_htables[unit + 1] != NULL) 374255332Scy softh->ipf_htables[unit + 1]->iph_pnext = &iph->iph_next; 375255332Scy softh->ipf_htables[unit + 1] = iph; 376145516Sdarrenr 377255332Scy softh->ipf_nhtables[unit + 1]++; 378255332Scy 379145516Sdarrenr return 0; 380145516Sdarrenr} 381145516Sdarrenr 382145516Sdarrenr 383255332Scy/* ------------------------------------------------------------------------ */ 384255332Scy/* Function: ipf_htable_table_del */ 385255332Scy/* Returns: int - 0 = success, else error */ 386255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 387255332Scy/* arg(I) - pointer to local context to use */ 388255332Scy/* op(I) - pointer to lookup operation data */ 389255332Scy/* */ 390255332Scy/* ------------------------------------------------------------------------ */ 391255332Scystatic int 392255332Scyipf_htable_table_del(softc, arg, op) 393255332Scy ipf_main_softc_t *softc; 394255332Scy void *arg; 395255332Scy iplookupop_t *op; 396145516Sdarrenr{ 397255332Scy return ipf_htable_destroy(softc, arg, op->iplo_unit, op->iplo_name); 398255332Scy} 399255332Scy 400255332Scy 401255332Scy/* ------------------------------------------------------------------------ */ 402255332Scy/* Function: ipf_htable_destroy */ 403255332Scy/* Returns: int - 0 = success, else error */ 404255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 405255332Scy/* arg(I) - pointer to local context to use */ 406255332Scy/* op(I) - pointer to lookup operation data */ 407255332Scy/* */ 408255332Scy/* Find the hash table that belongs to the relevant part of ipfilter with a */ 409255332Scy/* matching name and attempt to destroy it. If it is in use, empty it out */ 410255332Scy/* and mark it for deletion so that when all the references disappear, it */ 411255332Scy/* can be removed. */ 412255332Scy/* ------------------------------------------------------------------------ */ 413255332Scystatic int 414255332Scyipf_htable_destroy(softc, arg, unit, name) 415255332Scy ipf_main_softc_t *softc; 416255332Scy void *arg; 417255332Scy int unit; 418255332Scy char *name; 419255332Scy{ 420145516Sdarrenr iphtable_t *iph; 421145516Sdarrenr 422255332Scy iph = ipf_htable_find(arg, unit, name); 423255332Scy if (iph == NULL) { 424255332Scy IPFERROR(30007); 425145516Sdarrenr return ESRCH; 426255332Scy } 427145516Sdarrenr 428170268Sdarrenr if (iph->iph_unit != unit) { 429255332Scy IPFERROR(30008); 430145516Sdarrenr return EINVAL; 431145516Sdarrenr } 432145516Sdarrenr 433145516Sdarrenr if (iph->iph_ref != 0) { 434255332Scy ipf_htable_clear(softc, arg, iph); 435170268Sdarrenr iph->iph_flags |= IPHASH_DELETE; 436170268Sdarrenr return 0; 437145516Sdarrenr } 438145516Sdarrenr 439255332Scy ipf_htable_remove(softc, arg, iph); 440145516Sdarrenr 441145516Sdarrenr return 0; 442145516Sdarrenr} 443145516Sdarrenr 444145516Sdarrenr 445255332Scy/* ------------------------------------------------------------------------ */ 446255332Scy/* Function: ipf_htable_clear */ 447255332Scy/* Returns: int - 0 = success, else error */ 448255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 449255332Scy/* arg(I) - pointer to local context to use */ 450255332Scy/* iph(I) - pointer to hash table to destroy */ 451255332Scy/* */ 452255332Scy/* Clean out the hash table by walking the list of entries and removing */ 453255332Scy/* each one, one by one. */ 454255332Scy/* ------------------------------------------------------------------------ */ 455255332Scystatic int 456255332Scyipf_htable_clear(softc, arg, iph) 457255332Scy ipf_main_softc_t *softc; 458255332Scy void *arg; 459255332Scy iphtable_t *iph; 460145516Sdarrenr{ 461145516Sdarrenr iphtent_t *ipe; 462145516Sdarrenr 463170268Sdarrenr while ((ipe = iph->iph_list) != NULL) 464255332Scy if (ipf_htent_remove(softc, arg, iph, ipe) != 0) 465170268Sdarrenr return 1; 466170268Sdarrenr return 0; 467170268Sdarrenr} 468145516Sdarrenr 469170268Sdarrenr 470255332Scy/* ------------------------------------------------------------------------ */ 471255332Scy/* Function: ipf_htable_free */ 472255332Scy/* Returns: Nil */ 473255332Scy/* Parameters: arg(I) - pointer to local context to use */ 474255332Scy/* iph(I) - pointer to hash table to destroy */ 475255332Scy/* */ 476255332Scy/* ------------------------------------------------------------------------ */ 477255332Scystatic void 478255332Scyipf_htable_free(arg, iph) 479255332Scy void *arg; 480255332Scy iphtable_t *iph; 481170268Sdarrenr{ 482255332Scy ipf_htable_softc_t *softh = arg; 483170268Sdarrenr 484255332Scy if (iph->iph_next != NULL) 485255332Scy iph->iph_next->iph_pnext = iph->iph_pnext; 486255332Scy if (iph->iph_pnext != NULL) 487255332Scy *iph->iph_pnext = iph->iph_next; 488255332Scy iph->iph_pnext = NULL; 489255332Scy iph->iph_next = NULL; 490255332Scy 491255332Scy softh->ipf_nhtables[iph->iph_unit + 1]--; 492255332Scy 493255332Scy KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); 494255332Scy KFREE(iph); 495255332Scy} 496255332Scy 497255332Scy 498255332Scy/* ------------------------------------------------------------------------ */ 499255332Scy/* Function: ipf_htable_remove */ 500255332Scy/* Returns: int - 0 = success, else error */ 501255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 502255332Scy/* arg(I) - pointer to local context to use */ 503255332Scy/* iph(I) - pointer to hash table to destroy */ 504255332Scy/* */ 505255332Scy/* It is necessary to unlink here as well as free (called by deref) so that */ 506255332Scy/* the while loop in ipf_htable_flush() functions properly. */ 507255332Scy/* ------------------------------------------------------------------------ */ 508255332Scystatic int 509255332Scyipf_htable_remove(softc, arg, iph) 510255332Scy ipf_main_softc_t *softc; 511255332Scy void *arg; 512255332Scy iphtable_t *iph; 513255332Scy{ 514255332Scy 515255332Scy if (ipf_htable_clear(softc, arg, iph) != 0) 516170268Sdarrenr return 1; 517170268Sdarrenr 518170268Sdarrenr if (iph->iph_pnext != NULL) 519170268Sdarrenr *iph->iph_pnext = iph->iph_next; 520145516Sdarrenr if (iph->iph_next != NULL) 521145516Sdarrenr iph->iph_next->iph_pnext = iph->iph_pnext; 522255332Scy iph->iph_pnext = NULL; 523255332Scy iph->iph_next = NULL; 524145516Sdarrenr 525255332Scy return ipf_htable_deref(softc, arg, iph); 526255332Scy} 527145516Sdarrenr 528255332Scy 529255332Scy/* ------------------------------------------------------------------------ */ 530255332Scy/* Function: ipf_htable_node_del */ 531255332Scy/* Returns: int - 0 = success, else error */ 532255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 533255332Scy/* arg(I) - pointer to local context to use */ 534255332Scy/* op(I) - pointer to lookup operation data */ 535255332Scy/* uid(I) - real uid of process doing operation */ 536255332Scy/* */ 537255332Scy/* ------------------------------------------------------------------------ */ 538255332Scystatic int 539255332Scyipf_htable_node_del(softc, arg, op, uid) 540255332Scy ipf_main_softc_t *softc; 541255332Scy void *arg; 542255332Scy iplookupop_t *op; 543255332Scy int uid; 544255332Scy{ 545255332Scy iphtable_t *iph; 546255332Scy iphtent_t hte, *ent; 547255332Scy int err; 548255332Scy 549255332Scy if (op->iplo_size != sizeof(hte)) { 550255332Scy IPFERROR(30014); 551255332Scy return EINVAL; 552255332Scy } 553255332Scy 554255332Scy err = COPYIN(op->iplo_struct, &hte, sizeof(hte)); 555255332Scy if (err != 0) { 556255332Scy IPFERROR(30015); 557255332Scy return EFAULT; 558255332Scy } 559255332Scy 560255332Scy iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name); 561255332Scy if (iph == NULL) { 562255332Scy IPFERROR(30016); 563255332Scy return ESRCH; 564255332Scy } 565255332Scy 566255332Scy ent = ipf_htent_find(iph, &hte); 567255332Scy if (ent == NULL) { 568255332Scy IPFERROR(30022); 569255332Scy return ESRCH; 570255332Scy } 571255332Scy 572255332Scy if ((uid != 0) && (ent->ipe_uid != uid)) { 573255332Scy IPFERROR(30023); 574255332Scy return EACCES; 575255332Scy } 576255332Scy 577255332Scy err = ipf_htent_remove(softc, arg, iph, ent); 578255332Scy 579255332Scy return err; 580170268Sdarrenr} 581170268Sdarrenr 582170268Sdarrenr 583255332Scy/* ------------------------------------------------------------------------ */ 584255332Scy/* Function: ipf_htable_node_del */ 585255332Scy/* Returns: int - 0 = success, else error */ 586255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 587255332Scy/* arg(I) - pointer to local context to use */ 588255332Scy/* op(I) - pointer to lookup operation data */ 589255332Scy/* */ 590255332Scy/* ------------------------------------------------------------------------ */ 591255332Scystatic int 592255332Scyipf_htable_table_add(softc, arg, op) 593255332Scy ipf_main_softc_t *softc; 594255332Scy void *arg; 595255332Scy iplookupop_t *op; 596170268Sdarrenr{ 597255332Scy int err; 598170268Sdarrenr 599255332Scy if (ipf_htable_find(arg, op->iplo_unit, op->iplo_name) != NULL) { 600255332Scy IPFERROR(30017); 601255332Scy err = EEXIST; 602255332Scy } else { 603255332Scy err = ipf_htable_create(softc, arg, op); 604255332Scy } 605255332Scy 606255332Scy return err; 607255332Scy} 608255332Scy 609255332Scy 610255332Scy/* ------------------------------------------------------------------------ */ 611255332Scy/* Function: ipf_htent_remove */ 612255332Scy/* Returns: int - 0 = success, else error */ 613255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 614255332Scy/* arg(I) - pointer to local context to use */ 615255332Scy/* iph(I) - pointer to hash table */ 616255332Scy/* ipe(I) - pointer to hash table entry to remove */ 617255332Scy/* */ 618255332Scy/* Delete an entry from a hash table. */ 619255332Scy/* ------------------------------------------------------------------------ */ 620255332Scystatic int 621255332Scyipf_htent_remove(softc, arg, iph, ipe) 622255332Scy ipf_main_softc_t *softc; 623255332Scy void *arg; 624255332Scy iphtable_t *iph; 625255332Scy iphtent_t *ipe; 626255332Scy{ 627255332Scy 628255332Scy if (iph->iph_tail == &ipe->ipe_next) 629255332Scy iph->iph_tail = ipe->ipe_pnext; 630255332Scy 631255332Scy if (ipe->ipe_hnext != NULL) 632255332Scy ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext; 633170268Sdarrenr if (ipe->ipe_phnext != NULL) 634170268Sdarrenr *ipe->ipe_phnext = ipe->ipe_hnext; 635255332Scy ipe->ipe_phnext = NULL; 636255332Scy ipe->ipe_hnext = NULL; 637170268Sdarrenr 638255332Scy if (ipe->ipe_dnext != NULL) 639255332Scy ipe->ipe_dnext->ipe_pdnext = ipe->ipe_pdnext; 640255332Scy if (ipe->ipe_pdnext != NULL) 641255332Scy *ipe->ipe_pdnext = ipe->ipe_dnext; 642255332Scy ipe->ipe_pdnext = NULL; 643255332Scy ipe->ipe_dnext = NULL; 644255332Scy 645255332Scy if (ipe->ipe_next != NULL) 646255332Scy ipe->ipe_next->ipe_pnext = ipe->ipe_pnext; 647170268Sdarrenr if (ipe->ipe_pnext != NULL) 648170268Sdarrenr *ipe->ipe_pnext = ipe->ipe_next; 649255332Scy ipe->ipe_pnext = NULL; 650255332Scy ipe->ipe_next = NULL; 651170268Sdarrenr 652170268Sdarrenr switch (iph->iph_type & ~IPHASH_ANON) 653170268Sdarrenr { 654170268Sdarrenr case IPHASH_GROUPMAP : 655170268Sdarrenr if (ipe->ipe_group != NULL) 656255332Scy ipf_group_del(softc, ipe->ipe_ptr, NULL); 657170268Sdarrenr break; 658170268Sdarrenr 659170268Sdarrenr default : 660170268Sdarrenr ipe->ipe_ptr = NULL; 661170268Sdarrenr ipe->ipe_value = 0; 662170268Sdarrenr break; 663170268Sdarrenr } 664170268Sdarrenr 665255332Scy return ipf_htent_deref(arg, ipe); 666170268Sdarrenr} 667170268Sdarrenr 668170268Sdarrenr 669255332Scy/* ------------------------------------------------------------------------ */ 670255332Scy/* Function: ipf_htable_deref */ 671255332Scy/* Returns: int - 0 = success, else error */ 672255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 673255332Scy/* arg(I) - pointer to local context to use */ 674255332Scy/* object(I) - pointer to hash table */ 675255332Scy/* */ 676255332Scy/* ------------------------------------------------------------------------ */ 677255332Scystatic int 678255332Scyipf_htable_deref(softc, arg, object) 679255332Scy ipf_main_softc_t *softc; 680255332Scy void *arg, *object; 681170268Sdarrenr{ 682255332Scy ipf_htable_softc_t *softh = arg; 683255332Scy iphtable_t *iph = object; 684170268Sdarrenr int refs; 685170268Sdarrenr 686170268Sdarrenr iph->iph_ref--; 687170268Sdarrenr refs = iph->iph_ref; 688170268Sdarrenr 689145516Sdarrenr if (iph->iph_ref == 0) { 690255332Scy ipf_htable_free(softh, iph); 691145516Sdarrenr } 692170268Sdarrenr 693170268Sdarrenr return refs; 694145516Sdarrenr} 695145516Sdarrenr 696145516Sdarrenr 697255332Scy/* ------------------------------------------------------------------------ */ 698255332Scy/* Function: ipf_htent_deref */ 699255332Scy/* Parameters: arg(I) - pointer to local context to use */ 700255332Scy/* ipe(I) - */ 701255332Scy/* */ 702255332Scy/* ------------------------------------------------------------------------ */ 703255332Scystatic int 704255332Scyipf_htent_deref(arg, ipe) 705255332Scy void *arg; 706255332Scy iphtent_t *ipe; 707145516Sdarrenr{ 708255332Scy ipf_htable_softc_t *softh = arg; 709170268Sdarrenr 710170268Sdarrenr ipe->ipe_ref--; 711170268Sdarrenr if (ipe->ipe_ref == 0) { 712255332Scy softh->ipf_nhtnodes[ipe->ipe_unit + 1]--; 713170268Sdarrenr KFREE(ipe); 714170268Sdarrenr 715170268Sdarrenr return 0; 716170268Sdarrenr } 717170268Sdarrenr 718170268Sdarrenr return ipe->ipe_ref; 719145516Sdarrenr} 720145516Sdarrenr 721145516Sdarrenr 722255332Scy/* ------------------------------------------------------------------------ */ 723255332Scy/* Function: ipf_htable_exists */ 724255332Scy/* Parameters: arg(I) - pointer to local context to use */ 725255332Scy/* */ 726255332Scy/* ------------------------------------------------------------------------ */ 727255332Scystatic void * 728255332Scyipf_htable_exists(arg, unit, name) 729255332Scy void *arg; 730255332Scy int unit; 731255332Scy char *name; 732145516Sdarrenr{ 733255332Scy ipf_htable_softc_t *softh = arg; 734145516Sdarrenr iphtable_t *iph; 735145516Sdarrenr 736255332Scy if (unit == IPL_LOGALL) { 737255332Scy int i; 738255332Scy 739255332Scy for (i = 0; i <= LOOKUP_POOL_MAX; i++) { 740255332Scy for (iph = softh->ipf_htables[i]; iph != NULL; 741255332Scy iph = iph->iph_next) { 742255332Scy if (strncmp(iph->iph_name, name, 743255332Scy sizeof(iph->iph_name)) == 0) 744255332Scy break; 745255332Scy } 746255332Scy if (iph != NULL) 747255332Scy break; 748255332Scy } 749255332Scy } else { 750255332Scy for (iph = softh->ipf_htables[unit + 1]; iph != NULL; 751255332Scy iph = iph->iph_next) { 752255332Scy if (strncmp(iph->iph_name, name, 753255332Scy sizeof(iph->iph_name)) == 0) 754255332Scy break; 755255332Scy } 756255332Scy } 757145516Sdarrenr return iph; 758145516Sdarrenr} 759145516Sdarrenr 760145516Sdarrenr 761255332Scy/* ------------------------------------------------------------------------ */ 762255332Scy/* Function: ipf_htable_select_add_ref */ 763255332Scy/* Returns: void * - NULL = failure, else pointer to the hash table */ 764255332Scy/* Parameters: arg(I) - pointer to local context to use */ 765255332Scy/* unit(I) - ipfilter device to which we are working on */ 766255332Scy/* name(I) - name of the hash table */ 767255332Scy/* */ 768255332Scy/* ------------------------------------------------------------------------ */ 769255332Scystatic void * 770255332Scyipf_htable_select_add_ref(arg, unit, name) 771255332Scy void *arg; 772255332Scy int unit; 773255332Scy char *name; 774170268Sdarrenr{ 775170268Sdarrenr iphtable_t *iph; 776170268Sdarrenr 777255332Scy iph = ipf_htable_exists(arg, unit, name); 778255332Scy if (iph != NULL) { 779255332Scy ATOMIC_INC32(iph->iph_ref); 780255332Scy } 781255332Scy return iph; 782255332Scy} 783255332Scy 784255332Scy 785255332Scy/* ------------------------------------------------------------------------ */ 786255332Scy/* Function: ipf_htable_find */ 787255332Scy/* Returns: void * - NULL = failure, else pointer to the hash table */ 788255332Scy/* Parameters: arg(I) - pointer to local context to use */ 789255332Scy/* unit(I) - ipfilter device to which we are working on */ 790255332Scy/* name(I) - name of the hash table */ 791255332Scy/* */ 792255332Scy/* This function is exposed becaues it is used in the group-map feature. */ 793255332Scy/* ------------------------------------------------------------------------ */ 794255332Scyiphtable_t * 795255332Scyipf_htable_find(arg, unit, name) 796255332Scy void *arg; 797255332Scy int unit; 798255332Scy char *name; 799255332Scy{ 800255332Scy iphtable_t *iph; 801255332Scy 802255332Scy iph = ipf_htable_exists(arg, unit, name); 803170268Sdarrenr if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0) 804170268Sdarrenr return iph; 805170268Sdarrenr 806170268Sdarrenr return NULL; 807170268Sdarrenr} 808170268Sdarrenr 809170268Sdarrenr 810255332Scy/* ------------------------------------------------------------------------ */ 811255332Scy/* Function: ipf_htable_flush */ 812255332Scy/* Returns: size_t - number of entries flushed */ 813255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 814255332Scy/* arg(I) - pointer to local context to use */ 815255332Scy/* op(I) - pointer to lookup operation data */ 816255332Scy/* */ 817255332Scy/* ------------------------------------------------------------------------ */ 818255332Scystatic size_t 819255332Scyipf_htable_flush(softc, arg, op) 820255332Scy ipf_main_softc_t *softc; 821255332Scy void *arg; 822255332Scy iplookupflush_t *op; 823145516Sdarrenr{ 824255332Scy ipf_htable_softc_t *softh = arg; 825145516Sdarrenr iphtable_t *iph; 826145516Sdarrenr size_t freed; 827145516Sdarrenr int i; 828145516Sdarrenr 829145516Sdarrenr freed = 0; 830145516Sdarrenr 831255332Scy for (i = -1; i <= IPL_LOGMAX; i++) { 832145516Sdarrenr if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) { 833255332Scy while ((iph = softh->ipf_htables[i + 1]) != NULL) { 834255332Scy if (ipf_htable_remove(softc, arg, iph) == 0) { 835170268Sdarrenr freed++; 836170268Sdarrenr } else { 837170268Sdarrenr iph->iph_flags |= IPHASH_DELETE; 838170268Sdarrenr } 839145516Sdarrenr } 840145516Sdarrenr } 841145516Sdarrenr } 842145516Sdarrenr 843145516Sdarrenr return freed; 844145516Sdarrenr} 845145516Sdarrenr 846145516Sdarrenr 847255332Scy/* ------------------------------------------------------------------------ */ 848255332Scy/* Function: ipf_htable_node_add */ 849255332Scy/* Returns: int - 0 = success, else error */ 850255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 851255332Scy/* arg(I) - pointer to local context to use */ 852255332Scy/* op(I) - pointer to lookup operation data */ 853255332Scy/* uid(I) - real uid of process doing operation */ 854255332Scy/* */ 855255332Scy/* ------------------------------------------------------------------------ */ 856255332Scystatic int 857255332Scyipf_htable_node_add(softc, arg, op, uid) 858255332Scy ipf_main_softc_t *softc; 859255332Scy void *arg; 860255332Scy iplookupop_t *op; 861255332Scy int uid; 862145516Sdarrenr{ 863255332Scy iphtable_t *iph; 864255332Scy iphtent_t hte; 865255332Scy int err; 866255332Scy 867255332Scy if (op->iplo_size != sizeof(hte)) { 868255332Scy IPFERROR(30018); 869255332Scy return EINVAL; 870255332Scy } 871255332Scy 872255332Scy err = COPYIN(op->iplo_struct, &hte, sizeof(hte)); 873255332Scy if (err != 0) { 874255332Scy IPFERROR(30019); 875255332Scy return EFAULT; 876255332Scy } 877255332Scy hte.ipe_uid = uid; 878255332Scy 879255332Scy iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name); 880255332Scy if (iph == NULL) { 881255332Scy IPFERROR(30020); 882255332Scy return ESRCH; 883255332Scy } 884255332Scy 885255332Scy if (ipf_htent_find(iph, &hte) != NULL) { 886255332Scy IPFERROR(30021); 887255332Scy return EEXIST; 888255332Scy } 889255332Scy 890255332Scy err = ipf_htent_insert(softc, arg, iph, &hte); 891255332Scy 892255332Scy return err; 893255332Scy} 894255332Scy 895255332Scy 896255332Scy/* ------------------------------------------------------------------------ */ 897255332Scy/* Function: ipf_htent_insert */ 898255332Scy/* Returns: int - 0 = success, -1 = error */ 899255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 900255332Scy/* arg(I) - pointer to local context to use */ 901255332Scy/* op(I) - pointer to lookup operation data */ 902255332Scy/* ipeo(I) - */ 903255332Scy/* */ 904255332Scy/* Add an entry to a hash table. */ 905255332Scy/* ------------------------------------------------------------------------ */ 906255332Scystatic int 907255332Scyipf_htent_insert(softc, arg, iph, ipeo) 908255332Scy ipf_main_softc_t *softc; 909255332Scy void *arg; 910255332Scy iphtable_t *iph; 911255332Scy iphtent_t *ipeo; 912255332Scy{ 913255332Scy ipf_htable_softc_t *softh = arg; 914145516Sdarrenr iphtent_t *ipe; 915145516Sdarrenr u_int hv; 916145516Sdarrenr int bits; 917145516Sdarrenr 918145516Sdarrenr KMALLOC(ipe, iphtent_t *); 919145516Sdarrenr if (ipe == NULL) 920145516Sdarrenr return -1; 921145516Sdarrenr 922145516Sdarrenr bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe)); 923255332Scy ipe->ipe_addr.i6[0] &= ipe->ipe_mask.i6[0]; 924255332Scy if (ipe->ipe_family == AF_INET) { 925255332Scy bits = count4bits(ipe->ipe_mask.in4_addr); 926255332Scy ipe->ipe_addr.i6[1] = 0; 927255332Scy ipe->ipe_addr.i6[2] = 0; 928255332Scy ipe->ipe_addr.i6[3] = 0; 929255332Scy ipe->ipe_mask.i6[1] = 0; 930255332Scy ipe->ipe_mask.i6[2] = 0; 931255332Scy ipe->ipe_mask.i6[3] = 0; 932255332Scy hv = IPE_V4_HASH_FN(ipe->ipe_addr.in4_addr, 933255332Scy ipe->ipe_mask.in4_addr, iph->iph_size); 934255332Scy } else 935255332Scy#ifdef USE_INET6 936255332Scy if (ipe->ipe_family == AF_INET6) { 937255332Scy ipe->ipe_addr.i6[1] &= ipe->ipe_mask.i6[1]; 938255332Scy ipe->ipe_addr.i6[2] &= ipe->ipe_mask.i6[2]; 939255332Scy ipe->ipe_addr.i6[3] &= ipe->ipe_mask.i6[3]; 940145516Sdarrenr 941255332Scy bits = count6bits(ipe->ipe_mask.i6); 942255332Scy hv = IPE_V6_HASH_FN(ipe->ipe_addr.i6, 943255332Scy ipe->ipe_mask.i6, iph->iph_size); 944255332Scy } else 945255332Scy#endif 946255332Scy { 947255332Scy KFREE(ipe); 948255332Scy return -1; 949255332Scy } 950255332Scy 951255332Scy ipe->ipe_owner = iph; 952170268Sdarrenr ipe->ipe_ref = 1; 953170268Sdarrenr ipe->ipe_hnext = iph->iph_table[hv]; 954170268Sdarrenr ipe->ipe_phnext = iph->iph_table + hv; 955145516Sdarrenr 956145516Sdarrenr if (iph->iph_table[hv] != NULL) 957170268Sdarrenr iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext; 958145516Sdarrenr iph->iph_table[hv] = ipe; 959170268Sdarrenr 960255332Scy ipe->ipe_pnext = iph->iph_tail; 961255332Scy *iph->iph_tail = ipe; 962255332Scy iph->iph_tail = &ipe->ipe_next; 963255332Scy ipe->ipe_next = NULL; 964170268Sdarrenr 965255332Scy if (ipe->ipe_die != 0) { 966255332Scy /* 967255332Scy * If the new node has a given expiration time, insert it 968255332Scy * into the list of expiring nodes with the ones to be 969255332Scy * removed first added to the front of the list. The 970255332Scy * insertion is O(n) but it is kept sorted for quick scans 971255332Scy * at expiration interval checks. 972255332Scy */ 973255332Scy iphtent_t *n; 974145516Sdarrenr 975255332Scy ipe->ipe_die = softc->ipf_ticks + IPF_TTLVAL(ipe->ipe_die); 976255332Scy for (n = softh->ipf_node_explist; n != NULL; n = n->ipe_dnext) { 977255332Scy if (ipe->ipe_die < n->ipe_die) 978255332Scy break; 979255332Scy if (n->ipe_dnext == NULL) { 980255332Scy /* 981255332Scy * We've got to the last node and everything 982255332Scy * wanted to be expired before this new node, 983255332Scy * so we have to tack it on the end... 984255332Scy */ 985255332Scy n->ipe_dnext = ipe; 986255332Scy ipe->ipe_pdnext = &n->ipe_dnext; 987255332Scy n = NULL; 988255332Scy break; 989255332Scy } 990255332Scy } 991255332Scy 992255332Scy if (softh->ipf_node_explist == NULL) { 993255332Scy softh->ipf_node_explist = ipe; 994255332Scy ipe->ipe_pdnext = &softh->ipf_node_explist; 995255332Scy } else if (n != NULL) { 996255332Scy ipe->ipe_dnext = n; 997255332Scy ipe->ipe_pdnext = n->ipe_pdnext; 998255332Scy n->ipe_pdnext = &ipe->ipe_dnext; 999255332Scy } 1000255332Scy } 1001255332Scy 1002255332Scy if (ipe->ipe_family == AF_INET) { 1003255332Scy ipf_inet_mask_add(bits, &iph->iph_v4_masks); 1004255332Scy } 1005255332Scy#ifdef USE_INET6 1006255332Scy else if (ipe->ipe_family == AF_INET6) { 1007255332Scy ipf_inet6_mask_add(bits, &ipe->ipe_mask, &iph->iph_v6_masks); 1008255332Scy } 1009255332Scy#endif 1010255332Scy 1011145516Sdarrenr switch (iph->iph_type & ~IPHASH_ANON) 1012145516Sdarrenr { 1013145516Sdarrenr case IPHASH_GROUPMAP : 1014255332Scy ipe->ipe_ptr = ipf_group_add(softc, ipe->ipe_group, NULL, 1015145516Sdarrenr iph->iph_flags, IPL_LOGIPF, 1016255332Scy softc->ipf_active); 1017145516Sdarrenr break; 1018145516Sdarrenr 1019145516Sdarrenr default : 1020145516Sdarrenr ipe->ipe_ptr = NULL; 1021145516Sdarrenr ipe->ipe_value = 0; 1022145516Sdarrenr break; 1023145516Sdarrenr } 1024145516Sdarrenr 1025170268Sdarrenr ipe->ipe_unit = iph->iph_unit; 1026255332Scy softh->ipf_nhtnodes[ipe->ipe_unit + 1]++; 1027145516Sdarrenr 1028145516Sdarrenr return 0; 1029145516Sdarrenr} 1030145516Sdarrenr 1031145516Sdarrenr 1032255332Scy/* ------------------------------------------------------------------------ */ 1033255332Scy/* Function: ipf_htent_find */ 1034255332Scy/* Returns: int - 0 = success, else error */ 1035255332Scy/* Parameters: iph(I) - pointer to table to search */ 1036255332Scy/* ipeo(I) - pointer to entry to find */ 1037255332Scy/* */ 1038255332Scy/* While it isn't absolutely necessary to for the address and mask to be */ 1039255332Scy/* passed in through an iphtent_t structure, one is always present when it */ 1040255332Scy/* is time to call this function, so it is just more convenient. */ 1041255332Scy/* ------------------------------------------------------------------------ */ 1042255332Scystatic iphtent_t * 1043255332Scyipf_htent_find(iph, ipeo) 1044255332Scy iphtable_t *iph; 1045255332Scy iphtent_t *ipeo; 1046145516Sdarrenr{ 1047255332Scy iphtent_t ipe, *ent; 1048255332Scy u_int hv; 1049255332Scy int bits; 1050255332Scy 1051255332Scy bcopy((char *)ipeo, (char *)&ipe, sizeof(ipe)); 1052255332Scy ipe.ipe_addr.i6[0] &= ipe.ipe_mask.i6[0]; 1053255332Scy ipe.ipe_addr.i6[1] &= ipe.ipe_mask.i6[1]; 1054255332Scy ipe.ipe_addr.i6[2] &= ipe.ipe_mask.i6[2]; 1055255332Scy ipe.ipe_addr.i6[3] &= ipe.ipe_mask.i6[3]; 1056255332Scy if (ipe.ipe_family == AF_INET) { 1057255332Scy bits = count4bits(ipe.ipe_mask.in4_addr); 1058255332Scy ipe.ipe_addr.i6[1] = 0; 1059255332Scy ipe.ipe_addr.i6[2] = 0; 1060255332Scy ipe.ipe_addr.i6[3] = 0; 1061255332Scy ipe.ipe_mask.i6[1] = 0; 1062255332Scy ipe.ipe_mask.i6[2] = 0; 1063255332Scy ipe.ipe_mask.i6[3] = 0; 1064255332Scy hv = IPE_V4_HASH_FN(ipe.ipe_addr.in4_addr, 1065255332Scy ipe.ipe_mask.in4_addr, iph->iph_size); 1066255332Scy } else 1067255332Scy#ifdef USE_INET6 1068255332Scy if (ipe.ipe_family == AF_INET6) { 1069255332Scy bits = count6bits(ipe.ipe_mask.i6); 1070255332Scy hv = IPE_V6_HASH_FN(ipe.ipe_addr.i6, 1071255332Scy ipe.ipe_mask.i6, iph->iph_size); 1072255332Scy } else 1073255332Scy#endif 1074255332Scy return NULL; 1075255332Scy 1076255332Scy for (ent = iph->iph_table[hv]; ent != NULL; ent = ent->ipe_hnext) { 1077255332Scy if (ent->ipe_family != ipe.ipe_family) 1078255332Scy continue; 1079255332Scy if (IP6_NEQ(&ipe.ipe_addr, &ent->ipe_addr)) 1080255332Scy continue; 1081255332Scy if (IP6_NEQ(&ipe.ipe_mask, &ent->ipe_mask)) 1082255332Scy continue; 1083255332Scy break; 1084255332Scy } 1085255332Scy 1086255332Scy return ent; 1087255332Scy} 1088255332Scy 1089255332Scy 1090255332Scy/* ------------------------------------------------------------------------ */ 1091255332Scy/* Function: ipf_iphmfindgroup */ 1092255332Scy/* Returns: int - 0 = success, else error */ 1093255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 1094255332Scy/* tptr(I) - */ 1095255332Scy/* aptr(I) - */ 1096255332Scy/* */ 1097255332Scy/* Search a hash table for a matching entry and return the pointer stored */ 1098255332Scy/* in it for use as the next group of rules to search. */ 1099255332Scy/* */ 1100255332Scy/* This function is exposed becaues it is used in the group-map feature. */ 1101255332Scy/* ------------------------------------------------------------------------ */ 1102255332Scyvoid * 1103255332Scyipf_iphmfindgroup(softc, tptr, aptr) 1104255332Scy ipf_main_softc_t *softc; 1105255332Scy void *tptr, *aptr; 1106255332Scy{ 1107145516Sdarrenr struct in_addr *addr; 1108145516Sdarrenr iphtable_t *iph; 1109145516Sdarrenr iphtent_t *ipe; 1110145516Sdarrenr void *rval; 1111145516Sdarrenr 1112255332Scy READ_ENTER(&softc->ipf_poolrw); 1113145516Sdarrenr iph = tptr; 1114145516Sdarrenr addr = aptr; 1115145516Sdarrenr 1116255332Scy ipe = ipf_iphmfind(iph, addr); 1117145516Sdarrenr if (ipe != NULL) 1118145516Sdarrenr rval = ipe->ipe_ptr; 1119145516Sdarrenr else 1120145516Sdarrenr rval = NULL; 1121255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 1122145516Sdarrenr return rval; 1123145516Sdarrenr} 1124145516Sdarrenr 1125145516Sdarrenr 1126145516Sdarrenr/* ------------------------------------------------------------------------ */ 1127255332Scy/* Function: ipf_iphmfindip */ 1128145516Sdarrenr/* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ 1129255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 1130255332Scy/* tptr(I) - pointer to the pool to search */ 1131170268Sdarrenr/* ipversion(I) - IP protocol version (4 or 6) */ 1132170268Sdarrenr/* aptr(I) - pointer to address information */ 1133255332Scy/* bytes(I) - packet length */ 1134145516Sdarrenr/* */ 1135145516Sdarrenr/* Search the hash table for a given address and return a search result. */ 1136145516Sdarrenr/* ------------------------------------------------------------------------ */ 1137255332Scystatic int 1138255332Scyipf_iphmfindip(softc, tptr, ipversion, aptr, bytes) 1139255332Scy ipf_main_softc_t *softc; 1140255332Scy void *tptr, *aptr; 1141255332Scy int ipversion; 1142255332Scy u_int bytes; 1143145516Sdarrenr{ 1144145516Sdarrenr struct in_addr *addr; 1145145516Sdarrenr iphtable_t *iph; 1146145516Sdarrenr iphtent_t *ipe; 1147145516Sdarrenr int rval; 1148145516Sdarrenr 1149145516Sdarrenr if (tptr == NULL || aptr == NULL) 1150145516Sdarrenr return -1; 1151145516Sdarrenr 1152145516Sdarrenr iph = tptr; 1153145516Sdarrenr addr = aptr; 1154145516Sdarrenr 1155255332Scy READ_ENTER(&softc->ipf_poolrw); 1156255332Scy if (ipversion == 4) { 1157255332Scy ipe = ipf_iphmfind(iph, addr); 1158255332Scy#ifdef USE_INET6 1159255332Scy } else if (ipversion == 6) { 1160255332Scy ipe = ipf_iphmfind6(iph, (i6addr_t *)addr); 1161255332Scy#endif 1162255332Scy } else { 1163255332Scy ipe = NULL; 1164255332Scy } 1165255332Scy 1166255332Scy if (ipe != NULL) { 1167145516Sdarrenr rval = 0; 1168255332Scy ipe->ipe_hits++; 1169255332Scy ipe->ipe_bytes += bytes; 1170255332Scy } else { 1171145516Sdarrenr rval = 1; 1172255332Scy } 1173255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 1174145516Sdarrenr return rval; 1175145516Sdarrenr} 1176145516Sdarrenr 1177145516Sdarrenr 1178255332Scy/* ------------------------------------------------------------------------ */ 1179255332Scy/* Function: ipf_iphmfindip */ 1180255332Scy/* Parameters: iph(I) - pointer to hash table */ 1181255332Scy/* addr(I) - pointer to IPv4 address */ 1182255332Scy/* Locks: ipf_poolrw */ 1183255332Scy/* */ 1184255332Scy/* ------------------------------------------------------------------------ */ 1185255332Scystatic iphtent_t * 1186255332Scyipf_iphmfind(iph, addr) 1187255332Scy iphtable_t *iph; 1188255332Scy struct in_addr *addr; 1189145516Sdarrenr{ 1190255332Scy u_32_t msk, ips; 1191145516Sdarrenr iphtent_t *ipe; 1192145516Sdarrenr u_int hv; 1193255332Scy int i; 1194145516Sdarrenr 1195255332Scy i = 0; 1196145516Sdarrenrmaskloop: 1197255332Scy msk = iph->iph_v4_masks.imt4_active[i]; 1198255332Scy ips = addr->s_addr & msk; 1199255332Scy hv = IPE_V4_HASH_FN(ips, msk, iph->iph_size); 1200170268Sdarrenr for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) { 1201255332Scy if ((ipe->ipe_family != AF_INET) || 1202255332Scy (ipe->ipe_mask.in4_addr != msk) || 1203255332Scy (ipe->ipe_addr.in4_addr != ips)) { 1204145516Sdarrenr continue; 1205145516Sdarrenr } 1206145516Sdarrenr break; 1207145516Sdarrenr } 1208145516Sdarrenr 1209255332Scy if (ipe == NULL) { 1210255332Scy i++; 1211255332Scy if (i < iph->iph_v4_masks.imt4_max) 1212145516Sdarrenr goto maskloop; 1213145516Sdarrenr } 1214145516Sdarrenr return ipe; 1215145516Sdarrenr} 1216145516Sdarrenr 1217170268Sdarrenr 1218255332Scy/* ------------------------------------------------------------------------ */ 1219255332Scy/* Function: ipf_htable_iter_next */ 1220255332Scy/* Returns: int - 0 = success, else error */ 1221255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 1222255332Scy/* arg(I) - pointer to local context to use */ 1223255332Scy/* token(I) - */ 1224255332Scy/* ilp(I) - */ 1225255332Scy/* */ 1226255332Scy/* ------------------------------------------------------------------------ */ 1227255332Scystatic int 1228255332Scyipf_htable_iter_next(softc, arg, token, ilp) 1229255332Scy ipf_main_softc_t *softc; 1230255332Scy void *arg; 1231255332Scy ipftoken_t *token; 1232255332Scy ipflookupiter_t *ilp; 1233170268Sdarrenr{ 1234255332Scy ipf_htable_softc_t *softh = arg; 1235170268Sdarrenr iphtent_t *node, zn, *nextnode; 1236170268Sdarrenr iphtable_t *iph, zp, *nextiph; 1237255332Scy void *hnext; 1238170268Sdarrenr int err; 1239170268Sdarrenr 1240170268Sdarrenr err = 0; 1241170268Sdarrenr iph = NULL; 1242170268Sdarrenr node = NULL; 1243170268Sdarrenr nextiph = NULL; 1244170268Sdarrenr nextnode = NULL; 1245170268Sdarrenr 1246255332Scy READ_ENTER(&softc->ipf_poolrw); 1247170268Sdarrenr 1248170268Sdarrenr switch (ilp->ili_otype) 1249170268Sdarrenr { 1250170268Sdarrenr case IPFLOOKUPITER_LIST : 1251170268Sdarrenr iph = token->ipt_data; 1252170268Sdarrenr if (iph == NULL) { 1253255332Scy nextiph = softh->ipf_htables[(int)ilp->ili_unit + 1]; 1254170268Sdarrenr } else { 1255170268Sdarrenr nextiph = iph->iph_next; 1256170268Sdarrenr } 1257170268Sdarrenr 1258170268Sdarrenr if (nextiph != NULL) { 1259170268Sdarrenr ATOMIC_INC(nextiph->iph_ref); 1260172776Sdarrenr token->ipt_data = nextiph; 1261170268Sdarrenr } else { 1262170268Sdarrenr bzero((char *)&zp, sizeof(zp)); 1263170268Sdarrenr nextiph = &zp; 1264172776Sdarrenr token->ipt_data = NULL; 1265170268Sdarrenr } 1266255332Scy hnext = nextiph->iph_next; 1267170268Sdarrenr break; 1268170268Sdarrenr 1269170268Sdarrenr case IPFLOOKUPITER_NODE : 1270170268Sdarrenr node = token->ipt_data; 1271170268Sdarrenr if (node == NULL) { 1272255332Scy iph = ipf_htable_find(arg, ilp->ili_unit, 1273255332Scy ilp->ili_name); 1274255332Scy if (iph == NULL) { 1275255332Scy IPFERROR(30009); 1276170268Sdarrenr err = ESRCH; 1277255332Scy } else { 1278170268Sdarrenr nextnode = iph->iph_list; 1279170268Sdarrenr } 1280170268Sdarrenr } else { 1281170268Sdarrenr nextnode = node->ipe_next; 1282170268Sdarrenr } 1283170268Sdarrenr 1284170268Sdarrenr if (nextnode != NULL) { 1285170268Sdarrenr ATOMIC_INC(nextnode->ipe_ref); 1286172776Sdarrenr token->ipt_data = nextnode; 1287170268Sdarrenr } else { 1288170268Sdarrenr bzero((char *)&zn, sizeof(zn)); 1289170268Sdarrenr nextnode = &zn; 1290172776Sdarrenr token->ipt_data = NULL; 1291170268Sdarrenr } 1292255332Scy hnext = nextnode->ipe_next; 1293170268Sdarrenr break; 1294255332Scy 1295170268Sdarrenr default : 1296255332Scy IPFERROR(30010); 1297170268Sdarrenr err = EINVAL; 1298255332Scy hnext = NULL; 1299170268Sdarrenr break; 1300170268Sdarrenr } 1301170268Sdarrenr 1302255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 1303170268Sdarrenr if (err != 0) 1304170268Sdarrenr return err; 1305170268Sdarrenr 1306170268Sdarrenr switch (ilp->ili_otype) 1307170268Sdarrenr { 1308170268Sdarrenr case IPFLOOKUPITER_LIST : 1309255332Scy err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph)); 1310255332Scy if (err != 0) { 1311255332Scy IPFERROR(30011); 1312255332Scy err = EFAULT; 1313255332Scy } 1314170268Sdarrenr if (iph != NULL) { 1315255332Scy WRITE_ENTER(&softc->ipf_poolrw); 1316255332Scy ipf_htable_deref(softc, softh, iph); 1317255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 1318170268Sdarrenr } 1319170268Sdarrenr break; 1320170268Sdarrenr 1321170268Sdarrenr case IPFLOOKUPITER_NODE : 1322255332Scy err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode)); 1323255332Scy if (err != 0) { 1324255332Scy IPFERROR(30012); 1325255332Scy err = EFAULT; 1326255332Scy } 1327170268Sdarrenr if (node != NULL) { 1328255332Scy WRITE_ENTER(&softc->ipf_poolrw); 1329255332Scy ipf_htent_deref(softc, node); 1330255332Scy RWLOCK_EXIT(&softc->ipf_poolrw); 1331170268Sdarrenr } 1332170268Sdarrenr break; 1333170268Sdarrenr } 1334170268Sdarrenr 1335255332Scy if (hnext == NULL) 1336255332Scy ipf_token_mark_complete(token); 1337255332Scy 1338170268Sdarrenr return err; 1339170268Sdarrenr} 1340170268Sdarrenr 1341170268Sdarrenr 1342255332Scy/* ------------------------------------------------------------------------ */ 1343255332Scy/* Function: ipf_htable_iter_deref */ 1344255332Scy/* Returns: int - 0 = success, else error */ 1345255332Scy/* Parameters: softc(I) - pointer to soft context main structure */ 1346255332Scy/* arg(I) - pointer to local context to use */ 1347255332Scy/* otype(I) - which data structure type is being walked */ 1348255332Scy/* unit(I) - ipfilter device to which we are working on */ 1349255332Scy/* data(I) - pointer to old data structure */ 1350255332Scy/* */ 1351255332Scy/* ------------------------------------------------------------------------ */ 1352255332Scystatic int 1353255332Scyipf_htable_iter_deref(softc, arg, otype, unit, data) 1354255332Scy ipf_main_softc_t *softc; 1355255332Scy void *arg; 1356255332Scy int otype; 1357255332Scy int unit; 1358255332Scy void *data; 1359170268Sdarrenr{ 1360170268Sdarrenr 1361170268Sdarrenr if (data == NULL) 1362255332Scy return EFAULT; 1363170268Sdarrenr 1364255332Scy if (unit < -1 || unit > IPL_LOGMAX) 1365255332Scy return EINVAL; 1366170268Sdarrenr 1367170268Sdarrenr switch (otype) 1368170268Sdarrenr { 1369170268Sdarrenr case IPFLOOKUPITER_LIST : 1370255332Scy ipf_htable_deref(softc, arg, (iphtable_t *)data); 1371170268Sdarrenr break; 1372170268Sdarrenr 1373170268Sdarrenr case IPFLOOKUPITER_NODE : 1374255332Scy ipf_htent_deref(arg, (iphtent_t *)data); 1375170268Sdarrenr break; 1376170268Sdarrenr default : 1377170268Sdarrenr break; 1378170268Sdarrenr } 1379255332Scy 1380255332Scy return 0; 1381170268Sdarrenr} 1382170268Sdarrenr 1383255332Scy 1384255332Scy#ifdef USE_INET6 1385255332Scy/* ------------------------------------------------------------------------ */ 1386255332Scy/* Function: ipf_iphmfind6 */ 1387255332Scy/* Parameters: iph(I) - pointer to hash table */ 1388255332Scy/* addr(I) - pointer to IPv6 address */ 1389255332Scy/* Locks: ipf_poolrw */ 1390255332Scy/* */ 1391255332Scy/* ------------------------------------------------------------------------ */ 1392255332Scystatic iphtent_t * 1393255332Scyipf_iphmfind6(iph, addr) 1394255332Scy iphtable_t *iph; 1395255332Scy i6addr_t *addr; 1396255332Scy{ 1397255332Scy i6addr_t *msk, ips; 1398255332Scy iphtent_t *ipe; 1399255332Scy u_int hv; 1400255332Scy int i; 1401255332Scy 1402255332Scy i = 0; 1403255332Scymaskloop: 1404255332Scy msk = iph->iph_v6_masks.imt6_active + i; 1405255332Scy ips.i6[0] = addr->i6[0] & msk->i6[0]; 1406255332Scy ips.i6[1] = addr->i6[1] & msk->i6[1]; 1407255332Scy ips.i6[2] = addr->i6[2] & msk->i6[2]; 1408255332Scy ips.i6[3] = addr->i6[3] & msk->i6[3]; 1409255332Scy hv = IPE_V6_HASH_FN(ips.i6, msk->i6, iph->iph_size); 1410255332Scy for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) { 1411255332Scy if ((ipe->ipe_family != AF_INET6) || 1412255332Scy IP6_NEQ(&ipe->ipe_mask, msk) || 1413255332Scy IP6_NEQ(&ipe->ipe_addr, &ips)) { 1414255332Scy continue; 1415255332Scy } 1416255332Scy break; 1417255332Scy } 1418255332Scy 1419255332Scy if (ipe == NULL) { 1420255332Scy i++; 1421255332Scy if (i < iph->iph_v6_masks.imt6_max) 1422255332Scy goto maskloop; 1423255332Scy } 1424255332Scy return ipe; 1425255332Scy} 1426255332Scy#endif 1427255332Scy 1428255332Scy 1429255332Scystatic void 1430255332Scyipf_htable_expire(softc, arg) 1431255332Scy ipf_main_softc_t *softc; 1432255332Scy void *arg; 1433255332Scy{ 1434255332Scy ipf_htable_softc_t *softh = arg; 1435255332Scy iphtent_t *n; 1436255332Scy 1437255332Scy while ((n = softh->ipf_node_explist) != NULL) { 1438255332Scy if (n->ipe_die > softc->ipf_ticks) 1439255332Scy break; 1440255332Scy 1441255332Scy ipf_htent_remove(softc, softh, n->ipe_owner, n); 1442255332Scy } 1443255332Scy} 1444255332Scy 1445255332Scy 1446255332Scy#ifndef _KERNEL 1447255332Scy 1448255332Scy/* ------------------------------------------------------------------------ */ 1449255332Scy/* */ 1450255332Scy/* ------------------------------------------------------------------------ */ 1451255332Scyvoid 1452255332Scyipf_htable_dump(softc, arg) 1453255332Scy ipf_main_softc_t *softc; 1454255332Scy void *arg; 1455255332Scy{ 1456255332Scy ipf_htable_softc_t *softh = arg; 1457255332Scy iphtable_t *iph; 1458255332Scy int i; 1459255332Scy 1460255332Scy printf("List of configured hash tables\n"); 1461255332Scy for (i = 0; i < IPL_LOGSIZE; i++) 1462255332Scy for (iph = softh->ipf_htables[i]; iph != NULL; 1463255332Scy iph = iph->iph_next) 1464255332Scy printhash(iph, bcopywrap, NULL, opts, NULL); 1465255332Scy 1466255332Scy} 1467255332Scy#endif 1468