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