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 * This RCM module adds support to the RCM framework for IP managed 28 * interfaces. 29 */ 30 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <assert.h> 35 #include <string.h> 36 #include <synch.h> 37 #include <libintl.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <sys/types.h> 41 #include <sys/wait.h> 42 #include <sys/stat.h> 43 #include <sys/socket.h> 44 #include <sys/sockio.h> 45 #include <net/if.h> 46 #include <netinet/in.h> 47 #include <arpa/inet.h> 48 #include <stropts.h> 49 #include <strings.h> 50 #include <sys/sysmacros.h> 51 #include <inet/ip.h> 52 #include <libinetutil.h> 53 #include <libdllink.h> 54 #include <libgen.h> 55 #include <ipmp_admin.h> 56 57 #include "rcm_module.h" 58 59 /* 60 * Definitions 61 */ 62 #ifndef lint 63 #define _(x) gettext(x) 64 #else 65 #define _(x) x 66 #endif 67 68 /* Some generic well-knowns and defaults used in this module */ 69 #define ARP_MOD_NAME "arp" /* arp module */ 70 #define IP_MAX_MODS 9 /* max modules pushed on intr */ 71 #define MAX_RECONFIG_SIZE 1024 /* Max. reconfig string size */ 72 73 #define RCM_LINK_PREFIX "SUNW_datalink" /* RCM datalink name prefix */ 74 #define RCM_LINK_RESOURCE_MAX (13 + LINKID_STR_WIDTH) 75 76 #define RCM_STR_SUNW_IP "SUNW_ip/" /* IP address export prefix */ 77 78 #define SBIN_IFCONFIG "/sbin/ifconfig" /* ifconfig command */ 79 #define SBIN_IFPARSE "/sbin/ifparse" /* ifparse command */ 80 #define DHCPFILE_FMT "/etc/dhcp.%s" /* DHCP config file */ 81 #define CFGFILE_FMT_IPV4 "/etc/hostname.%s" /* IPV4 config file */ 82 #define CFGFILE_FMT_IPV6 "/etc/hostname6.%s" /* IPV6 config file */ 83 #define CFG_CMDS_STD " netmask + broadcast + up" /* Normal config string */ 84 #define CFG_DHCP_CMD "dhcp wait 0" /* command to start DHCP */ 85 86 /* Some useful macros */ 87 #define ISSPACE(c) ((c) == ' ' || (c) == '\t') 88 #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') 89 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 90 91 /* Interface Cache state flags */ 92 #define CACHE_IF_STALE 0x1 /* stale cached data */ 93 #define CACHE_IF_NEW 0x2 /* new cached interface */ 94 #define CACHE_IF_OFFLINED 0x4 /* interface offlined */ 95 #define CACHE_IF_IGNORE 0x8 /* state held elsewhere */ 96 97 /* Network Cache lookup options */ 98 #define CACHE_NO_REFRESH 0x1 /* cache refresh not needed */ 99 #define CACHE_REFRESH 0x2 /* refresh cache */ 100 101 /* RCM IPMP Module specific property definitions */ 102 #define RCM_IPMP_MIN_REDUNDANCY 1 /* default min. redundancy */ 103 104 /* Stream module operations */ 105 #define MOD_INSERT 0 /* Insert a mid-stream module */ 106 #define MOD_REMOVE 1 /* Remove a mid-stream module */ 107 #define MOD_CHECK 2 /* Check mid-stream module safety */ 108 109 /* 110 * IP module data types 111 */ 112 113 /* Physical interface representation */ 114 typedef struct ip_pif { 115 char pi_ifname[LIFNAMSIZ]; /* interface name */ 116 char pi_grname[LIFGRNAMSIZ]; /* IPMP group name */ 117 struct ip_lif *pi_lifs; /* ptr to logical interfaces */ 118 } ip_pif_t; 119 120 /* Logical interface representation */ 121 typedef struct ip_lif 122 { 123 struct ip_lif *li_next; /* ptr to next lif */ 124 struct ip_lif *li_prev; /* previous next ptr */ 125 ip_pif_t *li_pif; /* back ptr to phy int */ 126 ushort_t li_ifnum; /* interface number */ 127 union { 128 sa_family_t family; 129 struct sockaddr_storage storage; 130 struct sockaddr_in ip4; /* IPv4 */ 131 struct sockaddr_in6 ip6; /* IPv6 */ 132 } li_addr; 133 uint64_t li_ifflags; /* current IFF_* flags */ 134 int li_modcnt; /* # of modules */ 135 char *li_modules[IP_MAX_MODS]; /* module list pushed */ 136 char *li_reconfig; /* Reconfiguration string */ 137 int32_t li_cachestate; /* cache state flags */ 138 } ip_lif_t; 139 140 /* Cache element */ 141 typedef struct ip_cache 142 { 143 struct ip_cache *ip_next; /* next cached resource */ 144 struct ip_cache *ip_prev; /* prev cached resource */ 145 char *ip_resource; /* resource name */ 146 ip_pif_t *ip_pif; /* ptr to phy int */ 147 int32_t ip_ifred; /* min. redundancy */ 148 int ip_cachestate; /* cache state flags */ 149 } ip_cache_t; 150 151 /* 152 * Global cache for network interfaces 153 */ 154 static ip_cache_t cache_head; 155 static ip_cache_t cache_tail; 156 static mutex_t cache_lock; 157 static int events_registered = 0; 158 159 static dladm_handle_t dld_handle = NULL; 160 161 /* 162 * RCM module interface prototypes 163 */ 164 static int ip_register(rcm_handle_t *); 165 static int ip_unregister(rcm_handle_t *); 166 static int ip_get_info(rcm_handle_t *, char *, id_t, uint_t, 167 char **, char **, nvlist_t *, rcm_info_t **); 168 static int ip_suspend(rcm_handle_t *, char *, id_t, 169 timespec_t *, uint_t, char **, rcm_info_t **); 170 static int ip_resume(rcm_handle_t *, char *, id_t, uint_t, 171 char **, rcm_info_t **); 172 static int ip_offline(rcm_handle_t *, char *, id_t, uint_t, 173 char **, rcm_info_t **); 174 static int ip_undo_offline(rcm_handle_t *, char *, id_t, uint_t, 175 char **, rcm_info_t **); 176 static int ip_remove(rcm_handle_t *, char *, id_t, uint_t, 177 char **, rcm_info_t **); 178 static int ip_notify_event(rcm_handle_t *, char *, id_t, uint_t, 179 char **, nvlist_t *, rcm_info_t **); 180 181 /* Module private routines */ 182 static void free_cache(); 183 static int update_cache(rcm_handle_t *); 184 static void cache_remove(ip_cache_t *); 185 static ip_cache_t *cache_lookup(rcm_handle_t *, char *, char); 186 static void free_node(ip_cache_t *); 187 static void cache_insert(ip_cache_t *); 188 static char *ip_usage(ip_cache_t *); 189 static int update_pif(rcm_handle_t *, int, int, struct lifreq *); 190 static int ip_ipmp_offline(ip_cache_t *); 191 static int ip_ipmp_undo_offline(ip_cache_t *); 192 static int if_cfginfo(ip_cache_t *, uint_t); 193 static int if_unplumb(ip_cache_t *); 194 static int if_replumb(ip_cache_t *); 195 static void ip_log_err(ip_cache_t *, char **, char *); 196 static char *get_link_resource(const char *); 197 static void clr_cfg_state(ip_pif_t *); 198 static int modop(char *, char *, int, char); 199 static int get_modlist(char *, ip_lif_t *); 200 static int ip_domux2fd(int *, int *, int *, struct lifreq *); 201 static int ip_plink(int, int, int, struct lifreq *); 202 static int ip_onlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t, 203 rcm_info_t **); 204 static int ip_offlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t, 205 rcm_info_t **); 206 static char **ip_get_addrlist(ip_cache_t *); 207 static void ip_free_addrlist(char **); 208 static void ip_consumer_notify(rcm_handle_t *, datalink_id_t, char **, 209 uint_t, rcm_info_t **); 210 static boolean_t ip_addrstr(ip_lif_t *, char *, size_t); 211 212 static int if_configure(datalink_id_t); 213 static boolean_t isgrouped(const char *); 214 static int if_config_inst(const char *, FILE *, int, boolean_t); 215 static uint_t ntok(const char *cp); 216 static boolean_t ifconfig(const char *, const char *, const char *, boolean_t); 217 218 /* Module-Private data */ 219 static struct rcm_mod_ops ip_ops = 220 { 221 RCM_MOD_OPS_VERSION, 222 ip_register, 223 ip_unregister, 224 ip_get_info, 225 ip_suspend, 226 ip_resume, 227 ip_offline, 228 ip_undo_offline, 229 ip_remove, 230 NULL, 231 NULL, 232 ip_notify_event 233 }; 234 235 /* 236 * rcm_mod_init() - Update registrations, and return the ops structure. 237 */ 238 struct rcm_mod_ops * 239 rcm_mod_init(void) 240 { 241 rcm_log_message(RCM_TRACE1, "IP: mod_init\n"); 242 243 cache_head.ip_next = &cache_tail; 244 cache_head.ip_prev = NULL; 245 cache_tail.ip_prev = &cache_head; 246 cache_tail.ip_next = NULL; 247 (void) mutex_init(&cache_lock, NULL, NULL); 248 249 (void) dladm_open(&dld_handle); 250 251 /* Return the ops vectors */ 252 return (&ip_ops); 253 } 254 255 /* 256 * rcm_mod_info() - Return a string describing this module. 257 */ 258 const char * 259 rcm_mod_info(void) 260 { 261 rcm_log_message(RCM_TRACE1, "IP: mod_info\n"); 262 263 return ("IP Multipathing module version 1.23"); 264 } 265 266 /* 267 * rcm_mod_fini() - Destroy the network interfaces cache. 268 */ 269 int 270 rcm_mod_fini(void) 271 { 272 rcm_log_message(RCM_TRACE1, "IP: mod_fini\n"); 273 274 free_cache(); 275 (void) mutex_destroy(&cache_lock); 276 277 dladm_close(dld_handle); 278 return (RCM_SUCCESS); 279 } 280 281 /* 282 * ip_register() - Make sure the cache is properly sync'ed, and its 283 * registrations are in order. 284 */ 285 static int 286 ip_register(rcm_handle_t *hd) 287 { 288 rcm_log_message(RCM_TRACE1, "IP: register\n"); 289 290 /* Guard against bad arguments */ 291 assert(hd != NULL); 292 293 if (update_cache(hd) < 0) 294 return (RCM_FAILURE); 295 296 /* 297 * Need to register interest in all new resources 298 * getting attached, so we get attach event notifications 299 */ 300 if (!events_registered) { 301 if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL) 302 != RCM_SUCCESS) { 303 rcm_log_message(RCM_ERROR, 304 _("IP: failed to register %s\n"), 305 RCM_RESOURCE_LINK_NEW); 306 return (RCM_FAILURE); 307 } else { 308 rcm_log_message(RCM_DEBUG, "IP: registered %s\n", 309 RCM_RESOURCE_LINK_NEW); 310 events_registered++; 311 } 312 } 313 314 return (RCM_SUCCESS); 315 } 316 317 /* 318 * ip_unregister() - Walk the cache, unregistering all the networks. 319 */ 320 static int 321 ip_unregister(rcm_handle_t *hd) 322 { 323 ip_cache_t *probe; 324 325 rcm_log_message(RCM_TRACE1, "IP: unregister\n"); 326 327 /* Guard against bad arguments */ 328 assert(hd != NULL); 329 330 /* Walk the cache, unregistering everything */ 331 (void) mutex_lock(&cache_lock); 332 probe = cache_head.ip_next; 333 while (probe != &cache_tail) { 334 if (rcm_unregister_interest(hd, probe->ip_resource, 0) 335 != RCM_SUCCESS) { 336 /* unregister failed for whatever reason */ 337 (void) mutex_unlock(&cache_lock); 338 return (RCM_FAILURE); 339 } 340 cache_remove(probe); 341 free_node(probe); 342 probe = cache_head.ip_next; 343 } 344 (void) mutex_unlock(&cache_lock); 345 346 /* 347 * Need to unregister interest in all new resources 348 */ 349 if (events_registered) { 350 if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0) 351 != RCM_SUCCESS) { 352 rcm_log_message(RCM_ERROR, 353 _("IP: failed to unregister %s\n"), 354 RCM_RESOURCE_LINK_NEW); 355 return (RCM_FAILURE); 356 } else { 357 rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n", 358 RCM_RESOURCE_LINK_NEW); 359 events_registered--; 360 } 361 } 362 363 return (RCM_SUCCESS); 364 } 365 366 /* 367 * ip_offline() - Offline an interface. 368 */ 369 static int 370 ip_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 371 char **errorp, rcm_info_t **depend_info) 372 { 373 ip_cache_t *node; 374 ip_pif_t *pif; 375 boolean_t detachable = B_FALSE; 376 boolean_t ipmp; 377 int retval; 378 379 rcm_log_message(RCM_TRACE1, "IP: offline(%s)\n", rsrc); 380 381 /* Guard against bad arguments */ 382 assert(hd != NULL); 383 assert(rsrc != NULL); 384 assert(id == (id_t)0); 385 assert(errorp != NULL); 386 assert(depend_info != NULL); 387 388 /* Lock the cache and lookup the resource */ 389 (void) mutex_lock(&cache_lock); 390 node = cache_lookup(hd, rsrc, CACHE_REFRESH); 391 if (node == NULL) { 392 ip_log_err(node, errorp, "Unrecognized resource"); 393 errno = ENOENT; 394 (void) mutex_unlock(&cache_lock); 395 return (RCM_SUCCESS); 396 } 397 398 pif = node->ip_pif; 399 400 /* Establish default detachability criteria */ 401 if (flags & RCM_FORCE) 402 detachable = B_TRUE; 403 404 /* Check if the interface is under IPMP */ 405 ipmp = (pif->pi_grname[0] != '\0'); 406 407 /* 408 * Even if the interface is not under IPMP, it's possible that it's 409 * still okay to offline it as long as there are higher-level failover 410 * mechanisms for the addresses it owns (e.g., clustering). In this 411 * case, ip_offlinelist() will return RCM_SUCCESS, and we charge on. 412 */ 413 if (!ipmp && !detachable) { 414 /* Inform consumers of IP addresses being offlined */ 415 if (ip_offlinelist(hd, node, errorp, flags, depend_info) == 416 RCM_SUCCESS) { 417 rcm_log_message(RCM_DEBUG, 418 "IP: consumers agree on detach"); 419 } else { 420 ip_log_err(node, errorp, 421 "Device consumers prohibit offline"); 422 (void) mutex_unlock(&cache_lock); 423 return (RCM_FAILURE); 424 } 425 } 426 427 /* Check if it's a query */ 428 if (flags & RCM_QUERY) { 429 rcm_log_message(RCM_TRACE1, "IP: offline query success(%s)\n", 430 rsrc); 431 (void) mutex_unlock(&cache_lock); 432 return (RCM_SUCCESS); 433 } 434 435 /* Check detachability, save configuration if detachable */ 436 if (if_cfginfo(node, (flags & RCM_FORCE)) < 0) { 437 node->ip_cachestate |= CACHE_IF_IGNORE; 438 rcm_log_message(RCM_TRACE1, "IP: Ignoring node(%s)\n", rsrc); 439 (void) mutex_unlock(&cache_lock); 440 return (RCM_SUCCESS); 441 } 442 443 /* standalone detachable device */ 444 if (!ipmp) { 445 if (if_unplumb(node) < 0) { 446 ip_log_err(node, errorp, 447 "Failed to unplumb the device"); 448 449 errno = EIO; 450 (void) mutex_unlock(&cache_lock); 451 return (RCM_FAILURE); 452 } 453 454 node->ip_cachestate |= CACHE_IF_OFFLINED; 455 rcm_log_message(RCM_TRACE1, "IP: Offline success(%s)\n", rsrc); 456 (void) mutex_unlock(&cache_lock); 457 return (RCM_SUCCESS); 458 } 459 460 /* 461 * This is an IPMP interface that can be offlined. 462 * Request in.mpathd(1M) to offline the physical interface. 463 */ 464 if ((retval = ip_ipmp_offline(node)) != IPMP_SUCCESS) 465 ip_log_err(node, errorp, "in.mpathd offline failed"); 466 467 if (retval == IPMP_EMINRED && !detachable) { 468 /* 469 * in.mpathd(1M) could not offline the device because it was 470 * the last interface in the group. However, it's possible 471 * that it's still okay to offline it as long as there are 472 * higher-level failover mechanisms for the addresses it owns 473 * (e.g., clustering). In this case, ip_offlinelist() will 474 * return RCM_SUCCESS, and we charge on. 475 */ 476 /* Inform consumers of IP addresses being offlined */ 477 if (ip_offlinelist(hd, node, errorp, flags, 478 depend_info) == RCM_SUCCESS) { 479 rcm_log_message(RCM_DEBUG, 480 "IP: consumers agree on detach"); 481 } else { 482 ip_log_err(node, errorp, 483 "Device consumers prohibit offline"); 484 (void) mutex_unlock(&cache_lock); 485 errno = EBUSY; 486 return (RCM_FAILURE); 487 } 488 } 489 490 if (if_unplumb(node) < 0) { 491 rcm_log_message(RCM_ERROR, 492 _("IP: Unplumb failed (%s)\n"), 493 pif->pi_ifname); 494 495 /* Request in.mpathd to undo the offline */ 496 if (ip_ipmp_undo_offline(node) != IPMP_SUCCESS) { 497 ip_log_err(node, errorp, "Undo offline failed"); 498 (void) mutex_unlock(&cache_lock); 499 return (RCM_FAILURE); 500 } 501 (void) mutex_unlock(&cache_lock); 502 return (RCM_FAILURE); 503 } 504 505 node->ip_cachestate |= CACHE_IF_OFFLINED; 506 rcm_log_message(RCM_TRACE1, "IP: offline success(%s)\n", rsrc); 507 (void) mutex_unlock(&cache_lock); 508 return (RCM_SUCCESS); 509 } 510 511 /* 512 * ip_undo_offline() - Undo offline of a previously offlined device. 513 */ 514 /*ARGSUSED*/ 515 static int 516 ip_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 517 char **errorp, rcm_info_t **depend_info) 518 { 519 ip_cache_t *node; 520 521 rcm_log_message(RCM_TRACE1, "IP: online(%s)\n", rsrc); 522 523 /* Guard against bad arguments */ 524 assert(hd != NULL); 525 assert(rsrc != NULL); 526 assert(id == (id_t)0); 527 assert(errorp != NULL); 528 assert(depend_info != NULL); 529 530 (void) mutex_lock(&cache_lock); 531 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH); 532 533 if (node == NULL) { 534 ip_log_err(node, errorp, "No such device"); 535 (void) mutex_unlock(&cache_lock); 536 errno = ENOENT; 537 return (RCM_FAILURE); 538 } 539 540 /* Check if no attempt should be made to online the device here */ 541 if (node->ip_cachestate & CACHE_IF_IGNORE) { 542 node->ip_cachestate &= ~(CACHE_IF_IGNORE); 543 (void) mutex_unlock(&cache_lock); 544 return (RCM_SUCCESS); 545 } 546 547 /* Check if the interface was previously offlined */ 548 if (!(node->ip_cachestate & CACHE_IF_OFFLINED)) { 549 ip_log_err(node, errorp, "Device not offlined"); 550 (void) mutex_unlock(&cache_lock); 551 errno = ENOTSUP; 552 return (RCM_FAILURE); 553 } 554 555 if (if_replumb(node) == -1) { 556 /* re-plumb failed */ 557 ip_log_err(node, errorp, "Replumb failed"); 558 (void) mutex_unlock(&cache_lock); 559 errno = EIO; 560 return (RCM_FAILURE); 561 562 } 563 564 /* Inform consumers about IP addresses being un-offlined */ 565 (void) ip_onlinelist(hd, node, errorp, flags, depend_info); 566 567 node->ip_cachestate &= ~(CACHE_IF_OFFLINED); 568 rcm_log_message(RCM_TRACE1, "IP: online success(%s)\n", rsrc); 569 (void) mutex_unlock(&cache_lock); 570 return (RCM_SUCCESS); 571 } 572 573 /* 574 * ip_get_info() - Gather usage information for this resource. 575 */ 576 /*ARGSUSED*/ 577 int 578 ip_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 579 char **usagep, char **errorp, nvlist_t *props, rcm_info_t **depend_info) 580 { 581 ip_cache_t *node; 582 char *infostr; 583 584 /* Guard against bad arguments */ 585 assert(hd != NULL); 586 assert(rsrc != NULL); 587 assert(id == (id_t)0); 588 assert(usagep != NULL); 589 assert(errorp != NULL); 590 assert(depend_info != NULL); 591 592 rcm_log_message(RCM_TRACE1, "IP: get_info(%s)\n", rsrc); 593 594 (void) mutex_lock(&cache_lock); 595 node = cache_lookup(hd, rsrc, CACHE_REFRESH); 596 if (!node) { 597 rcm_log_message(RCM_INFO, 598 _("IP: get_info(%s) unrecognized resource\n"), rsrc); 599 (void) mutex_unlock(&cache_lock); 600 errno = ENOENT; 601 return (RCM_FAILURE); 602 } 603 604 infostr = ip_usage(node); 605 606 if (infostr == NULL) { 607 /* most likely malloc failure */ 608 rcm_log_message(RCM_ERROR, 609 _("IP: get_info(%s) malloc failure\n"), rsrc); 610 (void) mutex_unlock(&cache_lock); 611 errno = ENOMEM; 612 *errorp = NULL; 613 return (RCM_FAILURE); 614 } 615 616 /* Set client/role properties */ 617 (void) nvlist_add_string(props, RCM_CLIENT_NAME, "IP"); 618 619 /* Set usage property, infostr will be freed by caller */ 620 *usagep = infostr; 621 622 rcm_log_message(RCM_TRACE1, "IP: get_info(%s) info = %s \n", 623 rsrc, infostr); 624 625 (void) mutex_unlock(&cache_lock); 626 return (RCM_SUCCESS); 627 } 628 629 /* 630 * ip_suspend() - Nothing to do, always okay 631 */ 632 /*ARGSUSED*/ 633 static int 634 ip_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval, 635 uint_t flags, char **errorp, rcm_info_t **depend_info) 636 { 637 /* Guard against bad arguments */ 638 assert(hd != NULL); 639 assert(rsrc != NULL); 640 assert(id == (id_t)0); 641 assert(interval != NULL); 642 assert(errorp != NULL); 643 assert(depend_info != NULL); 644 645 rcm_log_message(RCM_TRACE1, "IP: suspend(%s)\n", rsrc); 646 return (RCM_SUCCESS); 647 } 648 649 /* 650 * ip_resume() - Nothing to do, always okay 651 */ 652 /*ARGSUSED*/ 653 static int 654 ip_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 655 char **errorp, rcm_info_t ** depend_info) 656 { 657 /* Guard against bad arguments */ 658 assert(hd != NULL); 659 assert(rsrc != NULL); 660 assert(id == (id_t)0); 661 assert(errorp != NULL); 662 assert(depend_info != NULL); 663 664 rcm_log_message(RCM_TRACE1, "IP: resume(%s)\n", rsrc); 665 666 return (RCM_SUCCESS); 667 } 668 669 /* 670 * ip_remove() - remove a resource from cache 671 */ 672 /*ARGSUSED*/ 673 static int 674 ip_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 675 char **errorp, rcm_info_t **depend_info) 676 { 677 ip_cache_t *node; 678 679 /* Guard against bad arguments */ 680 assert(hd != NULL); 681 assert(rsrc != NULL); 682 assert(id == (id_t)0); 683 assert(errorp != NULL); 684 assert(depend_info != NULL); 685 686 rcm_log_message(RCM_TRACE1, "IP: remove(%s)\n", rsrc); 687 688 (void) mutex_lock(&cache_lock); 689 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH); 690 if (!node) { 691 rcm_log_message(RCM_INFO, 692 _("IP: remove(%s) unrecognized resource\n"), rsrc); 693 (void) mutex_unlock(&cache_lock); 694 errno = ENOENT; 695 return (RCM_FAILURE); 696 } 697 698 /* remove the cached entry for the resource */ 699 cache_remove(node); 700 free_node(node); 701 702 (void) mutex_unlock(&cache_lock); 703 return (RCM_SUCCESS); 704 } 705 706 /* 707 * ip_notify_event - Project private implementation to receive new resource 708 * events. It intercepts all new resource events. If the 709 * new resource is a network resource, pass up a notify 710 * for it too. The new resource need not be cached, since 711 * it is done at register again. 712 */ 713 /*ARGSUSED*/ 714 static int 715 ip_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 716 char **errorp, nvlist_t *nvl, rcm_info_t **depend_info) 717 { 718 datalink_id_t linkid; 719 nvpair_t *nvp = NULL; 720 uint64_t id64; 721 722 assert(hd != NULL); 723 assert(rsrc != NULL); 724 assert(id == (id_t)0); 725 assert(nvl != NULL); 726 727 rcm_log_message(RCM_TRACE1, "IP: notify_event(%s)\n", rsrc); 728 729 if (!STREQ(rsrc, RCM_RESOURCE_LINK_NEW)) { 730 rcm_log_message(RCM_INFO, 731 _("IP: unrecognized event for %s\n"), rsrc); 732 ip_log_err(NULL, errorp, "unrecognized event"); 733 errno = EINVAL; 734 return (RCM_FAILURE); 735 } 736 737 /* Update cache to reflect latest interfaces */ 738 if (update_cache(hd) < 0) { 739 rcm_log_message(RCM_ERROR, _("IP: update_cache failed\n")); 740 ip_log_err(NULL, errorp, "Private Cache update failed"); 741 return (RCM_FAILURE); 742 } 743 744 rcm_log_message(RCM_TRACE1, "IP: process_nvlist\n"); 745 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 746 if (STREQ(nvpair_name(nvp), RCM_NV_LINKID)) { 747 if (nvpair_value_uint64(nvp, &id64) != 0) { 748 rcm_log_message(RCM_WARNING, 749 _("IP: cannot get linkid\n")); 750 return (RCM_FAILURE); 751 } 752 linkid = (datalink_id_t)id64; 753 if (if_configure(linkid) != 0) { 754 rcm_log_message(RCM_ERROR, 755 _("IP: Configuration failed (%u)\n"), 756 linkid); 757 ip_log_err(NULL, errorp, 758 "Failed configuring one or more IP " 759 "addresses"); 760 } 761 762 /* Notify all IP address consumers */ 763 ip_consumer_notify(hd, linkid, errorp, flags, 764 depend_info); 765 } 766 } 767 768 rcm_log_message(RCM_TRACE1, 769 "IP: notify_event: device configuration complete\n"); 770 771 return (RCM_SUCCESS); 772 } 773 774 /* 775 * ip_usage - Determine the usage of a device. Call with cache_lock held. 776 * The returned buffer is owned by caller, and the caller 777 * must free it up when done. 778 */ 779 static char * 780 ip_usage(ip_cache_t *node) 781 { 782 ip_lif_t *lif; 783 uint_t numup; 784 char *sep, *buf, *linkidstr; 785 datalink_id_t linkid; 786 const char *msg; 787 char link[MAXLINKNAMELEN]; 788 char addrstr[INET6_ADDRSTRLEN]; 789 char errmsg[DLADM_STRSIZE]; 790 dladm_status_t status; 791 boolean_t offline, ipmp; 792 size_t bufsz = 0; 793 794 rcm_log_message(RCM_TRACE2, "IP: usage(%s)\n", node->ip_resource); 795 796 /* 797 * Note that node->ip_resource is in the form of SUNW_datalink/<linkid> 798 */ 799 linkidstr = strchr(node->ip_resource, '/'); 800 assert(linkidstr != NULL); 801 linkidstr = linkidstr ? linkidstr + 1 : node->ip_resource; 802 803 errno = 0; 804 linkid = strtol(linkidstr, &buf, 10); 805 if (errno != 0 || *buf != '\0') { 806 rcm_log_message(RCM_ERROR, 807 _("IP: usage(%s) parse linkid failure (%s)\n"), 808 node->ip_resource, strerror(errno)); 809 return (NULL); 810 } 811 812 if ((status = dladm_datalink_id2info(dld_handle, linkid, NULL, NULL, 813 NULL, link, sizeof (link))) != DLADM_STATUS_OK) { 814 rcm_log_message(RCM_ERROR, 815 _("IP: usage(%s) get link name failure(%s)\n"), 816 node->ip_resource, dladm_status2str(status, errmsg)); 817 return (NULL); 818 } 819 820 /* TRANSLATION_NOTE: separator used between IP addresses */ 821 sep = _(", "); 822 823 numup = 0; 824 for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) 825 if (lif->li_ifflags & IFF_UP) 826 numup++; 827 828 ipmp = (node->ip_pif->pi_grname[0] != '\0'); 829 offline = ((node->ip_cachestate & CACHE_IF_OFFLINED) != 0); 830 831 if (offline) { 832 msg = _("offlined"); 833 } else if (numup == 0) { 834 msg = _("plumbed but down"); 835 } else { 836 if (ipmp) { 837 msg = _("providing connectivity for IPMP group "); 838 bufsz += LIFGRNAMSIZ; 839 } else { 840 msg = _("hosts IP addresses: "); 841 bufsz += (numup * (INET6_ADDRSTRLEN + strlen(sep))); 842 } 843 } 844 845 bufsz += strlen(link) + strlen(msg) + 1; 846 if ((buf = malloc(bufsz)) == NULL) { 847 rcm_log_message(RCM_ERROR, 848 _("IP: usage(%s) malloc failure(%s)\n"), 849 node->ip_resource, strerror(errno)); 850 return (NULL); 851 } 852 (void) snprintf(buf, bufsz, "%s: %s", link, msg); 853 854 if (!offline && numup > 0) { 855 if (ipmp) { 856 (void) strlcat(buf, node->ip_pif->pi_grname, bufsz); 857 } else { 858 lif = node->ip_pif->pi_lifs; 859 for (; lif != NULL; lif = lif->li_next) { 860 if (!(lif->li_ifflags & IFF_UP)) 861 continue; 862 863 if (!ip_addrstr(lif, addrstr, sizeof (addrstr))) 864 continue; 865 866 (void) strlcat(buf, addrstr, bufsz); 867 if (--numup > 0) 868 (void) strlcat(buf, sep, bufsz); 869 } 870 } 871 } 872 873 rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n", 874 node->ip_resource, buf); 875 876 return (buf); 877 } 878 879 static boolean_t 880 ip_addrstr(ip_lif_t *lif, char *addrstr, size_t addrsize) 881 { 882 int af = lif->li_addr.family; 883 void *addr; 884 885 if (af == AF_INET6) { 886 addr = &lif->li_addr.ip6.sin6_addr; 887 } else if (af == AF_INET) { 888 addr = &lif->li_addr.ip4.sin_addr; 889 } else { 890 rcm_log_message(RCM_DEBUG, 891 "IP: unknown addr family %d, assuming AF_INET\n", af); 892 af = AF_INET; 893 addr = &lif->li_addr.ip4.sin_addr; 894 } 895 if (inet_ntop(af, addr, addrstr, addrsize) == NULL) { 896 rcm_log_message(RCM_ERROR, 897 _("IP: inet_ntop: %s\n"), strerror(errno)); 898 return (B_FALSE); 899 } 900 901 rcm_log_message(RCM_DEBUG, "IP addr := %s\n", addrstr); 902 return (B_TRUE); 903 } 904 905 /* 906 * Cache management routines, all cache management functions should be 907 * be called with cache_lock held. 908 */ 909 910 /* 911 * cache_lookup() - Get a cache node for a resource. 912 * Call with cache lock held. 913 * 914 * This ensures that the cache is consistent with the system state and 915 * returns a pointer to the cache element corresponding to the resource. 916 */ 917 static ip_cache_t * 918 cache_lookup(rcm_handle_t *hd, char *rsrc, char options) 919 { 920 ip_cache_t *probe; 921 922 rcm_log_message(RCM_TRACE2, "IP: cache lookup(%s)\n", rsrc); 923 924 if ((options & CACHE_REFRESH) && (hd != NULL)) { 925 /* drop lock since update locks cache again */ 926 (void) mutex_unlock(&cache_lock); 927 (void) update_cache(hd); 928 (void) mutex_lock(&cache_lock); 929 } 930 931 probe = cache_head.ip_next; 932 while (probe != &cache_tail) { 933 if (probe->ip_resource && 934 STREQ(rsrc, probe->ip_resource)) { 935 rcm_log_message(RCM_TRACE2, 936 "IP: cache lookup success(%s)\n", rsrc); 937 return (probe); 938 } 939 probe = probe->ip_next; 940 } 941 return (NULL); 942 } 943 944 /* 945 * free_node - Free a node from the cache 946 * Call with cache_lock held. 947 */ 948 static void 949 free_node(ip_cache_t *node) 950 { 951 ip_pif_t *pif; 952 ip_lif_t *lif, *tmplif; 953 954 if (node) { 955 if (node->ip_resource) { 956 free(node->ip_resource); 957 } 958 959 /* free the pif */ 960 pif = node->ip_pif; 961 if (pif) { 962 /* free logical interfaces */ 963 lif = pif->pi_lifs; 964 while (lif) { 965 tmplif = lif->li_next; 966 free(lif); 967 lif = tmplif; 968 } 969 free(pif); 970 } 971 free(node); 972 } 973 } 974 975 /* 976 * cache_insert - Insert a resource node in cache 977 * Call with the cache_lock held. 978 */ 979 static void 980 cache_insert(ip_cache_t *node) 981 { 982 rcm_log_message(RCM_TRACE2, "IP: cache insert(%s)\n", 983 node->ip_resource); 984 985 /* insert at the head for best performance */ 986 node->ip_next = cache_head.ip_next; 987 node->ip_prev = &cache_head; 988 989 node->ip_next->ip_prev = node; 990 node->ip_prev->ip_next = node; 991 } 992 993 /* 994 * cache_remove() - Remove a resource node from cache. 995 * Call with the cache_lock held. 996 */ 997 static void 998 cache_remove(ip_cache_t *node) 999 { 1000 rcm_log_message(RCM_TRACE2, "IP: cache remove(%s)\n", 1001 node->ip_resource); 1002 1003 node->ip_next->ip_prev = node->ip_prev; 1004 node->ip_prev->ip_next = node->ip_next; 1005 node->ip_next = NULL; 1006 node->ip_prev = NULL; 1007 } 1008 1009 /* 1010 * update_pif() - Update physical interface properties 1011 * Call with cache_lock held 1012 */ 1013 /*ARGSUSED*/ 1014 static int 1015 update_pif(rcm_handle_t *hd, int af, int sock, struct lifreq *lifr) 1016 { 1017 char *rsrc; 1018 ifspec_t ifspec; 1019 ushort_t ifnumber = 0; 1020 ip_cache_t *probe; 1021 ip_pif_t pif; 1022 ip_pif_t *probepif; 1023 ip_lif_t *probelif; 1024 struct lifreq lifreq; 1025 struct sockaddr_storage ifaddr; 1026 uint64_t ifflags; 1027 int lif_listed = 0; 1028 1029 rcm_log_message(RCM_TRACE1, "IP: update_pif(%s)\n", lifr->lifr_name); 1030 1031 if (!ifparse_ifspec(lifr->lifr_name, &ifspec)) { 1032 rcm_log_message(RCM_ERROR, _("IP: bad network interface: %s\n"), 1033 lifr->lifr_name); 1034 return (-1); 1035 } 1036 1037 (void) snprintf(pif.pi_ifname, sizeof (pif.pi_ifname), "%s%d", 1038 ifspec.ifsp_devnm, ifspec.ifsp_ppa); 1039 if (ifspec.ifsp_lunvalid) 1040 ifnumber = ifspec.ifsp_lun; 1041 1042 /* Get the interface flags */ 1043 (void) strlcpy(lifreq.lifr_name, lifr->lifr_name, LIFNAMSIZ); 1044 if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) { 1045 if (errno != ENXIO) { 1046 rcm_log_message(RCM_ERROR, 1047 _("IP: SIOCGLIFFLAGS(%s): %s\n"), 1048 lifreq.lifr_name, strerror(errno)); 1049 } 1050 return (-1); 1051 } 1052 (void) memcpy(&ifflags, &lifreq.lifr_flags, sizeof (ifflags)); 1053 1054 /* 1055 * Ignore interfaces that are always incapable of DR: 1056 * - IFF_VIRTUAL: e.g., loopback and vni 1057 * - IFF_POINTOPOINT: e.g., sppp and ip.tun 1058 * - !IFF_MULTICAST: e.g., ip.6to4tun 1059 * - IFF_IPMP: IPMP meta-interfaces 1060 * 1061 * Note: The !IFF_MULTICAST check can be removed once iptun is 1062 * implemented as a datalink. 1063 */ 1064 if (!(ifflags & IFF_MULTICAST) || 1065 (ifflags & (IFF_POINTOPOINT | IFF_VIRTUAL | IFF_IPMP))) { 1066 rcm_log_message(RCM_TRACE3, "IP: if ignored (%s)\n", 1067 pif.pi_ifname); 1068 return (0); 1069 } 1070 1071 /* Get the interface group name for this interface */ 1072 if (ioctl(sock, SIOCGLIFGROUPNAME, (char *)&lifreq) < 0) { 1073 if (errno != ENXIO) { 1074 rcm_log_message(RCM_ERROR, 1075 _("IP: SIOCGLIFGROUPNAME(%s): %s\n"), 1076 lifreq.lifr_name, strerror(errno)); 1077 } 1078 return (-1); 1079 } 1080 1081 /* copy the group name */ 1082 (void) strlcpy(pif.pi_grname, lifreq.lifr_groupname, 1083 sizeof (pif.pi_grname)); 1084 1085 /* Get the interface address for this interface */ 1086 if (ioctl(sock, SIOCGLIFADDR, (char *)&lifreq) < 0) { 1087 if (errno != ENXIO) { 1088 rcm_log_message(RCM_ERROR, 1089 _("IP: SIOCGLIFADDR(%s): %s\n"), 1090 lifreq.lifr_name, strerror(errno)); 1091 return (-1); 1092 } 1093 } 1094 (void) memcpy(&ifaddr, &lifreq.lifr_addr, sizeof (ifaddr)); 1095 1096 rsrc = get_link_resource(pif.pi_ifname); 1097 if (rsrc == NULL) { 1098 rcm_log_message(RCM_ERROR, 1099 _("IP: get_link_resource(%s) failed\n"), 1100 lifreq.lifr_name); 1101 return (-1); 1102 } 1103 1104 probe = cache_lookup(hd, rsrc, CACHE_NO_REFRESH); 1105 if (probe != NULL) { 1106 free(rsrc); 1107 probe->ip_cachestate &= ~(CACHE_IF_STALE); 1108 } else { 1109 if ((probe = calloc(1, sizeof (ip_cache_t))) == NULL) { 1110 /* malloc errors are bad */ 1111 free(rsrc); 1112 rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"), 1113 strerror(errno)); 1114 return (-1); 1115 } 1116 1117 probe->ip_resource = rsrc; 1118 probe->ip_pif = NULL; 1119 probe->ip_ifred = RCM_IPMP_MIN_REDUNDANCY; 1120 probe->ip_cachestate |= CACHE_IF_NEW; 1121 1122 cache_insert(probe); 1123 } 1124 1125 probepif = probe->ip_pif; 1126 if (probepif != NULL) { 1127 /* Check if lifs need to be updated */ 1128 probelif = probepif->pi_lifs; 1129 while (probelif != NULL) { 1130 if ((probelif->li_ifnum == ifnumber) && 1131 (probelif->li_addr.family == ifaddr.ss_family)) { 1132 1133 rcm_log_message(RCM_TRACE2, 1134 "IP: refreshing lifs for %s, ifnum=%d\n", 1135 pif.pi_ifname, probelif->li_ifnum); 1136 1137 /* refresh lif properties */ 1138 (void) memcpy(&probelif->li_addr, &ifaddr, 1139 sizeof (probelif->li_addr)); 1140 1141 probelif->li_ifflags = ifflags; 1142 1143 lif_listed++; 1144 probelif->li_cachestate &= ~(CACHE_IF_STALE); 1145 break; 1146 } 1147 probelif = probelif->li_next; 1148 } 1149 } 1150 1151 if (probepif == NULL) { 1152 if ((probepif = calloc(1, sizeof (ip_pif_t))) == NULL) { 1153 rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"), 1154 strerror(errno)); 1155 if (probe->ip_pif == NULL) { 1156 /* we created it, so clean it up */ 1157 free(probe); 1158 } 1159 return (-1); 1160 } 1161 1162 probe->ip_pif = probepif; 1163 1164 /* Save interface name */ 1165 (void) memcpy(&probepif->pi_ifname, &pif.pi_ifname, 1166 sizeof (pif.pi_ifname)); 1167 } 1168 1169 /* save the group name */ 1170 (void) strlcpy(probepif->pi_grname, pif.pi_grname, 1171 sizeof (pif.pi_grname)); 1172 1173 /* add lif, if this is a lif and it is not in cache */ 1174 if (!lif_listed) { 1175 rcm_log_message(RCM_TRACE2, "IP: adding lifs to %s\n", 1176 pif.pi_ifname); 1177 1178 if ((probelif = calloc(1, sizeof (ip_lif_t))) == NULL) { 1179 rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"), 1180 strerror(errno)); 1181 return (-1); 1182 } 1183 1184 /* save lif properties */ 1185 (void) memcpy(&probelif->li_addr, &ifaddr, 1186 sizeof (probelif->li_addr)); 1187 1188 probelif->li_ifnum = ifnumber; 1189 probelif->li_ifflags = ifflags; 1190 1191 /* insert us at the head of the lif list */ 1192 probelif->li_next = probepif->pi_lifs; 1193 if (probelif->li_next != NULL) { 1194 probelif->li_next->li_prev = probelif; 1195 } 1196 probelif->li_prev = NULL; 1197 probelif->li_pif = probepif; 1198 1199 probepif->pi_lifs = probelif; 1200 } 1201 1202 rcm_log_message(RCM_TRACE3, "IP: update_pif: (%s) success\n", 1203 probe->ip_resource); 1204 1205 return (0); 1206 } 1207 1208 /* 1209 * update_ipifs() - Determine all network interfaces in the system 1210 * Call with cache_lock held 1211 */ 1212 static int 1213 update_ipifs(rcm_handle_t *hd, int af) 1214 { 1215 int sock; 1216 char *buf; 1217 struct lifnum lifn; 1218 struct lifconf lifc; 1219 struct lifreq *lifrp; 1220 int i; 1221 1222 rcm_log_message(RCM_TRACE2, "IP: update_ipifs\n"); 1223 1224 if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) { 1225 rcm_log_message(RCM_ERROR, 1226 _("IP: failure opening %s socket: %s\n"), 1227 af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno)); 1228 return (-1); 1229 } 1230 1231 lifn.lifn_family = af; 1232 lifn.lifn_flags = LIFC_UNDER_IPMP; 1233 if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 1234 rcm_log_message(RCM_ERROR, 1235 _("IP: SIOCLGIFNUM failed: %s\n"), 1236 strerror(errno)); 1237 (void) close(sock); 1238 return (-1); 1239 } 1240 1241 if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) { 1242 rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"), 1243 strerror(errno)); 1244 (void) close(sock); 1245 return (-1); 1246 } 1247 1248 lifc.lifc_family = af; 1249 lifc.lifc_flags = LIFC_UNDER_IPMP; 1250 lifc.lifc_len = sizeof (struct lifreq) * lifn.lifn_count; 1251 lifc.lifc_buf = buf; 1252 1253 if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) { 1254 rcm_log_message(RCM_ERROR, 1255 _("IP: SIOCGLIFCONF failed: %s\n"), 1256 strerror(errno)); 1257 free(buf); 1258 (void) close(sock); 1259 return (-1); 1260 } 1261 1262 /* now we need to search for active interfaces */ 1263 lifrp = lifc.lifc_req; 1264 for (i = 0; i < lifn.lifn_count; i++) { 1265 (void) update_pif(hd, af, sock, lifrp); 1266 lifrp++; 1267 } 1268 1269 free(buf); 1270 (void) close(sock); 1271 return (0); 1272 } 1273 1274 /* 1275 * update_cache() - Update cache with latest interface info 1276 */ 1277 static int 1278 update_cache(rcm_handle_t *hd) 1279 { 1280 ip_cache_t *probe; 1281 struct ip_lif *lif; 1282 struct ip_lif *nextlif; 1283 int rv; 1284 int i; 1285 1286 rcm_log_message(RCM_TRACE2, "IP: update_cache\n"); 1287 1288 (void) mutex_lock(&cache_lock); 1289 1290 /* first we walk the entire cache, marking each entry stale */ 1291 probe = cache_head.ip_next; 1292 while (probe != &cache_tail) { 1293 probe->ip_cachestate |= CACHE_IF_STALE; 1294 if ((probe->ip_pif != NULL) && 1295 ((lif = probe->ip_pif->pi_lifs) != NULL)) { 1296 while (lif != NULL) { 1297 lif->li_cachestate |= CACHE_IF_STALE; 1298 lif = lif->li_next; 1299 } 1300 } 1301 probe = probe->ip_next; 1302 } 1303 1304 rcm_log_message(RCM_TRACE2, "IP: scanning IPv4 interfaces\n"); 1305 if (update_ipifs(hd, AF_INET) < 0) { 1306 (void) mutex_unlock(&cache_lock); 1307 return (-1); 1308 } 1309 1310 rcm_log_message(RCM_TRACE2, "IP: scanning IPv6 interfaces\n"); 1311 if (update_ipifs(hd, AF_INET6) < 0) { 1312 (void) mutex_unlock(&cache_lock); 1313 return (-1); 1314 } 1315 1316 probe = cache_head.ip_next; 1317 /* unregister devices that are not offlined and still in cache */ 1318 while (probe != &cache_tail) { 1319 ip_cache_t *freeit; 1320 if ((probe->ip_pif != NULL) && 1321 ((lif = probe->ip_pif->pi_lifs) != NULL)) { 1322 /* clear stale lifs */ 1323 while (lif != NULL) { 1324 if (lif->li_cachestate & CACHE_IF_STALE) { 1325 nextlif = lif->li_next; 1326 if (lif->li_prev != NULL) 1327 lif->li_prev->li_next = nextlif; 1328 if (nextlif != NULL) 1329 nextlif->li_prev = lif->li_prev; 1330 if (probe->ip_pif->pi_lifs == lif) 1331 probe->ip_pif->pi_lifs = 1332 nextlif; 1333 for (i = 0; i < IP_MAX_MODS; i++) { 1334 free(lif->li_modules[i]); 1335 } 1336 free(lif->li_reconfig); 1337 free(lif); 1338 lif = nextlif; 1339 } else { 1340 lif = lif->li_next; 1341 } 1342 } 1343 } 1344 if ((probe->ip_cachestate & CACHE_IF_STALE) && 1345 !(probe->ip_cachestate & CACHE_IF_OFFLINED)) { 1346 (void) rcm_unregister_interest(hd, probe->ip_resource, 1347 0); 1348 rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n", 1349 probe->ip_resource); 1350 freeit = probe; 1351 probe = probe->ip_next; 1352 cache_remove(freeit); 1353 free_node(freeit); 1354 continue; 1355 } 1356 1357 if (!(probe->ip_cachestate & CACHE_IF_NEW)) { 1358 probe = probe->ip_next; 1359 continue; 1360 } 1361 1362 rv = rcm_register_interest(hd, probe->ip_resource, 0, NULL); 1363 if (rv != RCM_SUCCESS) { 1364 rcm_log_message(RCM_ERROR, 1365 _("IP: failed to register %s\n"), 1366 probe->ip_resource); 1367 (void) mutex_unlock(&cache_lock); 1368 return (-1); 1369 } else { 1370 rcm_log_message(RCM_DEBUG, "IP: registered %s\n", 1371 probe->ip_resource); 1372 probe->ip_cachestate &= ~(CACHE_IF_NEW); 1373 } 1374 probe = probe->ip_next; 1375 } 1376 1377 (void) mutex_unlock(&cache_lock); 1378 return (0); 1379 } 1380 1381 /* 1382 * free_cache() - Empty the cache 1383 */ 1384 static void 1385 free_cache() 1386 { 1387 ip_cache_t *probe; 1388 1389 rcm_log_message(RCM_TRACE2, "IP: free_cache\n"); 1390 1391 (void) mutex_lock(&cache_lock); 1392 probe = cache_head.ip_next; 1393 while (probe != &cache_tail) { 1394 cache_remove(probe); 1395 free_node(probe); 1396 probe = cache_head.ip_next; 1397 } 1398 (void) mutex_unlock(&cache_lock); 1399 } 1400 1401 /* 1402 * ip_log_err() - RCM error log wrapper 1403 */ 1404 static void 1405 ip_log_err(ip_cache_t *node, char **errorp, char *errmsg) 1406 { 1407 char *ifname = NULL; 1408 int size; 1409 const char *errfmt; 1410 char *error = NULL; 1411 1412 if ((node != NULL) && (node->ip_pif != NULL) && 1413 (node->ip_pif->pi_ifname != NULL)) { 1414 ifname = node->ip_pif->pi_ifname; 1415 } 1416 1417 if (ifname == NULL) { 1418 rcm_log_message(RCM_ERROR, _("IP: %s\n"), errmsg); 1419 errfmt = _("IP: %s"); 1420 size = strlen(errfmt) + strlen(errmsg) + 1; 1421 if (errorp != NULL && (error = malloc(size)) != NULL) 1422 (void) snprintf(error, size, errfmt, errmsg); 1423 } else { 1424 rcm_log_message(RCM_ERROR, _("IP: %s(%s)\n"), errmsg, ifname); 1425 errfmt = _("IP: %s(%s)"); 1426 size = strlen(errfmt) + strlen(errmsg) + strlen(ifname) + 1; 1427 if (errorp != NULL && (error = malloc(size)) != NULL) 1428 (void) snprintf(error, size, errfmt, errmsg, ifname); 1429 } 1430 1431 if (errorp != NULL) 1432 *errorp = error; 1433 } 1434 1435 /* 1436 * if_cfginfo() - Save off the config info for all interfaces 1437 */ 1438 static int 1439 if_cfginfo(ip_cache_t *node, uint_t force) 1440 { 1441 ip_lif_t *lif; 1442 ip_pif_t *pif; 1443 int i; 1444 FILE *fp; 1445 char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ]; 1446 char buf[MAX_RECONFIG_SIZE]; 1447 1448 rcm_log_message(RCM_TRACE2, "IP: if_cfginfo(%s)\n", node->ip_resource); 1449 1450 pif = node->ip_pif; 1451 lif = pif->pi_lifs; 1452 1453 while (lif != NULL) { 1454 /* Make a list of modules pushed and save */ 1455 if (lif->li_ifnum == 0) { /* physical instance */ 1456 if (get_modlist(pif->pi_ifname, lif) == -1) { 1457 rcm_log_message(RCM_ERROR, 1458 _("IP: get modlist error (%s) %s\n"), 1459 pif->pi_ifname, strerror(errno)); 1460 clr_cfg_state(pif); 1461 return (-1); 1462 } 1463 1464 if (!force) { 1465 /* Look if unknown modules have been inserted */ 1466 for (i = (lif->li_modcnt - 2); i > 0; i--) { 1467 if (modop(pif->pi_ifname, 1468 lif->li_modules[i], 1469 i, MOD_CHECK) == -1) { 1470 rcm_log_message(RCM_ERROR, 1471 _("IP: module %s@%d\n"), 1472 lif->li_modules[i], i); 1473 clr_cfg_state(pif); 1474 return (-1); 1475 } 1476 } 1477 } 1478 1479 /* Last module is the device driver, so ignore that */ 1480 for (i = (lif->li_modcnt - 2); i > 0; i--) { 1481 rcm_log_message(RCM_TRACE2, 1482 "IP: modremove Pos = %d, Module = %s \n", 1483 i, lif->li_modules[i]); 1484 if (modop(pif->pi_ifname, lif->li_modules[i], 1485 i, MOD_REMOVE) == -1) { 1486 while (i != (lif->li_modcnt - 2)) { 1487 if (modop(pif->pi_ifname, 1488 lif->li_modules[i], 1489 i, MOD_INSERT) == -1) { 1490 /* Gross error */ 1491 rcm_log_message( 1492 RCM_ERROR, 1493 _("IP: if_cfginfo" 1494 "(%s) %s\n"), 1495 pif->pi_ifname, 1496 strerror(errno)); 1497 clr_cfg_state(pif); 1498 return (-1); 1499 } 1500 i++; 1501 } 1502 rcm_log_message( 1503 RCM_ERROR, 1504 _("IP: if_cfginfo(%s): modremove " 1505 "%s failed: %s\n"), pif->pi_ifname, 1506 lif->li_modules[i], 1507 strerror(errno)); 1508 clr_cfg_state(pif); 1509 return (-1); 1510 } 1511 } 1512 } 1513 1514 /* Save reconfiguration information */ 1515 if (lif->li_ifflags & IFF_IPV4) { 1516 (void) snprintf(syscmd, sizeof (syscmd), 1517 "%s %s:%d configinfo\n", SBIN_IFCONFIG, 1518 pif->pi_ifname, lif->li_ifnum); 1519 } else if (lif->li_ifflags & IFF_IPV6) { 1520 (void) snprintf(syscmd, sizeof (syscmd), 1521 "%s %s:%d inet6 configinfo\n", SBIN_IFCONFIG, 1522 pif->pi_ifname, lif->li_ifnum); 1523 } 1524 rcm_log_message(RCM_TRACE2, "IP: %s\n", syscmd); 1525 1526 /* open a pipe to retrieve reconfiguration info */ 1527 if ((fp = popen(syscmd, "r")) == NULL) { 1528 rcm_log_message(RCM_ERROR, 1529 _("IP: ifconfig configinfo error (%s:%d) %s\n"), 1530 pif->pi_ifname, lif->li_ifnum, strerror(errno)); 1531 clr_cfg_state(pif); 1532 return (-1); 1533 } 1534 bzero(buf, MAX_RECONFIG_SIZE); 1535 1536 if (fgets(buf, MAX_RECONFIG_SIZE, fp) == NULL) { 1537 rcm_log_message(RCM_ERROR, 1538 _("IP: ifconfig configinfo error (%s:%d) %s\n"), 1539 pif->pi_ifname, lif->li_ifnum, strerror(errno)); 1540 (void) pclose(fp); 1541 clr_cfg_state(pif); 1542 return (-1); 1543 } 1544 (void) pclose(fp); 1545 1546 if ((lif->li_reconfig = strdup(buf)) == NULL) { 1547 rcm_log_message(RCM_ERROR, 1548 _("IP: malloc error (%s) %s\n"), 1549 pif->pi_ifname, strerror(errno)); 1550 clr_cfg_state(pif); 1551 return (-1); 1552 } 1553 rcm_log_message(RCM_DEBUG, 1554 "IP: if_cfginfo: reconfig string(%s:%d) = %s\n", 1555 pif->pi_ifname, lif->li_ifnum, lif->li_reconfig); 1556 1557 lif = lif->li_next; 1558 } 1559 1560 return (0); 1561 } 1562 1563 /* 1564 * if_unplumb() - Unplumb the interface 1565 * Save off the modlist, ifconfig options and unplumb. 1566 * Fail, if an unknown module lives between IP and driver and 1567 * force is not set 1568 * Call with cache_lock held 1569 */ 1570 static int 1571 if_unplumb(ip_cache_t *node) 1572 { 1573 ip_lif_t *lif; 1574 ip_pif_t *pif = node->ip_pif; 1575 boolean_t ipv4 = B_FALSE; 1576 boolean_t ipv6 = B_FALSE; 1577 1578 rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s)\n", node->ip_resource); 1579 1580 for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) { 1581 if (lif->li_ifflags & IFF_IPV4) { 1582 ipv4 = B_TRUE; 1583 } else if (lif->li_ifflags & IFF_IPV6) { 1584 ipv6 = B_TRUE; 1585 } else { 1586 /* Unlikely case */ 1587 rcm_log_message(RCM_DEBUG, 1588 "IP: Unplumb ignored (%s:%d)\n", 1589 pif->pi_ifname, lif->li_ifnum); 1590 } 1591 } 1592 1593 if (ipv4 && !ifconfig(pif->pi_ifname, "inet", "unplumb", B_FALSE)) { 1594 rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"), 1595 pif->pi_ifname, strerror(errno)); 1596 return (-1); 1597 } 1598 1599 if (ipv6 && !ifconfig(pif->pi_ifname, "inet6", "unplumb", B_FALSE)) { 1600 rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"), 1601 pif->pi_ifname, strerror(errno)); 1602 return (-1); 1603 } 1604 1605 rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s) success\n", 1606 node->ip_resource); 1607 1608 return (0); 1609 } 1610 1611 /* 1612 * if_replumb() - Undo previous unplumb i.e. plumb back the physical interface 1613 * instances and the logical interfaces in order, restoring 1614 * all ifconfig options 1615 * Call with cache_lock held 1616 */ 1617 static int 1618 if_replumb(ip_cache_t *node) 1619 { 1620 ip_lif_t *lif; 1621 ip_pif_t *pif; 1622 int i; 1623 boolean_t success, ipmp; 1624 const char *fstr; 1625 char lifname[LIFNAMSIZ]; 1626 char buf[MAX_RECONFIG_SIZE]; 1627 int max_lifnum = 0; 1628 1629 rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s)\n", node->ip_resource); 1630 1631 /* 1632 * Be extra careful about bringing up the interfaces in the 1633 * correct order: 1634 * - First plumb in the physical interface instances 1635 * - modinsert the necessary modules@pos 1636 * - Next, add the logical interfaces being careful about 1637 * the order, (follow the cached interface number li_ifnum order) 1638 */ 1639 1640 pif = node->ip_pif; 1641 ipmp = (node->ip_pif->pi_grname[0] != '\0'); 1642 1643 /* 1644 * Make a first pass to plumb in physical interfaces and get a count 1645 * of the max logical interfaces 1646 */ 1647 for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) { 1648 max_lifnum = MAX(lif->li_ifnum, max_lifnum); 1649 if (lif->li_ifflags & IFF_IPV4) { 1650 fstr = "inet"; 1651 } else if (lif->li_ifflags & IFF_IPV6) { 1652 fstr = "inet6"; 1653 } else { 1654 /* Unlikely case */ 1655 rcm_log_message(RCM_DEBUG, 1656 "IP: Re-plumb ignored (%s:%d)\n", 1657 pif->pi_ifname, lif->li_ifnum); 1658 continue; 1659 } 1660 1661 /* ignore logical interface instances */ 1662 if (lif->li_ifnum != 0) 1663 continue; 1664 1665 if ((lif->li_ifflags & IFF_NOFAILOVER) || !ipmp) { 1666 success = ifconfig("", "", lif->li_reconfig, B_FALSE); 1667 } else { 1668 (void) snprintf(buf, sizeof (buf), "plumb group %s", 1669 pif->pi_grname); 1670 success = ifconfig(pif->pi_ifname, fstr, buf, B_FALSE); 1671 } 1672 1673 if (!success) { 1674 rcm_log_message(RCM_ERROR, 1675 _("IP: Cannot plumb (%s) %s\n"), pif->pi_ifname, 1676 strerror(errno)); 1677 return (-1); 1678 } 1679 1680 /* 1681 * Restart DHCP if necessary. 1682 */ 1683 if ((lif->li_ifflags & IFF_DHCPRUNNING) && 1684 !ifconfig(pif->pi_ifname, fstr, CFG_DHCP_CMD, B_FALSE)) { 1685 rcm_log_message(RCM_ERROR, _("IP: Cannot start DHCP " 1686 "(%s) %s\n"), pif->pi_ifname, strerror(errno)); 1687 return (-1); 1688 } 1689 1690 rcm_log_message(RCM_TRACE2, 1691 "IP: if_replumb: Modcnt = %d\n", lif->li_modcnt); 1692 /* modinsert modules in order, ignore driver(last) */ 1693 for (i = 0; i < (lif->li_modcnt - 1); i++) { 1694 rcm_log_message(RCM_TRACE2, 1695 "IP: modinsert: Pos = %d Mod = %s\n", 1696 i, lif->li_modules[i]); 1697 if (modop(pif->pi_ifname, lif->li_modules[i], i, 1698 MOD_INSERT) == -1) { 1699 rcm_log_message(RCM_ERROR, 1700 _("IP: modinsert error(%s)\n"), 1701 pif->pi_ifname); 1702 return (-1); 1703 } 1704 } 1705 } 1706 1707 /* Now, add all the logical interfaces in the correct order */ 1708 for (i = 1; i <= max_lifnum; i++) { 1709 (void) snprintf(lifname, LIFNAMSIZ, "%s:%d", pif->pi_ifname, i); 1710 1711 /* reset lif through every iteration */ 1712 for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) { 1713 /* 1714 * Process entries in order. If the interface is 1715 * using IPMP, only process test addresses. 1716 */ 1717 if (lif->li_ifnum != i || 1718 (ipmp && !(lif->li_ifflags & IFF_NOFAILOVER))) 1719 continue; 1720 1721 if (!ifconfig("", "", lif->li_reconfig, B_FALSE)) { 1722 rcm_log_message(RCM_ERROR, 1723 _("IP: Cannot addif (%s) %s\n"), lifname, 1724 strerror(errno)); 1725 return (-1); 1726 } 1727 1728 /* 1729 * Restart DHCP if necessary. 1730 */ 1731 if ((lif->li_ifflags & IFF_DHCPRUNNING) && 1732 !ifconfig(lifname, fstr, CFG_DHCP_CMD, B_FALSE)) { 1733 rcm_log_message(RCM_ERROR, 1734 _("IP: Cannot start DHCP (%s) %s\n"), 1735 lifname, strerror(errno)); 1736 return (-1); 1737 } 1738 } 1739 } 1740 1741 rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s) success \n", 1742 node->ip_resource); 1743 1744 return (0); 1745 } 1746 1747 /* 1748 * clr_cfg_state() - Cleanup after errors in unplumb 1749 */ 1750 static void 1751 clr_cfg_state(ip_pif_t *pif) 1752 { 1753 ip_lif_t *lif; 1754 int i; 1755 1756 lif = pif->pi_lifs; 1757 1758 while (lif != NULL) { 1759 lif->li_modcnt = 0; 1760 free(lif->li_reconfig); 1761 lif->li_reconfig = NULL; 1762 for (i = 0; i < IP_MAX_MODS; i++) { 1763 free(lif->li_modules[i]); 1764 lif->li_modules[i] = NULL; 1765 } 1766 lif = lif->li_next; 1767 } 1768 } 1769 1770 /* 1771 * Attempt to offline ip_cache_t `node'; returns an IPMP error code. 1772 */ 1773 static int 1774 ip_ipmp_offline(ip_cache_t *node) 1775 { 1776 int retval; 1777 ipmp_handle_t handle; 1778 1779 rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline\n"); 1780 1781 if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) { 1782 rcm_log_message(RCM_ERROR, 1783 _("IP: cannot create ipmp handle: %s\n"), 1784 ipmp_errmsg(retval)); 1785 return (retval); 1786 } 1787 1788 retval = ipmp_offline(handle, node->ip_pif->pi_ifname, node->ip_ifred); 1789 if (retval != IPMP_SUCCESS) { 1790 rcm_log_message(RCM_ERROR, _("IP: ipmp_offline error: %s\n"), 1791 ipmp_errmsg(retval)); 1792 } else { 1793 rcm_log_message(RCM_TRACE1, "IP: ipmp_offline success\n"); 1794 } 1795 1796 ipmp_close(handle); 1797 return (retval); 1798 } 1799 1800 /* 1801 * Attempt to undo the offline ip_cache_t `node'; returns an IPMP error code. 1802 */ 1803 static int 1804 ip_ipmp_undo_offline(ip_cache_t *node) 1805 { 1806 int retval; 1807 ipmp_handle_t handle; 1808 1809 rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_undo_offline\n"); 1810 1811 if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) { 1812 rcm_log_message(RCM_ERROR, 1813 _("IP: cannot create ipmp handle: %s\n"), 1814 ipmp_errmsg(retval)); 1815 return (retval); 1816 } 1817 1818 retval = ipmp_undo_offline(handle, node->ip_pif->pi_ifname); 1819 if (retval != IPMP_SUCCESS) { 1820 rcm_log_message(RCM_ERROR, 1821 _("IP: ipmp_undo_offline error: %s\n"), 1822 ipmp_errmsg(retval)); 1823 } else { 1824 rcm_log_message(RCM_TRACE1, "IP: ipmp_undo_offline success\n"); 1825 } 1826 1827 ipmp_close(handle); 1828 return (retval); 1829 } 1830 1831 /* 1832 * get_link_resource() - Convert a link name (e.g., net0, hme1000) into a 1833 * dynamically allocated string containing the associated link resource 1834 * name ("SUNW_datalink/<linkid>"). 1835 */ 1836 static char * 1837 get_link_resource(const char *link) 1838 { 1839 char errmsg[DLADM_STRSIZE]; 1840 datalink_id_t linkid; 1841 uint32_t flags; 1842 char *resource; 1843 dladm_status_t status; 1844 1845 status = dladm_name2info(dld_handle, link, &linkid, &flags, NULL, NULL); 1846 if (status != DLADM_STATUS_OK) 1847 goto fail; 1848 1849 if (!(flags & DLADM_OPT_ACTIVE)) { 1850 status = DLADM_STATUS_FAILED; 1851 goto fail; 1852 } 1853 1854 resource = malloc(RCM_LINK_RESOURCE_MAX); 1855 if (resource == NULL) { 1856 rcm_log_message(RCM_ERROR, _("IP: malloc error(%s): %s\n"), 1857 strerror(errno), link); 1858 return (NULL); 1859 } 1860 1861 (void) snprintf(resource, RCM_LINK_RESOURCE_MAX, "%s/%u", 1862 RCM_LINK_PREFIX, linkid); 1863 1864 return (resource); 1865 1866 fail: 1867 rcm_log_message(RCM_ERROR, 1868 _("IP: get_link_resource for %s error(%s)\n"), 1869 link, dladm_status2str(status, errmsg)); 1870 return (NULL); 1871 } 1872 1873 /* 1874 * modop() - Remove/insert a module 1875 */ 1876 static int 1877 modop(char *name, char *arg, int pos, char op) 1878 { 1879 char syscmd[LIFNAMSIZ+MAXPATHLEN]; /* must be big enough */ 1880 1881 rcm_log_message(RCM_TRACE1, "IP: modop(%s)\n", name); 1882 1883 /* Nothing to do with "ip", "arp" */ 1884 if ((arg == NULL) || (strcmp(arg, "") == 0) || 1885 STREQ(arg, IP_MOD_NAME) || STREQ(arg, ARP_MOD_NAME)) { 1886 rcm_log_message(RCM_TRACE1, "IP: modop success\n"); 1887 return (0); 1888 } 1889 1890 if (op == MOD_CHECK) { 1891 /* 1892 * No known good modules (yet) apart from ip and arp 1893 * which are handled above 1894 */ 1895 return (-1); 1896 } 1897 1898 if (op == MOD_REMOVE) { 1899 (void) snprintf(syscmd, sizeof (syscmd), 1900 "%s %s modremove %s@%d\n", SBIN_IFCONFIG, name, arg, pos); 1901 } else if (op == MOD_INSERT) { 1902 (void) snprintf(syscmd, sizeof (syscmd), 1903 "%s %s modinsert %s@%d\n", SBIN_IFCONFIG, name, arg, pos); 1904 } else { 1905 rcm_log_message(RCM_ERROR, 1906 _("IP: modop(%s): unknown operation\n"), name); 1907 return (-1); 1908 } 1909 1910 rcm_log_message(RCM_TRACE1, "IP: modop(%s): %s\n", name, syscmd); 1911 if (rcm_exec_cmd(syscmd) == -1) { 1912 rcm_log_message(RCM_ERROR, 1913 _("IP: modop(%s): %s\n"), name, strerror(errno)); 1914 return (-1); 1915 } 1916 1917 rcm_log_message(RCM_TRACE1, "IP: modop success\n"); 1918 return (0); 1919 } 1920 1921 /* 1922 * get_modlist() - return a list of pushed mid-stream modules 1923 * Required memory is malloced to construct the list, 1924 * Caller must free this memory list 1925 * Call with cache_lock held 1926 */ 1927 static int 1928 get_modlist(char *name, ip_lif_t *lif) 1929 { 1930 int mux_fd; 1931 int muxid_fd; 1932 int fd; 1933 int i; 1934 int num_mods; 1935 struct lifreq lifr; 1936 struct str_list strlist = { 0 }; 1937 1938 rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s)\n", name); 1939 1940 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1941 lifr.lifr_flags = lif->li_ifflags; 1942 if (ip_domux2fd(&mux_fd, &muxid_fd, &fd, &lifr) < 0) { 1943 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd(%s)\n"), name); 1944 return (-1); 1945 } 1946 1947 if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) { 1948 rcm_log_message(RCM_ERROR, 1949 _("IP: get_modlist(%s): I_LIST(%s) \n"), 1950 name, strerror(errno)); 1951 goto fail; 1952 } 1953 1954 strlist.sl_nmods = num_mods; 1955 strlist.sl_modlist = malloc(sizeof (struct str_mlist) * num_mods); 1956 if (strlist.sl_modlist == NULL) { 1957 rcm_log_message(RCM_ERROR, _("IP: get_modlist(%s): %s\n"), 1958 name, strerror(errno)); 1959 goto fail; 1960 } 1961 1962 if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) { 1963 rcm_log_message(RCM_ERROR, 1964 _("IP: get_modlist(%s): I_LIST error: %s\n"), 1965 name, strerror(errno)); 1966 goto fail; 1967 } 1968 1969 for (i = 0; i < strlist.sl_nmods; i++) { 1970 lif->li_modules[i] = strdup(strlist.sl_modlist[i].l_name); 1971 if (lif->li_modules[i] == NULL) { 1972 rcm_log_message(RCM_ERROR, 1973 _("IP: get_modlist(%s): %s\n"), 1974 name, strerror(errno)); 1975 while (i > 0) 1976 free(lif->li_modules[--i]); 1977 goto fail; 1978 } 1979 } 1980 1981 lif->li_modcnt = strlist.sl_nmods; 1982 free(strlist.sl_modlist); 1983 1984 rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s) success\n", name); 1985 return (ip_plink(mux_fd, muxid_fd, fd, &lifr)); 1986 fail: 1987 free(strlist.sl_modlist); 1988 (void) ip_plink(mux_fd, muxid_fd, fd, &lifr); 1989 return (-1); 1990 } 1991 1992 /* 1993 * ip_domux2fd() - Helper function for mod*() functions 1994 * Stolen from ifconfig.c 1995 */ 1996 static int 1997 ip_domux2fd(int *mux_fd, int *muxid_fdp, int *fd, struct lifreq *lifr) 1998 { 1999 int muxid_fd; 2000 char *udp_dev_name; 2001 2002 if (lifr->lifr_flags & IFF_IPV6) { 2003 udp_dev_name = UDP6_DEV_NAME; 2004 } else { 2005 udp_dev_name = UDP_DEV_NAME; 2006 } 2007 2008 if ((muxid_fd = open(udp_dev_name, O_RDWR)) < 0) { 2009 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"), 2010 udp_dev_name, strerror(errno)); 2011 return (-1); 2012 } 2013 if ((*mux_fd = open(udp_dev_name, O_RDWR)) < 0) { 2014 rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"), 2015 udp_dev_name, strerror(errno)); 2016 (void) close(muxid_fd); 2017 return (-1); 2018 } 2019 if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)lifr) < 0) { 2020 rcm_log_message(RCM_ERROR, 2021 _("IP: ip_domux2fd: SIOCGLIFMUXID(%s): %s\n"), 2022 udp_dev_name, strerror(errno)); 2023 (void) close(*mux_fd); 2024 (void) close(muxid_fd); 2025 return (-1); 2026 } 2027 2028 rcm_log_message(RCM_TRACE2, 2029 "IP: ip_domux2fd: ARP_muxid %d IP_muxid %d\n", 2030 lifr->lifr_arp_muxid, lifr->lifr_ip_muxid); 2031 2032 if ((*fd = ioctl(*mux_fd, _I_MUXID2FD, lifr->lifr_ip_muxid)) < 0) { 2033 rcm_log_message(RCM_ERROR, 2034 _("IP: ip_domux2fd: _I_MUXID2FD(%s): %s\n"), 2035 udp_dev_name, strerror(errno)); 2036 (void) close(*mux_fd); 2037 (void) close(muxid_fd); 2038 return (-1); 2039 } 2040 if (ioctl(*mux_fd, I_PUNLINK, lifr->lifr_ip_muxid) < 0) { 2041 rcm_log_message(RCM_ERROR, 2042 _("IP: ip_domux2fd: I_PUNLINK(%s): %s\n"), 2043 udp_dev_name, strerror(errno)); 2044 (void) close(*mux_fd); 2045 (void) close(muxid_fd); 2046 return (-1); 2047 } 2048 2049 /* Note: mux_fd and muxid_fd are closed in ip_plink below */ 2050 *muxid_fdp = muxid_fd; 2051 return (0); 2052 } 2053 2054 /* 2055 * ip_plink() - Helper function for mod*() functions. 2056 * Stolen from ifconfig.c 2057 */ 2058 static int 2059 ip_plink(int mux_fd, int muxid_fd, int fd, struct lifreq *lifr) 2060 { 2061 int mux_id; 2062 2063 if ((mux_id = ioctl(mux_fd, I_PLINK, fd)) < 0) { 2064 rcm_log_message(RCM_ERROR, _("IP: ip_plink I_PLINK(%s): %s\n"), 2065 UDP_DEV_NAME, strerror(errno)); 2066 (void) close(mux_fd); 2067 (void) close(muxid_fd); 2068 (void) close(fd); 2069 return (-1); 2070 } 2071 2072 lifr->lifr_ip_muxid = mux_id; 2073 if (ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)lifr) < 0) { 2074 rcm_log_message(RCM_ERROR, 2075 _("IP: ip_plink SIOCSLIFMUXID(%s): %s\n"), 2076 UDP_DEV_NAME, strerror(errno)); 2077 (void) close(mux_fd); 2078 (void) close(muxid_fd); 2079 (void) close(fd); 2080 return (-1); 2081 } 2082 2083 (void) close(mux_fd); 2084 (void) close(muxid_fd); 2085 (void) close(fd); 2086 return (0); 2087 } 2088 2089 /* 2090 * ip_onlinelist() 2091 * 2092 * Notify online to IP address consumers. 2093 */ 2094 /*ARGSUSED*/ 2095 static int 2096 ip_onlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags, 2097 rcm_info_t **depend_info) 2098 { 2099 char **addrlist; 2100 int ret = RCM_SUCCESS; 2101 2102 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist\n"); 2103 2104 addrlist = ip_get_addrlist(node); 2105 if (addrlist == NULL || addrlist[0] == NULL) { 2106 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist none\n"); 2107 ip_free_addrlist(addrlist); 2108 return (ret); 2109 } 2110 2111 ret = rcm_notify_online_list(hd, addrlist, 0, depend_info); 2112 2113 ip_free_addrlist(addrlist); 2114 rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist done\n"); 2115 return (ret); 2116 } 2117 2118 /* 2119 * ip_offlinelist() 2120 * 2121 * Offline IP address consumers. 2122 */ 2123 /*ARGSUSED*/ 2124 static int 2125 ip_offlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags, 2126 rcm_info_t **depend_info) 2127 { 2128 char **addrlist; 2129 int ret = RCM_SUCCESS; 2130 2131 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist\n"); 2132 2133 addrlist = ip_get_addrlist(node); 2134 if (addrlist == NULL || addrlist[0] == NULL) { 2135 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist none\n"); 2136 ip_free_addrlist(addrlist); 2137 return (RCM_SUCCESS); 2138 } 2139 2140 if ((ret = rcm_request_offline_list(hd, addrlist, flags, depend_info)) 2141 != RCM_SUCCESS) { 2142 if (ret == RCM_FAILURE) 2143 (void) rcm_notify_online_list(hd, addrlist, 0, NULL); 2144 2145 ret = RCM_FAILURE; 2146 } 2147 2148 ip_free_addrlist(addrlist); 2149 rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist done\n"); 2150 return (ret); 2151 } 2152 2153 /* 2154 * ip_get_addrlist() - Get the list of IP addresses on this interface (node); 2155 * This routine malloc()s required memory for the list. 2156 * Returns the list on success, NULL on failure. 2157 * Call with cache_lock held. 2158 */ 2159 static char ** 2160 ip_get_addrlist(ip_cache_t *node) 2161 { 2162 ip_lif_t *lif; 2163 char **addrlist = NULL; 2164 int i, numifs; 2165 size_t addrlistsize; 2166 char addrstr[INET6_ADDRSTRLEN]; 2167 2168 rcm_log_message(RCM_TRACE2, "IP: ip_get_addrlist(%s)\n", 2169 node->ip_resource); 2170 2171 numifs = 0; 2172 for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) { 2173 numifs++; 2174 } 2175 2176 /* 2177 * Allocate space for resource names list; add 1 and use calloc() 2178 * so that the list is NULL-terminated. 2179 */ 2180 if ((addrlist = calloc(numifs + 1, sizeof (char *))) == NULL) { 2181 rcm_log_message(RCM_ERROR, 2182 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"), 2183 node->ip_resource, strerror(errno)); 2184 return (NULL); 2185 } 2186 2187 for (lif = node->ip_pif->pi_lifs, i = 0; lif != NULL; 2188 lif = lif->li_next, i++) { 2189 2190 if (!ip_addrstr(lif, addrstr, sizeof (addrstr))) { 2191 ip_free_addrlist(addrlist); 2192 return (NULL); 2193 } 2194 2195 addrlistsize = strlen(addrstr) + sizeof (RCM_STR_SUNW_IP); 2196 if ((addrlist[i] = malloc(addrlistsize)) == NULL) { 2197 rcm_log_message(RCM_ERROR, 2198 _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"), 2199 node->ip_resource, strerror(errno)); 2200 ip_free_addrlist(addrlist); 2201 return (NULL); 2202 } 2203 (void) snprintf(addrlist[i], addrlistsize, "%s%s", 2204 RCM_STR_SUNW_IP, addrstr); 2205 2206 rcm_log_message(RCM_DEBUG, "Anon Address: %s\n", addrlist[i]); 2207 } 2208 2209 rcm_log_message(RCM_TRACE2, "IP: get_addrlist (%s) done\n", 2210 node->ip_resource); 2211 2212 return (addrlist); 2213 } 2214 2215 static void 2216 ip_free_addrlist(char **addrlist) 2217 { 2218 int i; 2219 2220 if (addrlist == NULL) 2221 return; 2222 2223 for (i = 0; addrlist[i] != NULL; i++) 2224 free(addrlist[i]); 2225 free(addrlist); 2226 } 2227 2228 /* 2229 * ip_consumer_notify() - Notify consumers of IP addresses coming back online. 2230 */ 2231 2232 static void 2233 ip_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp, 2234 uint_t flags, rcm_info_t **depend_info) 2235 { 2236 char cached_name[RCM_LINK_RESOURCE_MAX]; 2237 ip_cache_t *node; 2238 2239 assert(linkid != DATALINK_INVALID_LINKID); 2240 2241 rcm_log_message(RCM_TRACE1, _("IP: ip_consumer_notify(%u)\n"), linkid); 2242 2243 /* Check for the interface in the cache */ 2244 (void) snprintf(cached_name, sizeof (cached_name), "%s/%u", 2245 RCM_LINK_PREFIX, linkid); 2246 2247 (void) mutex_lock(&cache_lock); 2248 if ((node = cache_lookup(hd, cached_name, CACHE_REFRESH)) == NULL) { 2249 rcm_log_message(RCM_TRACE1, _("IP: Skipping interface(%u)\n"), 2250 linkid); 2251 (void) mutex_unlock(&cache_lock); 2252 return; 2253 } 2254 /* 2255 * Inform anonymous consumers about IP addresses being onlined. 2256 */ 2257 (void) ip_onlinelist(hd, node, errorp, flags, depend_info); 2258 2259 (void) mutex_unlock(&cache_lock); 2260 2261 rcm_log_message(RCM_TRACE2, "IP: ip_consumer_notify success\n"); 2262 } 2263 2264 /* 2265 * if_configure() - Configure a physical interface after attach 2266 */ 2267 static int 2268 if_configure(datalink_id_t linkid) 2269 { 2270 char ifinst[MAXLINKNAMELEN]; 2271 char cfgfile[MAXPATHLEN]; 2272 char cached_name[RCM_LINK_RESOURCE_MAX]; 2273 FILE *hostfp, *host6fp; 2274 ip_cache_t *node; 2275 boolean_t ipmp = B_FALSE; 2276 2277 assert(linkid != DATALINK_INVALID_LINKID); 2278 rcm_log_message(RCM_TRACE1, _("IP: if_configure(%u)\n"), linkid); 2279 2280 /* Check for the interface in the cache */ 2281 (void) snprintf(cached_name, sizeof (cached_name), "%s/%u", 2282 RCM_LINK_PREFIX, linkid); 2283 2284 /* Check if the interface is new or was not previously offlined */ 2285 (void) mutex_lock(&cache_lock); 2286 if (((node = cache_lookup(NULL, cached_name, CACHE_REFRESH)) != NULL) && 2287 (!(node->ip_cachestate & CACHE_IF_OFFLINED))) { 2288 rcm_log_message(RCM_TRACE1, 2289 _("IP: Skipping configured interface(%u)\n"), linkid); 2290 (void) mutex_unlock(&cache_lock); 2291 return (0); 2292 } 2293 (void) mutex_unlock(&cache_lock); 2294 2295 if (dladm_datalink_id2info(dld_handle, linkid, NULL, NULL, NULL, ifinst, 2296 sizeof (ifinst)) != DLADM_STATUS_OK) { 2297 rcm_log_message(RCM_ERROR, 2298 _("IP: get %u link name failed\n"), linkid); 2299 return (-1); 2300 } 2301 2302 /* 2303 * Scan the IPv4 and IPv6 hostname files to see if (a) they exist 2304 * and (b) if either one places the interface into an IPMP group. 2305 */ 2306 (void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV4, ifinst); 2307 rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile); 2308 if ((hostfp = fopen(cfgfile, "r")) != NULL) { 2309 if (isgrouped(cfgfile)) 2310 ipmp = B_TRUE; 2311 } 2312 2313 (void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV6, ifinst); 2314 rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile); 2315 if ((host6fp = fopen(cfgfile, "r")) != NULL) { 2316 if (!ipmp && isgrouped(cfgfile)) 2317 ipmp = B_TRUE; 2318 } 2319 2320 /* 2321 * Configure the interface according to its hostname files. 2322 */ 2323 if (hostfp != NULL && 2324 if_config_inst(ifinst, hostfp, AF_INET, ipmp) == -1) { 2325 rcm_log_message(RCM_ERROR, 2326 _("IP: IPv4 Post-attach failed (%s)\n"), ifinst); 2327 goto fail; 2328 } 2329 2330 if (host6fp != NULL && 2331 if_config_inst(ifinst, host6fp, AF_INET6, ipmp) == -1) { 2332 rcm_log_message(RCM_ERROR, 2333 _("IP: IPv6 Post-attach failed (%s)\n"), ifinst); 2334 goto fail; 2335 } 2336 2337 (void) fclose(hostfp); 2338 (void) fclose(host6fp); 2339 rcm_log_message(RCM_TRACE1, "IP: if_configure(%s) success\n", ifinst); 2340 return (0); 2341 fail: 2342 (void) fclose(hostfp); 2343 (void) fclose(host6fp); 2344 return (-1); 2345 } 2346 2347 /* 2348 * isgrouped() - Scans the given config file to see if this interface is 2349 * using IPMP. Returns B_TRUE or B_FALSE. 2350 */ 2351 static boolean_t 2352 isgrouped(const char *cfgfile) 2353 { 2354 FILE *fp; 2355 struct stat statb; 2356 char *nlp, *line, *token, *lasts, *buf; 2357 boolean_t grouped = B_FALSE; 2358 2359 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s)\n", cfgfile); 2360 2361 if (stat(cfgfile, &statb) != 0) { 2362 rcm_log_message(RCM_TRACE1, 2363 _("IP: No config file(%s)\n"), cfgfile); 2364 return (B_FALSE); 2365 } 2366 2367 /* 2368 * We also ignore single-byte config files because the file should 2369 * always be newline-terminated, so we know there's nothing of 2370 * interest. Further, a single-byte file would cause the fgets() loop 2371 * below to spin forever. 2372 */ 2373 if (statb.st_size <= 1) { 2374 rcm_log_message(RCM_TRACE1, 2375 _("IP: Empty config file(%s)\n"), cfgfile); 2376 return (B_FALSE); 2377 } 2378 2379 if ((fp = fopen(cfgfile, "r")) == NULL) { 2380 rcm_log_message(RCM_ERROR, 2381 _("IP: Cannot open configuration file(%s): %s\n"), cfgfile, 2382 strerror(errno)); 2383 return (B_FALSE); 2384 } 2385 2386 if ((buf = malloc(statb.st_size)) == NULL) { 2387 rcm_log_message(RCM_ERROR, 2388 _("IP: malloc failure(%s): %s\n"), cfgfile, 2389 strerror(errno)); 2390 goto out; 2391 } 2392 2393 while (fgets(buf, statb.st_size, fp) != NULL) { 2394 if ((nlp = strrchr(buf, '\n')) != NULL) 2395 *nlp = '\0'; 2396 2397 line = buf; 2398 while ((token = strtok_r(line, " \t", &lasts)) != NULL) { 2399 line = NULL; 2400 if (STREQ("group", token) && 2401 strtok_r(NULL, " \t", &lasts) != NULL) { 2402 grouped = B_TRUE; 2403 goto out; 2404 } 2405 } 2406 } 2407 out: 2408 free(buf); 2409 (void) fclose(fp); 2410 2411 rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s): %d\n", cfgfile, 2412 grouped); 2413 2414 return (grouped); 2415 } 2416 2417 /* 2418 * if_config_inst() - Configure an interface instance as specified by the 2419 * address family af and if it is grouped (ipmp). 2420 */ 2421 static int 2422 if_config_inst(const char *ifinst, FILE *hfp, int af, boolean_t ipmp) 2423 { 2424 FILE *ifparsefp; 2425 struct stat statb; 2426 char *buf = NULL; 2427 char *ifparsebuf = NULL; 2428 uint_t ifparsebufsize; 2429 const char *fstr; /* address family string */ 2430 boolean_t stdif = B_FALSE; 2431 2432 rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) ipmp = %d\n", 2433 ifinst, ipmp); 2434 2435 if (fstat(fileno(hfp), &statb) != 0) { 2436 rcm_log_message(RCM_ERROR, 2437 _("IP: Cannot fstat file(%s)\n"), ifinst); 2438 goto fail; 2439 } 2440 2441 switch (af) { 2442 case AF_INET: 2443 fstr = "inet"; 2444 break; 2445 case AF_INET6: 2446 fstr = "inet6"; 2447 break; 2448 default: 2449 assert(0); 2450 } 2451 2452 /* 2453 * The hostname file exists; plumb the physical interface. 2454 */ 2455 if (!ifconfig(ifinst, fstr, "plumb", B_FALSE)) 2456 goto fail; 2457 2458 /* Skip static configuration if the hostname file is empty */ 2459 if (statb.st_size <= 1) { 2460 rcm_log_message(RCM_TRACE1, 2461 _("IP: Zero size hostname file(%s)\n"), ifinst); 2462 goto configured; 2463 } 2464 2465 if (fseek(hfp, 0, SEEK_SET) == -1) { 2466 rcm_log_message(RCM_ERROR, 2467 _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst, 2468 strerror(errno)); 2469 goto fail; 2470 } 2471 2472 /* 2473 * Allocate the worst-case single-line buffer sizes. A bit skanky, 2474 * but since hostname files are small, this should suffice. 2475 */ 2476 if ((buf = calloc(1, statb.st_size)) == NULL) { 2477 rcm_log_message(RCM_ERROR, 2478 _("IP: calloc(%s): %s\n"), ifinst, strerror(errno)); 2479 goto fail; 2480 } 2481 2482 ifparsebufsize = statb.st_size + sizeof (SBIN_IFPARSE " -s inet6 "); 2483 if ((ifparsebuf = calloc(1, ifparsebufsize)) == NULL) { 2484 rcm_log_message(RCM_ERROR, 2485 _("IP: calloc(%s): %s\n"), ifinst, strerror(errno)); 2486 goto fail; 2487 } 2488 2489 /* 2490 * For IPv4, determine whether the hostname file consists of a single 2491 * line. We need to handle these specially since they should 2492 * automatically be suffixed with "netmask + broadcast + up". 2493 */ 2494 if (af == AF_INET && 2495 fgets(buf, statb.st_size, hfp) != NULL && 2496 fgets(buf, statb.st_size, hfp) == NULL) { 2497 rcm_log_message(RCM_TRACE1, "IP: one-line hostname file\n"); 2498 stdif = B_TRUE; 2499 } 2500 2501 if (fseek(hfp, 0L, SEEK_SET) == -1) { 2502 rcm_log_message(RCM_ERROR, 2503 _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst, 2504 strerror(errno)); 2505 goto fail; 2506 } 2507 2508 /* 2509 * Loop through the file one line at a time and feed it to ifconfig. 2510 * If the interface is using IPMP, then we use /sbin/ifparse -s to 2511 * weed out all of the data addresses, since those are already on the 2512 * IPMP meta-interface. 2513 */ 2514 while (fgets(buf, statb.st_size, hfp) != NULL) { 2515 if (ntok(buf) == 0) 2516 continue; 2517 2518 if (!ipmp) { 2519 (void) ifconfig(ifinst, fstr, buf, stdif); 2520 continue; 2521 } 2522 2523 (void) snprintf(ifparsebuf, ifparsebufsize, SBIN_IFPARSE 2524 " -s %s %s", fstr, buf); 2525 if ((ifparsefp = popen(ifparsebuf, "r")) == NULL) { 2526 rcm_log_message(RCM_ERROR, 2527 _("IP: cannot configure %s: popen \"%s\" " 2528 "failed: %s\n"), ifinst, buf, strerror(errno)); 2529 goto fail; 2530 } 2531 2532 while (fgets(buf, statb.st_size, ifparsefp) != NULL) { 2533 if (ntok(buf) > 0) 2534 (void) ifconfig(ifinst, fstr, buf, stdif); 2535 } 2536 2537 if (pclose(ifparsefp) == -1) { 2538 rcm_log_message(RCM_ERROR, 2539 _("IP: cannot configure %s: pclose \"%s\" " 2540 "failed: %s\n"), ifinst, buf, strerror(errno)); 2541 goto fail; 2542 } 2543 } 2544 2545 configured: 2546 /* 2547 * Bring up the interface (it may already be up) 2548 * 2549 * Technically, since the boot scripts only unconditionally bring up 2550 * IPv6 interfaces, we should only unconditionally bring up IPv6 here. 2551 * However, if we don't bring up IPv4, and a legacy IPMP configuration 2552 * without test addresses is being used, we will never bring the 2553 * interface up even though we would've at boot. One fix is to check 2554 * if the IPv4 hostname file contains data addresses that we would've 2555 * brought up, but there's no simple way to do that. Given that it's 2556 * rare to have persistent IP configuration for an interface that 2557 * leaves it down, we cheap out and always bring it up for IPMP. 2558 */ 2559 if ((af == AF_INET6 || ipmp) && !ifconfig(ifinst, fstr, "up", B_FALSE)) 2560 goto fail; 2561 2562 /* 2563 * For IPv4, if a DHCP configuration file exists, have DHCP configure 2564 * the interface. As with the boot scripts, this is done after the 2565 * hostname files are processed so that configuration in those files 2566 * (such as IPMP group names) will be applied first. 2567 */ 2568 if (af == AF_INET) { 2569 char dhcpfile[MAXPATHLEN]; 2570 char *dhcpbuf; 2571 off_t i, dhcpsize; 2572 2573 (void) snprintf(dhcpfile, MAXPATHLEN, DHCPFILE_FMT, ifinst); 2574 if (stat(dhcpfile, &statb) == -1) 2575 goto out; 2576 2577 if ((dhcpbuf = copylist(dhcpfile, &dhcpsize)) == NULL) { 2578 rcm_log_message(RCM_ERROR, _("IP: cannot read " 2579 "(%s): %s\n"), dhcpfile, strerror(errno)); 2580 goto fail; 2581 } 2582 2583 /* 2584 * The copylist() API converts \n's to \0's, but we want them 2585 * to be spaces. 2586 */ 2587 if (dhcpsize > 0) { 2588 for (i = 0; i < dhcpsize; i++) 2589 if (dhcpbuf[i] == '\0') 2590 dhcpbuf[i] = ' '; 2591 dhcpbuf[dhcpsize - 1] = '\0'; 2592 } 2593 (void) ifconfig(ifinst, CFG_DHCP_CMD, dhcpbuf, B_FALSE); 2594 free(dhcpbuf); 2595 } 2596 out: 2597 free(ifparsebuf); 2598 free(buf); 2599 rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) success\n", ifinst); 2600 return (0); 2601 fail: 2602 free(ifparsebuf); 2603 free(buf); 2604 rcm_log_message(RCM_ERROR, "IP: if_config_inst(%s) failure\n", ifinst); 2605 return (-1); 2606 } 2607 2608 /* 2609 * ntok() - count the number of tokens in the provided buffer. 2610 */ 2611 static uint_t 2612 ntok(const char *cp) 2613 { 2614 uint_t ntok = 0; 2615 2616 for (;;) { 2617 while (ISSPACE(*cp)) 2618 cp++; 2619 2620 if (ISEOL(*cp)) 2621 break; 2622 2623 do { 2624 cp++; 2625 } while (!ISSPACE(*cp) && !ISEOL(*cp)); 2626 2627 ntok++; 2628 } 2629 return (ntok); 2630 } 2631 2632 static boolean_t 2633 ifconfig(const char *ifinst, const char *fstr, const char *buf, boolean_t stdif) 2634 { 2635 char syscmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1]; 2636 int status; 2637 2638 (void) snprintf(syscmd, sizeof (syscmd), SBIN_IFCONFIG " %s %s %s", 2639 ifinst, fstr, buf); 2640 2641 if (stdif) 2642 (void) strlcat(syscmd, CFG_CMDS_STD, sizeof (syscmd)); 2643 2644 rcm_log_message(RCM_TRACE1, "IP: Exec: %s\n", syscmd); 2645 if ((status = rcm_exec_cmd(syscmd)) != 0) { 2646 if (WIFEXITED(status)) { 2647 rcm_log_message(RCM_ERROR, _("IP: \"%s\" failed with " 2648 "exit status %d\n"), syscmd, WEXITSTATUS(status)); 2649 } else { 2650 rcm_log_message(RCM_ERROR, _("IP: Error: %s: %s\n"), 2651 syscmd, strerror(errno)); 2652 } 2653 return (B_FALSE); 2654 } 2655 return (B_TRUE); 2656 } 2657