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