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