1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * RCM module to prevent plumbed IP addresses from being removed.
30  */
31 
32 
33 #include <stdlib.h>
34 #include <ctype.h>
35 #include <memory.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <string.h>
39 #include <thread.h>
40 #include <synch.h>
41 #include <assert.h>
42 #include <errno.h>
43 #include <libintl.h>
44 #include <sys/param.h>
45 #include <sys/wait.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <sys/cladm.h>
49 #include <sys/file.h>
50 #include <sys/ioctl.h>
51 #include <sys/socket.h>
52 #include <sys/sockio.h>
53 #include <sys/time.h>
54 #include <net/if.h>
55 #include <netinet/in.h>
56 #include <arpa/inet.h>
57 #include <netinet/ip6.h>
58 #include <inet/ip.h>
59 #include <inet/ip6.h>
60 #include <libinetutil.h>
61 
62 #include "rcm_module.h"
63 
64 #define	SUNW_IP		"SUNW_ip/"
65 #define	IP_REG_SIZE	(9 + INET6_ADDRSTRLEN)
66 #define	IP_ANON_USAGE	gettext("Plumbed IP Address")
67 #define	IP_SUSPEND_ERR	gettext("Plumbed IP Addresses cannot be suspended")
68 #define	IP_OFFLINE_ERR	gettext("Invalid operation: IP cannot be offlined")
69 #define	IP_REMOVE_ERR	gettext("Invalid operation: IP cannot be removed")
70 #define	IP_REG_FAIL	gettext("Registration Failed")
71 #define	IP_NO_CLUSTER	gettext("Could not read cluster network addresses")
72 
73 #define	IP_FLAG_NEW	0x00
74 #define	IP_FLAG_REG	0x01
75 #define	IP_FLAG_CL	0x02
76 #define	IP_FLAG_IGNORE	0x04
77 #define	IP_FLAG_DELETE	0x08
78 
79 static int		ip_anon_register(rcm_handle_t *);
80 static int		ip_anon_unregister(rcm_handle_t *);
81 static int		ip_anon_getinfo(rcm_handle_t *, char *, id_t, uint_t,
82 			    char **, char **, nvlist_t *, rcm_info_t **);
83 static int		ip_anon_suspend(rcm_handle_t *, char *, id_t,
84 			    timespec_t *, uint_t, char **, rcm_info_t **);
85 static int		ip_anon_resume(rcm_handle_t *, char *, id_t, uint_t,
86 			    char **, rcm_info_t **);
87 static int		ip_anon_offline(rcm_handle_t *, char *, id_t, uint_t,
88 			    char **, rcm_info_t **);
89 static int		ip_anon_online(rcm_handle_t *, char *, id_t, uint_t,
90 			    char **, rcm_info_t **);
91 static int		ip_anon_remove(rcm_handle_t *, char *, id_t, uint_t,
92 			    char **, rcm_info_t **);
93 
94 static int		exclude_ipv4(cladm_netaddrs_t exclude_addrs,
95 			    ipaddr_t address);
96 static int		exclude_ipv6(cladm_netaddrs_t exclude_addrs,
97 			    uint32_t address[4]);
98 
99 
100 typedef struct ip_status {
101 	int			flags;
102 	char			device[IP_REG_SIZE];
103 	struct ip_status	*next;
104 } ip_status_t;
105 
106 static ip_status_t	*findreg(char *reg);
107 static ip_status_t	*addreg(char *reg);
108 static int		deletereg(ip_status_t *entry);
109 
110 static ip_status_t	*ip_list = NULL;
111 static mutex_t		ip_list_lock;
112 
113 static struct rcm_mod_ops ip_anon_ops =
114 {
115 	RCM_MOD_OPS_VERSION,
116 	ip_anon_register,
117 	ip_anon_unregister,
118 	ip_anon_getinfo,
119 	ip_anon_suspend,
120 	ip_anon_resume,
121 	ip_anon_offline,
122 	ip_anon_online,
123 	ip_anon_remove,
124 	NULL,
125 	NULL,
126 	NULL
127 };
128 
129 struct rcm_mod_ops *
130 rcm_mod_init()
131 {
132 	return (&ip_anon_ops);
133 }
134 
135 const char *
136 rcm_mod_info()
137 {
138 	return ("RCM IP address module 1.4");
139 }
140 
141 int
142 rcm_mod_fini()
143 {
144 	ip_status_t *tlist;
145 
146 	/* free the registration list */
147 
148 	(void) mutex_lock(&ip_list_lock);
149 	while (ip_list != NULL) {
150 		tlist = ip_list->next;
151 		free(ip_list);
152 		ip_list = tlist;
153 	}
154 	(void) mutex_unlock(&ip_list_lock);
155 
156 	(void) mutex_destroy(&ip_list_lock);
157 	return (RCM_SUCCESS);
158 }
159 
160 static int
161 ip_anon_register(rcm_handle_t *hdl)
162 {
163 	int bootflags;
164 	struct ifaddrlist *al = NULL, *al6 = NULL;
165 	char errbuf[ERRBUFSIZE];
166 	char treg[IP_REG_SIZE], tstr[IP_REG_SIZE];
167 	cladm_netaddrs_t exclude_addrs;
168 	int num_ifs, num_ifs6,  i, ret;
169 	uint32_t num_exclude_addrs = 0;
170 	ip_status_t *tlist, *tentry;
171 
172 	(void) mutex_lock(&ip_list_lock);
173 
174 	rcm_log_message(RCM_DEBUG, "ip_anon: registration refresh.\n");
175 
176 	exclude_addrs.cladm_num_netaddrs = 0;
177 
178 	if (_cladm(CL_INITIALIZE, CL_GET_BOOTFLAG, &bootflags) != 0) {
179 		rcm_log_message(RCM_ERROR,
180 			gettext("unable to check cluster status\n"));
181 		(void) mutex_unlock(&ip_list_lock);
182 		return (RCM_FAILURE);
183 	}
184 
185 	rcm_log_message(RCM_DEBUG,
186 	    "ip_anon: cladm bootflags=%d\n", bootflags);
187 
188 	if (bootflags == 3) {
189 
190 		/* build the exclusion list */
191 
192 		if ((ret = _cladm(CL_CONFIG, CL_GET_NUM_NETADDRS,
193 		    &num_exclude_addrs)) == 0) {
194 			exclude_addrs.cladm_num_netaddrs = num_exclude_addrs;
195 
196 			if (num_exclude_addrs == 0)
197 				rcm_log_message(RCM_DEBUG,
198 				    "ip_anon: no addresses excluded\n");
199 			else {
200 				if ((exclude_addrs.cladm_netaddrs_array =
201 				    malloc(sizeof (cladm_netaddr_entry_t) *
202 					    (num_exclude_addrs))) == NULL) {
203 					rcm_log_message(RCM_ERROR,
204 					    gettext("out of memory\n"));
205 					(void) mutex_unlock(&ip_list_lock);
206 					return (RCM_FAILURE);
207 				}
208 
209 				if ((ret = _cladm(CL_CONFIG,
210 				    CL_GET_NETADDRS, &exclude_addrs))
211 				    != 0) {
212 					rcm_log_message(RCM_ERROR,
213 					    IP_NO_CLUSTER);
214 					(void) mutex_unlock(&ip_list_lock);
215 					return (RCM_FAILURE);
216 				}
217 			}
218 
219 		} else {
220 			if ((ret != 0) && (errno == EINVAL)) {
221 				rcm_log_message(RCM_DEBUG,
222 				    "no _cladm() backend to get addrs\n");
223 			} else {
224 				rcm_log_message(RCM_ERROR, IP_NO_CLUSTER);
225 				(void) mutex_unlock(&ip_list_lock);
226 				return (RCM_FAILURE);
227 			}
228 		}
229 		rcm_log_message(RCM_DEBUG,
230 		    "cladm returned %d errno=%d\n", ret, errno);
231 
232 		rcm_log_message(RCM_DEBUG,
233 		    "ip_anon: num exclude addrs: %d\n",
234 		    exclude_addrs.cladm_num_netaddrs);
235 
236 		/* print the exclusion list for debugging purposes */
237 
238 		for (i = 0; i < exclude_addrs.cladm_num_netaddrs; i++) {
239 			(void) strcpy(treg, "<UNKNOWN>");
240 			(void) strcpy(tstr, "<UNKNOWN>");
241 			if (exclude_addrs.cladm_netaddrs_array[i].\
242 			    cl_ipversion == IPV4_VERSION) {
243 				(void) inet_ntop(AF_INET,
244 				    &exclude_addrs.cladm_netaddrs_array[i].
245 				    cl_ipv_un.cl_ipv4.ipv4_netaddr,
246 				    treg, INET_ADDRSTRLEN);
247 
248 				(void) inet_ntop(AF_INET,
249 				    &exclude_addrs.cladm_netaddrs_array[i].
250 				    cl_ipv_un.cl_ipv4.ipv4_netmask,
251 				    tstr, INET_ADDRSTRLEN);
252 			}
253 
254 			if (exclude_addrs.cladm_netaddrs_array[i].\
255 			    cl_ipversion == IPV6_VERSION) {
256 				(void) inet_ntop(AF_INET6,
257 				    &exclude_addrs.cladm_netaddrs_array[i].
258 				    cl_ipv_un.cl_ipv6.ipv6_netaddr,
259 				    treg, INET6_ADDRSTRLEN);
260 
261 				(void) inet_ntop(AF_INET6,
262 				    &exclude_addrs.cladm_netaddrs_array[i].
263 				    cl_ipv_un.cl_ipv6.ipv6_netmask,
264 				    tstr, INET6_ADDRSTRLEN);
265 			}
266 			rcm_log_message(RCM_DEBUG, "IPV%d: %s %s\n",
267 			    exclude_addrs.cladm_netaddrs_array[i].
268 			    cl_ipversion, treg, tstr);
269 
270 		}
271 	}
272 
273 	/* obtain a list of all IPv4 and IPv6 addresses in the system */
274 
275 	rcm_log_message(RCM_DEBUG,
276 	    "ip_anon: obtaining list of IPv4 addresses.\n");
277 	num_ifs = ifaddrlist(&al, AF_INET, errbuf);
278 	if (num_ifs == -1) {
279 		rcm_log_message(RCM_ERROR,
280 		    gettext("cannot get IPv4 address list errno=%d (%s)\n"),
281 		    errno, errbuf);
282 		(void) mutex_unlock(&ip_list_lock);
283 		return (RCM_FAILURE);
284 	}
285 
286 	rcm_log_message(RCM_DEBUG,
287 	    "ip_anon: obtaining list of IPv6 addresses.\n");
288 
289 	num_ifs6 = ifaddrlist(&al6, AF_INET6, errbuf);
290 	if (num_ifs6 == -1) {
291 		rcm_log_message(RCM_ERROR,
292 		    gettext("cannot get IPv6 address list errno=%d (%s)\n"),
293 		    errno, errbuf);
294 		free(al);
295 		(void) mutex_unlock(&ip_list_lock);
296 		return (RCM_FAILURE);
297 	}
298 
299 	/* check the state of outstanding registrations against the list */
300 
301 	rcm_log_message(RCM_DEBUG,
302 	    "ip_anon: checking outstanding registrations.\n");
303 
304 	tlist = ip_list;
305 	while (tlist != NULL) {
306 		tlist->flags |= IP_FLAG_DELETE;
307 		tlist = tlist->next;
308 	}
309 
310 	/* IPv4 */
311 
312 	rcm_log_message(RCM_DEBUG, "ip_anon: checking IPv4 addresses.\n");
313 
314 	for (i = 0; i < num_ifs; i++) {
315 		(void) inet_ntop(AF_INET, &al[i].addr.addr, tstr,
316 		    INET_ADDRSTRLEN);
317 		(void) strcpy(treg, SUNW_IP);
318 		(void) strcat(treg, tstr);
319 
320 		if ((tlist = findreg(treg)) == NULL)
321 			tlist = addreg(treg);
322 		else
323 			tlist->flags &= (~IP_FLAG_DELETE);
324 
325 		if (tlist == NULL) {
326 			rcm_log_message(RCM_ERROR,
327 			    gettext("out of memory\n"));
328 			free(al);
329 			free(al6);
330 			(void) mutex_unlock(&ip_list_lock);
331 			return (RCM_FAILURE);
332 		}
333 
334 		if (exclude_ipv4(exclude_addrs, al[i].addr.addr.s_addr))
335 			tlist->flags |= IP_FLAG_CL;
336 	}
337 
338 	/* IPv6 */
339 
340 	rcm_log_message(RCM_DEBUG, "ip_anon: checking IPv6 addresses.\n");
341 
342 	for (i = 0; i < num_ifs6; i++) {
343 		(void) inet_ntop(AF_INET6, &al6[i].addr.addr, tstr,
344 		    INET6_ADDRSTRLEN);
345 		(void) strcpy(treg, SUNW_IP);
346 		(void) strcat(treg, tstr);
347 
348 		if ((tlist = findreg(treg)) == NULL)
349 			tlist = addreg(treg);
350 		else
351 			tlist->flags &= (~IP_FLAG_DELETE);
352 
353 		if (tlist == NULL) {
354 			rcm_log_message(RCM_ERROR,
355 			    gettext("out of memory\n"));
356 			free(al);
357 			free(al6);
358 			(void) mutex_unlock(&ip_list_lock);
359 			return (RCM_FAILURE);
360 		}
361 
362 		if (exclude_ipv6(exclude_addrs, al6[i].addr.addr6._S6_un.\
363 		    _S6_u32))
364 			tlist->flags |= IP_FLAG_CL;
365 	}
366 
367 	rcm_log_message(RCM_DEBUG, "ip_anon: updating reg. state.\n");
368 
369 	/* examine the list of ip address registrations and their state */
370 
371 	tlist = ip_list;
372 	while (tlist != NULL) {
373 		tentry = tlist;
374 		tlist = tlist->next;
375 
376 		if (tentry->flags & IP_FLAG_DELETE) {
377 			if (tentry->flags & IP_FLAG_REG) {
378 				rcm_log_message(RCM_DEBUG,
379 				    "ip_anon: unregistering interest in %s\n",
380 				    tentry->device);
381 				if (rcm_unregister_interest(hdl,
382 				    tentry->device, 0) != 0) {
383 					rcm_log_message(RCM_ERROR,
384 					    gettext("failed to unregister"));
385 				}
386 			}
387 			(void) deletereg(tentry);
388 		} else if (!(tentry->flags & IP_FLAG_IGNORE)) {
389 			/*
390 			 * If the registration is not a clustered devices and
391 			 * not already registered, then RCM doesn't
392 			 * currently know about it.
393 			 */
394 			if (!(tentry->flags & IP_FLAG_CL) &&
395 				!(tentry->flags & IP_FLAG_REG)) {
396 				tentry->flags |= IP_FLAG_REG;
397 				rcm_log_message(RCM_DEBUG,
398 				    "ip_anon: registering interest in %s\n",
399 				    tentry->device);
400 				if (rcm_register_interest(hdl,
401 				    tentry->device, 0, NULL) !=
402 				    RCM_SUCCESS) {
403 					rcm_log_message(RCM_ERROR,
404 					    IP_REG_FAIL);
405 					free(al);
406 					free(al6);
407 					(void) mutex_unlock(&ip_list_lock);
408 					return (RCM_FAILURE);
409 				} else {
410 					rcm_log_message(RCM_DEBUG,
411 					    "ip_anon: registered %s\n",
412 					    tentry->device);
413 				}
414 			}
415 
416 			/*
417 			 * If the entry is registered and clustered, then
418 			 * the configuration has been changed and it
419 			 * should be unregistered.
420 			 */
421 			if ((tentry->flags & IP_FLAG_REG) &
422 			    (tentry->flags & IP_FLAG_CL)) {
423 				rcm_log_message(RCM_DEBUG,
424 				    "ip_anon: unregistering in %s\n",
425 				    tentry->device);
426 				if (rcm_unregister_interest(hdl,
427 				    tentry->device, 0) != 0) {
428 					rcm_log_message(RCM_ERROR,
429 					    gettext("failed to unregister"));
430 				}
431 				tentry->flags &= (~IP_FLAG_REG);
432 			}
433 		}
434 	}
435 
436 	tlist = ip_list;
437 	while (tlist != NULL) {
438 		rcm_log_message(RCM_DEBUG, "ip_anon: %s (%Xh)\n",
439 		    tlist->device, tlist->flags);
440 		tlist = tlist->next;
441 	}
442 	rcm_log_message(RCM_DEBUG, "ip_anon: registration complete.\n");
443 
444 	free(al);
445 	free(al6);
446 	(void) mutex_unlock(&ip_list_lock);
447 	return (RCM_SUCCESS);
448 }
449 
450 static int
451 ip_anon_unregister(rcm_handle_t *hdl)
452 {
453 	ip_status_t *tlist;
454 
455 	(void) mutex_lock(&ip_list_lock);
456 
457 	tlist = ip_list;
458 	while (tlist != NULL) {
459 		if ((tlist->flags & IP_FLAG_REG)) {
460 			if (rcm_unregister_interest(hdl,
461 			    tlist->device, 0) != 0) {
462 				rcm_log_message(RCM_ERROR,
463 				    gettext("failed to unregister"));
464 			}
465 			tlist->flags &= (~IP_FLAG_REG);
466 		}
467 		tlist = tlist->next;
468 	}
469 
470 	(void) mutex_unlock(&ip_list_lock);
471 
472 	return (RCM_SUCCESS);
473 }
474 
475 /*ARGSUSED*/
476 static int
477 ip_anon_getinfo(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags,
478     char **infostr, char **errstr, nvlist_t *props, rcm_info_t **dependent)
479 {
480 
481 	assert(rsrcname != NULL && infostr != NULL);
482 
483 	if ((*infostr = strdup(IP_ANON_USAGE)) == NULL)
484 		rcm_log_message(RCM_ERROR, gettext("strdup failure\n"));
485 
486 	return (RCM_SUCCESS);
487 }
488 
489 /*ARGSUSED*/
490 static int
491 ip_anon_suspend(rcm_handle_t *hdl, char *rsrcname, id_t id,
492     timespec_t *interval, uint_t flags, char **errstr,
493     rcm_info_t **dependent)
494 {
495 	if ((*errstr = strdup(IP_SUSPEND_ERR)) == NULL)
496 		rcm_log_message(RCM_ERROR, gettext("strdup failure\n"));
497 
498 	return (RCM_FAILURE);
499 }
500 
501 /*ARGSUSED*/
502 static int
503 ip_anon_resume(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags,
504     char **errstr, rcm_info_t **dependent)
505 {
506 	return (RCM_SUCCESS);
507 }
508 
509 /*ARGSUSED*/
510 static int
511 ip_anon_offline(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags,
512     char **errstr, rcm_info_t **dependent)
513 {
514 	if ((*errstr = strdup(IP_OFFLINE_ERR)) == NULL)
515 		rcm_log_message(RCM_ERROR, gettext("strdup failure\n"));
516 
517 	return (RCM_FAILURE);
518 }
519 
520 /*ARGSUSED*/
521 static int
522 ip_anon_online(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags,
523     char  **errstr, rcm_info_t **dependent)
524 {
525 	return (RCM_SUCCESS);
526 }
527 
528 /*ARGSUSED*/
529 static int
530 ip_anon_remove(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags,
531     char **errstr, rcm_info_t **dependent)
532 {
533 	if ((*errstr = strdup(IP_REMOVE_ERR)) == NULL)
534 		rcm_log_message(RCM_ERROR, gettext("strdup failure\n"));
535 
536 	return (RCM_FAILURE);
537 }
538 
539 /*
540  * Call with ip_list_lock held.
541  */
542 
543 static ip_status_t *
544 findreg(char *reg)
545 {
546 	ip_status_t *tlist;
547 	int done;
548 
549 	tlist = ip_list;
550 	done = 0;
551 	while ((tlist != NULL) && (!done)) {
552 		if (strcmp(tlist->device, reg) == 0)
553 			done = 1;
554 		else
555 			tlist = tlist->next;
556 	}
557 
558 	return (tlist);
559 }
560 
561 static ip_status_t *
562 addreg(char *reg)
563 {
564 	ip_status_t *tlist, *tentry;
565 
566 	tentry = (ip_status_t *)malloc(sizeof (ip_status_t));
567 	if (tentry == NULL)
568 		return (tentry);
569 
570 	tentry->flags = IP_FLAG_NEW;
571 	tentry->next = NULL;
572 	(void) strcpy(tentry->device, reg);
573 
574 	if (ip_list == NULL)
575 		ip_list = tentry;
576 	else {
577 		tlist = ip_list;
578 		while (tlist->next != NULL)
579 			tlist = tlist->next;
580 		tlist->next = tentry;
581 	}
582 
583 	return (tentry);
584 }
585 
586 static int
587 deletereg(ip_status_t *entry)
588 {
589 	ip_status_t *tlist;
590 
591 	if (entry == NULL)
592 		return (-1);
593 
594 	if (entry == ip_list) {
595 		ip_list = ip_list->next;
596 		free(entry);
597 	} else {
598 		tlist = ip_list;
599 		while ((tlist->next != NULL) && (tlist->next != entry))
600 			tlist = tlist->next;
601 
602 		if (tlist->next != entry)
603 			return (-1);
604 		tlist->next = entry->next;
605 		free(entry);
606 	}
607 	return (0);
608 }
609 
610 static int
611 exclude_ipv4(cladm_netaddrs_t exclude_addrs, ipaddr_t address)
612 {
613 	int i;
614 	char taddr[IP_REG_SIZE], tmask[IP_REG_SIZE], tmatch[IP_REG_SIZE];
615 	ipaddr_t ipv4_netaddr, ipv4_netmask;
616 
617 	(void) inet_ntop(AF_INET, &address, taddr, INET_ADDRSTRLEN);
618 
619 	rcm_log_message(RCM_DEBUG, "ip_anon: exclude_ipv4 (%s, %d)\n",
620 	    taddr, exclude_addrs.cladm_num_netaddrs);
621 	/*
622 	 * If this falls in the exclusion list, the IP_FLAG_CL
623 	 * bit should be set for the adapter.
624 	 */
625 	for (i = 0; i < exclude_addrs.cladm_num_netaddrs; i++) {
626 		if (exclude_addrs.cladm_netaddrs_array[i].\
627 		    cl_ipversion == IPV4_VERSION) {
628 
629 			ipv4_netaddr = exclude_addrs.\
630 			    cladm_netaddrs_array[i].cl_ipv_un.cl_ipv4.\
631 			    ipv4_netaddr;
632 			ipv4_netmask = exclude_addrs.\
633 			    cladm_netaddrs_array[i].cl_ipv_un.cl_ipv4.\
634 			    ipv4_netmask;
635 
636 			(void) inet_ntop(AF_INET, &ipv4_netaddr, tmatch,
637 			    INET_ADDRSTRLEN);
638 			(void) inet_ntop(AF_INET, &ipv4_netmask, tmask,
639 			    INET_ADDRSTRLEN);
640 
641 			if ((address & ipv4_netmask) == ipv4_netaddr) {
642 				rcm_log_message(RCM_DEBUG,
643 				    "ip_anon: matched %s:%s => %s\n",
644 				    taddr, tmask, tmatch);
645 				return (1);
646 			}
647 		}
648 	}
649 	rcm_log_message(RCM_DEBUG, "ip_anon: no match for %s\n",
650 	    taddr);
651 	return (0);
652 }
653 
654 static int
655 exclude_ipv6(cladm_netaddrs_t exclude_addrs, uint32_t address[4])
656 {
657 	int i, j, numequal;
658 	uint32_t addr[4], ipv6_netaddr[4], ipv6_netmask[4];
659 	char taddr[IP_REG_SIZE], tmask[IP_REG_SIZE], tmatch[IP_REG_SIZE];
660 
661 	(void) inet_ntop(AF_INET6, address, taddr, INET6_ADDRSTRLEN);
662 
663 	/*
664 	 * If this falls in the exclusion list, the IP_FLAG_CL
665 	 * bit should be set for the adapter.
666 	 */
667 
668 	for (i = 0; i < exclude_addrs.cladm_num_netaddrs; i++) {
669 		if (exclude_addrs.cladm_netaddrs_array[i].\
670 		    cl_ipversion == IPV6_VERSION) {
671 			numequal = 0;
672 			for (j = 0; j < 4; j++) {
673 				ipv6_netaddr[j] = exclude_addrs.\
674 				    cladm_netaddrs_array[i].\
675 				    cl_ipv_un.cl_ipv6.ipv6_netaddr[j];
676 
677 				ipv6_netmask[j] = exclude_addrs.\
678 				    cladm_netaddrs_array[i].\
679 				    cl_ipv_un.cl_ipv6.ipv6_netmask[j];
680 
681 				addr[j] = address[j] & ipv6_netmask[j];
682 				if (addr[j] == ipv6_netaddr[j])
683 					numequal++;
684 			}
685 
686 			(void) inet_ntop(AF_INET6, ipv6_netaddr, tmatch,
687 			    INET6_ADDRSTRLEN);
688 			(void) inet_ntop(AF_INET6, ipv6_netmask, tmask,
689 			    INET6_ADDRSTRLEN);
690 
691 			if (numequal == 4)
692 				return (1);
693 		}
694 	}
695 	rcm_log_message(RCM_DEBUG, "ip_anon: no match for %s\n",
696 	    taddr);
697 	return (0);
698 }
699