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