1 1.6 christos /* $NetBSD: radix_ipf.c,v 1.6 2015/12/15 12:30:34 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (C) 2012 by Darren Reed. 5 1.1 christos * 6 1.1 christos * See the IPFILTER.LICENCE file for details on licencing. 7 1.1 christos */ 8 1.1 christos #include <sys/types.h> 9 1.1 christos #include <sys/time.h> 10 1.1 christos #include <sys/socket.h> 11 1.1 christos #include <sys/param.h> 12 1.1 christos #include <netinet/in.h> 13 1.1 christos #include <net/if.h> 14 1.1 christos #if !defined(_KERNEL) 15 1.1 christos # include <stddef.h> 16 1.1 christos # include <stdlib.h> 17 1.1 christos # include <strings.h> 18 1.1 christos # include <string.h> 19 1.1 christos #endif 20 1.1 christos #include "netinet/ip_compat.h" 21 1.1 christos #include "netinet/ip_fil.h" 22 1.1 christos #ifdef RDX_DEBUG 23 1.1 christos # include <arpa/inet.h> 24 1.1 christos # include <stdlib.h> 25 1.1 christos # include <stdio.h> 26 1.1 christos #endif 27 1.1 christos #include "netinet/radix_ipf.h" 28 1.1 christos 29 1.1 christos #define ADF_OFF offsetof(addrfamily_t, adf_addr) 30 1.2 christos #define ADF_OFF_BITS ((ADF_OFF << 3) & 0xffff) 31 1.1 christos 32 1.2 christos static ipf_rdx_node_t *ipf_rx_insert(ipf_rdx_head_t *, 33 1.2 christos ipf_rdx_node_t nodes[2], int *); 34 1.2 christos static void ipf_rx_attach_mask(ipf_rdx_node_t *, ipf_rdx_mask_t *); 35 1.2 christos static int count_mask_bits(addrfamily_t *, u_32_t **); 36 1.2 christos static void buildnodes(addrfamily_t *, addrfamily_t *, 37 1.2 christos ipf_rdx_node_t n[2]); 38 1.2 christos static ipf_rdx_node_t *ipf_rx_find_addr(ipf_rdx_node_t *, u_32_t *); 39 1.2 christos static ipf_rdx_node_t *ipf_rx_lookup(ipf_rdx_head_t *, addrfamily_t *, 40 1.2 christos addrfamily_t *); 41 1.2 christos static ipf_rdx_node_t *ipf_rx_match(ipf_rdx_head_t *, addrfamily_t *); 42 1.1 christos 43 1.1 christos /* 44 1.1 christos * Foreword. 45 1.1 christos * --------- 46 1.1 christos * The code in this file has been written to target using the addrfamily_t 47 1.1 christos * data structure to house the address information and no other. Thus there 48 1.1 christos * are certain aspects of thise code (such as offsets to the address itself) 49 1.1 christos * that are hard coded here whilst they might be more variable elsewhere. 50 1.1 christos * Similarly, this code enforces no maximum key length as that's implied by 51 1.1 christos * all keys needing to be stored in addrfamily_t. 52 1.1 christos */ 53 1.1 christos 54 1.1 christos /* ------------------------------------------------------------------------ */ 55 1.1 christos /* Function: count_mask_bits */ 56 1.1 christos /* Returns: number of consecutive bits starting at "mask". */ 57 1.1 christos /* */ 58 1.1 christos /* Count the number of bits set in the address section of addrfamily_t and */ 59 1.1 christos /* return both that number and a pointer to the last word with a bit set if */ 60 1.1 christos /* lastp is not NULL. The bit count is performed using network byte order */ 61 1.1 christos /* as the guide for which bit is the most significant bit. */ 62 1.1 christos /* ------------------------------------------------------------------------ */ 63 1.1 christos static int 64 1.2 christos count_mask_bits(addrfamily_t *mask, u_32_t **lastp) 65 1.1 christos { 66 1.1 christos u_32_t *mp = (u_32_t *)&mask->adf_addr; 67 1.1 christos u_32_t m; 68 1.1 christos int count = 0; 69 1.1 christos int mlen; 70 1.1 christos 71 1.1 christos mlen = mask->adf_len - offsetof(addrfamily_t, adf_addr); 72 1.3 darrenr for (; mlen > 0; mlen -= 4, mp++) { 73 1.1 christos if ((m = ntohl(*mp)) == 0) 74 1.1 christos break; 75 1.1 christos if (lastp != NULL) 76 1.1 christos *lastp = mp; 77 1.1 christos for (; m & 0x80000000; m <<= 1) 78 1.1 christos count++; 79 1.1 christos } 80 1.1 christos 81 1.1 christos return count; 82 1.1 christos } 83 1.1 christos 84 1.1 christos 85 1.1 christos /* ------------------------------------------------------------------------ */ 86 1.1 christos /* Function: buildnodes */ 87 1.1 christos /* Returns: Nil */ 88 1.1 christos /* Parameters: addr(I) - network address for this radix node */ 89 1.1 christos /* mask(I) - netmask associated with the above address */ 90 1.1 christos /* nodes(O) - pair of ipf_rdx_node_t's to initialise with data */ 91 1.1 christos /* associated with addr and mask. */ 92 1.1 christos /* */ 93 1.1 christos /* Initialise the fields in a pair of radix tree nodes according to the */ 94 1.1 christos /* data supplied in the paramters "addr" and "mask". It is expected that */ 95 1.1 christos /* "mask" will contain a consecutive string of bits set. Masks with gaps in */ 96 1.1 christos /* the middle are not handled by this implementation. */ 97 1.1 christos /* ------------------------------------------------------------------------ */ 98 1.1 christos static void 99 1.2 christos buildnodes(addrfamily_t *addr, addrfamily_t *mask, ipf_rdx_node_t nodes[2]) 100 1.1 christos { 101 1.1 christos u_32_t maskbits; 102 1.1 christos u_32_t lastmask; 103 1.1 christos u_32_t *last; 104 1.1 christos int masklen; 105 1.1 christos 106 1.1 christos last = NULL; 107 1.1 christos maskbits = count_mask_bits(mask, &last); 108 1.1 christos if (last == NULL) { 109 1.1 christos masklen = 0; 110 1.1 christos lastmask = 0; 111 1.1 christos } else { 112 1.1 christos masklen = last - (u_32_t *)mask; 113 1.1 christos lastmask = *last; 114 1.1 christos } 115 1.1 christos 116 1.1 christos bzero(&nodes[0], sizeof(ipf_rdx_node_t) * 2); 117 1.1 christos nodes[0].maskbitcount = maskbits; 118 1.1 christos nodes[0].index = -1 - (ADF_OFF_BITS + maskbits); 119 1.1 christos nodes[0].addrkey = (u_32_t *)addr; 120 1.1 christos nodes[0].maskkey = (u_32_t *)mask; 121 1.1 christos nodes[0].addroff = nodes[0].addrkey + masklen; 122 1.1 christos nodes[0].maskoff = nodes[0].maskkey + masklen; 123 1.1 christos nodes[0].parent = &nodes[1]; 124 1.1 christos nodes[0].offset = masklen; 125 1.1 christos nodes[0].lastmask = lastmask; 126 1.1 christos nodes[1].offset = masklen; 127 1.1 christos nodes[1].left = &nodes[0]; 128 1.1 christos nodes[1].maskbitcount = maskbits; 129 1.1 christos #ifdef RDX_DEBUG 130 1.1 christos (void) strcpy(nodes[0].name, "_BUILD.0"); 131 1.1 christos (void) strcpy(nodes[1].name, "_BUILD.1"); 132 1.1 christos #endif 133 1.1 christos } 134 1.1 christos 135 1.1 christos 136 1.1 christos /* ------------------------------------------------------------------------ */ 137 1.1 christos /* Function: ipf_rx_find_addr */ 138 1.1 christos /* Returns: ipf_rdx_node_t * - pointer to a node in the radix tree. */ 139 1.1 christos /* Parameters: tree(I) - pointer to first right node in tree to search */ 140 1.1 christos /* addr(I) - pointer to address to match */ 141 1.1 christos /* */ 142 1.1 christos /* Walk the radix tree given by "tree", looking for a leaf node that is a */ 143 1.1 christos /* match for the address given by "addr". */ 144 1.1 christos /* ------------------------------------------------------------------------ */ 145 1.1 christos static ipf_rdx_node_t * 146 1.2 christos ipf_rx_find_addr(ipf_rdx_node_t *tree, u_32_t *addr) 147 1.1 christos { 148 1.1 christos ipf_rdx_node_t *cur; 149 1.1 christos 150 1.1 christos for (cur = tree; cur->index >= 0;) { 151 1.1 christos if (cur->bitmask & addr[cur->offset]) { 152 1.1 christos cur = cur->right; 153 1.1 christos } else { 154 1.1 christos cur = cur->left; 155 1.1 christos } 156 1.1 christos } 157 1.1 christos 158 1.1 christos return (cur); 159 1.1 christos } 160 1.1 christos 161 1.1 christos 162 1.1 christos /* ------------------------------------------------------------------------ */ 163 1.1 christos /* Function: ipf_rx_match */ 164 1.1 christos /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */ 165 1.1 christos /* added to the tree. */ 166 1.1 christos /* Paramters: head(I) - pointer to tree head to search */ 167 1.1 christos /* addr(I) - pointer to address to find */ 168 1.1 christos /* */ 169 1.1 christos /* Search the radix tree for the best match to the address pointed to by */ 170 1.1 christos /* "addr" and return a pointer to that node. This search will not match the */ 171 1.1 christos /* address information stored in either of the root leaves as neither of */ 172 1.1 christos /* them are considered to be part of the tree of data being stored. */ 173 1.1 christos /* ------------------------------------------------------------------------ */ 174 1.1 christos static ipf_rdx_node_t * 175 1.2 christos ipf_rx_match(ipf_rdx_head_t *head, addrfamily_t *addr) 176 1.1 christos { 177 1.1 christos ipf_rdx_mask_t *masknode; 178 1.1 christos ipf_rdx_node_t *prev; 179 1.1 christos ipf_rdx_node_t *node; 180 1.1 christos ipf_rdx_node_t *cur; 181 1.1 christos u_32_t *data; 182 1.1 christos u_32_t *mask; 183 1.1 christos u_32_t *key; 184 1.1 christos u_32_t *end; 185 1.1 christos int len; 186 1.1 christos int i; 187 1.1 christos 188 1.1 christos len = addr->adf_len; 189 1.1 christos end = (u_32_t *)((u_char *)addr + len); 190 1.1 christos node = ipf_rx_find_addr(head->root, (u_32_t *)addr); 191 1.1 christos 192 1.1 christos /* 193 1.1 christos * Search the dupkey list for a potential match. 194 1.1 christos */ 195 1.1 christos for (cur = node; (cur != NULL) && (cur->root == 0); cur = cur->dupkey) { 196 1.3 darrenr i = cur[0].addroff - cur[0].addrkey; 197 1.3 darrenr data = cur[0].addrkey + i; 198 1.3 darrenr mask = cur[0].maskkey + i; 199 1.3 darrenr key = (u_32_t *)addr + i; 200 1.1 christos for (; key < end; data++, key++, mask++) 201 1.1 christos if ((*key & *mask) != *data) 202 1.1 christos break; 203 1.1 christos if ((end == key) && (cur->root == 0)) 204 1.1 christos return (cur); /* Equal keys */ 205 1.1 christos } 206 1.1 christos prev = node->parent; 207 1.1 christos key = (u_32_t *)addr; 208 1.1 christos 209 1.1 christos for (node = prev; node->root == 0; node = node->parent) { 210 1.1 christos /* 211 1.1 christos * We know that the node hasn't matched so therefore only 212 1.1 christos * the entries in the mask list are searched, not the top 213 1.1 christos * node nor the dupkey list. 214 1.1 christos */ 215 1.1 christos masknode = node->masks; 216 1.1 christos for (; masknode != NULL; masknode = masknode->next) { 217 1.1 christos if (masknode->maskbitcount > node->maskbitcount) 218 1.1 christos continue; 219 1.1 christos cur = masknode->node; 220 1.1 christos for (i = ADF_OFF >> 2; i <= node->offset; i++) { 221 1.1 christos if ((key[i] & masknode->mask[i]) == 222 1.1 christos cur->addrkey[i]) 223 1.1 christos return (cur); 224 1.1 christos } 225 1.1 christos } 226 1.1 christos } 227 1.1 christos 228 1.1 christos return NULL; 229 1.1 christos } 230 1.1 christos 231 1.1 christos 232 1.1 christos /* ------------------------------------------------------------------------ */ 233 1.1 christos /* Function: ipf_rx_lookup */ 234 1.1 christos /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */ 235 1.1 christos /* added to the tree. */ 236 1.1 christos /* Paramters: head(I) - pointer to tree head to search */ 237 1.1 christos /* addr(I) - address part of the key to match */ 238 1.1 christos /* mask(I) - netmask part of the key to match */ 239 1.1 christos /* */ 240 1.1 christos /* ipf_rx_lookup searches for an exact match on (addr,mask). The intention */ 241 1.1 christos /* is to see if a given key is in the tree, not to see if a route exists. */ 242 1.1 christos /* ------------------------------------------------------------------------ */ 243 1.1 christos ipf_rdx_node_t * 244 1.2 christos ipf_rx_lookup(ipf_rdx_head_t *head, addrfamily_t *addr, addrfamily_t *mask) 245 1.1 christos { 246 1.1 christos ipf_rdx_node_t *found; 247 1.1 christos ipf_rdx_node_t *node; 248 1.1 christos u_32_t *akey; 249 1.1 christos int count; 250 1.1 christos 251 1.1 christos found = ipf_rx_find_addr(head->root, (u_32_t *)addr); 252 1.1 christos if (found->root == 1) 253 1.1 christos return NULL; 254 1.1 christos 255 1.1 christos /* 256 1.1 christos * It is possible to find a matching address in the tree but for the 257 1.1 christos * netmask to not match. If the netmask does not match and there is 258 1.1 christos * no list of alternatives present at dupkey, return a failure. 259 1.1 christos */ 260 1.1 christos count = count_mask_bits(mask, NULL); 261 1.1 christos if (count != found->maskbitcount && found->dupkey == NULL) 262 1.1 christos return (NULL); 263 1.1 christos 264 1.1 christos akey = (u_32_t *)addr; 265 1.1 christos if ((found->addrkey[found->offset] & found->maskkey[found->offset]) != 266 1.1 christos akey[found->offset]) 267 1.1 christos return NULL; 268 1.1 christos 269 1.1 christos if (found->dupkey != NULL) { 270 1.1 christos node = found; 271 1.1 christos while (node != NULL && node->maskbitcount != count) 272 1.1 christos node = node->dupkey; 273 1.1 christos if (node == NULL) 274 1.1 christos return (NULL); 275 1.1 christos found = node; 276 1.1 christos } 277 1.1 christos return found; 278 1.1 christos } 279 1.1 christos 280 1.1 christos 281 1.1 christos /* ------------------------------------------------------------------------ */ 282 1.1 christos /* Function: ipf_rx_attach_mask */ 283 1.1 christos /* Returns: Nil */ 284 1.1 christos /* Parameters: node(I) - pointer to a radix tree node */ 285 1.1 christos /* mask(I) - pointer to mask structure to add */ 286 1.1 christos /* */ 287 1.1 christos /* Add the netmask to the given node in an ordering where the most specific */ 288 1.1 christos /* netmask is at the top of the list. */ 289 1.1 christos /* ------------------------------------------------------------------------ */ 290 1.1 christos static void 291 1.2 christos ipf_rx_attach_mask(ipf_rdx_node_t *node, ipf_rdx_mask_t *mask) 292 1.1 christos { 293 1.1 christos ipf_rdx_mask_t **pm; 294 1.1 christos ipf_rdx_mask_t *m; 295 1.1 christos 296 1.1 christos for (pm = &node->masks; (m = *pm) != NULL; pm = &m->next) 297 1.1 christos if (m->maskbitcount < mask->maskbitcount) 298 1.1 christos break; 299 1.1 christos mask->next = *pm; 300 1.1 christos *pm = mask; 301 1.1 christos } 302 1.1 christos 303 1.1 christos 304 1.1 christos /* ------------------------------------------------------------------------ */ 305 1.1 christos /* Function: ipf_rx_insert */ 306 1.1 christos /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */ 307 1.1 christos /* added to the tree. */ 308 1.1 christos /* Paramters: head(I) - pointer to tree head to add nodes to */ 309 1.1 christos /* nodes(I) - pointer to radix nodes to be added */ 310 1.1 christos /* dup(O) - set to 1 if node is a duplicate, else 0. */ 311 1.1 christos /* */ 312 1.1 christos /* Add the new radix tree entry that owns nodes[] to the tree given by head.*/ 313 1.1 christos /* If there is already a matching key in the table, "dup" will be set to 1 */ 314 1.1 christos /* and the existing node pointer returned if there is a complete key match. */ 315 1.1 christos /* A complete key match is a matching of all key data that is presented by */ 316 1.1 christos /* by the netmask. */ 317 1.1 christos /* ------------------------------------------------------------------------ */ 318 1.1 christos static ipf_rdx_node_t * 319 1.2 christos ipf_rx_insert(ipf_rdx_head_t *head, ipf_rdx_node_t nodes[2], int *dup) 320 1.1 christos { 321 1.1 christos ipf_rdx_mask_t **pmask; 322 1.1 christos ipf_rdx_node_t *node; 323 1.1 christos ipf_rdx_node_t *prev; 324 1.1 christos ipf_rdx_mask_t *mask; 325 1.1 christos ipf_rdx_node_t *cur; 326 1.1 christos u_32_t nodemask; 327 1.1 christos u_32_t *addr; 328 1.1 christos u_32_t *data; 329 1.1 christos int nodebits; 330 1.1 christos u_32_t *key; 331 1.1 christos u_32_t *end; 332 1.1 christos u_32_t bits; 333 1.1 christos int nodekey; 334 1.1 christos int nodeoff; 335 1.1 christos int nlen; 336 1.1 christos int len; 337 1.1 christos 338 1.1 christos addr = nodes[0].addrkey; 339 1.1 christos 340 1.1 christos node = ipf_rx_find_addr(head->root, addr); 341 1.1 christos len = ((addrfamily_t *)addr)->adf_len; 342 1.1 christos key = (u_32_t *)&((addrfamily_t *)addr)->adf_addr; 343 1.1 christos data= (u_32_t *)&((addrfamily_t *)node->addrkey)->adf_addr; 344 1.1 christos end = (u_32_t *)((u_char *)addr + len); 345 1.3 darrenr for (nlen = 0; key < end; data++, key++, nlen += 32) 346 1.1 christos if (*key != *data) 347 1.1 christos break; 348 1.1 christos if (end == data) { 349 1.1 christos *dup = 1; 350 1.1 christos return (node); /* Equal keys */ 351 1.1 christos } 352 1.1 christos *dup = 0; 353 1.1 christos 354 1.1 christos bits = (ntohl(*data) ^ ntohl(*key)); 355 1.3 darrenr for (; bits != 0; nlen++) { 356 1.1 christos if ((bits & 0x80000000) != 0) 357 1.1 christos break; 358 1.1 christos bits <<= 1; 359 1.1 christos } 360 1.1 christos nlen += ADF_OFF_BITS; 361 1.1 christos nodes[1].index = nlen; 362 1.1 christos nodes[1].bitmask = htonl(0x80000000 >> (nlen & 0x1f)); 363 1.3 darrenr nodes[0].offset = nlen / 32; 364 1.3 darrenr nodes[1].offset = nlen / 32; 365 1.1 christos 366 1.1 christos /* 367 1.1 christos * Walk through the tree and look for the correct place to attach 368 1.1 christos * this node. ipf_rx_fin_addr is not used here because the place 369 1.1 christos * to attach this node may be an internal node (same key, different 370 1.1 christos * netmask.) Additionally, the depth of the search is forcibly limited 371 1.1 christos * here to not exceed the netmask, so that a short netmask will be 372 1.1 christos * added higher up the tree even if there are lower branches. 373 1.1 christos */ 374 1.1 christos cur = head->root; 375 1.1 christos key = nodes[0].addrkey; 376 1.1 christos do { 377 1.1 christos prev = cur; 378 1.1 christos if (key[cur->offset] & cur->bitmask) { 379 1.1 christos cur = cur->right; 380 1.1 christos } else { 381 1.1 christos cur = cur->left; 382 1.1 christos } 383 1.1 christos } while (nlen > (unsigned)cur->index); 384 1.1 christos 385 1.1 christos if ((key[prev->offset] & prev->bitmask) == 0) { 386 1.1 christos prev->left = &nodes[1]; 387 1.1 christos } else { 388 1.1 christos prev->right = &nodes[1]; 389 1.1 christos } 390 1.1 christos cur->parent = &nodes[1]; 391 1.1 christos nodes[1].parent = prev; 392 1.3 darrenr if ((key[nodes[1].offset] & nodes[1].bitmask) == 0) { 393 1.1 christos nodes[1].right = cur; 394 1.1 christos } else { 395 1.1 christos nodes[1].right = &nodes[0]; 396 1.1 christos nodes[1].left = cur; 397 1.1 christos } 398 1.1 christos 399 1.1 christos nodeoff = nodes[0].offset; 400 1.1 christos nodekey = nodes[0].addrkey[nodeoff]; 401 1.1 christos nodemask = nodes[0].lastmask; 402 1.1 christos nodebits = nodes[0].maskbitcount; 403 1.1 christos prev = NULL; 404 1.1 christos /* 405 1.1 christos * Find the node up the tree with the largest pattern that still 406 1.1 christos * matches the node being inserted to see if this mask can be 407 1.1 christos * moved there. 408 1.1 christos */ 409 1.1 christos for (cur = nodes[1].parent; cur->root == 0; cur = cur->parent) { 410 1.1 christos if (cur->maskbitcount <= nodebits) 411 1.1 christos break; 412 1.1 christos if (((cur - 1)->addrkey[nodeoff] & nodemask) != nodekey) 413 1.1 christos break; 414 1.1 christos prev = cur; 415 1.1 christos } 416 1.1 christos 417 1.1 christos KMALLOC(mask, ipf_rdx_mask_t *); 418 1.1 christos if (mask == NULL) 419 1.1 christos return NULL; 420 1.1 christos bzero(mask, sizeof(*mask)); 421 1.1 christos mask->next = NULL; 422 1.1 christos mask->node = &nodes[0]; 423 1.1 christos mask->maskbitcount = nodebits; 424 1.1 christos mask->mask = nodes[0].maskkey; 425 1.1 christos nodes[0].mymask = mask; 426 1.1 christos 427 1.1 christos if (prev != NULL) { 428 1.1 christos ipf_rdx_mask_t *m; 429 1.1 christos 430 1.1 christos for (pmask = &prev->masks; (m = *pmask) != NULL; 431 1.1 christos pmask = &m->next) { 432 1.1 christos if (m->maskbitcount < nodebits) 433 1.1 christos break; 434 1.1 christos } 435 1.1 christos } else { 436 1.1 christos /* 437 1.1 christos * No higher up nodes qualify, so attach mask locally. 438 1.1 christos */ 439 1.1 christos pmask = &nodes[0].masks; 440 1.1 christos } 441 1.1 christos mask->next = *pmask; 442 1.1 christos *pmask = mask; 443 1.1 christos 444 1.1 christos /* 445 1.1 christos * Search the mask list on each child to see if there are any masks 446 1.1 christos * there that can be moved up to this newly inserted node. 447 1.1 christos */ 448 1.1 christos cur = nodes[1].right; 449 1.1 christos if (cur->root == 0) { 450 1.1 christos for (pmask = &cur->masks; (mask = *pmask) != NULL; ) { 451 1.1 christos if (mask->maskbitcount < nodebits) { 452 1.1 christos *pmask = mask->next; 453 1.1 christos ipf_rx_attach_mask(&nodes[0], mask); 454 1.1 christos } else { 455 1.1 christos pmask = &mask->next; 456 1.1 christos } 457 1.1 christos } 458 1.1 christos } 459 1.1 christos cur = nodes[1].left; 460 1.1 christos if (cur->root == 0 && cur != &nodes[0]) { 461 1.1 christos for (pmask = &cur->masks; (mask = *pmask) != NULL; ) { 462 1.1 christos if (mask->maskbitcount < nodebits) { 463 1.1 christos *pmask = mask->next; 464 1.1 christos ipf_rx_attach_mask(&nodes[0], mask); 465 1.1 christos } else { 466 1.1 christos pmask = &mask->next; 467 1.1 christos } 468 1.1 christos } 469 1.1 christos } 470 1.1 christos return (&nodes[0]); 471 1.1 christos } 472 1.1 christos 473 1.1 christos /* ------------------------------------------------------------------------ */ 474 1.1 christos /* Function: ipf_rx_addroute */ 475 1.1 christos /* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */ 476 1.1 christos /* added to the tree. */ 477 1.1 christos /* Paramters: head(I) - pointer to tree head to search */ 478 1.1 christos /* addr(I) - address portion of "route" to add */ 479 1.1 christos /* mask(I) - netmask portion of "route" to add */ 480 1.1 christos /* nodes(I) - radix tree data nodes inside allocate structure */ 481 1.1 christos /* */ 482 1.1 christos /* Attempt to add a node to the radix tree. The key for the node is the */ 483 1.1 christos /* (addr,mask). No memory allocation for the radix nodes themselves is */ 484 1.1 christos /* performed here, the data structure that this radix node is being used to */ 485 1.1 christos /* find is expected to house the node data itself however the call to */ 486 1.1 christos /* ipf_rx_insert() will attempt to allocate memory in order for netmask to */ 487 1.1 christos /* be promoted further up the tree. */ 488 1.1 christos /* In this case, the ip_pool_node_t structure from ip_pool.h contains both */ 489 1.1 christos /* the key material (addr,mask) and the radix tree nodes[]. */ 490 1.1 christos /* */ 491 1.1 christos /* The mechanics of inserting the node into the tree is handled by the */ 492 1.1 christos /* function ipf_rx_insert() above. Here, the code deals with the case */ 493 1.1 christos /* where the data to be inserted is a duplicate. */ 494 1.1 christos /* ------------------------------------------------------------------------ */ 495 1.1 christos ipf_rdx_node_t * 496 1.2 christos ipf_rx_addroute(ipf_rdx_head_t *head, addrfamily_t *addr, addrfamily_t *mask, 497 1.2 christos ipf_rdx_node_t *nodes) 498 1.1 christos { 499 1.1 christos ipf_rdx_node_t *node; 500 1.1 christos ipf_rdx_node_t *prev; 501 1.1 christos ipf_rdx_node_t *x; 502 1.1 christos int dup; 503 1.1 christos 504 1.1 christos buildnodes(addr, mask, nodes); 505 1.1 christos x = ipf_rx_insert(head, nodes, &dup); 506 1.1 christos if (x == NULL) 507 1.1 christos return NULL; 508 1.1 christos 509 1.1 christos if (dup == 1) { 510 1.1 christos node = &nodes[0]; 511 1.1 christos prev = NULL; 512 1.1 christos /* 513 1.1 christos * The duplicate list is kept sorted with the longest 514 1.1 christos * mask at the top, meaning that the most specific entry 515 1.1 christos * in the listis found first. This list thus allows for 516 1.1 christos * duplicates such as 128.128.0.0/32 and 128.128.0.0/16. 517 1.1 christos */ 518 1.1 christos while ((x != NULL) && (x->maskbitcount > node->maskbitcount)) { 519 1.1 christos prev = x; 520 1.1 christos x = x->dupkey; 521 1.1 christos } 522 1.1 christos 523 1.1 christos /* 524 1.1 christos * Is it a complete duplicate? If so, return NULL and 525 1.1 christos * fail the insert. Otherwise, insert it into the list 526 1.1 christos * of netmasks active for this key. 527 1.1 christos */ 528 1.1 christos if ((x != NULL) && (x->maskbitcount == node->maskbitcount)) 529 1.1 christos return (NULL); 530 1.1 christos 531 1.1 christos if (prev != NULL) { 532 1.1 christos nodes[0].dupkey = x; 533 1.1 christos prev->dupkey = &nodes[0]; 534 1.1 christos nodes[0].parent = prev; 535 1.1 christos if (x != NULL) 536 1.1 christos x->parent = &nodes[0]; 537 1.1 christos } else { 538 1.1 christos nodes[0].dupkey = x->dupkey; 539 1.1 christos prev = x->parent; 540 1.1 christos nodes[0].parent = prev; 541 1.1 christos x->parent = &nodes[0]; 542 1.1 christos if (prev->left == x) 543 1.1 christos prev->left = &nodes[0]; 544 1.1 christos else 545 1.1 christos prev->right = &nodes[0]; 546 1.1 christos } 547 1.1 christos } 548 1.1 christos 549 1.1 christos return &nodes[0]; 550 1.1 christos } 551 1.1 christos 552 1.1 christos 553 1.1 christos /* ------------------------------------------------------------------------ */ 554 1.1 christos /* Function: ipf_rx_delete */ 555 1.1 christos /* Returns: ipf_rdx_node_t * - NULL on error, else node removed from */ 556 1.1 christos /* the tree. */ 557 1.1 christos /* Paramters: head(I) - pointer to tree head to search */ 558 1.1 christos /* addr(I) - pointer to the address part of the key */ 559 1.1 christos /* mask(I) - pointer to the netmask part of the key */ 560 1.1 christos /* */ 561 1.1 christos /* Search for an entry in the radix tree that is an exact match for (addr, */ 562 1.1 christos /* mask) and remove it if it exists. In the case where (addr,mask) is a not */ 563 1.1 christos /* a unique key, the tree structure itself is not changed - only the list */ 564 1.1 christos /* of duplicate keys. */ 565 1.1 christos /* ------------------------------------------------------------------------ */ 566 1.1 christos ipf_rdx_node_t * 567 1.2 christos ipf_rx_delete(ipf_rdx_head_t *head, addrfamily_t *addr, addrfamily_t *mask) 568 1.1 christos { 569 1.1 christos ipf_rdx_mask_t **pmask; 570 1.1 christos ipf_rdx_node_t *parent; 571 1.1 christos ipf_rdx_node_t *found; 572 1.1 christos ipf_rdx_node_t *prev; 573 1.1 christos ipf_rdx_node_t *node; 574 1.1 christos ipf_rdx_node_t *cur; 575 1.1 christos ipf_rdx_mask_t *m; 576 1.1 christos int count; 577 1.1 christos 578 1.1 christos found = ipf_rx_find_addr(head->root, (u_32_t *)addr); 579 1.3 darrenr if (found == NULL) 580 1.3 darrenr return NULL; 581 1.1 christos if (found->root == 1) 582 1.1 christos return NULL; 583 1.1 christos count = count_mask_bits(mask, NULL); 584 1.1 christos parent = found->parent; 585 1.1 christos if (found->dupkey != NULL) { 586 1.1 christos node = found; 587 1.1 christos while (node != NULL && node->maskbitcount != count) 588 1.1 christos node = node->dupkey; 589 1.1 christos if (node == NULL) 590 1.1 christos return (NULL); 591 1.1 christos if (node != found) { 592 1.1 christos /* 593 1.1 christos * Remove from the dupkey list. Here, "parent" is 594 1.1 christos * the previous node on the list (rather than tree) 595 1.1 christos * and "dupkey" is the next node on the list. 596 1.1 christos */ 597 1.1 christos parent = node->parent; 598 1.1 christos parent->dupkey = node->dupkey; 599 1.1 christos node->dupkey->parent = parent; 600 1.1 christos } else { 601 1.1 christos /* 602 1.1 christos * 603 1.1 christos * When removing the top node of the dupkey list, 604 1.1 christos * the pointers at the top of the list that point 605 1.1 christos * to other tree nodes need to be preserved and 606 1.1 christos * any children must have their parent updated. 607 1.1 christos */ 608 1.1 christos node = node->dupkey; 609 1.1 christos node->parent = found->parent; 610 1.1 christos node->right = found->right; 611 1.1 christos node->left = found->left; 612 1.1 christos found->right->parent = node; 613 1.1 christos found->left->parent = node; 614 1.1 christos if (parent->left == found) 615 1.1 christos parent->left = node; 616 1.1 christos else 617 1.1 christos parent->right= node; 618 1.1 christos } 619 1.1 christos } else { 620 1.1 christos if (count != found->maskbitcount) 621 1.1 christos return (NULL); 622 1.1 christos /* 623 1.1 christos * Remove the node from the tree and reconnect the subtree 624 1.1 christos * below. 625 1.1 christos */ 626 1.1 christos /* 627 1.1 christos * If there is a tree to the left, look for something to 628 1.1 christos * attach in place of "found". 629 1.1 christos */ 630 1.1 christos prev = found + 1; 631 1.3 darrenr cur = parent->parent; 632 1.1 christos if (parent != found + 1) { 633 1.3 darrenr if ((found + 1)->parent->right == found + 1) 634 1.3 darrenr (found + 1)->parent->right = parent; 635 1.3 darrenr else 636 1.3 darrenr (found + 1)->parent->left = parent; 637 1.1 christos if (cur->right == parent) { 638 1.3 darrenr if (parent->left == found) { 639 1.3 darrenr cur->right = parent->right; 640 1.3 darrenr } else if (parent->left != parent - 1) { 641 1.3 darrenr cur->right = parent->left; 642 1.3 darrenr } else { 643 1.3 darrenr cur->right = parent - 1; 644 1.1 christos } 645 1.3 darrenr cur->right->parent = cur; 646 1.3 darrenr } else { 647 1.3 darrenr if (parent->right == found) { 648 1.3 darrenr cur->left = parent->left; 649 1.3 darrenr } else if (parent->right != parent - 1) { 650 1.3 darrenr cur->left = parent->right; 651 1.1 christos } else { 652 1.3 darrenr cur->left = parent - 1; 653 1.1 christos } 654 1.3 darrenr cur->left->parent = cur; 655 1.3 darrenr } 656 1.3 darrenr parent->left = (found + 1)->left; 657 1.3 darrenr if ((found + 1)->right != parent) 658 1.3 darrenr parent->right = (found + 1)->right; 659 1.3 darrenr parent->left->parent = parent; 660 1.3 darrenr parent->right->parent = parent; 661 1.3 darrenr parent->parent = (found + 1)->parent; 662 1.1 christos 663 1.1 christos parent->bitmask = prev->bitmask; 664 1.1 christos parent->offset = prev->offset; 665 1.1 christos parent->index = prev->index; 666 1.1 christos } else { 667 1.1 christos /* 668 1.1 christos * We found an edge node. 669 1.1 christos */ 670 1.1 christos cur = parent->parent; 671 1.1 christos if (cur->left == parent) { 672 1.1 christos if (parent->left == found) { 673 1.1 christos cur->left = parent->right; 674 1.1 christos parent->right->parent = cur; 675 1.1 christos } else { 676 1.1 christos cur->left = parent->left; 677 1.1 christos parent->left->parent = cur; 678 1.1 christos } 679 1.1 christos } else { 680 1.1 christos if (parent->right != found) { 681 1.1 christos cur->right = parent->right; 682 1.1 christos parent->right->parent = cur; 683 1.1 christos } else { 684 1.1 christos cur->right = parent->left; 685 1.1 christos prev->left->parent = cur; 686 1.1 christos } 687 1.1 christos } 688 1.1 christos } 689 1.1 christos } 690 1.1 christos 691 1.1 christos /* 692 1.1 christos * Remove mask associated with this node. 693 1.1 christos */ 694 1.1 christos for (cur = parent; cur->root == 0; cur = cur->parent) { 695 1.1 christos ipf_rdx_mask_t **pm; 696 1.1 christos 697 1.1 christos if (cur->maskbitcount <= found->maskbitcount) 698 1.1 christos break; 699 1.1 christos if (((cur - 1)->addrkey[found->offset] & found->bitmask) != 700 1.1 christos found->addrkey[found->offset]) 701 1.1 christos break; 702 1.1 christos for (pm = &cur->masks; (m = *pm) != NULL; ) 703 1.1 christos if (m->node == cur) { 704 1.1 christos *pm = m->next; 705 1.1 christos break; 706 1.1 christos } else { 707 1.1 christos pm = &m->next; 708 1.1 christos } 709 1.1 christos } 710 1.1 christos KFREE(found->mymask); 711 1.1 christos 712 1.1 christos /* 713 1.1 christos * Masks that have been brought up to this node from below need to 714 1.1 christos * be sent back down. 715 1.1 christos */ 716 1.1 christos for (pmask = &parent->masks; (m = *pmask) != NULL; ) { 717 1.1 christos *pmask = m->next; 718 1.1 christos cur = m->node; 719 1.1 christos if (cur == found) 720 1.1 christos continue; 721 1.1 christos if (found->addrkey[cur->offset] & cur->lastmask) { 722 1.1 christos ipf_rx_attach_mask(parent->right, m); 723 1.1 christos } else if (parent->left != found) { 724 1.1 christos ipf_rx_attach_mask(parent->left, m); 725 1.1 christos } 726 1.1 christos } 727 1.1 christos 728 1.1 christos return (found); 729 1.1 christos } 730 1.1 christos 731 1.1 christos 732 1.1 christos /* ------------------------------------------------------------------------ */ 733 1.1 christos /* Function: ipf_rx_walktree */ 734 1.1 christos /* Returns: Nil */ 735 1.1 christos /* Paramters: head(I) - pointer to tree head to search */ 736 1.1 christos /* walker(I) - function to call for each node in the tree */ 737 1.1 christos /* arg(I) - parameter to pass to walker, in addition to the */ 738 1.1 christos /* node pointer */ 739 1.1 christos /* */ 740 1.1 christos /* A standard tree walking function except that it is iterative, rather */ 741 1.1 christos /* than recursive and tracks the next node in case the "walker" function */ 742 1.1 christos /* should happen to delete and free the current node. It thus goes without */ 743 1.1 christos /* saying that the "walker" function is not permitted to cause any change */ 744 1.1 christos /* in the validity of the data found at either the left or right child. */ 745 1.1 christos /* ------------------------------------------------------------------------ */ 746 1.1 christos void 747 1.2 christos ipf_rx_walktree(ipf_rdx_head_t *head, radix_walk_func_t walker, void *arg) 748 1.1 christos { 749 1.1 christos ipf_rdx_node_t *next; 750 1.1 christos ipf_rdx_node_t *node = head->root; 751 1.1 christos ipf_rdx_node_t *base; 752 1.1 christos 753 1.1 christos while (node->index >= 0) 754 1.1 christos node = node->left; 755 1.1 christos 756 1.1 christos for (;;) { 757 1.1 christos base = node; 758 1.1 christos while ((node->parent->right == node) && (node->root == 0)) 759 1.1 christos node = node->parent; 760 1.1 christos 761 1.1 christos for (node = node->parent->right; node->index >= 0; ) 762 1.1 christos node = node->left; 763 1.1 christos next = node; 764 1.1 christos 765 1.1 christos for (node = base; node != NULL; node = base) { 766 1.1 christos base = node->dupkey; 767 1.1 christos if (node->root == 0) 768 1.1 christos walker(node, arg); 769 1.1 christos } 770 1.1 christos node = next; 771 1.1 christos if (node->root) 772 1.1 christos return; 773 1.1 christos } 774 1.1 christos } 775 1.1 christos 776 1.1 christos 777 1.1 christos /* ------------------------------------------------------------------------ */ 778 1.1 christos /* Function: ipf_rx_inithead */ 779 1.1 christos /* Returns: int - 0 = success, else failure */ 780 1.1 christos /* Paramters: softr(I) - pointer to radix context */ 781 1.1 christos /* headp(O) - location for where to store allocated tree head */ 782 1.1 christos /* */ 783 1.1 christos /* This function allocates and initialises a radix tree head structure. */ 784 1.1 christos /* As a traditional radix tree, node 0 is used as the "0" sentinel and node */ 785 1.1 christos /* "2" is used as the all ones sentinel, leaving node "1" as the root from */ 786 1.1 christos /* which the tree is hung with node "0" on its left and node "2" to the */ 787 1.1 christos /* right. The context, "softr", is used here to provide a common source of */ 788 1.1 christos /* the zeroes and ones data rather than have one per head. */ 789 1.1 christos /* ------------------------------------------------------------------------ */ 790 1.1 christos int 791 1.2 christos ipf_rx_inithead(radix_softc_t *softr, ipf_rdx_head_t **headp) 792 1.1 christos { 793 1.1 christos ipf_rdx_head_t *ptr; 794 1.1 christos ipf_rdx_node_t *node; 795 1.1 christos 796 1.1 christos KMALLOC(ptr, ipf_rdx_head_t *); 797 1.1 christos *headp = ptr; 798 1.1 christos if (ptr == NULL) 799 1.1 christos return -1; 800 1.1 christos bzero(ptr, sizeof(*ptr)); 801 1.1 christos node = ptr->nodes; 802 1.1 christos ptr->root = node + 1; 803 1.1 christos node[0].index = ADF_OFF_BITS; 804 1.1 christos node[0].index = -1 - node[0].index; 805 1.1 christos node[1].index = ADF_OFF_BITS; 806 1.1 christos node[2].index = node[0].index; 807 1.1 christos node[0].parent = node + 1; 808 1.1 christos node[1].parent = node + 1; 809 1.1 christos node[2].parent = node + 1; 810 1.1 christos node[1].bitmask = htonl(0x80000000); 811 1.1 christos node[0].root = 1; 812 1.1 christos node[1].root = 1; 813 1.1 christos node[2].root = 1; 814 1.1 christos node[0].offset = ADF_OFF_BITS >> 5; 815 1.1 christos node[1].offset = ADF_OFF_BITS >> 5; 816 1.1 christos node[2].offset = ADF_OFF_BITS >> 5; 817 1.1 christos node[1].left = &node[0]; 818 1.1 christos node[1].right = &node[2]; 819 1.1 christos node[0].addrkey = (u_32_t *)softr->zeros; 820 1.1 christos node[2].addrkey = (u_32_t *)softr->ones; 821 1.1 christos #ifdef RDX_DEBUG 822 1.1 christos (void) strcpy(node[0].name, "0_ROOT"); 823 1.1 christos (void) strcpy(node[1].name, "1_ROOT"); 824 1.1 christos (void) strcpy(node[2].name, "2_ROOT"); 825 1.1 christos #endif 826 1.1 christos 827 1.1 christos ptr->addaddr = ipf_rx_addroute; 828 1.1 christos ptr->deladdr = ipf_rx_delete; 829 1.1 christos ptr->lookup = ipf_rx_lookup; 830 1.1 christos ptr->matchaddr = ipf_rx_match; 831 1.1 christos ptr->walktree = ipf_rx_walktree; 832 1.1 christos return 0; 833 1.1 christos } 834 1.1 christos 835 1.3 darrenr 836 1.3 darrenr /* ------------------------------------------------------------------------ */ 837 1.3 darrenr /* Function: ipf_rx_freehead */ 838 1.3 darrenr /* Returns: Nil */ 839 1.3 darrenr /* Paramters: head(I) - pointer to tree head to free */ 840 1.3 darrenr /* */ 841 1.3 darrenr /* This function simply free's up the radix tree head. Prior to calling */ 842 1.3 darrenr /* this function, it is expected that the tree will have been emptied. */ 843 1.3 darrenr /* ------------------------------------------------------------------------ */ 844 1.1 christos void 845 1.2 christos ipf_rx_freehead(ipf_rdx_head_t *head) 846 1.1 christos { 847 1.1 christos KFREE(head); 848 1.1 christos } 849 1.1 christos 850 1.3 darrenr 851 1.3 darrenr /* ------------------------------------------------------------------------ */ 852 1.3 darrenr /* Function: ipf_rx_create */ 853 1.3 darrenr /* Parameters: Nil */ 854 1.3 darrenr /* */ 855 1.3 darrenr /* ------------------------------------------------------------------------ */ 856 1.1 christos void * 857 1.2 christos ipf_rx_create(void) 858 1.1 christos { 859 1.1 christos radix_softc_t *softr; 860 1.1 christos 861 1.1 christos KMALLOC(softr, radix_softc_t *); 862 1.1 christos if (softr == NULL) 863 1.1 christos return NULL; 864 1.1 christos bzero((char *)softr, sizeof(*softr)); 865 1.1 christos 866 1.3 darrenr KMALLOCS(softr->zeros, u_char *, 3 * sizeof(addrfamily_t)); 867 1.3 darrenr if (softr->zeros == NULL) { 868 1.3 darrenr KFREE(softr); 869 1.3 darrenr return (NULL); 870 1.3 darrenr } 871 1.3 darrenr softr->ones = softr->zeros + sizeof(addrfamily_t); 872 1.3 darrenr 873 1.1 christos return softr; 874 1.1 christos } 875 1.1 christos 876 1.3 darrenr 877 1.3 darrenr /* ------------------------------------------------------------------------ */ 878 1.3 darrenr /* Function: ipf_rx_init */ 879 1.3 darrenr /* Returns: int - 0 = success (always) */ 880 1.3 darrenr /* */ 881 1.3 darrenr /* ------------------------------------------------------------------------ */ 882 1.1 christos int 883 1.2 christos ipf_rx_init(void *ctx) 884 1.1 christos { 885 1.1 christos radix_softc_t *softr = ctx; 886 1.1 christos 887 1.3 darrenr memset(softr->zeros, 0, 3 * sizeof(addrfamily_t)); 888 1.1 christos memset(softr->ones, 0xff, sizeof(addrfamily_t)); 889 1.3 darrenr 890 1.1 christos return (0); 891 1.1 christos } 892 1.1 christos 893 1.3 darrenr 894 1.3 darrenr /* ------------------------------------------------------------------------ */ 895 1.3 darrenr /* Function: ipf_rx_destroy */ 896 1.3 darrenr /* Returns: Nil */ 897 1.3 darrenr /* */ 898 1.3 darrenr /* ------------------------------------------------------------------------ */ 899 1.1 christos void 900 1.2 christos ipf_rx_destroy(void *ctx) 901 1.1 christos { 902 1.1 christos radix_softc_t *softr = ctx; 903 1.1 christos 904 1.1 christos if (softr->zeros != NULL) 905 1.1 christos KFREES(softr->zeros, 3 * sizeof(addrfamily_t)); 906 1.1 christos KFREE(softr); 907 1.1 christos } 908 1.1 christos 909 1.1 christos /* ====================================================================== */ 910 1.1 christos 911 1.1 christos #ifdef RDX_DEBUG 912 1.3 darrenr /* 913 1.3 darrenr * To compile this file as a standalone test unit, use -DRDX_DEBUG=1 914 1.3 darrenr */ 915 1.1 christos #define NAME(x) ((x)->index < 0 ? (x)->name : (x)->name) 916 1.1 christos #define GNAME(y) ((y) == NULL ? "NULL" : NAME(y)) 917 1.1 christos 918 1.1 christos typedef struct myst { 919 1.1 christos struct ipf_rdx_node nodes[2]; 920 1.1 christos addrfamily_t dst; 921 1.1 christos addrfamily_t mask; 922 1.1 christos struct myst *next; 923 1.1 christos int printed; 924 1.1 christos } myst_t; 925 1.1 christos 926 1.3 darrenr typedef struct tabe_s { 927 1.3 darrenr char *host; 928 1.3 darrenr char *mask; 929 1.3 darrenr char *what; 930 1.3 darrenr } tabe_t; 931 1.3 darrenr 932 1.3 darrenr tabe_t builtin[] = { 933 1.3 darrenr #if 1 934 1.3 darrenr { "192:168:100::0", "48", "d" }, 935 1.3 darrenr { "192:168:100::2", "128", "d" }, 936 1.3 darrenr #else 937 1.3 darrenr { "127.192.0.0", "255.255.255.0", "d" }, 938 1.3 darrenr { "127.128.0.0", "255.255.255.0", "d" }, 939 1.3 darrenr { "127.96.0.0", "255.255.255.0", "d" }, 940 1.3 darrenr { "127.80.0.0", "255.255.255.0", "d" }, 941 1.3 darrenr { "127.72.0.0", "255.255.255.0", "d" }, 942 1.3 darrenr { "127.64.0.0", "255.255.255.0", "d" }, 943 1.3 darrenr { "127.56.0.0", "255.255.255.0", "d" }, 944 1.3 darrenr { "127.48.0.0", "255.255.255.0", "d" }, 945 1.3 darrenr { "127.40.0.0", "255.255.255.0", "d" }, 946 1.3 darrenr { "127.32.0.0", "255.255.255.0", "d" }, 947 1.3 darrenr { "127.24.0.0", "255.255.255.0", "d" }, 948 1.3 darrenr { "127.16.0.0", "255.255.255.0", "d" }, 949 1.3 darrenr { "127.8.0.0", "255.255.255.0", "d" }, 950 1.3 darrenr { "124.0.0.0", "255.0.0.0", "d" }, 951 1.3 darrenr { "125.0.0.0", "255.0.0.0", "d" }, 952 1.3 darrenr { "126.0.0.0", "255.0.0.0", "d" }, 953 1.3 darrenr { "127.0.0.0", "255.0.0.0", "d" }, 954 1.3 darrenr { "10.0.0.0", "255.0.0.0", "d" }, 955 1.3 darrenr { "128.250.0.0", "255.255.0.0", "d" }, 956 1.3 darrenr { "192.168.0.0", "255.255.0.0", "d" }, 957 1.3 darrenr { "192.168.1.0", "255.255.255.0", "d" }, 958 1.3 darrenr #endif 959 1.3 darrenr { NULL, NULL, NULL } 960 1.3 darrenr }; 961 1.3 darrenr 962 1.3 darrenr char *mtable[][1] = { 963 1.3 darrenr #if 1 964 1.3 darrenr { "192:168:100::2" }, 965 1.3 darrenr { "192:168:101::2" }, 966 1.3 darrenr #else 967 1.3 darrenr { "9.0.0.0" }, 968 1.3 darrenr { "9.0.0.1" }, 969 1.3 darrenr { "11.0.0.0" }, 970 1.3 darrenr { "11.0.0.1" }, 971 1.3 darrenr { "127.0.0.1" }, 972 1.3 darrenr { "127.0.1.0" }, 973 1.3 darrenr { "255.255.255.0" }, 974 1.3 darrenr { "126.0.0.1" }, 975 1.3 darrenr { "128.251.0.0" }, 976 1.3 darrenr { "128.251.0.1" }, 977 1.3 darrenr { "128.251.255.255" }, 978 1.3 darrenr { "129.250.0.0" }, 979 1.3 darrenr { "129.250.0.1" }, 980 1.3 darrenr { "192.168.255.255" }, 981 1.3 darrenr #endif 982 1.3 darrenr { NULL } 983 1.3 darrenr }; 984 1.3 darrenr 985 1.3 darrenr 986 1.3 darrenr int forder[22] = { 987 1.3 darrenr 14, 13, 12, 5, 10, 3, 19, 7, 4, 20, 8, 988 1.3 darrenr 2, 17, 9, 16, 11, 15, 1, 6, 18, 0, 21 989 1.3 darrenr }; 990 1.3 darrenr 991 1.1 christos static int nodecount = 0; 992 1.1 christos myst_t *myst_top = NULL; 993 1.3 darrenr tabe_t *ttable = NULL; 994 1.1 christos 995 1.1 christos void add_addr(ipf_rdx_head_t *, int , int); 996 1.1 christos void checktree(ipf_rdx_head_t *); 997 1.1 christos void delete_addr(ipf_rdx_head_t *rnh, int item); 998 1.1 christos void dumptree(ipf_rdx_head_t *rnh); 999 1.1 christos void nodeprinter(ipf_rdx_node_t *, void *); 1000 1.1 christos void printroots(ipf_rdx_head_t *); 1001 1.1 christos void random_add(ipf_rdx_head_t *); 1002 1.1 christos void random_delete(ipf_rdx_head_t *); 1003 1.3 darrenr void test_addr(ipf_rdx_head_t *rnh, int pref, addrfamily_t *, int); 1004 1.3 darrenr 1005 1.1 christos 1006 1.1 christos static void 1007 1.1 christos ipf_rx_freenode(node, arg) 1008 1.1 christos ipf_rdx_node_t *node; 1009 1.1 christos void *arg; 1010 1.1 christos { 1011 1.1 christos ipf_rdx_head_t *head = arg; 1012 1.1 christos ipf_rdx_node_t *rv; 1013 1.1 christos myst_t *stp; 1014 1.1 christos 1015 1.1 christos stp = (myst_t *)node; 1016 1.1 christos rv = ipf_rx_delete(head, &stp->dst, &stp->mask); 1017 1.1 christos if (rv != NULL) { 1018 1.1 christos free(rv); 1019 1.1 christos } 1020 1.1 christos } 1021 1.1 christos 1022 1.3 darrenr 1023 1.3 darrenr const char * 1024 1.3 darrenr addrname(ap) 1025 1.3 darrenr addrfamily_t *ap; 1026 1.3 darrenr { 1027 1.3 darrenr static char name[80]; 1028 1.3 darrenr const char *txt; 1029 1.3 darrenr 1030 1.3 darrenr bzero((char *)name, sizeof(name)); 1031 1.3 darrenr txt = inet_ntop(ap->adf_family, &ap->adf_addr, name, 1032 1.3 darrenr sizeof(name)); 1033 1.3 darrenr return txt; 1034 1.3 darrenr } 1035 1.3 darrenr 1036 1.3 darrenr 1037 1.3 darrenr void 1038 1.3 darrenr fill6bits(bits, msk) 1039 1.3 darrenr int bits; 1040 1.3 darrenr u_int *msk; 1041 1.3 darrenr { 1042 1.3 darrenr if (bits == 0) { 1043 1.3 darrenr msk[0] = 0; 1044 1.3 darrenr msk[1] = 0; 1045 1.3 darrenr msk[2] = 0; 1046 1.3 darrenr msk[3] = 0; 1047 1.3 darrenr return; 1048 1.3 darrenr } 1049 1.3 darrenr 1050 1.3 darrenr msk[0] = 0xffffffff; 1051 1.3 darrenr msk[1] = 0xffffffff; 1052 1.3 darrenr msk[2] = 0xffffffff; 1053 1.3 darrenr msk[3] = 0xffffffff; 1054 1.3 darrenr 1055 1.3 darrenr if (bits == 128) 1056 1.3 darrenr return; 1057 1.3 darrenr if (bits > 96) { 1058 1.3 darrenr msk[3] = htonl(msk[3] << (128 - bits)); 1059 1.3 darrenr } else if (bits > 64) { 1060 1.3 darrenr msk[3] = 0; 1061 1.3 darrenr msk[2] = htonl(msk[2] << (96 - bits)); 1062 1.3 darrenr } else if (bits > 32) { 1063 1.3 darrenr msk[3] = 0; 1064 1.3 darrenr msk[2] = 0; 1065 1.3 darrenr msk[1] = htonl(msk[1] << (64 - bits)); 1066 1.3 darrenr } else { 1067 1.3 darrenr msk[3] = 0; 1068 1.3 darrenr msk[2] = 0; 1069 1.3 darrenr msk[1] = 0; 1070 1.3 darrenr msk[0] = htonl(msk[0] << (32 - bits)); 1071 1.3 darrenr } 1072 1.3 darrenr } 1073 1.3 darrenr 1074 1.3 darrenr 1075 1.3 darrenr void 1076 1.3 darrenr setaddr(afp, str) 1077 1.3 darrenr addrfamily_t *afp; 1078 1.3 darrenr char *str; 1079 1.3 darrenr { 1080 1.3 darrenr 1081 1.3 darrenr bzero((char *)afp, sizeof(*afp)); 1082 1.3 darrenr 1083 1.3 darrenr if (strchr(str, ':') == NULL) { 1084 1.3 darrenr afp->adf_family = AF_INET; 1085 1.3 darrenr afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4; 1086 1.3 darrenr } else { 1087 1.3 darrenr afp->adf_family = AF_INET6; 1088 1.3 darrenr afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16; 1089 1.3 darrenr } 1090 1.3 darrenr inet_pton(afp->adf_family, str, &afp->adf_addr); 1091 1.3 darrenr } 1092 1.3 darrenr 1093 1.3 darrenr 1094 1.3 darrenr void 1095 1.3 darrenr setmask(afp, str) 1096 1.3 darrenr addrfamily_t *afp; 1097 1.3 darrenr char *str; 1098 1.3 darrenr { 1099 1.3 darrenr if (strchr(str, '.') != NULL) { 1100 1.3 darrenr afp->adf_addr.in4.s_addr = inet_addr(str); 1101 1.3 darrenr afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4; 1102 1.3 darrenr } else if (afp->adf_family == AF_INET) { 1103 1.3 darrenr afp->adf_addr.i6[0] = htonl(0xffffffff << (32 - atoi(str))); 1104 1.3 darrenr afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4; 1105 1.3 darrenr } else if (afp->adf_family == AF_INET6) { 1106 1.3 darrenr fill6bits(atoi(str), afp->adf_addr.i6); 1107 1.3 darrenr afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16; 1108 1.3 darrenr } 1109 1.3 darrenr } 1110 1.3 darrenr 1111 1.3 darrenr 1112 1.1 christos void 1113 1.1 christos nodeprinter(node, arg) 1114 1.1 christos ipf_rdx_node_t *node; 1115 1.1 christos void *arg; 1116 1.1 christos { 1117 1.1 christos myst_t *stp = (myst_t *)node; 1118 1.1 christos 1119 1.1 christos printf("Node %-9.9s L %-9.9s R %-9.9s P %9.9s/%-9.9s %s/%d\n", 1120 1.1 christos node[0].name, 1121 1.1 christos GNAME(node[1].left), GNAME(node[1].right), 1122 1.1 christos GNAME(node[0].parent), GNAME(node[1].parent), 1123 1.3 darrenr addrname(&stp->dst), node[0].maskbitcount); 1124 1.3 darrenr if (stp->printed == -1) 1125 1.3 darrenr printf("!!! %d\n", stp->printed); 1126 1.3 darrenr else 1127 1.3 darrenr stp->printed = 1; 1128 1.1 christos } 1129 1.1 christos 1130 1.3 darrenr 1131 1.1 christos void 1132 1.1 christos printnode(stp) 1133 1.1 christos myst_t *stp; 1134 1.1 christos { 1135 1.1 christos ipf_rdx_node_t *node = &stp->nodes[0]; 1136 1.1 christos 1137 1.1 christos if (stp->nodes[0].index > 0) 1138 1.1 christos stp = (myst_t *)&stp->nodes[-1]; 1139 1.1 christos 1140 1.1 christos printf("Node %-9.9s ", node[0].name); 1141 1.1 christos printf("L %-9.9s ", GNAME(node[1].left)); 1142 1.1 christos printf("R %-9.9s ", GNAME(node[1].right)); 1143 1.1 christos printf("P %9.9s", GNAME(node[0].parent)); 1144 1.1 christos printf("/%-9.9s ", GNAME(node[1].parent)); 1145 1.3 darrenr printf("%s P%d\n", addrname(&stp->dst), stp->printed); 1146 1.1 christos } 1147 1.1 christos 1148 1.1 christos 1149 1.3 darrenr void 1150 1.3 darrenr buildtab(void) 1151 1.3 darrenr { 1152 1.3 darrenr char line[80], *s; 1153 1.3 darrenr tabe_t *tab; 1154 1.3 darrenr int lines; 1155 1.3 darrenr FILE *fp; 1156 1.3 darrenr 1157 1.3 darrenr lines = 0; 1158 1.3 darrenr fp = fopen("hosts", "r"); 1159 1.3 darrenr 1160 1.3 darrenr while (fgets(line, sizeof(line), fp) != NULL) { 1161 1.3 darrenr s = strchr(line, '\n'); 1162 1.3 darrenr if (s != NULL) 1163 1.3 darrenr *s = '\0'; 1164 1.3 darrenr lines++; 1165 1.3 darrenr if (lines == 1) 1166 1.3 darrenr tab = malloc(sizeof(*tab) * 2); 1167 1.3 darrenr else 1168 1.3 darrenr tab = realloc(tab, (lines + 1) * sizeof(*tab)); 1169 1.3 darrenr tab[lines - 1].host = strdup(line); 1170 1.3 darrenr s = strchr(tab[lines - 1].host, '/'); 1171 1.3 darrenr *s++ = '\0'; 1172 1.3 darrenr tab[lines - 1].mask = s; 1173 1.3 darrenr tab[lines - 1].what = "d"; 1174 1.3 darrenr } 1175 1.3 darrenr fclose(fp); 1176 1.3 darrenr 1177 1.3 darrenr tab[lines].host = NULL; 1178 1.3 darrenr tab[lines].mask = NULL; 1179 1.3 darrenr tab[lines].what = NULL; 1180 1.3 darrenr ttable = tab; 1181 1.3 darrenr } 1182 1.1 christos 1183 1.1 christos 1184 1.1 christos void 1185 1.1 christos printroots(rnh) 1186 1.1 christos ipf_rdx_head_t *rnh; 1187 1.1 christos { 1188 1.1 christos printf("Root.0.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n", 1189 1.1 christos GNAME(&rnh->nodes[0]), 1190 1.1 christos rnh->nodes[0].index, GNAME(rnh->nodes[0].parent), 1191 1.1 christos GNAME(rnh->nodes[0].left), GNAME(rnh->nodes[0].right)); 1192 1.1 christos printf("Root.1.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n", 1193 1.1 christos GNAME(&rnh->nodes[1]), 1194 1.1 christos rnh->nodes[1].index, GNAME(rnh->nodes[1].parent), 1195 1.1 christos GNAME(rnh->nodes[1].left), GNAME(rnh->nodes[1].right)); 1196 1.1 christos printf("Root.2.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n", 1197 1.1 christos GNAME(&rnh->nodes[2]), 1198 1.1 christos rnh->nodes[2].index, GNAME(rnh->nodes[2].parent), 1199 1.1 christos GNAME(rnh->nodes[2].left), GNAME(rnh->nodes[2].right)); 1200 1.1 christos } 1201 1.1 christos 1202 1.3 darrenr 1203 1.1 christos int 1204 1.1 christos main(int argc, char *argv[]) 1205 1.1 christos { 1206 1.3 darrenr addrfamily_t af; 1207 1.1 christos ipf_rdx_head_t *rnh; 1208 1.1 christos radix_softc_t *ctx; 1209 1.1 christos int j; 1210 1.1 christos int i; 1211 1.1 christos 1212 1.1 christos rnh = NULL; 1213 1.1 christos 1214 1.3 darrenr buildtab(); 1215 1.1 christos ctx = ipf_rx_create(); 1216 1.1 christos ipf_rx_init(ctx); 1217 1.1 christos ipf_rx_inithead(ctx, &rnh); 1218 1.1 christos 1219 1.1 christos printf("=== ADD-0 ===\n"); 1220 1.3 darrenr for (i = 0; ttable[i].host != NULL; i++) { 1221 1.1 christos add_addr(rnh, i, i); 1222 1.1 christos checktree(rnh); 1223 1.1 christos } 1224 1.3 darrenr printroots(rnh); 1225 1.1 christos ipf_rx_walktree(rnh, nodeprinter, NULL); 1226 1.1 christos printf("=== DELETE-0 ===\n"); 1227 1.3 darrenr for (i = 0; ttable[i].host != NULL; i++) { 1228 1.1 christos delete_addr(rnh, i); 1229 1.3 darrenr printroots(rnh); 1230 1.1 christos ipf_rx_walktree(rnh, nodeprinter, NULL); 1231 1.1 christos } 1232 1.1 christos printf("=== ADD-1 ===\n"); 1233 1.3 darrenr for (i = 0; ttable[i].host != NULL; i++) { 1234 1.3 darrenr setaddr(&af, ttable[i].host); 1235 1.3 darrenr add_addr(rnh, i, i); /*forder[i]); */ 1236 1.1 christos checktree(rnh); 1237 1.1 christos } 1238 1.1 christos dumptree(rnh); 1239 1.1 christos ipf_rx_walktree(rnh, nodeprinter, NULL); 1240 1.1 christos printf("=== TEST-1 ===\n"); 1241 1.3 darrenr for (i = 0; ttable[i].host != NULL; i++) { 1242 1.3 darrenr setaddr(&af, ttable[i].host); 1243 1.3 darrenr test_addr(rnh, i, &af, -1); 1244 1.1 christos } 1245 1.1 christos 1246 1.1 christos printf("=== TEST-2 ===\n"); 1247 1.1 christos for (i = 0; mtable[i][0] != NULL; i++) { 1248 1.3 darrenr setaddr(&af, mtable[i][0]); 1249 1.3 darrenr test_addr(rnh, i, &af, -1); 1250 1.1 christos } 1251 1.1 christos printf("=== DELETE-1 ===\n"); 1252 1.3 darrenr for (i = 0; ttable[i].host != NULL; i++) { 1253 1.3 darrenr if (ttable[i].what[0] != 'd') 1254 1.1 christos continue; 1255 1.1 christos delete_addr(rnh, i); 1256 1.3 darrenr for (j = 0; ttable[j].host != NULL; j++) { 1257 1.3 darrenr setaddr(&af, ttable[j].host); 1258 1.3 darrenr test_addr(rnh, i, &af, 3); 1259 1.1 christos } 1260 1.3 darrenr printroots(rnh); 1261 1.1 christos ipf_rx_walktree(rnh, nodeprinter, NULL); 1262 1.1 christos } 1263 1.1 christos 1264 1.1 christos dumptree(rnh); 1265 1.1 christos 1266 1.1 christos printf("=== ADD-2 ===\n"); 1267 1.1 christos random_add(rnh); 1268 1.1 christos checktree(rnh); 1269 1.1 christos dumptree(rnh); 1270 1.1 christos ipf_rx_walktree(rnh, nodeprinter, NULL); 1271 1.1 christos printf("=== DELETE-2 ===\n"); 1272 1.1 christos random_delete(rnh); 1273 1.1 christos checktree(rnh); 1274 1.1 christos dumptree(rnh); 1275 1.1 christos 1276 1.1 christos ipf_rx_walktree(rnh, ipf_rx_freenode, rnh); 1277 1.1 christos 1278 1.1 christos return 0; 1279 1.1 christos } 1280 1.1 christos 1281 1.3 darrenr 1282 1.1 christos void 1283 1.1 christos dumptree(rnh) 1284 1.1 christos ipf_rdx_head_t *rnh; 1285 1.1 christos { 1286 1.1 christos myst_t *stp; 1287 1.1 christos 1288 1.1 christos printf("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n"); 1289 1.3 darrenr printroots(rnh); 1290 1.1 christos for (stp = myst_top; stp; stp = stp->next) 1291 1.1 christos printnode(stp); 1292 1.1 christos printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"); 1293 1.1 christos } 1294 1.1 christos 1295 1.3 darrenr 1296 1.1 christos void 1297 1.1 christos test_addr(rnh, pref, addr, limit) 1298 1.1 christos ipf_rdx_head_t *rnh; 1299 1.1 christos int pref; 1300 1.3 darrenr addrfamily_t *addr; 1301 1.1 christos { 1302 1.1 christos static int extras[14] = { 0, -1, 1, 3, 5, 8, 9, 1303 1.1 christos 15, 16, 19, 255, 256, 65535, 65536 1304 1.1 christos }; 1305 1.1 christos ipf_rdx_node_t *rn; 1306 1.1 christos addrfamily_t af; 1307 1.3 darrenr char name[80]; 1308 1.1 christos myst_t *stp; 1309 1.1 christos int i; 1310 1.1 christos 1311 1.1 christos memset(&af, 0, sizeof(af)); 1312 1.3 darrenr #if 0 1313 1.1 christos if (limit < 0 || limit > 14) 1314 1.1 christos limit = 14; 1315 1.1 christos 1316 1.1 christos for (i = 0; i < limit; i++) { 1317 1.3 darrenr if (ttable[i].host == NULL) 1318 1.3 darrenr break; 1319 1.3 darrenr setaddr(&af, ttable[i].host); 1320 1.3 darrenr printf("%d.%d.LOOKUP(%s)", pref, i, addrname(&af)); 1321 1.1 christos rn = ipf_rx_match(rnh, &af); 1322 1.1 christos stp = (myst_t *)rn; 1323 1.1 christos printf(" = %s (%s/%d)\n", GNAME(rn), 1324 1.3 darrenr rn ? addrname(&stp->dst) : "NULL", 1325 1.1 christos rn ? rn->maskbitcount : 0); 1326 1.1 christos } 1327 1.3 darrenr #else 1328 1.3 darrenr printf("%d.%d.LOOKUP(%s)", pref, -1, addrname(addr)); 1329 1.3 darrenr rn = ipf_rx_match(rnh, addr); 1330 1.3 darrenr stp = (myst_t *)rn; 1331 1.3 darrenr printf(" = %s (%s/%d)\n", GNAME(rn), 1332 1.3 darrenr rn ? addrname(&stp->dst) : "NULL", rn ? rn->maskbitcount : 0); 1333 1.3 darrenr #endif 1334 1.1 christos } 1335 1.1 christos 1336 1.3 darrenr 1337 1.1 christos void 1338 1.1 christos delete_addr(rnh, item) 1339 1.1 christos ipf_rdx_head_t *rnh; 1340 1.1 christos int item; 1341 1.1 christos { 1342 1.1 christos ipf_rdx_node_t *rn; 1343 1.1 christos addrfamily_t mask; 1344 1.1 christos addrfamily_t af; 1345 1.1 christos myst_t **pstp; 1346 1.1 christos myst_t *stp; 1347 1.1 christos 1348 1.1 christos memset(&af, 0, sizeof(af)); 1349 1.1 christos memset(&mask, 0, sizeof(mask)); 1350 1.3 darrenr setaddr(&af, ttable[item].host); 1351 1.3 darrenr mask.adf_family = af.adf_family; 1352 1.3 darrenr setmask(&mask, ttable[item].mask); 1353 1.3 darrenr 1354 1.3 darrenr printf("DELETE(%s)\n", addrname(&af)); 1355 1.1 christos rn = ipf_rx_delete(rnh, &af, &mask); 1356 1.3 darrenr if (rn == NULL) { 1357 1.3 darrenr printf("FAIL LOOKUP DELETE\n"); 1358 1.3 darrenr checktree(rnh); 1359 1.3 darrenr for (stp = myst_top; stp != NULL; stp = stp->next) 1360 1.3 darrenr if (stp->printed != -1) 1361 1.3 darrenr stp->printed = -2; 1362 1.3 darrenr ipf_rx_walktree(rnh, nodeprinter, NULL); 1363 1.3 darrenr dumptree(rnh); 1364 1.3 darrenr abort(); 1365 1.3 darrenr } 1366 1.3 darrenr printf("%d.delete(%s) = %s\n", item, addrname(&af), GNAME(rn)); 1367 1.1 christos 1368 1.1 christos for (pstp = &myst_top; (stp = *pstp) != NULL; pstp = &stp->next) 1369 1.1 christos if (stp == (myst_t *)rn) 1370 1.1 christos break; 1371 1.3 darrenr stp->printed = -1; 1372 1.3 darrenr stp->nodes[0].parent = &stp->nodes[0]; 1373 1.3 darrenr stp->nodes[1].parent = &stp->nodes[1]; 1374 1.1 christos *pstp = stp->next; 1375 1.1 christos free(stp); 1376 1.1 christos nodecount--; 1377 1.1 christos checktree(rnh); 1378 1.1 christos } 1379 1.1 christos 1380 1.3 darrenr 1381 1.1 christos void 1382 1.1 christos add_addr(rnh, n, item) 1383 1.1 christos ipf_rdx_head_t *rnh; 1384 1.1 christos int n, item; 1385 1.1 christos { 1386 1.1 christos ipf_rdx_node_t *rn; 1387 1.1 christos myst_t *stp; 1388 1.1 christos 1389 1.1 christos stp = calloc(1, sizeof(*stp)); 1390 1.1 christos rn = (ipf_rdx_node_t *)stp; 1391 1.3 darrenr setaddr(&stp->dst, ttable[item].host); 1392 1.3 darrenr stp->mask.adf_family = stp->dst.adf_family; 1393 1.3 darrenr setmask(&stp->mask, ttable[item].mask); 1394 1.1 christos stp->next = myst_top; 1395 1.1 christos myst_top = stp; 1396 1.5 christos (void) snprintf(rn[0].name, sizeof(rn[0].name), "_BORN.0"); 1397 1.5 christos (void) snprintf(rn[1].name, sizeof(rn[1].name), "_BORN.1"); 1398 1.1 christos rn = ipf_rx_addroute(rnh, &stp->dst, &stp->mask, stp->nodes); 1399 1.5 christos (void) snprintf(rn[0].name, sizeof(rn[0].name), "%d_NODE.0", item); 1400 1.5 christos (void) snprintf(rn[1].name, sizeof(rn[1].name), "%d_NODE.1", item); 1401 1.1 christos printf("ADD %d/%d %s/%s\n", n, item, rn[0].name, rn[1].name); 1402 1.1 christos nodecount++; 1403 1.1 christos checktree(rnh); 1404 1.1 christos } 1405 1.1 christos 1406 1.3 darrenr 1407 1.1 christos void 1408 1.1 christos checktree(ipf_rdx_head_t *head) 1409 1.1 christos { 1410 1.1 christos myst_t *s1; 1411 1.1 christos ipf_rdx_node_t *rn; 1412 1.1 christos 1413 1.1 christos if (nodecount <= 1) 1414 1.1 christos return; 1415 1.1 christos 1416 1.1 christos for (s1 = myst_top; s1 != NULL; s1 = s1->next) { 1417 1.1 christos int fault = 0; 1418 1.3 darrenr if (s1->printed == -1) 1419 1.3 darrenr continue; 1420 1.1 christos rn = &s1->nodes[1]; 1421 1.1 christos if (rn->right->parent != rn) 1422 1.1 christos fault |= 1; 1423 1.1 christos if (rn->left->parent != rn) 1424 1.1 christos fault |= 2; 1425 1.1 christos if (rn->parent->left != rn && rn->parent->right != rn) 1426 1.1 christos fault |= 4; 1427 1.1 christos if (fault != 0) { 1428 1.1 christos printf("FAULT %#x %s\n", fault, rn->name); 1429 1.1 christos dumptree(head); 1430 1.1 christos ipf_rx_walktree(head, nodeprinter, NULL); 1431 1.3 darrenr fflush(stdout); 1432 1.3 darrenr fflush(stderr); 1433 1.3 darrenr printf("--\n"); 1434 1.3 darrenr abort(); 1435 1.1 christos } 1436 1.1 christos } 1437 1.1 christos } 1438 1.1 christos 1439 1.3 darrenr 1440 1.1 christos int * 1441 1.1 christos randomize(int *pnitems) 1442 1.1 christos { 1443 1.1 christos int *order; 1444 1.1 christos int nitems; 1445 1.1 christos int choice; 1446 1.1 christos int j; 1447 1.1 christos int i; 1448 1.1 christos 1449 1.1 christos nitems = sizeof(ttable) / sizeof(ttable[0]); 1450 1.1 christos *pnitems = nitems; 1451 1.1 christos order = calloc(nitems, sizeof(*order)); 1452 1.1 christos srandom(getpid() * time(NULL)); 1453 1.1 christos memset(order, 0xff, nitems * sizeof(*order)); 1454 1.1 christos order[21] = 21; 1455 1.1 christos for (i = 0; i < nitems - 1; i++) { 1456 1.1 christos do { 1457 1.1 christos choice = rand() % (nitems - 1); 1458 1.1 christos for (j = 0; j < nitems; j++) 1459 1.1 christos if (order[j] == choice) 1460 1.1 christos break; 1461 1.1 christos } while (j != nitems); 1462 1.1 christos order[i] = choice; 1463 1.1 christos } 1464 1.1 christos 1465 1.1 christos return order; 1466 1.1 christos } 1467 1.1 christos 1468 1.3 darrenr 1469 1.1 christos void 1470 1.1 christos random_add(rnh) 1471 1.1 christos ipf_rdx_head_t *rnh; 1472 1.1 christos { 1473 1.1 christos int *order; 1474 1.1 christos int nitems; 1475 1.1 christos int i; 1476 1.1 christos 1477 1.1 christos order = randomize(&nitems); 1478 1.1 christos 1479 1.1 christos for (i = 0; i < nitems - 1; i++) { 1480 1.1 christos add_addr(rnh, i, order[i]); 1481 1.1 christos checktree(rnh); 1482 1.1 christos } 1483 1.6 christos 1484 1.6 christos free(order); 1485 1.1 christos } 1486 1.1 christos 1487 1.3 darrenr 1488 1.1 christos void 1489 1.1 christos random_delete(rnh) 1490 1.1 christos ipf_rdx_head_t *rnh; 1491 1.1 christos { 1492 1.1 christos int *order; 1493 1.1 christos int nitems; 1494 1.1 christos int i; 1495 1.1 christos 1496 1.1 christos order = randomize(&nitems); 1497 1.1 christos 1498 1.1 christos for (i = 0; i < nitems - 1; i++) { 1499 1.1 christos delete_addr(rnh, i); 1500 1.1 christos checktree(rnh); 1501 1.1 christos } 1502 1.6 christos 1503 1.6 christos free(order); 1504 1.1 christos } 1505 1.1 christos #endif /* RDX_DEBUG */ 1506