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