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