xref: /illumos-gate/usr/src/uts/common/inet/ip/ip_listutils.c (revision 7c478bd95313f5f23a4c958a745db2134aa0324)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/strlog.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
40*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
41*7c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include <inet/common.h>
44*7c478bd9Sstevel@tonic-gate #include <inet/mi.h>
45*7c478bd9Sstevel@tonic-gate #include <inet/ip.h>
46*7c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
47*7c478bd9Sstevel@tonic-gate #include <inet/ip_listutils.h>
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate /*
50*7c478bd9Sstevel@tonic-gate  * These functions perform set operations on sets of ipv6 addresses.
51*7c478bd9Sstevel@tonic-gate  * The sets are formatted as slist_t's (defined in <inet/ip.h>):
52*7c478bd9Sstevel@tonic-gate  *	typedef struct slist_s {
53*7c478bd9Sstevel@tonic-gate  *		int		sl_nusmrc;
54*7c478bd9Sstevel@tonic-gate  *		in6_addr_t	sl_addr[MAX_FILTER_SIZE];
55*7c478bd9Sstevel@tonic-gate  *	} slist_t;
56*7c478bd9Sstevel@tonic-gate  *
57*7c478bd9Sstevel@tonic-gate  * The functions were designed specifically for the implementation of
58*7c478bd9Sstevel@tonic-gate  * IGMPv3 and MLDv2 in ip; they were not meant to be general-purpose.
59*7c478bd9Sstevel@tonic-gate  */
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate /*
62*7c478bd9Sstevel@tonic-gate  * Tells if lists A and B are different or not - true if different;
63*7c478bd9Sstevel@tonic-gate  * caller guarantees that lists are <= MAX_FILTER_SIZE
64*7c478bd9Sstevel@tonic-gate  */
65*7c478bd9Sstevel@tonic-gate boolean_t
66*7c478bd9Sstevel@tonic-gate lists_are_different(const slist_t *a, const slist_t *b)
67*7c478bd9Sstevel@tonic-gate {
68*7c478bd9Sstevel@tonic-gate 	int i, j;
69*7c478bd9Sstevel@tonic-gate 	int acnt = SLIST_CNT(a);
70*7c478bd9Sstevel@tonic-gate 	int bcnt = SLIST_CNT(b);
71*7c478bd9Sstevel@tonic-gate 	boolean_t found;
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate 	if (acnt != bcnt)
74*7c478bd9Sstevel@tonic-gate 		return (B_TRUE);
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate 	ASSERT(acnt <= MAX_FILTER_SIZE);
77*7c478bd9Sstevel@tonic-gate 	ASSERT(bcnt <= MAX_FILTER_SIZE);
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < acnt; i++) {
80*7c478bd9Sstevel@tonic-gate 		found = B_FALSE;
81*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < bcnt; j++) {
82*7c478bd9Sstevel@tonic-gate 			if (IN6_ARE_ADDR_EQUAL(
83*7c478bd9Sstevel@tonic-gate 			    &a->sl_addr[i], &b->sl_addr[j])) {
84*7c478bd9Sstevel@tonic-gate 				found = B_TRUE;
85*7c478bd9Sstevel@tonic-gate 				break;
86*7c478bd9Sstevel@tonic-gate 			}
87*7c478bd9Sstevel@tonic-gate 		}
88*7c478bd9Sstevel@tonic-gate 		if (!found)
89*7c478bd9Sstevel@tonic-gate 			return (B_TRUE);
90*7c478bd9Sstevel@tonic-gate 	}
91*7c478bd9Sstevel@tonic-gate 	return (B_FALSE);
92*7c478bd9Sstevel@tonic-gate }
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate /*
95*7c478bd9Sstevel@tonic-gate  * Tells if list a contains address addr - true if it does, false if not;
96*7c478bd9Sstevel@tonic-gate  * caller guarantees that list is <= MAX_FILTER_SIZE.
97*7c478bd9Sstevel@tonic-gate  */
98*7c478bd9Sstevel@tonic-gate boolean_t
99*7c478bd9Sstevel@tonic-gate list_has_addr(const slist_t *a, const in6_addr_t *addr)
100*7c478bd9Sstevel@tonic-gate {
101*7c478bd9Sstevel@tonic-gate 	int i;
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate 	if (SLIST_IS_EMPTY(a))
104*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < a->sl_numsrc; i++) {
109*7c478bd9Sstevel@tonic-gate 		if (IN6_ARE_ADDR_EQUAL(&a->sl_addr[i], addr))
110*7c478bd9Sstevel@tonic-gate 			return (B_TRUE);
111*7c478bd9Sstevel@tonic-gate 	}
112*7c478bd9Sstevel@tonic-gate 	return (B_FALSE);
113*7c478bd9Sstevel@tonic-gate }
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate /*
116*7c478bd9Sstevel@tonic-gate  * Implements a * b and stores the result in target; caller guarantees
117*7c478bd9Sstevel@tonic-gate  * that a and b are <= MAX_FILTER_SIZE, and that target is a valid pointer.
118*7c478bd9Sstevel@tonic-gate  * target must not be the same as a or b; for that case see
119*7c478bd9Sstevel@tonic-gate  * l_intersection_in_a().
120*7c478bd9Sstevel@tonic-gate  */
121*7c478bd9Sstevel@tonic-gate void
122*7c478bd9Sstevel@tonic-gate l_intersection(const slist_t *a, const slist_t *b, slist_t *target)
123*7c478bd9Sstevel@tonic-gate {
124*7c478bd9Sstevel@tonic-gate 	int i, j;
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	target->sl_numsrc = 0;
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	if (SLIST_IS_EMPTY(a) || SLIST_IS_EMPTY(b))
129*7c478bd9Sstevel@tonic-gate 		return;
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
132*7c478bd9Sstevel@tonic-gate 	ASSERT(b->sl_numsrc <= MAX_FILTER_SIZE);
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < a->sl_numsrc; i++) {
135*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < b->sl_numsrc; j++) {
136*7c478bd9Sstevel@tonic-gate 			if (IN6_ARE_ADDR_EQUAL(
137*7c478bd9Sstevel@tonic-gate 			    &a->sl_addr[i], &b->sl_addr[j])) {
138*7c478bd9Sstevel@tonic-gate 				target->sl_addr[target->sl_numsrc++] =
139*7c478bd9Sstevel@tonic-gate 				    a->sl_addr[i];
140*7c478bd9Sstevel@tonic-gate 				break;
141*7c478bd9Sstevel@tonic-gate 			}
142*7c478bd9Sstevel@tonic-gate 		}
143*7c478bd9Sstevel@tonic-gate 	}
144*7c478bd9Sstevel@tonic-gate }
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate /*
147*7c478bd9Sstevel@tonic-gate  * Implements a - b and stores the result in target; caller guarantees
148*7c478bd9Sstevel@tonic-gate  * that a and b are <= MAX_FILTER_SIZE, and that target is a valid pointer.
149*7c478bd9Sstevel@tonic-gate  * target must not be the same as a or b; for that case see l_difference_in_a().
150*7c478bd9Sstevel@tonic-gate  */
151*7c478bd9Sstevel@tonic-gate void
152*7c478bd9Sstevel@tonic-gate l_difference(const slist_t *a, const slist_t *b, slist_t *target)
153*7c478bd9Sstevel@tonic-gate {
154*7c478bd9Sstevel@tonic-gate 	int i, j;
155*7c478bd9Sstevel@tonic-gate 	boolean_t found = B_FALSE;
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 	target->sl_numsrc = 0;
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 	if (SLIST_IS_EMPTY(a))
160*7c478bd9Sstevel@tonic-gate 		return;
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	if (SLIST_IS_EMPTY(b)) {
163*7c478bd9Sstevel@tonic-gate 		l_copy(a, target);
164*7c478bd9Sstevel@tonic-gate 		return;
165*7c478bd9Sstevel@tonic-gate 	}
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
168*7c478bd9Sstevel@tonic-gate 	ASSERT(b->sl_numsrc <= MAX_FILTER_SIZE);
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < a->sl_numsrc; i++) {
171*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < b->sl_numsrc; j++) {
172*7c478bd9Sstevel@tonic-gate 			if (IN6_ARE_ADDR_EQUAL(
173*7c478bd9Sstevel@tonic-gate 			    &a->sl_addr[i], &b->sl_addr[j])) {
174*7c478bd9Sstevel@tonic-gate 				found = B_TRUE;
175*7c478bd9Sstevel@tonic-gate 				break;
176*7c478bd9Sstevel@tonic-gate 			}
177*7c478bd9Sstevel@tonic-gate 		}
178*7c478bd9Sstevel@tonic-gate 		if (!found) {
179*7c478bd9Sstevel@tonic-gate 			target->sl_addr[target->sl_numsrc++] = a->sl_addr[i];
180*7c478bd9Sstevel@tonic-gate 		} else {
181*7c478bd9Sstevel@tonic-gate 			found = B_FALSE;
182*7c478bd9Sstevel@tonic-gate 		}
183*7c478bd9Sstevel@tonic-gate 	}
184*7c478bd9Sstevel@tonic-gate }
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate /*
187*7c478bd9Sstevel@tonic-gate  * Removes addr from list a.  Caller guarantees that addr is a valid
188*7c478bd9Sstevel@tonic-gate  * pointer, and that a <= MAX_FILTER_SIZE.  addr will only be removed
189*7c478bd9Sstevel@tonic-gate  * once from the list; if it appears in the list multiple times, extra
190*7c478bd9Sstevel@tonic-gate  * copies may remain.
191*7c478bd9Sstevel@tonic-gate  */
192*7c478bd9Sstevel@tonic-gate void
193*7c478bd9Sstevel@tonic-gate l_remove(slist_t *a, const in6_addr_t *addr)
194*7c478bd9Sstevel@tonic-gate {
195*7c478bd9Sstevel@tonic-gate 	int i, mvsize;
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate 	if (SLIST_IS_EMPTY(a))
198*7c478bd9Sstevel@tonic-gate 		return;
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < a->sl_numsrc; i++) {
203*7c478bd9Sstevel@tonic-gate 		if (IN6_ARE_ADDR_EQUAL(&a->sl_addr[i], addr)) {
204*7c478bd9Sstevel@tonic-gate 			a->sl_numsrc--;
205*7c478bd9Sstevel@tonic-gate 			mvsize = (a->sl_numsrc - i) * sizeof (in6_addr_t);
206*7c478bd9Sstevel@tonic-gate 			(void) memmove(&a->sl_addr[i], &a->sl_addr[i + 1],
207*7c478bd9Sstevel@tonic-gate 			    mvsize);
208*7c478bd9Sstevel@tonic-gate 			break;
209*7c478bd9Sstevel@tonic-gate 		}
210*7c478bd9Sstevel@tonic-gate 	}
211*7c478bd9Sstevel@tonic-gate }
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate /*
214*7c478bd9Sstevel@tonic-gate  * Make a copy of list a by allocating a new slist_t and copying only
215*7c478bd9Sstevel@tonic-gate  * a->sl_numsrc addrs.  Caller guarantees that a <= MAX_FILTER_SIZE.
216*7c478bd9Sstevel@tonic-gate  * Return a pointer to the newly alloc'd list, or NULL if a is empty
217*7c478bd9Sstevel@tonic-gate  * (no memory is alloc'd in this case).
218*7c478bd9Sstevel@tonic-gate  */
219*7c478bd9Sstevel@tonic-gate slist_t *
220*7c478bd9Sstevel@tonic-gate l_alloc_copy(const slist_t *a)
221*7c478bd9Sstevel@tonic-gate {
222*7c478bd9Sstevel@tonic-gate 	slist_t *b;
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	if (SLIST_IS_EMPTY(a))
225*7c478bd9Sstevel@tonic-gate 		return (NULL);
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	if ((b = l_alloc()) == NULL)
228*7c478bd9Sstevel@tonic-gate 		return (NULL);
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	l_copy(a, b);
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	return (b);
233*7c478bd9Sstevel@tonic-gate }
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate /*
236*7c478bd9Sstevel@tonic-gate  * Copy the address list from slist a into slist b, overwriting anything
237*7c478bd9Sstevel@tonic-gate  * that might already be in slist b.  Assumes that a <= MAX_FILTER_SIZE
238*7c478bd9Sstevel@tonic-gate  * and that b points to a properly allocated slist.
239*7c478bd9Sstevel@tonic-gate  */
240*7c478bd9Sstevel@tonic-gate void
241*7c478bd9Sstevel@tonic-gate l_copy(const slist_t *a, slist_t *b)
242*7c478bd9Sstevel@tonic-gate {
243*7c478bd9Sstevel@tonic-gate 	if (SLIST_IS_EMPTY(a)) {
244*7c478bd9Sstevel@tonic-gate 		b->sl_numsrc = 0;
245*7c478bd9Sstevel@tonic-gate 		return;
246*7c478bd9Sstevel@tonic-gate 	}
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	b->sl_numsrc = a->sl_numsrc;
251*7c478bd9Sstevel@tonic-gate 	(void) memcpy(b->sl_addr, a->sl_addr,
252*7c478bd9Sstevel@tonic-gate 	    a->sl_numsrc * sizeof (in6_addr_t));
253*7c478bd9Sstevel@tonic-gate }
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate /*
256*7c478bd9Sstevel@tonic-gate  * Append to a any addrs in b that are not already in a (i.e. perform
257*7c478bd9Sstevel@tonic-gate  * a + b and store the result in a).  If b is empty, the function returns
258*7c478bd9Sstevel@tonic-gate  * without taking any action.
259*7c478bd9Sstevel@tonic-gate  *
260*7c478bd9Sstevel@tonic-gate  * Caller guarantees that a and b are <= MAX_FILTER_SIZE, and that a
261*7c478bd9Sstevel@tonic-gate  * and overflow are valid pointers.
262*7c478bd9Sstevel@tonic-gate  *
263*7c478bd9Sstevel@tonic-gate  * If an overflow occurs (a + b > MAX_FILTER_SIZE), a will contain the
264*7c478bd9Sstevel@tonic-gate  * first MAX_FILTER_SIZE addresses of the union, and *overflow will be
265*7c478bd9Sstevel@tonic-gate  * set to true.  Otherwise, *overflow will be set to false.
266*7c478bd9Sstevel@tonic-gate  */
267*7c478bd9Sstevel@tonic-gate void
268*7c478bd9Sstevel@tonic-gate l_union_in_a(slist_t *a, const slist_t *b, boolean_t *overflow)
269*7c478bd9Sstevel@tonic-gate {
270*7c478bd9Sstevel@tonic-gate 	int i, j;
271*7c478bd9Sstevel@tonic-gate 	boolean_t found;
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	*overflow = B_FALSE;
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	if (SLIST_IS_EMPTY(b))
276*7c478bd9Sstevel@tonic-gate 		return;
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
279*7c478bd9Sstevel@tonic-gate 	ASSERT(b->sl_numsrc <= MAX_FILTER_SIZE);
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < b->sl_numsrc; i++) {
282*7c478bd9Sstevel@tonic-gate 		found = B_FALSE;
283*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < a->sl_numsrc; j++) {
284*7c478bd9Sstevel@tonic-gate 			if (IN6_ARE_ADDR_EQUAL(
285*7c478bd9Sstevel@tonic-gate 			    &b->sl_addr[i], &a->sl_addr[j])) {
286*7c478bd9Sstevel@tonic-gate 				found = B_TRUE;
287*7c478bd9Sstevel@tonic-gate 				break;
288*7c478bd9Sstevel@tonic-gate 			}
289*7c478bd9Sstevel@tonic-gate 		}
290*7c478bd9Sstevel@tonic-gate 		if (!found) {
291*7c478bd9Sstevel@tonic-gate 			if (a->sl_numsrc == MAX_FILTER_SIZE) {
292*7c478bd9Sstevel@tonic-gate 				*overflow = B_TRUE;
293*7c478bd9Sstevel@tonic-gate 				break;
294*7c478bd9Sstevel@tonic-gate 			} else {
295*7c478bd9Sstevel@tonic-gate 				a->sl_addr[a->sl_numsrc++] = b->sl_addr[i];
296*7c478bd9Sstevel@tonic-gate 			}
297*7c478bd9Sstevel@tonic-gate 		}
298*7c478bd9Sstevel@tonic-gate 	}
299*7c478bd9Sstevel@tonic-gate }
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate /*
302*7c478bd9Sstevel@tonic-gate  * Remove from list a any addresses that are not also in list b
303*7c478bd9Sstevel@tonic-gate  * (i.e. perform a * b and store the result in a).
304*7c478bd9Sstevel@tonic-gate  *
305*7c478bd9Sstevel@tonic-gate  * Caller guarantees that a and b are <= MAX_FILTER_SIZE, and that
306*7c478bd9Sstevel@tonic-gate  * a is a valid pointer.
307*7c478bd9Sstevel@tonic-gate  */
308*7c478bd9Sstevel@tonic-gate void
309*7c478bd9Sstevel@tonic-gate l_intersection_in_a(slist_t *a, const slist_t *b)
310*7c478bd9Sstevel@tonic-gate {
311*7c478bd9Sstevel@tonic-gate 	int i, j, shift;
312*7c478bd9Sstevel@tonic-gate 	boolean_t found;
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 	if (SLIST_IS_EMPTY(b)) {
315*7c478bd9Sstevel@tonic-gate 		a->sl_numsrc = 0;
316*7c478bd9Sstevel@tonic-gate 		return;
317*7c478bd9Sstevel@tonic-gate 	}
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
320*7c478bd9Sstevel@tonic-gate 	ASSERT(b->sl_numsrc <= MAX_FILTER_SIZE);
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	shift = 0;
323*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < a->sl_numsrc; i++) {
324*7c478bd9Sstevel@tonic-gate 		found = B_FALSE;
325*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < b->sl_numsrc; j++) {
326*7c478bd9Sstevel@tonic-gate 			if (IN6_ARE_ADDR_EQUAL(
327*7c478bd9Sstevel@tonic-gate 			    &a->sl_addr[i], &b->sl_addr[j])) {
328*7c478bd9Sstevel@tonic-gate 				found = B_TRUE;
329*7c478bd9Sstevel@tonic-gate 				break;
330*7c478bd9Sstevel@tonic-gate 			}
331*7c478bd9Sstevel@tonic-gate 		}
332*7c478bd9Sstevel@tonic-gate 		if (!found)
333*7c478bd9Sstevel@tonic-gate 			shift++;
334*7c478bd9Sstevel@tonic-gate 		else if (shift > 0)
335*7c478bd9Sstevel@tonic-gate 			a->sl_addr[i - shift] = a->sl_addr[i];
336*7c478bd9Sstevel@tonic-gate 	}
337*7c478bd9Sstevel@tonic-gate 	a->sl_numsrc -= shift;
338*7c478bd9Sstevel@tonic-gate }
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate /*
341*7c478bd9Sstevel@tonic-gate  * Remove from list a any addresses that are in list b (i.e. perform
342*7c478bd9Sstevel@tonic-gate  * a - b and store the result in a).
343*7c478bd9Sstevel@tonic-gate  *
344*7c478bd9Sstevel@tonic-gate  * Caller guarantees that a and b are <= MAX_FILTER_SIZE.  If either
345*7c478bd9Sstevel@tonic-gate  * list is empty (or a null pointer), the function returns without
346*7c478bd9Sstevel@tonic-gate  * taking any action.
347*7c478bd9Sstevel@tonic-gate  */
348*7c478bd9Sstevel@tonic-gate void
349*7c478bd9Sstevel@tonic-gate l_difference_in_a(slist_t *a, const slist_t *b)
350*7c478bd9Sstevel@tonic-gate {
351*7c478bd9Sstevel@tonic-gate 	int i, j, shift;
352*7c478bd9Sstevel@tonic-gate 	boolean_t found;
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	if (SLIST_IS_EMPTY(a) || SLIST_IS_EMPTY(b))
355*7c478bd9Sstevel@tonic-gate 		return;
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
358*7c478bd9Sstevel@tonic-gate 	ASSERT(b->sl_numsrc <= MAX_FILTER_SIZE);
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	shift = 0;
361*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < a->sl_numsrc; i++) {
362*7c478bd9Sstevel@tonic-gate 		found = B_FALSE;
363*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < b->sl_numsrc; j++) {
364*7c478bd9Sstevel@tonic-gate 			if (IN6_ARE_ADDR_EQUAL(
365*7c478bd9Sstevel@tonic-gate 			    &a->sl_addr[i], &b->sl_addr[j])) {
366*7c478bd9Sstevel@tonic-gate 				found = B_TRUE;
367*7c478bd9Sstevel@tonic-gate 				break;
368*7c478bd9Sstevel@tonic-gate 			}
369*7c478bd9Sstevel@tonic-gate 		}
370*7c478bd9Sstevel@tonic-gate 		if (found)
371*7c478bd9Sstevel@tonic-gate 			shift++;
372*7c478bd9Sstevel@tonic-gate 		else if (shift > 0)
373*7c478bd9Sstevel@tonic-gate 			a->sl_addr[i - shift] = a->sl_addr[i];
374*7c478bd9Sstevel@tonic-gate 	}
375*7c478bd9Sstevel@tonic-gate 	a->sl_numsrc -= shift;
376*7c478bd9Sstevel@tonic-gate }
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate /*
379*7c478bd9Sstevel@tonic-gate  * Wrapper function to alloc an slist_t.
380*7c478bd9Sstevel@tonic-gate  */
381*7c478bd9Sstevel@tonic-gate slist_t *
382*7c478bd9Sstevel@tonic-gate l_alloc()
383*7c478bd9Sstevel@tonic-gate {
384*7c478bd9Sstevel@tonic-gate 	slist_t *p;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	p = (slist_t *)mi_alloc(sizeof (slist_t), BPRI_MED);
387*7c478bd9Sstevel@tonic-gate 	if (p != NULL)
388*7c478bd9Sstevel@tonic-gate 		p->sl_numsrc = 0;
389*7c478bd9Sstevel@tonic-gate 	return (p);
390*7c478bd9Sstevel@tonic-gate }
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate /*
393*7c478bd9Sstevel@tonic-gate  * Frees an slist_t structure.  Provided for symmetry with l_alloc().
394*7c478bd9Sstevel@tonic-gate  */
395*7c478bd9Sstevel@tonic-gate void
396*7c478bd9Sstevel@tonic-gate l_free(slist_t *a)
397*7c478bd9Sstevel@tonic-gate {
398*7c478bd9Sstevel@tonic-gate 	mi_free(a);
399*7c478bd9Sstevel@tonic-gate }
400