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