ip_pool.c revision 153872
1145516Sdarrenr/* 2145516Sdarrenr * Copyright (C) 1993-2001, 2003 by Darren Reed. 3145516Sdarrenr * 4145516Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 5145516Sdarrenr */ 6145516Sdarrenr#if defined(KERNEL) || defined(_KERNEL) 7145516Sdarrenr# undef KERNEL 8145516Sdarrenr# undef _KERNEL 9145516Sdarrenr# define KERNEL 1 10145516Sdarrenr# define _KERNEL 1 11145516Sdarrenr#endif 12145516Sdarrenr#if defined(__osf__) 13145516Sdarrenr# define _PROTO_NET_H_ 14145516Sdarrenr#endif 15145516Sdarrenr#include <sys/errno.h> 16145516Sdarrenr#include <sys/types.h> 17145516Sdarrenr#include <sys/param.h> 18145516Sdarrenr#include <sys/file.h> 19145516Sdarrenr#if !defined(_KERNEL) && !defined(__KERNEL__) 20145516Sdarrenr# include <stdio.h> 21145516Sdarrenr# include <stdlib.h> 22145516Sdarrenr# include <string.h> 23145516Sdarrenr# define _KERNEL 24145516Sdarrenr# ifdef __OpenBSD__ 25145516Sdarrenrstruct file; 26145516Sdarrenr# endif 27145516Sdarrenr# include <sys/uio.h> 28145516Sdarrenr# undef _KERNEL 29145516Sdarrenr#else 30145516Sdarrenr# include <sys/systm.h> 31145516Sdarrenr# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000) 32145516Sdarrenr# include <sys/proc.h> 33145516Sdarrenr# endif 34145516Sdarrenr#endif 35145516Sdarrenr#include <sys/time.h> 36145516Sdarrenr#if !defined(linux) 37145516Sdarrenr# include <sys/protosw.h> 38145516Sdarrenr#endif 39145516Sdarrenr#include <sys/socket.h> 40145516Sdarrenr#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__)) 41145516Sdarrenr# include <sys/mbuf.h> 42145516Sdarrenr#endif 43145516Sdarrenr#if defined(__SVR4) || defined(__svr4__) 44145516Sdarrenr# include <sys/filio.h> 45145516Sdarrenr# include <sys/byteorder.h> 46145516Sdarrenr# ifdef _KERNEL 47145516Sdarrenr# include <sys/dditypes.h> 48145516Sdarrenr# endif 49145516Sdarrenr# include <sys/stream.h> 50145516Sdarrenr# include <sys/kmem.h> 51145516Sdarrenr#endif 52145516Sdarrenr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 53145516Sdarrenr# include <sys/malloc.h> 54145516Sdarrenr#endif 55145516Sdarrenr 56153872Sguido#if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \ 57153872Sguido defined(__hpux) || defined(__sgi)) 58145516Sdarrenr# ifdef __osf__ 59145516Sdarrenr# include <net/radix.h> 60145516Sdarrenr# endif 61145516Sdarrenr# include "radix_ipf_local.h" 62145516Sdarrenr# define _RADIX_H_ 63145516Sdarrenr#endif 64145516Sdarrenr#include <net/if.h> 65145516Sdarrenr#include <netinet/in.h> 66145516Sdarrenr 67145516Sdarrenr#include "netinet/ip_compat.h" 68145516Sdarrenr#include "netinet/ip_fil.h" 69145516Sdarrenr#include "netinet/ip_pool.h" 70145516Sdarrenr 71145516Sdarrenr#if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \ 72145516Sdarrenr ((BSD >= 198911) && !defined(__osf__) && \ 73145516Sdarrenr !defined(__hpux) && !defined(__sgi)) 74145516Sdarrenrstatic int rn_freenode __P((struct radix_node *, void *)); 75145516Sdarrenr#endif 76145516Sdarrenr 77145516Sdarrenr/* END OF INCLUDES */ 78145516Sdarrenr 79145516Sdarrenr#if !defined(lint) 80145516Sdarrenrstatic const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; 81153872Sguidostatic const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.15 2005/11/13 15:38:37 darrenr Exp $"; 82145516Sdarrenr#endif 83145516Sdarrenr 84145516Sdarrenr#ifdef IPFILTER_LOOKUP 85145516Sdarrenr 86145516Sdarrenr# ifndef RADIX_NODE_HEAD_LOCK 87145516Sdarrenr# define RADIX_NODE_HEAD_LOCK(x) ; 88145516Sdarrenr# endif 89145516Sdarrenr# ifndef RADIX_NODE_HEAD_UNLOCK 90145516Sdarrenr# define RADIX_NODE_HEAD_UNLOCK(x) ; 91145516Sdarrenr# endif 92145516Sdarrenr 93145516Sdarrenrip_pool_stat_t ipoolstat; 94145516Sdarrenripfrwlock_t ip_poolrw; 95145516Sdarrenr 96145516Sdarrenr/* 97145516Sdarrenr * Binary tree routines from Sedgewick and enhanced to do ranges of addresses. 98145516Sdarrenr * NOTE: Insertion *MUST* be from greatest range to least for it to work! 99145516Sdarrenr * These should be replaced, eventually, by something else - most notably a 100145516Sdarrenr * interval searching method. The important feature is to be able to find 101145516Sdarrenr * the best match. 102145516Sdarrenr * 103145516Sdarrenr * So why not use a radix tree for this? As the first line implies, it 104145516Sdarrenr * has been written to work with a _range_ of addresses. A range is not 105145516Sdarrenr * necessarily a match with any given netmask so what we end up dealing 106145516Sdarrenr * with is an interval tree. Implementations of these are hard to find 107145516Sdarrenr * and the one herein is far from bug free. 108145516Sdarrenr * 109145516Sdarrenr * Sigh, in the end I became convinced that the bugs the code contained did 110145516Sdarrenr * not make it worthwhile not using radix trees. For now the radix tree from 111145516Sdarrenr * 4.4 BSD is used, but this is not viewed as a long term solution. 112145516Sdarrenr */ 113145516Sdarrenrip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL, 114145516Sdarrenr NULL, NULL, NULL, NULL }; 115145516Sdarrenr 116145516Sdarrenr 117145516Sdarrenr#ifdef TEST_POOL 118145516Sdarrenrvoid treeprint __P((ip_pool_t *)); 119145516Sdarrenr 120145516Sdarrenrint 121145516Sdarrenrmain(argc, argv) 122145516Sdarrenr int argc; 123145516Sdarrenr char *argv[]; 124145516Sdarrenr{ 125145516Sdarrenr addrfamily_t a, b; 126145516Sdarrenr iplookupop_t op; 127145516Sdarrenr ip_pool_t *ipo; 128145516Sdarrenr i6addr_t ip; 129145516Sdarrenr 130145516Sdarrenr RWLOCK_INIT(&ip_poolrw, "poolrw"); 131145516Sdarrenr ip_pool_init(); 132145516Sdarrenr 133145516Sdarrenr bzero((char *)&a, sizeof(a)); 134145516Sdarrenr bzero((char *)&b, sizeof(b)); 135145516Sdarrenr bzero((char *)&ip, sizeof(ip)); 136145516Sdarrenr bzero((char *)&op, sizeof(op)); 137145516Sdarrenr strcpy(op.iplo_name, "0"); 138145516Sdarrenr 139145516Sdarrenr if (ip_pool_create(&op) == 0) 140145516Sdarrenr ipo = ip_pool_find(0, "0"); 141145516Sdarrenr 142145516Sdarrenr a.adf_addr.in4.s_addr = 0x0a010203; 143145516Sdarrenr b.adf_addr.in4.s_addr = 0xffffffff; 144145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 145145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 146145516Sdarrenr 147145516Sdarrenr a.adf_addr.in4.s_addr = 0x0a000000; 148145516Sdarrenr b.adf_addr.in4.s_addr = 0xff000000; 149145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); 150145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); 151145516Sdarrenr 152145516Sdarrenr a.adf_addr.in4.s_addr = 0x0a010100; 153145516Sdarrenr b.adf_addr.in4.s_addr = 0xffffff00; 154145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 155145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 156145516Sdarrenr 157145516Sdarrenr a.adf_addr.in4.s_addr = 0x0a010200; 158145516Sdarrenr b.adf_addr.in4.s_addr = 0xffffff00; 159145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); 160145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); 161145516Sdarrenr 162145516Sdarrenr a.adf_addr.in4.s_addr = 0x0a010000; 163145516Sdarrenr b.adf_addr.in4.s_addr = 0xffff0000; 164145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 165145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 166145516Sdarrenr 167145516Sdarrenr a.adf_addr.in4.s_addr = 0x0a01020f; 168145516Sdarrenr b.adf_addr.in4.s_addr = 0xffffffff; 169145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 170145516Sdarrenr ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); 171145516Sdarrenr#ifdef DEBUG_POOL 172145516Sdarrenrtreeprint(ipo); 173145516Sdarrenr#endif 174145516Sdarrenr ip.in4.s_addr = 0x0a00aabb; 175145516Sdarrenr printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 176145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 177145516Sdarrenr 178145516Sdarrenr ip.in4.s_addr = 0x0a000001; 179145516Sdarrenr printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 180145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 181145516Sdarrenr 182145516Sdarrenr ip.in4.s_addr = 0x0a000101; 183145516Sdarrenr printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 184145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 185145516Sdarrenr 186145516Sdarrenr ip.in4.s_addr = 0x0a010001; 187145516Sdarrenr printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 188145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 189145516Sdarrenr 190145516Sdarrenr ip.in4.s_addr = 0x0a010101; 191145516Sdarrenr printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 192145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 193145516Sdarrenr 194145516Sdarrenr ip.in4.s_addr = 0x0a010201; 195145516Sdarrenr printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 196145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 197145516Sdarrenr 198145516Sdarrenr ip.in4.s_addr = 0x0a010203; 199145516Sdarrenr printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 200145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 201145516Sdarrenr 202145516Sdarrenr ip.in4.s_addr = 0x0a01020f; 203145516Sdarrenr printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 204145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 205145516Sdarrenr 206145516Sdarrenr ip.in4.s_addr = 0x0b00aabb; 207145516Sdarrenr printf("search(%#x) = %d (-1)\n", ip.in4.s_addr, 208145516Sdarrenr ip_pool_search(ipo, 4, &ip)); 209145516Sdarrenr 210145516Sdarrenr#ifdef DEBUG_POOL 211145516Sdarrenrtreeprint(ipo); 212145516Sdarrenr#endif 213145516Sdarrenr 214145516Sdarrenr ip_pool_fini(); 215145516Sdarrenr 216145516Sdarrenr return 0; 217145516Sdarrenr} 218145516Sdarrenr 219145516Sdarrenr 220145516Sdarrenrvoid 221145516Sdarrenrtreeprint(ipo) 222145516Sdarrenrip_pool_t *ipo; 223145516Sdarrenr{ 224145516Sdarrenr ip_pool_node_t *c; 225145516Sdarrenr 226145516Sdarrenr for (c = ipo->ipo_list; c != NULL; c = c->ipn_next) 227145516Sdarrenr printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n", 228145516Sdarrenr c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr, 229145516Sdarrenr c->ipn_mask.adf_addr.in4.s_addr, 230145516Sdarrenr c->ipn_info, c->ipn_hits); 231145516Sdarrenr} 232145516Sdarrenr#endif /* TEST_POOL */ 233145516Sdarrenr 234145516Sdarrenr 235145516Sdarrenr/* ------------------------------------------------------------------------ */ 236145516Sdarrenr/* Function: ip_pool_init */ 237145516Sdarrenr/* Returns: int - 0 = success, else error */ 238145516Sdarrenr/* */ 239145516Sdarrenr/* Initialise the routing table data structures where required. */ 240145516Sdarrenr/* ------------------------------------------------------------------------ */ 241145516Sdarrenrint ip_pool_init() 242145516Sdarrenr{ 243145516Sdarrenr 244145516Sdarrenr bzero((char *)&ipoolstat, sizeof(ipoolstat)); 245145516Sdarrenr 246145516Sdarrenr#if (!defined(_KERNEL) || (BSD < 199306)) 247145516Sdarrenr rn_init(); 248145516Sdarrenr#endif 249145516Sdarrenr return 0; 250145516Sdarrenr} 251145516Sdarrenr 252145516Sdarrenr 253145516Sdarrenr/* ------------------------------------------------------------------------ */ 254145516Sdarrenr/* Function: ip_pool_fini */ 255145516Sdarrenr/* Returns: int - 0 = success, else error */ 256145516Sdarrenr/* Locks: WRITE(ipf_global) */ 257145516Sdarrenr/* */ 258145516Sdarrenr/* Clean up all the pool data structures allocated and call the cleanup */ 259145516Sdarrenr/* function for the radix tree that supports the pools. ip_pool_destroy() is*/ 260145516Sdarrenr/* used to delete the pools one by one to ensure they're properly freed up. */ 261145516Sdarrenr/* ------------------------------------------------------------------------ */ 262145516Sdarrenrvoid ip_pool_fini() 263145516Sdarrenr{ 264145516Sdarrenr ip_pool_t *p, *q; 265145516Sdarrenr iplookupop_t op; 266145516Sdarrenr int i; 267145516Sdarrenr 268145516Sdarrenr ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0); 269145516Sdarrenr 270145516Sdarrenr for (i = 0; i <= IPL_LOGMAX; i++) { 271145516Sdarrenr for (q = ip_pool_list[i]; (p = q) != NULL; ) { 272145516Sdarrenr op.iplo_unit = i; 273145516Sdarrenr (void)strncpy(op.iplo_name, p->ipo_name, 274145516Sdarrenr sizeof(op.iplo_name)); 275145516Sdarrenr q = p->ipo_next; 276145516Sdarrenr (void) ip_pool_destroy(&op); 277145516Sdarrenr } 278145516Sdarrenr } 279145516Sdarrenr 280145516Sdarrenr#if (!defined(_KERNEL) || (BSD < 199306)) 281145516Sdarrenr rn_fini(); 282145516Sdarrenr#endif 283145516Sdarrenr} 284145516Sdarrenr 285145516Sdarrenr 286145516Sdarrenr/* ------------------------------------------------------------------------ */ 287145516Sdarrenr/* Function: ip_pool_statistics */ 288145516Sdarrenr/* Returns: int - 0 = success, else error */ 289145516Sdarrenr/* Parameters: op(I) - pointer to lookup operation arguments */ 290145516Sdarrenr/* */ 291145516Sdarrenr/* Copy the current statistics out into user space, collecting pool list */ 292145516Sdarrenr/* pointers as appropriate for later use. */ 293145516Sdarrenr/* ------------------------------------------------------------------------ */ 294145516Sdarrenrint ip_pool_statistics(op) 295145516Sdarrenriplookupop_t *op; 296145516Sdarrenr{ 297145516Sdarrenr ip_pool_stat_t stats; 298145516Sdarrenr int unit, i, err = 0; 299145516Sdarrenr 300145516Sdarrenr if (op->iplo_size != sizeof(ipoolstat)) 301145516Sdarrenr return EINVAL; 302145516Sdarrenr 303145516Sdarrenr bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats)); 304145516Sdarrenr unit = op->iplo_unit; 305145516Sdarrenr if (unit == IPL_LOGALL) { 306145516Sdarrenr for (i = 0; i < IPL_LOGSIZE; i++) 307145516Sdarrenr stats.ipls_list[i] = ip_pool_list[i]; 308145516Sdarrenr } else if (unit >= 0 && unit < IPL_LOGSIZE) { 309145516Sdarrenr if (op->iplo_name[0] != '\0') 310145516Sdarrenr stats.ipls_list[unit] = ip_pool_find(unit, 311145516Sdarrenr op->iplo_name); 312145516Sdarrenr else 313145516Sdarrenr stats.ipls_list[unit] = ip_pool_list[unit]; 314145516Sdarrenr } else 315145516Sdarrenr err = EINVAL; 316145516Sdarrenr if (err == 0) 317145516Sdarrenr err = COPYOUT(&stats, op->iplo_struct, sizeof(stats)); 318145516Sdarrenr return err; 319145516Sdarrenr} 320145516Sdarrenr 321145516Sdarrenr 322145516Sdarrenr 323145516Sdarrenr/* ------------------------------------------------------------------------ */ 324145516Sdarrenr/* Function: ip_pool_find */ 325145516Sdarrenr/* Returns: int - 0 = success, else error */ 326145516Sdarrenr/* Parameters: ipo(I) - pointer to the pool getting the new node. */ 327145516Sdarrenr/* */ 328145516Sdarrenr/* Find a matching pool inside the collection of pools for a particular */ 329145516Sdarrenr/* device, indicated by the unit number. */ 330145516Sdarrenr/* ------------------------------------------------------------------------ */ 331145516Sdarrenrvoid *ip_pool_find(unit, name) 332145516Sdarrenrint unit; 333145516Sdarrenrchar *name; 334145516Sdarrenr{ 335145516Sdarrenr ip_pool_t *p; 336145516Sdarrenr 337145516Sdarrenr for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next) 338145516Sdarrenr if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0) 339145516Sdarrenr break; 340145516Sdarrenr return p; 341145516Sdarrenr} 342145516Sdarrenr 343145516Sdarrenr 344145516Sdarrenr/* ------------------------------------------------------------------------ */ 345145516Sdarrenr/* Function: ip_pool_findeq */ 346145516Sdarrenr/* Returns: int - 0 = success, else error */ 347145516Sdarrenr/* Parameters: ipo(I) - pointer to the pool getting the new node. */ 348145516Sdarrenr/* addr(I) - pointer to address information to delete */ 349145516Sdarrenr/* mask(I) - */ 350145516Sdarrenr/* */ 351145516Sdarrenr/* Searches for an exact match of an entry in the pool. */ 352145516Sdarrenr/* ------------------------------------------------------------------------ */ 353145516Sdarrenrip_pool_node_t *ip_pool_findeq(ipo, addr, mask) 354145516Sdarrenrip_pool_t *ipo; 355145516Sdarrenraddrfamily_t *addr, *mask; 356145516Sdarrenr{ 357145516Sdarrenr struct radix_node *n; 358153872Sguido SPL_INT(s); 359145516Sdarrenr 360145516Sdarrenr SPL_NET(s); 361145516Sdarrenr RADIX_NODE_HEAD_LOCK(ipo->ipo_head); 362145516Sdarrenr n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head); 363145516Sdarrenr RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); 364145516Sdarrenr SPL_X(s); 365145516Sdarrenr return (ip_pool_node_t *)n; 366145516Sdarrenr} 367145516Sdarrenr 368145516Sdarrenr 369145516Sdarrenr/* ------------------------------------------------------------------------ */ 370145516Sdarrenr/* Function: ip_pool_search */ 371145516Sdarrenr/* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ 372145516Sdarrenr/* Parameters: tptr(I) - pointer to the pool to search */ 373145516Sdarrenr/* version(I) - IP protocol version (4 or 6) */ 374145516Sdarrenr/* dptr(I) - pointer to address information */ 375145516Sdarrenr/* */ 376145516Sdarrenr/* Search the pool for a given address and return a search result. */ 377145516Sdarrenr/* ------------------------------------------------------------------------ */ 378145516Sdarrenrint ip_pool_search(tptr, version, dptr) 379145516Sdarrenrvoid *tptr; 380145516Sdarrenrint version; 381145516Sdarrenrvoid *dptr; 382145516Sdarrenr{ 383145516Sdarrenr struct radix_node *rn; 384145516Sdarrenr ip_pool_node_t *m; 385145516Sdarrenr i6addr_t *addr; 386145516Sdarrenr addrfamily_t v; 387145516Sdarrenr ip_pool_t *ipo; 388145516Sdarrenr int rv; 389145516Sdarrenr 390145516Sdarrenr ipo = tptr; 391145516Sdarrenr if (ipo == NULL) 392145516Sdarrenr return -1; 393145516Sdarrenr 394145516Sdarrenr rv = 1; 395145516Sdarrenr m = NULL; 396145516Sdarrenr addr = (i6addr_t *)dptr; 397145516Sdarrenr bzero(&v, sizeof(v)); 398145516Sdarrenr v.adf_len = offsetof(addrfamily_t, adf_addr); 399145516Sdarrenr 400145516Sdarrenr if (version == 4) { 401145516Sdarrenr v.adf_len += sizeof(addr->in4); 402145516Sdarrenr v.adf_addr.in4 = addr->in4; 403145516Sdarrenr#ifdef USE_INET6 404145516Sdarrenr } else if (version == 6) { 405145516Sdarrenr v.adf_len += sizeof(addr->in6); 406145516Sdarrenr v.adf_addr.in6 = addr->in6; 407145516Sdarrenr#endif 408145516Sdarrenr } else 409145516Sdarrenr return -1; 410145516Sdarrenr 411145516Sdarrenr READ_ENTER(&ip_poolrw); 412145516Sdarrenr 413145516Sdarrenr RADIX_NODE_HEAD_LOCK(ipo->ipo_head); 414145516Sdarrenr rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head); 415145516Sdarrenr RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); 416145516Sdarrenr 417145516Sdarrenr if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) { 418145516Sdarrenr m = (ip_pool_node_t *)rn; 419145516Sdarrenr ipo->ipo_hits++; 420145516Sdarrenr m->ipn_hits++; 421145516Sdarrenr rv = m->ipn_info; 422145516Sdarrenr } 423145516Sdarrenr RWLOCK_EXIT(&ip_poolrw); 424145516Sdarrenr return rv; 425145516Sdarrenr} 426145516Sdarrenr 427145516Sdarrenr 428145516Sdarrenr/* ------------------------------------------------------------------------ */ 429145516Sdarrenr/* Function: ip_pool_insert */ 430145516Sdarrenr/* Returns: int - 0 = success, else error */ 431145516Sdarrenr/* Parameters: ipo(I) - pointer to the pool getting the new node. */ 432145516Sdarrenr/* addr(I) - address being added as a node */ 433145516Sdarrenr/* mask(I) - netmask to with the node being added */ 434145516Sdarrenr/* info(I) - extra information to store in this node. */ 435145516Sdarrenr/* Locks: WRITE(ip_poolrw) */ 436145516Sdarrenr/* */ 437145516Sdarrenr/* Add another node to the pool given by ipo. The three parameters passed */ 438145516Sdarrenr/* in (addr, mask, info) shold all be stored in the node. */ 439145516Sdarrenr/* ------------------------------------------------------------------------ */ 440145516Sdarrenrint ip_pool_insert(ipo, addr, mask, info) 441145516Sdarrenrip_pool_t *ipo; 442145516Sdarrenri6addr_t *addr, *mask; 443145516Sdarrenrint info; 444145516Sdarrenr{ 445145516Sdarrenr struct radix_node *rn; 446145516Sdarrenr ip_pool_node_t *x; 447145516Sdarrenr 448145516Sdarrenr ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); 449145516Sdarrenr 450145516Sdarrenr KMALLOC(x, ip_pool_node_t *); 451145516Sdarrenr if (x == NULL) { 452145516Sdarrenr return ENOMEM; 453145516Sdarrenr } 454145516Sdarrenr 455145516Sdarrenr bzero(x, sizeof(*x)); 456145516Sdarrenr 457145516Sdarrenr x->ipn_info = info; 458145516Sdarrenr (void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name)); 459145516Sdarrenr 460145516Sdarrenr bcopy(addr, &x->ipn_addr.adf_addr, sizeof(*addr)); 461145516Sdarrenr x->ipn_addr.adf_len = sizeof(x->ipn_addr); 462145516Sdarrenr bcopy(mask, &x->ipn_mask.adf_addr, sizeof(*mask)); 463145516Sdarrenr x->ipn_mask.adf_len = sizeof(x->ipn_mask); 464145516Sdarrenr 465145516Sdarrenr RADIX_NODE_HEAD_LOCK(ipo->ipo_head); 466145516Sdarrenr rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask, 467145516Sdarrenr ipo->ipo_head, x->ipn_nodes); 468145516Sdarrenr RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); 469145516Sdarrenr#ifdef DEBUG_POOL 470145516Sdarrenr printf("Added %p at %p\n", x, rn); 471145516Sdarrenr#endif 472145516Sdarrenr 473145516Sdarrenr if (rn == NULL) { 474145516Sdarrenr KFREE(x); 475145516Sdarrenr return ENOMEM; 476145516Sdarrenr } 477145516Sdarrenr 478145516Sdarrenr x->ipn_next = ipo->ipo_list; 479145516Sdarrenr x->ipn_pnext = &ipo->ipo_list; 480145516Sdarrenr if (ipo->ipo_list != NULL) 481145516Sdarrenr ipo->ipo_list->ipn_pnext = &x->ipn_next; 482145516Sdarrenr ipo->ipo_list = x; 483145516Sdarrenr 484145516Sdarrenr ipoolstat.ipls_nodes++; 485145516Sdarrenr 486145516Sdarrenr return 0; 487145516Sdarrenr} 488145516Sdarrenr 489145516Sdarrenr 490145516Sdarrenr/* ------------------------------------------------------------------------ */ 491145516Sdarrenr/* Function: ip_pool_create */ 492145516Sdarrenr/* Returns: int - 0 = success, else error */ 493145516Sdarrenr/* Parameters: op(I) - pointer to iplookup struct with call details */ 494145516Sdarrenr/* Locks: WRITE(ip_poolrw) */ 495145516Sdarrenr/* */ 496145516Sdarrenr/* Creates a new group according to the paramters passed in via the */ 497145516Sdarrenr/* iplookupop structure. Does not check to see if the group already exists */ 498145516Sdarrenr/* when being inserted - assume this has already been done. If the pool is */ 499145516Sdarrenr/* marked as being anonymous, give it a new, unique, identifier. Call any */ 500145516Sdarrenr/* other functions required to initialise the structure. */ 501145516Sdarrenr/* ------------------------------------------------------------------------ */ 502145516Sdarrenrint ip_pool_create(op) 503145516Sdarrenriplookupop_t *op; 504145516Sdarrenr{ 505145516Sdarrenr char name[FR_GROUPLEN]; 506145516Sdarrenr int poolnum, unit; 507145516Sdarrenr ip_pool_t *h; 508145516Sdarrenr 509145516Sdarrenr ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); 510145516Sdarrenr 511145516Sdarrenr KMALLOC(h, ip_pool_t *); 512145516Sdarrenr if (h == NULL) 513145516Sdarrenr return ENOMEM; 514145516Sdarrenr bzero(h, sizeof(*h)); 515145516Sdarrenr 516145516Sdarrenr if (rn_inithead((void **)&h->ipo_head, 517145516Sdarrenr offsetof(addrfamily_t, adf_addr) << 3) == 0) { 518145516Sdarrenr KFREE(h); 519145516Sdarrenr return ENOMEM; 520145516Sdarrenr } 521145516Sdarrenr 522145516Sdarrenr unit = op->iplo_unit; 523145516Sdarrenr 524145516Sdarrenr if ((op->iplo_arg & IPOOL_ANON) != 0) { 525145516Sdarrenr ip_pool_t *p; 526145516Sdarrenr 527145516Sdarrenr poolnum = IPOOL_ANON; 528145516Sdarrenr 529145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL) 530145516Sdarrenr SNPRINTF(name, sizeof(name), "%x", poolnum); 531145516Sdarrenr#else 532145516Sdarrenr (void)sprintf(name, "%x", poolnum); 533145516Sdarrenr#endif 534145516Sdarrenr 535145516Sdarrenr for (p = ip_pool_list[unit]; p != NULL; ) { 536145516Sdarrenr if (strncmp(name, p->ipo_name, 537145516Sdarrenr sizeof(p->ipo_name)) == 0) { 538145516Sdarrenr poolnum++; 539145516Sdarrenr#if defined(SNPRINTF) && defined(_KERNEL) 540145516Sdarrenr SNPRINTF(name, sizeof(name), "%x", poolnum); 541145516Sdarrenr#else 542145516Sdarrenr (void)sprintf(name, "%x", poolnum); 543145516Sdarrenr#endif 544145516Sdarrenr p = ip_pool_list[unit]; 545145516Sdarrenr } else 546145516Sdarrenr p = p->ipo_next; 547145516Sdarrenr } 548145516Sdarrenr 549145516Sdarrenr (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name)); 550153872Sguido (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name)); 551145516Sdarrenr } else { 552145516Sdarrenr (void) strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name)); 553145516Sdarrenr } 554145516Sdarrenr 555145516Sdarrenr h->ipo_ref = 1; 556145516Sdarrenr h->ipo_list = NULL; 557145516Sdarrenr h->ipo_unit = unit; 558145516Sdarrenr h->ipo_next = ip_pool_list[unit]; 559145516Sdarrenr if (ip_pool_list[unit] != NULL) 560145516Sdarrenr ip_pool_list[unit]->ipo_pnext = &h->ipo_next; 561145516Sdarrenr h->ipo_pnext = &ip_pool_list[unit]; 562145516Sdarrenr ip_pool_list[unit] = h; 563145516Sdarrenr 564145516Sdarrenr ipoolstat.ipls_pools++; 565145516Sdarrenr 566145516Sdarrenr return 0; 567145516Sdarrenr} 568145516Sdarrenr 569145516Sdarrenr 570145516Sdarrenr/* ------------------------------------------------------------------------ */ 571145516Sdarrenr/* Function: ip_pool_remove */ 572145516Sdarrenr/* Returns: int - 0 = success, else error */ 573145516Sdarrenr/* Parameters: ipo(I) - pointer to the pool to remove the node from. */ 574145516Sdarrenr/* ipe(I) - address being deleted as a node */ 575145516Sdarrenr/* Locks: WRITE(ip_poolrw) */ 576145516Sdarrenr/* */ 577145516Sdarrenr/* Add another node to the pool given by ipo. The three parameters passed */ 578145516Sdarrenr/* in (addr, mask, info) shold all be stored in the node. */ 579145516Sdarrenr/* ------------------------------------------------------------------------ */ 580145516Sdarrenrint ip_pool_remove(ipo, ipe) 581145516Sdarrenrip_pool_t *ipo; 582145516Sdarrenrip_pool_node_t *ipe; 583145516Sdarrenr{ 584145516Sdarrenr ip_pool_node_t **ipp, *n; 585145516Sdarrenr 586145516Sdarrenr ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); 587145516Sdarrenr 588145516Sdarrenr for (ipp = &ipo->ipo_list; (n = *ipp) != NULL; ipp = &n->ipn_next) { 589145516Sdarrenr if (ipe == n) { 590145516Sdarrenr *n->ipn_pnext = n->ipn_next; 591145516Sdarrenr if (n->ipn_next) 592145516Sdarrenr n->ipn_next->ipn_pnext = n->ipn_pnext; 593145516Sdarrenr break; 594145516Sdarrenr } 595145516Sdarrenr } 596145516Sdarrenr 597145516Sdarrenr if (n == NULL) 598145516Sdarrenr return ENOENT; 599145516Sdarrenr 600145516Sdarrenr RADIX_NODE_HEAD_LOCK(ipo->ipo_head); 601145516Sdarrenr ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask, 602145516Sdarrenr ipo->ipo_head); 603145516Sdarrenr RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); 604145516Sdarrenr KFREE(n); 605145516Sdarrenr 606145516Sdarrenr ipoolstat.ipls_nodes--; 607145516Sdarrenr 608145516Sdarrenr return 0; 609145516Sdarrenr} 610145516Sdarrenr 611145516Sdarrenr 612145516Sdarrenr/* ------------------------------------------------------------------------ */ 613145516Sdarrenr/* Function: ip_pool_destroy */ 614145516Sdarrenr/* Returns: int - 0 = success, else error */ 615145516Sdarrenr/* Parameters: op(I) - information about the pool to remove */ 616145516Sdarrenr/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ 617145516Sdarrenr/* */ 618145516Sdarrenr/* Search for a pool using paramters passed in and if it's not otherwise */ 619145516Sdarrenr/* busy, free it. */ 620145516Sdarrenr/* */ 621145516Sdarrenr/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */ 622145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking */ 623145516Sdarrenr/* assertion that one of the two (ip_poolrw,ipf_global) is held. */ 624145516Sdarrenr/* ------------------------------------------------------------------------ */ 625145516Sdarrenrint ip_pool_destroy(op) 626145516Sdarrenriplookupop_t *op; 627145516Sdarrenr{ 628145516Sdarrenr ip_pool_t *ipo; 629145516Sdarrenr 630145516Sdarrenr ipo = ip_pool_find(op->iplo_unit, op->iplo_name); 631145516Sdarrenr if (ipo == NULL) 632145516Sdarrenr return ESRCH; 633145516Sdarrenr 634145516Sdarrenr if (ipo->ipo_ref != 1) 635145516Sdarrenr return EBUSY; 636145516Sdarrenr 637145516Sdarrenr ip_pool_free(ipo); 638145516Sdarrenr return 0; 639145516Sdarrenr} 640145516Sdarrenr 641145516Sdarrenr 642145516Sdarrenr/* ------------------------------------------------------------------------ */ 643145516Sdarrenr/* Function: ip_pool_flush */ 644145516Sdarrenr/* Returns: int - number of pools deleted */ 645145516Sdarrenr/* Parameters: fp(I) - which pool(s) to flush */ 646145516Sdarrenr/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ 647145516Sdarrenr/* */ 648145516Sdarrenr/* Free all pools associated with the device that matches the unit number */ 649145516Sdarrenr/* passed in with operation. */ 650145516Sdarrenr/* */ 651145516Sdarrenr/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */ 652145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking */ 653145516Sdarrenr/* assertion that one of the two (ip_poolrw,ipf_global) is held. */ 654145516Sdarrenr/* ------------------------------------------------------------------------ */ 655145516Sdarrenrint ip_pool_flush(fp) 656145516Sdarrenriplookupflush_t *fp; 657145516Sdarrenr{ 658145516Sdarrenr int i, num = 0, unit, err; 659145516Sdarrenr ip_pool_t *p, *q; 660145516Sdarrenr iplookupop_t op; 661145516Sdarrenr 662145516Sdarrenr unit = fp->iplf_unit; 663145516Sdarrenr 664145516Sdarrenr for (i = 0; i <= IPL_LOGMAX; i++) { 665145516Sdarrenr if (unit != IPLT_ALL && i != unit) 666145516Sdarrenr continue; 667145516Sdarrenr for (q = ip_pool_list[i]; (p = q) != NULL; ) { 668145516Sdarrenr op.iplo_unit = i; 669145516Sdarrenr (void)strncpy(op.iplo_name, p->ipo_name, 670145516Sdarrenr sizeof(op.iplo_name)); 671145516Sdarrenr q = p->ipo_next; 672145516Sdarrenr err = ip_pool_destroy(&op); 673145516Sdarrenr if (err == 0) 674145516Sdarrenr num++; 675145516Sdarrenr else 676145516Sdarrenr break; 677145516Sdarrenr } 678145516Sdarrenr } 679145516Sdarrenr return num; 680145516Sdarrenr} 681145516Sdarrenr 682145516Sdarrenr 683145516Sdarrenr/* ------------------------------------------------------------------------ */ 684145516Sdarrenr/* Function: ip_pool_free */ 685145516Sdarrenr/* Returns: void */ 686145516Sdarrenr/* Parameters: ipo(I) - pointer to pool structure */ 687145516Sdarrenr/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ 688145516Sdarrenr/* */ 689145516Sdarrenr/* Deletes the pool strucutre passed in from the list of pools and deletes */ 690145516Sdarrenr/* all of the address information stored in it, including any tree data */ 691145516Sdarrenr/* structures also allocated. */ 692145516Sdarrenr/* */ 693145516Sdarrenr/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */ 694145516Sdarrenr/* may not be initialised, we can't use an ASSERT to enforce the locking */ 695145516Sdarrenr/* assertion that one of the two (ip_poolrw,ipf_global) is held. */ 696145516Sdarrenr/* ------------------------------------------------------------------------ */ 697145516Sdarrenrvoid ip_pool_free(ipo) 698145516Sdarrenrip_pool_t *ipo; 699145516Sdarrenr{ 700145516Sdarrenr ip_pool_node_t *n; 701145516Sdarrenr 702145516Sdarrenr RADIX_NODE_HEAD_LOCK(ipo->ipo_head); 703145516Sdarrenr while ((n = ipo->ipo_list) != NULL) { 704145516Sdarrenr ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask, 705145516Sdarrenr ipo->ipo_head); 706145516Sdarrenr 707145516Sdarrenr *n->ipn_pnext = n->ipn_next; 708145516Sdarrenr if (n->ipn_next) 709145516Sdarrenr n->ipn_next->ipn_pnext = n->ipn_pnext; 710145516Sdarrenr 711145516Sdarrenr KFREE(n); 712145516Sdarrenr 713145516Sdarrenr ipoolstat.ipls_nodes--; 714145516Sdarrenr } 715145516Sdarrenr RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); 716145516Sdarrenr 717145516Sdarrenr ipo->ipo_list = NULL; 718145516Sdarrenr if (ipo->ipo_next != NULL) 719145516Sdarrenr ipo->ipo_next->ipo_pnext = ipo->ipo_pnext; 720145516Sdarrenr *ipo->ipo_pnext = ipo->ipo_next; 721145516Sdarrenr rn_freehead(ipo->ipo_head); 722145516Sdarrenr KFREE(ipo); 723145516Sdarrenr 724145516Sdarrenr ipoolstat.ipls_pools--; 725145516Sdarrenr} 726145516Sdarrenr 727145516Sdarrenr 728145516Sdarrenr/* ------------------------------------------------------------------------ */ 729145516Sdarrenr/* Function: ip_pool_deref */ 730145516Sdarrenr/* Returns: void */ 731145516Sdarrenr/* Parameters: ipo(I) - pointer to pool structure */ 732145516Sdarrenr/* Locks: WRITE(ip_poolrw) */ 733145516Sdarrenr/* */ 734145516Sdarrenr/* Drop the number of known references to this pool structure by one and if */ 735145516Sdarrenr/* we arrive at zero known references, free it. */ 736145516Sdarrenr/* ------------------------------------------------------------------------ */ 737145516Sdarrenrvoid ip_pool_deref(ipo) 738145516Sdarrenrip_pool_t *ipo; 739145516Sdarrenr{ 740145516Sdarrenr 741145516Sdarrenr ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); 742145516Sdarrenr 743145516Sdarrenr ipo->ipo_ref--; 744145516Sdarrenr if (ipo->ipo_ref == 0) 745145516Sdarrenr ip_pool_free(ipo); 746145516Sdarrenr} 747145516Sdarrenr 748145516Sdarrenr 749145516Sdarrenr# if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \ 750145516Sdarrenr !defined(__hpux) && !defined(__sgi)) 751145516Sdarrenrstatic int 752145516Sdarrenrrn_freenode(struct radix_node *n, void *p) 753145516Sdarrenr{ 754145516Sdarrenr struct radix_node_head *rnh = p; 755145516Sdarrenr struct radix_node *d; 756145516Sdarrenr 757145516Sdarrenr d = rnh->rnh_deladdr(n->rn_key, NULL, rnh); 758145516Sdarrenr if (d != NULL) { 759145516Sdarrenr FreeS(d, max_keylen + 2 * sizeof (*d)); 760145516Sdarrenr } 761145516Sdarrenr return 0; 762145516Sdarrenr} 763145516Sdarrenr 764145516Sdarrenr 765145516Sdarrenrvoid 766145516Sdarrenrrn_freehead(rnh) 767145516Sdarrenr struct radix_node_head *rnh; 768145516Sdarrenr{ 769145516Sdarrenr 770145516Sdarrenr RADIX_NODE_HEAD_LOCK(rnh); 771145516Sdarrenr (*rnh->rnh_walktree)(rnh, rn_freenode, rnh); 772145516Sdarrenr 773145516Sdarrenr rnh->rnh_addaddr = NULL; 774145516Sdarrenr rnh->rnh_deladdr = NULL; 775145516Sdarrenr rnh->rnh_matchaddr = NULL; 776145516Sdarrenr rnh->rnh_lookup = NULL; 777145516Sdarrenr rnh->rnh_walktree = NULL; 778145516Sdarrenr RADIX_NODE_HEAD_UNLOCK(rnh); 779145516Sdarrenr 780145516Sdarrenr Free(rnh); 781145516Sdarrenr} 782145516Sdarrenr# endif 783145516Sdarrenr 784145516Sdarrenr#endif /* IPFILTER_LOOKUP */ 785