17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bdstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bdstevel@tonic-gate * (the "License").  You may not use this file except in compliance
77c478bdstevel@tonic-gate * with the License.
87c478bdstevel@tonic-gate *
97c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bdstevel@tonic-gate * See the License for the specific language governing permissions
127c478bdstevel@tonic-gate * and limitations under the License.
137c478bdstevel@tonic-gate *
147c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bdstevel@tonic-gate *
207c478bdstevel@tonic-gate * CDDL HEADER END
217c478bdstevel@tonic-gate */
227c478bdstevel@tonic-gate/*
237c478bdstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bdstevel@tonic-gate * Use is subject to license terms.
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bdstevel@tonic-gate
297c478bdstevel@tonic-gate#include <sys/types.h>
307c478bdstevel@tonic-gate#include <sys/stream.h>
317c478bdstevel@tonic-gate#include <sys/dlpi.h>
327c478bdstevel@tonic-gate#include <sys/stropts.h>
337c478bdstevel@tonic-gate#include <sys/strlog.h>
347c478bdstevel@tonic-gate#include <sys/systm.h>
357c478bdstevel@tonic-gate#include <sys/ddi.h>
367c478bdstevel@tonic-gate#include <sys/cmn_err.h>
377c478bdstevel@tonic-gate
387c478bdstevel@tonic-gate#include <sys/param.h>
397c478bdstevel@tonic-gate#include <sys/tihdr.h>
407c478bdstevel@tonic-gate#include <netinet/in.h>
417c478bdstevel@tonic-gate#include <netinet/ip6.h>
427c478bdstevel@tonic-gate
437c478bdstevel@tonic-gate#include <inet/common.h>
447c478bdstevel@tonic-gate#include <inet/mi.h>
457c478bdstevel@tonic-gate#include <inet/ip.h>
467c478bdstevel@tonic-gate#include <inet/ip6.h>
477c478bdstevel@tonic-gate#include <inet/ip_listutils.h>
487c478bdstevel@tonic-gate
497c478bdstevel@tonic-gate/*
507c478bdstevel@tonic-gate * These functions perform set operations on sets of ipv6 addresses.
517c478bdstevel@tonic-gate * The sets are formatted as slist_t's (defined in <inet/ip.h>):
527c478bdstevel@tonic-gate *	typedef struct slist_s {
537c478bdstevel@tonic-gate *		int		sl_nusmrc;
547c478bdstevel@tonic-gate *		in6_addr_t	sl_addr[MAX_FILTER_SIZE];
557c478bdstevel@tonic-gate *	} slist_t;
567c478bdstevel@tonic-gate *
577c478bdstevel@tonic-gate * The functions were designed specifically for the implementation of
587c478bdstevel@tonic-gate * IGMPv3 and MLDv2 in ip; they were not meant to be general-purpose.
597c478bdstevel@tonic-gate */
607c478bdstevel@tonic-gate
617c478bdstevel@tonic-gate/*
627c478bdstevel@tonic-gate * Tells if lists A and B are different or not - true if different;
637c478bdstevel@tonic-gate * caller guarantees that lists are <= MAX_FILTER_SIZE
647c478bdstevel@tonic-gate */
657c478bdstevel@tonic-gateboolean_t
667c478bdstevel@tonic-gatelists_are_different(const slist_t *a, const slist_t *b)
677c478bdstevel@tonic-gate{
687c478bdstevel@tonic-gate	int i, j;
697c478bdstevel@tonic-gate	int acnt = SLIST_CNT(a);
707c478bdstevel@tonic-gate	int bcnt = SLIST_CNT(b);
717c478bdstevel@tonic-gate	boolean_t found;
727c478bdstevel@tonic-gate
737c478bdstevel@tonic-gate	if (acnt != bcnt)
747c478bdstevel@tonic-gate		return (B_TRUE);
757c478bdstevel@tonic-gate
767c478bdstevel@tonic-gate	ASSERT(acnt <= MAX_FILTER_SIZE);
777c478bdstevel@tonic-gate	ASSERT(bcnt <= MAX_FILTER_SIZE);
787c478bdstevel@tonic-gate
797c478bdstevel@tonic-gate	for (i = 0; i < acnt; i++) {
807c478bdstevel@tonic-gate		found = B_FALSE;
817c478bdstevel@tonic-gate		for (j = 0; j < bcnt; j++) {
827c478bdstevel@tonic-gate			if (IN6_ARE_ADDR_EQUAL(
837c478bdstevel@tonic-gate			    &a->sl_addr[i], &b->sl_addr[j])) {
847c478bdstevel@tonic-gate				found = B_TRUE;
857c478bdstevel@tonic-gate				break;
867c478bdstevel@tonic-gate			}
877c478bdstevel@tonic-gate		}
887c478bdstevel@tonic-gate		if (!found)
897c478bdstevel@tonic-gate			return (B_TRUE);
907c478bdstevel@tonic-gate	}
917c478bdstevel@tonic-gate	return (B_FALSE);
927c478bdstevel@tonic-gate}
937c478bdstevel@tonic-gate
947c478bdstevel@tonic-gate/*
957c478bdstevel@tonic-gate * Tells if list a contains address addr - true if it does, false if not;
967c478bdstevel@tonic-gate * caller guarantees that list is <= MAX_FILTER_SIZE.
977c478bdstevel@tonic-gate */
987c478bdstevel@tonic-gateboolean_t
997c478bdstevel@tonic-gatelist_has_addr(const slist_t *a, const in6_addr_t *addr)
1007c478bdstevel@tonic-gate{
1017c478bdstevel@tonic-gate	int i;
1027c478bdstevel@tonic-gate
1037c478bdstevel@tonic-gate	if (SLIST_IS_EMPTY(a))
1047c478bdstevel@tonic-gate		return (B_FALSE);
1057c478bdstevel@tonic-gate
1067c478bdstevel@tonic-gate	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
1077c478bdstevel@tonic-gate
1087c478bdstevel@tonic-gate	for (i = 0; i < a->sl_numsrc; i++) {
1097c478bdstevel@tonic-gate		if (IN6_ARE_ADDR_EQUAL(&a->sl_addr[i], addr))
1107c478bdstevel@tonic-gate			return (B_TRUE);
1117c478bdstevel@tonic-gate	}
1127c478bdstevel@tonic-gate	return (B_FALSE);
1137c478bdstevel@tonic-gate}
1147c478bdstevel@tonic-gate
1157c478bdstevel@tonic-gate/*
1167c478bdstevel@tonic-gate * Implements a * b and stores the result in target; caller guarantees
1177c478bdstevel@tonic-gate * that a and b are <= MAX_FILTER_SIZE, and that target is a valid pointer.
1187c478bdstevel@tonic-gate * target must not be the same as a or b; for that case see
1197c478bdstevel@tonic-gate * l_intersection_in_a().
1207c478bdstevel@tonic-gate */
1217c478bdstevel@tonic-gatevoid
1227c478bdstevel@tonic-gatel_intersection(const slist_t *a, const slist_t *b, slist_t *target)
1237c478bdstevel@tonic-gate{
1247c478bdstevel@tonic-gate	int i, j;
1257c478bdstevel@tonic-gate
1267c478bdstevel@tonic-gate	target->sl_numsrc = 0;
1277c478bdstevel@tonic-gate
1287c478bdstevel@tonic-gate	if (SLIST_IS_EMPTY(a) || SLIST_IS_EMPTY(b))
1297c478bdstevel@tonic-gate		return;
1307c478bdstevel@tonic-gate
1317c478bdstevel@tonic-gate	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
1327c478bdstevel@tonic-gate	ASSERT(b->sl_numsrc <= MAX_FILTER_SIZE);
1337c478bdstevel@tonic-gate
1347c478bdstevel@tonic-gate	for (i = 0; i < a->sl_numsrc; i++) {
1357c478bdstevel@tonic-gate		for (j = 0; j < b->sl_numsrc; j++) {
1367c478bdstevel@tonic-gate			if (IN6_ARE_ADDR_EQUAL(
1377c478bdstevel@tonic-gate			    &a->sl_addr[i], &b->sl_addr[j])) {
1387c478bdstevel@tonic-gate				target->sl_addr[target->sl_numsrc++] =
1397c478bdstevel@tonic-gate				    a->sl_addr[i];
1407c478bdstevel@tonic-gate				break;
1417c478bdstevel@tonic-gate			}
1427c478bdstevel@tonic-gate		}
1437c478bdstevel@tonic-gate	}
1447c478bdstevel@tonic-gate}
1457c478bdstevel@tonic-gate
1467c478bdstevel@tonic-gate/*
1477c478bdstevel@tonic-gate * Implements a - b and stores the result in target; caller guarantees
1487c478bdstevel@tonic-gate * that a and b are <= MAX_FILTER_SIZE, and that target is a valid pointer.
1497c478bdstevel@tonic-gate * target must not be the same as a or b; for that case see l_difference_in_a().
1507c478bdstevel@tonic-gate */
1517c478bdstevel@tonic-gatevoid
1527c478bdstevel@tonic-gatel_difference(const slist_t *a, const slist_t *b, slist_t *target)
1537c478bdstevel@tonic-gate{
1547c478bdstevel@tonic-gate	int i, j;
1557c478bdstevel@tonic-gate	boolean_t found = B_FALSE;
1567c478bdstevel@tonic-gate
1577c478bdstevel@tonic-gate	target->sl_numsrc = 0;
1587c478bdstevel@tonic-gate
1597c478bdstevel@tonic-gate	if (SLIST_IS_EMPTY(a))
1607c478bdstevel@tonic-gate		return;
1617c478bdstevel@tonic-gate
1627c478bdstevel@tonic-gate	if (SLIST_IS_EMPTY(b)) {
1637c478bdstevel@tonic-gate		l_copy(a, target);
1647c478bdstevel@tonic-gate		return;
1657c478bdstevel@tonic-gate	}
1667c478bdstevel@tonic-gate
1677c478bdstevel@tonic-gate	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
1687c478bdstevel@tonic-gate	ASSERT(b->sl_numsrc <= MAX_FILTER_SIZE);
1697c478bdstevel@tonic-gate
1707c478bdstevel@tonic-gate	for (i = 0; i < a->sl_numsrc; i++) {
1717c478bdstevel@tonic-gate		for (j = 0; j < b->sl_numsrc; j++) {
1727c478bdstevel@tonic-gate			if (IN6_ARE_ADDR_EQUAL(
1737c478bdstevel@tonic-gate			    &a->sl_addr[i], &b->sl_addr[j])) {
1747c478bdstevel@tonic-gate				found = B_TRUE;
1757c478bdstevel@tonic-gate				break;
1767c478bdstevel@tonic-gate			}
1777c478bdstevel@tonic-gate		}
1787c478bdstevel@tonic-gate		if (!found) {
1797c478bdstevel@tonic-gate			target->sl_addr[target->sl_numsrc++] = a->sl_addr[i];
1807c478bdstevel@tonic-gate		} else {
1817c478bdstevel@tonic-gate			found = B_FALSE;
1827c478bdstevel@tonic-gate		}
1837c478bdstevel@tonic-gate	}
1847c478bdstevel@tonic-gate}
1857c478bdstevel@tonic-gate
1867c478bdstevel@tonic-gate/*
1877c478bdstevel@tonic-gate * Removes addr from list a.  Caller guarantees that addr is a valid
1887c478bdstevel@tonic-gate * pointer, and that a <= MAX_FILTER_SIZE.  addr will only be removed
1897c478bdstevel@tonic-gate * once from the list; if it appears in the list multiple times, extra
1907c478bdstevel@tonic-gate * copies may remain.
1917c478bdstevel@tonic-gate */
1927c478bdstevel@tonic-gatevoid
1937c478bdstevel@tonic-gatel_remove(slist_t *a, const in6_addr_t *addr)
1947c478bdstevel@tonic-gate{
1957c478bdstevel@tonic-gate	int i, mvsize;
1967c478bdstevel@tonic-gate
1977c478bdstevel@tonic-gate	if (SLIST_IS_EMPTY(a))
1987c478bdstevel@tonic-gate		return;
1997c478bdstevel@tonic-gate
2007c478bdstevel@tonic-gate	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
2017c478bdstevel@tonic-gate
2027c478bdstevel@tonic-gate	for (i = 0; i < a->sl_numsrc; i++) {
2037c478bdstevel@tonic-gate		if (IN6_ARE_ADDR_EQUAL(&a->sl_addr[i], addr)) {
2047c478bdstevel@tonic-gate			a->sl_numsrc--;
2057c478bdstevel@tonic-gate			mvsize = (a->sl_numsrc - i) * sizeof (in6_addr_t);
2067c478bdstevel@tonic-gate			(void) memmove(&a->sl_addr[i], &a->sl_addr[i + 1],
2077c478bdstevel@tonic-gate			    mvsize);
2087c478bdstevel@tonic-gate			break;
2097c478bdstevel@tonic-gate		}
2107c478bdstevel@tonic-gate	}
2117c478bdstevel@tonic-gate}
2127c478bdstevel@tonic-gate
2137c478bdstevel@tonic-gate/*
2147c478bdstevel@tonic-gate * Make a copy of list a by allocating a new slist_t and copying only
2157c478bdstevel@tonic-gate * a->sl_numsrc addrs.  Caller guarantees that a <= MAX_FILTER_SIZE.
2167c478bdstevel@tonic-gate * Return a pointer to the newly alloc'd list, or NULL if a is empty
2177c478bdstevel@tonic-gate * (no memory is alloc'd in this case).
2187c478bdstevel@tonic-gate */
2197c478bdstevel@tonic-gateslist_t *
2207c478bdstevel@tonic-gatel_alloc_copy(const slist_t *a)
2217c478bdstevel@tonic-gate{
2227c478bdstevel@tonic-gate	slist_t *b;
2237c478bdstevel@tonic-gate
2247c478bdstevel@tonic-gate	if (SLIST_IS_EMPTY(a))
2257c478bdstevel@tonic-gate		return (NULL);
2267c478bdstevel@tonic-gate
2277c478bdstevel@tonic-gate	if ((b = l_alloc()) == NULL)
2287c478bdstevel@tonic-gate		return (NULL);
2297c478bdstevel@tonic-gate
2307c478bdstevel@tonic-gate	l_copy(a, b);
2317c478bdstevel@tonic-gate
2327c478bdstevel@tonic-gate	return (b);
2337c478bdstevel@tonic-gate}
2347c478bdstevel@tonic-gate
2357c478bdstevel@tonic-gate/*
2367c478bdstevel@tonic-gate * Copy the address list from slist a into slist b, overwriting anything
2377c478bdstevel@tonic-gate * that might already be in slist b.  Assumes that a <= MAX_FILTER_SIZE
2387c478bdstevel@tonic-gate * and that b points to a properly allocated slist.
2397c478bdstevel@tonic-gate */
2407c478bdstevel@tonic-gatevoid
2417c478bdstevel@tonic-gatel_copy(const slist_t *a, slist_t *b)
2427c478bdstevel@tonic-gate{
2437c478bdstevel@tonic-gate	if (SLIST_IS_EMPTY(a)) {
2447c478bdstevel@tonic-gate		b->sl_numsrc = 0;
2457c478bdstevel@tonic-gate		return;
2467c478bdstevel@tonic-gate	}
2477c478bdstevel@tonic-gate
2487c478bdstevel@tonic-gate	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
2497c478bdstevel@tonic-gate
2507c478bdstevel@tonic-gate	b->sl_numsrc = a->sl_numsrc;
2517c478bdstevel@tonic-gate	(void) memcpy(b->sl_addr, a->sl_addr,
2527c478bdstevel@tonic-gate	    a->sl_numsrc * sizeof (in6_addr_t));
2537c478bdstevel@tonic-gate}
2547c478bdstevel@tonic-gate
2557c478bdstevel@tonic-gate/*
2567c478bdstevel@tonic-gate * Append to a any addrs in b that are not already in a (i.e. perform
2577c478bdstevel@tonic-gate * a + b and store the result in a).  If b is empty, the function returns
2587c478bdstevel@tonic-gate * without taking any action.
2597c478bdstevel@tonic-gate *
2607c478bdstevel@tonic-gate * Caller guarantees that a and b are <= MAX_FILTER_SIZE, and that a
2617c478bdstevel@tonic-gate * and overflow are valid pointers.
2627c478bdstevel@tonic-gate *
2637c478bdstevel@tonic-gate * If an overflow occurs (a + b > MAX_FILTER_SIZE), a will contain the
2647c478bdstevel@tonic-gate * first MAX_FILTER_SIZE addresses of the union, and *overflow will be
2657c478bdstevel@tonic-gate * set to true.  Otherwise, *overflow will be set to false.
2667c478bdstevel@tonic-gate */
2677c478bdstevel@tonic-gatevoid
2687c478bdstevel@tonic-gatel_union_in_a(slist_t *a, const slist_t *b, boolean_t *overflow)
2697c478bdstevel@tonic-gate{
2707c478bdstevel@tonic-gate	int i, j;
2717c478bdstevel@tonic-gate	boolean_t found;
2727c478bdstevel@tonic-gate
2737c478bdstevel@tonic-gate	*overflow = B_FALSE;
2747c478bdstevel@tonic-gate
2757c478bdstevel@tonic-gate	if (SLIST_IS_EMPTY(b))
2767c478bdstevel@tonic-gate		return;
2777c478bdstevel@tonic-gate
2787c478bdstevel@tonic-gate	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
2797c478bdstevel@tonic-gate	ASSERT(b->sl_numsrc <= MAX_FILTER_SIZE);
2807c478bdstevel@tonic-gate
2817c478bdstevel@tonic-gate	for (i = 0; i < b->sl_numsrc; i++) {
2827c478bdstevel@tonic-gate		found = B_FALSE;
2837c478bdstevel@tonic-gate		for (j = 0; j < a->sl_numsrc; j++) {
2847c478bdstevel@tonic-gate			if (IN6_ARE_ADDR_EQUAL(
2857c478bdstevel@tonic-gate			    &b->sl_addr[i], &a->sl_addr[j])) {
2867c478bdstevel@tonic-gate				found = B_TRUE;
2877c478bdstevel@tonic-gate				break;
2887c478bdstevel@tonic-gate			}
2897c478bdstevel@tonic-gate		}
2907c478bdstevel@tonic-gate		if (!found) {
2917c478bdstevel@tonic-gate			if (a->sl_numsrc == MAX_FILTER_SIZE) {
2927c478bdstevel@tonic-gate				*overflow = B_TRUE;
2937c478bdstevel@tonic-gate				break;
2947c478bdstevel@tonic-gate			} else {
2957c478bdstevel@tonic-gate				a->sl_addr[a->sl_numsrc++] = b->sl_addr[i];
2967c478bdstevel@tonic-gate			}
2977c478bdstevel@tonic-gate		}
2987c478bdstevel@tonic-gate	}
2997c478bdstevel@tonic-gate}
3007c478bdstevel@tonic-gate
3017c478bdstevel@tonic-gate/*
3027c478bdstevel@tonic-gate * Remove from list a any addresses that are not also in list b
3037c478bdstevel@tonic-gate * (i.e. perform a * b and store the result in a).
3047c478bdstevel@tonic-gate *
3057c478bdstevel@tonic-gate * Caller guarantees that a and b are <= MAX_FILTER_SIZE, and that
3067c478bdstevel@tonic-gate * a is a valid pointer.
3077c478bdstevel@tonic-gate */
3087c478bdstevel@tonic-gatevoid
3097c478bdstevel@tonic-gatel_intersection_in_a(slist_t *a, const slist_t *b)
3107c478bdstevel@tonic-gate{
3117c478bdstevel@tonic-gate	int i, j, shift;
3127c478bdstevel@tonic-gate	boolean_t found;
3137c478bdstevel@tonic-gate
3147c478bdstevel@tonic-gate	if (SLIST_IS_EMPTY(b)) {
3157c478bdstevel@tonic-gate		a->sl_numsrc = 0;
3167c478bdstevel@tonic-gate		return;
3177c478bdstevel@tonic-gate	}
3187c478bdstevel@tonic-gate
3197c478bdstevel@tonic-gate	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
3207c478bdstevel@tonic-gate	ASSERT(b->sl_numsrc <= MAX_FILTER_SIZE);
3217c478bdstevel@tonic-gate
3227c478bdstevel@tonic-gate	shift = 0;
3237c478bdstevel@tonic-gate	for (i = 0; i < a->sl_numsrc; i++) {
3247c478bdstevel@tonic-gate		found = B_FALSE;
3257c478bdstevel@tonic-gate		for (j = 0; j < b->sl_numsrc; j++) {
3267c478bdstevel@tonic-gate			if (IN6_ARE_ADDR_EQUAL(
3277c478bdstevel@tonic-gate			    &a->sl_addr[i], &b->sl_addr[j])) {
3287c478bdstevel@tonic-gate				found = B_TRUE;
3297c478bdstevel@tonic-gate				break;
3307c478bdstevel@tonic-gate			}
3317c478bdstevel@tonic-gate		}
3327c478bdstevel@tonic-gate		if (!found)
3337c478bdstevel@tonic-gate			shift++;
3347c478bdstevel@tonic-gate		else if (shift > 0)
3357c478bdstevel@tonic-gate			a->sl_addr[i - shift] = a->sl_addr[i];
3367c478bdstevel@tonic-gate	}
3377c478bdstevel@tonic-gate	a->sl_numsrc -= shift;
3387c478bdstevel@tonic-gate}
3397c478bdstevel@tonic-gate
3407c478bdstevel@tonic-gate/*
3417c478bdstevel@tonic-gate * Remove from list a any addresses that are in list b (i.e. perform
3427c478bdstevel@tonic-gate * a - b and store the result in a).
3437c478bdstevel@tonic-gate *
3447c478bdstevel@tonic-gate * Caller guarantees that a and b are <= MAX_FILTER_SIZE.  If either
3457c478bdstevel@tonic-gate * list is empty (or a null pointer), the function returns without
3467c478bdstevel@tonic-gate * taking any action.
3477c478bdstevel@tonic-gate */
3487c478bdstevel@tonic-gatevoid
3497c478bdstevel@tonic-gatel_difference_in_a(slist_t *a, const slist_t *b)
3507c478bdstevel@tonic-gate{
3517c478bdstevel@tonic-gate	int i, j, shift;
3527c478bdstevel@tonic-gate	boolean_t found;
3537c478bdstevel@tonic-gate
3547c478bdstevel@tonic-gate	if (SLIST_IS_EMPTY(a) || SLIST_IS_EMPTY(b))
3557c478bdstevel@tonic-gate		return;
3567c478bdstevel@tonic-gate
3577c478bdstevel@tonic-gate	ASSERT(a->sl_numsrc <= MAX_FILTER_SIZE);
3587c478bdstevel@tonic-gate	ASSERT(b->sl_numsrc <= MAX_FILTER_SIZE);
3597c478bdstevel@tonic-gate
3607c478bdstevel@tonic-gate	shift = 0;
3617c478bdstevel@tonic-gate	for (i = 0; i < a->sl_numsrc; i++) {
3627c478bdstevel@tonic-gate		found = B_FALSE;
3637c478bdstevel@tonic-gate		for (j = 0; j < b->sl_numsrc; j++) {
3647c478bdstevel@tonic-gate			if (IN6_ARE_ADDR_EQUAL(
3657c478bdstevel@tonic-gate			    &a->sl_addr[i], &b->sl_addr[j])) {
3667c478bdstevel@tonic-gate				found = B_TRUE;
3677c478bdstevel@tonic-gate				break;
3687c478bdstevel@tonic-gate			}
3697c478bdstevel@tonic-gate		}
3707c478bdstevel@tonic-gate		if (found)
3717c478bdstevel@tonic-gate			shift++;
3727c478bdstevel@tonic-gate		else if (shift > 0)
3737c478bdstevel@tonic-gate			a->sl_addr[i - shift] = a->sl_addr[i];
3747c478bdstevel@tonic-gate	}
3757c478bdstevel@tonic-gate	a->sl_numsrc -= shift;
3767c478bdstevel@tonic-gate}
3777c478bdstevel@tonic-gate
3787c478bdstevel@tonic-gate/*
3797c478bdstevel@tonic-gate * Wrapper function to alloc an slist_t.
3807c478bdstevel@tonic-gate */
3817c478bdstevel@tonic-gateslist_t *
3827c478bdstevel@tonic-gatel_alloc()
3837c478bdstevel@tonic-gate{
3847c478bdstevel@tonic-gate	slist_t *p;
3857c478bdstevel@tonic-gate
3867c478bdstevel@tonic-gate	p = (slist_t *)mi_alloc(sizeof (slist_t), BPRI_MED);
3877c478bdstevel@tonic-gate	if (p != NULL)
3887c478bdstevel@tonic-gate		p->sl_numsrc = 0;
3897c478bdstevel@tonic-gate	return (p);
3907c478bdstevel@tonic-gate}
3917c478bdstevel@tonic-gate
3927c478bdstevel@tonic-gate/*
3937c478bdstevel@tonic-gate * Frees an slist_t structure.  Provided for symmetry with l_alloc().
3947c478bdstevel@tonic-gate */
3957c478bdstevel@tonic-gatevoid
3967c478bdstevel@tonic-gatel_free(slist_t *a)
3977c478bdstevel@tonic-gate{
3987c478bdstevel@tonic-gate	mi_free(a);
3997c478bdstevel@tonic-gate}
400