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