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