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 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <arpa/inet.h> 28 #include <errno.h> 29 #include <inet/ip.h> 30 #include <inetcfg.h> 31 #include <libdladm.h> 32 #include <libdllink.h> 33 #include <libdlwlan.h> 34 #include <libscf.h> 35 #include <netinet/in.h> 36 #include <netdb.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <sys/socket.h> 41 #include <sys/types.h> 42 43 #include <libnwam.h> 44 #include "conditions.h" 45 #include "events.h" 46 #include "objects.h" 47 #include "util.h" 48 49 /* 50 * enm.c - contains routines which handle ENM (external network modifier) 51 * abstraction. ENMs represent scripts or services that can be activated either 52 * manually or in response to network conditions. 53 */ 54 55 #define CTRUN "/usr/bin/ctrun" 56 57 static int 58 enm_create_init_fini_event(nwam_enm_handle_t enmh, void *data) 59 { 60 boolean_t *init = data; 61 char *name; 62 nwamd_event_t enm_event; 63 64 if (nwam_enm_get_name(enmh, &name) != NWAM_SUCCESS) { 65 nlog(LOG_ERR, "enm_init_fini: could not get ENM name"); 66 return (0); 67 } 68 69 enm_event = nwamd_event_init(*init ? 70 NWAM_EVENT_TYPE_OBJECT_INIT : NWAM_EVENT_TYPE_OBJECT_FINI, 71 NWAM_OBJECT_TYPE_ENM, 0, name); 72 if (enm_event != NULL) 73 nwamd_event_enqueue(enm_event); 74 free(name); 75 76 return (0); 77 } 78 79 /* 80 * Walk all ENMs, creating init events for each. 81 */ 82 void 83 nwamd_init_enms(void) 84 { 85 boolean_t init = B_TRUE; 86 87 (void) nwam_walk_enms(enm_create_init_fini_event, &init, 0, NULL); 88 } 89 90 /* 91 * Walk all ENMs, creating fini events for each. 92 */ 93 void 94 nwamd_fini_enms(void) 95 { 96 boolean_t init = B_FALSE; 97 98 (void) nwam_walk_enms(enm_create_init_fini_event, &init, 0, NULL); 99 } 100 101 static boolean_t 102 enm_is_enabled(nwam_enm_handle_t enmh) 103 { 104 nwam_value_t enabledval; 105 boolean_t enabled = B_FALSE; 106 107 if (nwam_enm_get_prop_value(enmh, NWAM_ENM_PROP_ENABLED, 108 &enabledval) != NWAM_SUCCESS) { 109 /* It's legal for a conditional ENM to not specify "enabled" */ 110 return (B_FALSE); 111 } 112 if (nwam_value_get_boolean(enabledval, &enabled) != NWAM_SUCCESS) { 113 nlog(LOG_ERR, "enm_is_enabled: could not retrieve " 114 "enabled value"); 115 } 116 nwam_value_free(enabledval); 117 return (enabled); 118 } 119 120 static int64_t 121 enm_get_activation_mode(nwam_enm_handle_t enmh) 122 { 123 uint64_t activation; 124 int64_t ret; 125 nwam_value_t activationval; 126 127 if (nwam_enm_get_prop_value(enmh, NWAM_ENM_PROP_ACTIVATION_MODE, 128 &activationval) != NWAM_SUCCESS) { 129 nlog(LOG_ERR, "enm_get_activation_mode: could not retrieve " 130 "activation mode value"); 131 return (-1); 132 } 133 if (nwam_value_get_uint64(activationval, &activation) != NWAM_SUCCESS) { 134 nlog(LOG_ERR, "enm_get_activation_mode: could not retrieve " 135 "activation mode value"); 136 ret = -1; 137 } else { 138 ret = activation; 139 } 140 nwam_value_free(activationval); 141 142 return (ret); 143 } 144 145 static void * 146 nwamd_enm_activate_deactivate_thread(void *arg) 147 { 148 char *object_name = arg; 149 nwamd_object_t object; 150 nwam_enm_handle_t enmh; 151 nwam_value_t scriptval = NULL; 152 nwam_state_t state; 153 nwam_aux_state_t aux_state; 154 char *script; 155 boolean_t going_online, disable_succeeded = B_FALSE; 156 int ret; 157 158 object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, object_name); 159 if (object == NULL) { 160 nlog(LOG_ERR, "nwamd_enm_activate_deactivate_thread: " 161 "could not find ENM %s", object_name); 162 free(object_name); 163 return (NULL); 164 } 165 /* object_name was malloc() before this thread was created, free() it */ 166 free(object_name); 167 168 enmh = object->nwamd_object_handle; 169 170 going_online = 171 (object->nwamd_object_state == NWAM_STATE_OFFLINE_TO_ONLINE); 172 /* 173 * We're starting if current state is offline* and stopping otherwise. 174 */ 175 if (nwam_enm_get_prop_value(enmh, 176 going_online ? NWAM_ENM_PROP_START : NWAM_ENM_PROP_STOP, 177 &scriptval) != NWAM_SUCCESS || 178 nwam_value_get_string(scriptval, &script) != NWAM_SUCCESS) { 179 /* 180 * If we're stopping, it's not an error for no script to 181 * be specified. 182 */ 183 nlog(going_online ? LOG_ERR : LOG_DEBUG, 184 "nwamd_enm_activate_deactivate_thread: " 185 "no script specified for enm %s", 186 object->nwamd_object_name); 187 if (going_online) { 188 state = NWAM_STATE_MAINTENANCE; 189 aux_state = NWAM_AUX_STATE_METHOD_MISSING; 190 } else { 191 disable_succeeded = B_TRUE; 192 } 193 } else { 194 char *copy = NULL, *lasts; 195 const char **newargv, **argv = NULL; 196 int i = 0; 197 198 nlog(LOG_DEBUG, "nwamd_enm_activate_deactivate_thread: " 199 "running script %s for ENM %s", script, 200 object->nwamd_object_name); 201 202 /* 203 * The script may take a number of arguments. We need to 204 * create a string array consisting of the wrapper command 205 * (ctrun), ENM script name, arguments and NULL array 206 * terminator. Start with an array of size equal to the 207 * string length (since the number of arguments will always 208 * be less than this) and shrink array to the actual number 209 * of arguments when we have parsed the string. 210 */ 211 if ((copy = strdup(script)) == NULL || 212 (argv = calloc(strlen(script), sizeof (char *))) == NULL) { 213 ret = 1; 214 goto err; 215 } 216 argv[i++] = CTRUN; 217 argv[i++] = strtok_r(copy, " ", &lasts); 218 if (argv[1] == NULL) { 219 ret = 1; 220 goto err; 221 } 222 223 for (; (argv[i] = strtok_r(NULL, " ", &lasts)) != NULL; i++) {} 224 225 newargv = realloc(argv, (i + 1) * sizeof (char *)); 226 argv = newargv; 227 228 ret = nwamd_start_childv(CTRUN, argv); 229 230 err: 231 /* 232 * If script execution fails and we're not destroying the 233 * object, go to maintenance. 234 */ 235 if (ret != 0) { 236 nlog(LOG_ERR, "nwamd_enm_activate_deactivate_thread: " 237 "execution of '%s' failed for ENM %s", 238 script, object->nwamd_object_name); 239 if (object->nwamd_object_aux_state != 240 NWAM_AUX_STATE_UNINITIALIZED) { 241 state = NWAM_STATE_MAINTENANCE; 242 aux_state = NWAM_AUX_STATE_METHOD_FAILED; 243 } else { 244 state = NWAM_STATE_UNINITIALIZED; 245 aux_state = NWAM_AUX_STATE_UNINITIALIZED; 246 } 247 } else { 248 if (going_online) { 249 state = NWAM_STATE_ONLINE; 250 aux_state = NWAM_AUX_STATE_ACTIVE; 251 } else { 252 disable_succeeded = B_TRUE; 253 } 254 } 255 free(argv); 256 free(copy); 257 } 258 nwam_value_free(scriptval); 259 260 if (disable_succeeded) { 261 /* 262 * If aux state is "manual disable", we know 263 * this was a disable request, otherwise it was 264 * _fini request or a condition satisfaction 265 * failure. 266 */ 267 switch (object->nwamd_object_aux_state) { 268 case NWAM_AUX_STATE_MANUAL_DISABLE: 269 state = NWAM_STATE_DISABLED; 270 aux_state = NWAM_AUX_STATE_MANUAL_DISABLE; 271 break; 272 case NWAM_AUX_STATE_UNINITIALIZED: 273 state = NWAM_STATE_UNINITIALIZED; 274 aux_state = NWAM_AUX_STATE_UNINITIALIZED; 275 break; 276 default: 277 state = NWAM_STATE_OFFLINE; 278 aux_state = NWAM_AUX_STATE_CONDITIONS_NOT_MET; 279 break; 280 } 281 } 282 283 /* If state/aux state are uninitialized/unintialized, destroy the ENM */ 284 if (state == NWAM_STATE_UNINITIALIZED && 285 aux_state == NWAM_AUX_STATE_UNINITIALIZED) { 286 object->nwamd_object_state = state; 287 object->nwamd_object_aux_state = aux_state; 288 (void) nwamd_object_release_and_destroy_after_preserve(object); 289 } else { 290 nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, 291 object->nwamd_object_name, state, aux_state); 292 (void) nwamd_object_release_after_preserve(object); 293 } 294 295 return (NULL); 296 } 297 298 /* 299 * Run start/stop method for ENM in a separate thread. The object lock is not 300 * held across threads, so we duplicate the object name for the method 301 * execution thread. Returns true if thread is successfully launched. 302 */ 303 boolean_t 304 nwamd_enm_run_method(nwamd_object_t object) 305 { 306 char *name; 307 pthread_t script; 308 309 /* 310 * Launch separate thread to wait for execution of script 311 * to complete. Do not hold object lock across threads. 312 */ 313 if ((name = strdup(object->nwamd_object_name)) == NULL) { 314 nlog(LOG_ERR, "nwamd_enm_run_method: %s: out of memory", 315 object->nwamd_object_name); 316 return (B_FALSE); 317 } 318 319 if (pthread_create(&script, NULL, 320 nwamd_enm_activate_deactivate_thread, name) != 0) { 321 nlog(LOG_ERR, "nwamd_enm_run_method: could not create " 322 "enm script thread for %s", name); 323 free(name); 324 return (B_FALSE); 325 } 326 /* "name" will be freed by the newly-created thread. */ 327 328 /* detach thread so that it doesn't become a zombie */ 329 (void) pthread_detach(script); 330 331 return (B_TRUE); 332 } 333 334 /* 335 * Activate the ENM, either in response to an enable event or conditions 336 * being satisfied. 337 */ 338 static void 339 nwamd_enm_activate(const char *object_name) 340 { 341 nwamd_object_t object; 342 nwam_value_t fmrival; 343 char *fmri, *smf_state; 344 int ret; 345 nwam_enm_handle_t enmh; 346 nwam_state_t state; 347 nwam_aux_state_t aux_state; 348 nwam_error_t err; 349 boolean_t ran_method = B_FALSE; 350 351 object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, object_name); 352 if (object == NULL) { 353 nlog(LOG_ERR, "nwamd_enm_activate: could not find ENM %s", 354 object_name); 355 return; 356 } 357 state = object->nwamd_object_state; 358 aux_state = object->nwamd_object_aux_state; 359 enmh = object->nwamd_object_handle; 360 361 nlog(LOG_DEBUG, "nwamd_enm_activate: activating ENM %s", 362 object->nwamd_object_name); 363 364 err = nwam_enm_get_prop_value(enmh, NWAM_ENM_PROP_FMRI, &fmrival); 365 switch (err) { 366 case NWAM_SUCCESS: 367 368 if (nwam_value_get_string(fmrival, &fmri) != NWAM_SUCCESS) { 369 nlog(LOG_ERR, "nwamd_enm_activate: could not retrieve " 370 "FMRI string for ENM %s", 371 object->nwamd_object_name); 372 nwam_value_free(fmrival); 373 state = NWAM_STATE_MAINTENANCE; 374 aux_state = NWAM_AUX_STATE_INVALID_CONFIG; 375 break; 376 } 377 378 if ((smf_state = smf_get_state(fmri)) == NULL) { 379 nlog(LOG_ERR, "nwamd_enm_activate: invalid FMRI %s " 380 "for ENM %s", fmri, object->nwamd_object_name); 381 nwam_value_free(fmrival); 382 state = NWAM_STATE_MAINTENANCE; 383 aux_state = NWAM_AUX_STATE_INVALID_CONFIG; 384 break; 385 } 386 387 nlog(LOG_DEBUG, "nwamd_enm_activate: activating %s for ENM %s", 388 fmri, object->nwamd_object_name); 389 390 if (strcmp(smf_state, SCF_STATE_STRING_ONLINE) == 0) 391 ret = smf_restart_instance(fmri); 392 else if (strcmp(smf_state, SCF_STATE_STRING_OFFLINE) == 0) 393 ret = smf_restart_instance(fmri); 394 else if (strcmp(smf_state, SCF_STATE_STRING_DISABLED) == 0) 395 ret = smf_enable_instance(fmri, SMF_TEMPORARY); 396 else 397 ret = smf_restore_instance(fmri); 398 399 if (ret == 0) { 400 state = NWAM_STATE_ONLINE; 401 aux_state = NWAM_AUX_STATE_ACTIVE; 402 } else { 403 nlog(LOG_ERR, "nwamd_enm_activate: failed to enable " 404 "FMRI %s for ENM %s", fmri, 405 object->nwamd_object_name); 406 state = NWAM_STATE_MAINTENANCE; 407 aux_state = NWAM_AUX_STATE_METHOD_FAILED; 408 } 409 free(smf_state); 410 nwam_value_free(fmrival); 411 break; 412 default: 413 /* 414 * Must be a method-based ENM with start (and stop) script(s). 415 */ 416 if (!nwamd_enm_run_method(object)) { 417 /* Could not launch method execution thread */ 418 state = NWAM_STATE_MAINTENANCE; 419 aux_state = NWAM_AUX_STATE_METHOD_FAILED; 420 } else { 421 ran_method = B_TRUE; 422 } 423 break; 424 } 425 426 if (state != object->nwamd_object_state || 427 aux_state != object->nwamd_object_aux_state) { 428 nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, 429 object->nwamd_object_name, state, aux_state); 430 } 431 432 /* 433 * If the method thread was created, we drop the lock to the ENM 434 * object without decreasing the reference count, ensuring it will not 435 * be destroyed until method execution has completed. 436 */ 437 if (ran_method) { 438 nwamd_object_release_and_preserve(object); 439 } else { 440 nwamd_object_release(object); 441 } 442 } 443 444 /* Deactivates the ENM. */ 445 static void 446 nwamd_enm_deactivate(const char *object_name) 447 { 448 nwamd_object_t object; 449 nwam_enm_handle_t enmh; 450 nwam_value_t fmrival; 451 char *fmri, *smf_state; 452 int ret; 453 nwam_state_t state; 454 nwam_aux_state_t aux_state; 455 boolean_t destroying = B_FALSE; 456 457 object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, object_name); 458 if (object == NULL) { 459 nlog(LOG_ERR, "nwamd_enm_deactivate: could not find ENM %s", 460 object_name); 461 return; 462 } 463 464 state = object->nwamd_object_state; 465 aux_state = object->nwamd_object_aux_state; 466 enmh = object->nwamd_object_handle; 467 state = object->nwamd_object_state; 468 /* If destroying, we don't care about method failure/config err */ 469 destroying = (aux_state == NWAM_AUX_STATE_UNINITIALIZED); 470 471 nlog(LOG_DEBUG, "nwamd_enm_deactivate: deactivating enm %s", 472 object->nwamd_object_name); 473 474 if (nwam_enm_get_prop_value(enmh, NWAM_ENM_PROP_FMRI, &fmrival) 475 != NWAM_SUCCESS) { 476 /* 477 * Must be a method-based ENM with start (and stop) script(s). 478 * Script execution thread will take care of the rest. 479 * If the method thread was created, we drop the lock to the ENM 480 * object without decreasing the reference count, ensuring it 481 * will not be destroyed until method execution has completed. 482 */ 483 if (nwamd_enm_run_method(object)) { 484 nwamd_object_release_and_preserve(object); 485 return; 486 } 487 /* Could not launch method execution thread */ 488 if (!destroying) { 489 state = NWAM_STATE_MAINTENANCE; 490 aux_state = NWAM_AUX_STATE_METHOD_FAILED; 491 } 492 } else { 493 if (nwam_value_get_string(fmrival, &fmri) != NWAM_SUCCESS) { 494 nlog(LOG_ERR, 495 "nwamd_enm_deactivate: could not retrieve " 496 "FMRI string for ENM %s", 497 object->nwamd_object_name); 498 if (!destroying) { 499 state = NWAM_STATE_MAINTENANCE; 500 aux_state = NWAM_AUX_STATE_INVALID_CONFIG; 501 } 502 } else { 503 if ((smf_state = smf_get_state(fmri)) == NULL) { 504 nlog(LOG_ERR, "nwamd_enm_deactivate: invalid " 505 "FMRI %s for ENM %s", fmri, 506 object->nwamd_object_name); 507 nwam_value_free(fmrival); 508 if (!destroying) { 509 state = NWAM_STATE_MAINTENANCE; 510 aux_state = 511 NWAM_AUX_STATE_INVALID_CONFIG; 512 } 513 goto done; 514 } 515 free(smf_state); 516 517 nlog(LOG_DEBUG, "nwamd_enm_deactivate: deactivating %s " 518 "for ENM %s", fmri, object->nwamd_object_name); 519 520 ret = smf_disable_instance(fmri, SMF_TEMPORARY); 521 522 if (ret != 0) { 523 nlog(LOG_ERR, "nwamd_enm_deactivate: " 524 "smf_disable_instance(%s) failed for " 525 "ENM %s: %s", fmri, 526 object->nwamd_object_name, 527 scf_strerror(scf_error())); 528 if (!destroying) { 529 state = NWAM_STATE_MAINTENANCE; 530 aux_state = 531 NWAM_AUX_STATE_METHOD_FAILED; 532 } 533 } 534 } 535 nwam_value_free(fmrival); 536 } 537 done: 538 if (state == object->nwamd_object_state && 539 aux_state == object->nwamd_object_aux_state) { 540 /* 541 * If aux state is "manual disable", we know 542 * this was a disable request, otherwise it was 543 * a _fini request or a condition satisfaction 544 * failure. 545 */ 546 switch (object->nwamd_object_aux_state) { 547 case NWAM_AUX_STATE_MANUAL_DISABLE: 548 state = NWAM_STATE_DISABLED; 549 aux_state = NWAM_AUX_STATE_MANUAL_DISABLE; 550 break; 551 case NWAM_AUX_STATE_UNINITIALIZED: 552 state = NWAM_STATE_UNINITIALIZED; 553 aux_state = NWAM_AUX_STATE_UNINITIALIZED; 554 break; 555 default: 556 state = NWAM_STATE_OFFLINE; 557 aux_state = NWAM_AUX_STATE_CONDITIONS_NOT_MET; 558 break; 559 } 560 } 561 562 /* Only change state if we aren't destroying the ENM */ 563 if (!destroying && (state != object->nwamd_object_state || 564 aux_state != object->nwamd_object_aux_state)) { 565 nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, 566 object->nwamd_object_name, state, aux_state); 567 } 568 569 /* If state/aux state are uninitialized/unintialized, destroy the ENM */ 570 if (state == NWAM_STATE_UNINITIALIZED && 571 aux_state == NWAM_AUX_STATE_UNINITIALIZED) { 572 (void) nwamd_object_release_and_destroy(object); 573 } else { 574 (void) nwamd_object_release(object); 575 } 576 } 577 578 /* 579 * Determine whether an ENM should be (de)activated. 580 */ 581 /* ARGSUSED1 */ 582 static int 583 nwamd_enm_check(nwamd_object_t object, void *data) 584 { 585 nwam_enm_handle_t enmh; 586 nwam_value_t conditionval; 587 int64_t eactivation; 588 boolean_t enabled, satisfied; 589 char **conditions; 590 nwam_state_t state; 591 uint_t nelem; 592 593 state = object->nwamd_object_state; 594 595 enmh = object->nwamd_object_handle; 596 597 eactivation = enm_get_activation_mode(enmh); 598 if (eactivation == -1) 599 return (0); 600 601 switch (eactivation) { 602 case NWAM_ACTIVATION_MODE_MANUAL: 603 enabled = enm_is_enabled(enmh); 604 605 if (enabled) { 606 nlog(LOG_DEBUG, "nwamd_enm_check: %s is enabled", 607 object->nwamd_object_name); 608 switch (state) { 609 case NWAM_STATE_ONLINE: 610 case NWAM_STATE_MAINTENANCE: 611 /* Do nothing */ 612 break; 613 default: 614 if (nwamd_enm_action(object->nwamd_object_name, 615 NWAM_ACTION_ENABLE) != 0) { 616 nlog(LOG_ERR, 617 "nwamd_enm_check: enable failed " 618 "for enm %s", 619 object->nwamd_object_name); 620 } 621 break; 622 } 623 } else { 624 nlog(LOG_DEBUG, "nwamd_enm_check: %s is disabled", 625 object->nwamd_object_name); 626 switch (state) { 627 case NWAM_STATE_ONLINE: 628 if (nwamd_enm_action(object->nwamd_object_name, 629 NWAM_ACTION_DISABLE) != 0) { 630 nlog(LOG_ERR, "nwamd_enm_check: " 631 "disable failed for enm %s", 632 object->nwamd_object_name); 633 } 634 break; 635 case NWAM_STATE_MAINTENANCE: 636 /* Do nothing */ 637 break; 638 case NWAM_STATE_DISABLED: 639 /* Do nothing */ 640 break; 641 default: 642 nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, 643 object->nwamd_object_name, 644 NWAM_STATE_DISABLED, 645 NWAM_AUX_STATE_MANUAL_DISABLE); 646 break; 647 } 648 } 649 break; 650 651 case NWAM_ACTIVATION_MODE_CONDITIONAL_ANY: 652 case NWAM_ACTIVATION_MODE_CONDITIONAL_ALL: 653 if (nwam_enm_get_prop_value(enmh, 654 NWAM_ENM_PROP_CONDITIONS, &conditionval) != NWAM_SUCCESS) { 655 nlog(LOG_ERR, "nwamd_enm_check: could not retrieve " 656 "condition value"); 657 break; 658 } 659 if (nwam_value_get_string_array(conditionval, 660 &conditions, &nelem) != NWAM_SUCCESS) { 661 nlog(LOG_ERR, "nwamd_enm_check: could not retrieve " 662 "condition value"); 663 nwam_value_free(conditionval); 664 break; 665 } 666 satisfied = nwamd_check_conditions((uint64_t)eactivation, 667 conditions, nelem); 668 669 nlog(LOG_DEBUG, "nwamd_enm_check: conditions for enm %s " 670 "%s satisfied", object->nwamd_object_name, 671 satisfied ? "is" : "is not"); 672 if (state != NWAM_STATE_ONLINE && satisfied) { 673 nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, 674 object->nwamd_object_name, 675 NWAM_STATE_OFFLINE_TO_ONLINE, 676 NWAM_AUX_STATE_METHOD_RUNNING); 677 } 678 if (state == NWAM_STATE_ONLINE && !satisfied) { 679 nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, 680 object->nwamd_object_name, 681 NWAM_STATE_ONLINE_TO_OFFLINE, 682 NWAM_AUX_STATE_CONDITIONS_NOT_MET); 683 } 684 nwam_value_free(conditionval); 685 break; 686 687 } 688 return (0); 689 } 690 691 void 692 nwamd_enm_check_conditions(void) 693 { 694 (void) nwamd_walk_objects(NWAM_OBJECT_TYPE_ENM, nwamd_enm_check, NULL); 695 } 696 697 int 698 nwamd_enm_action(const char *enm, nwam_action_t action) 699 { 700 nwamd_event_t event = nwamd_event_init_object_action 701 (NWAM_OBJECT_TYPE_ENM, enm, NULL, action); 702 if (event == NULL) 703 return (1); 704 nwamd_event_enqueue(event); 705 return (0); 706 } 707 708 /* 709 * Event handling functions. 710 */ 711 712 /* Handle ENM initialization/refresh event */ 713 void 714 nwamd_enm_handle_init_event(nwamd_event_t event) 715 { 716 nwamd_object_t object; 717 nwam_enm_handle_t enmh; 718 nwam_error_t err; 719 boolean_t manual_disabled = B_FALSE; 720 721 if ((err = nwam_enm_read(event->event_object, 0, &enmh)) 722 != NWAM_SUCCESS) { 723 nlog(LOG_ERR, "nwamd_enm_handle_init_event: could not " 724 "read object '%s': %s", event->event_object, 725 nwam_strerror(err)); 726 nwamd_event_do_not_send(event); 727 return; 728 } 729 if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, 730 event->event_object)) != NULL) { 731 nwam_enm_free(object->nwamd_object_handle); 732 object->nwamd_object_handle = enmh; 733 } else { 734 object = nwamd_object_init(NWAM_OBJECT_TYPE_ENM, 735 event->event_object, enmh, NULL); 736 object->nwamd_object_state = NWAM_STATE_OFFLINE; 737 object->nwamd_object_aux_state = 738 NWAM_AUX_STATE_CONDITIONS_NOT_MET; 739 } 740 manual_disabled = (enm_get_activation_mode(enmh) == 741 NWAM_ACTIVATION_MODE_MANUAL && !enm_is_enabled(enmh)); 742 743 /* 744 * If this ENM is ONLINE, and not manual and disabled (since in 745 * that case it was online but we've just set enabled = false as part 746 * of a disable action), then it is still active but refreshing. 747 * Change states to re-activate itself. 748 */ 749 if (!manual_disabled && 750 object->nwamd_object_state == NWAM_STATE_ONLINE) { 751 nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, 752 event->event_object, NWAM_STATE_OFFLINE_TO_ONLINE, 753 NWAM_AUX_STATE_METHOD_RUNNING); 754 } 755 nwamd_object_release(object); 756 } 757 758 /* Handle ENM finish event */ 759 void 760 nwamd_enm_handle_fini_event(nwamd_event_t event) 761 { 762 nwamd_event_t state_event; 763 764 nlog(LOG_DEBUG, "nwamd_enm_handle_fini_event(%s)", event->event_object); 765 766 /* 767 * Simulate a state event so that the state machine can correctly 768 * deactivate the ENM and free up the handle. 769 */ 770 state_event = nwamd_event_init_object_state(NWAM_OBJECT_TYPE_ENM, 771 event->event_object, NWAM_STATE_ONLINE_TO_OFFLINE, 772 NWAM_AUX_STATE_UNINITIALIZED); 773 if (state_event == NULL) { 774 nwamd_event_do_not_send(event); 775 return; 776 } 777 nwamd_enm_handle_state_event(state_event); 778 nwamd_event_fini(state_event); 779 /* 780 * Do not free the handle and object. 781 * nwamd_enm_activate_deactivate_thread() and 782 * nwamd_enm_deactivate() does this after running the stop script 783 * and disabling the FMRI respectively. 784 */ 785 } 786 787 void 788 nwamd_enm_handle_action_event(nwamd_event_t event) 789 { 790 nwamd_object_t object; 791 792 switch (event->event_msg->nwe_data.nwe_object_action.nwe_action) { 793 case NWAM_ACTION_ENABLE: 794 object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, 795 event->event_object); 796 if (object == NULL) { 797 nlog(LOG_ERR, "nwamd_enm_handle_action_event: " 798 "could not find enm %s", event->event_object); 799 nwamd_event_do_not_send(event); 800 return; 801 } 802 if (object->nwamd_object_state == NWAM_STATE_ONLINE) { 803 nlog(LOG_DEBUG, "nwamd_enm_handle_action_event: " 804 "enm %s already online, nothing to do", 805 event->event_object); 806 nwamd_object_release(object); 807 return; 808 } 809 nwamd_object_release(object); 810 811 nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, 812 event->event_object, NWAM_STATE_OFFLINE_TO_ONLINE, 813 NWAM_AUX_STATE_METHOD_RUNNING); 814 break; 815 case NWAM_ACTION_DISABLE: 816 object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, 817 event->event_object); 818 if (object == NULL) { 819 nlog(LOG_ERR, "nwamd_enm_handle_action_event: " 820 "could not find enm %s", event->event_object); 821 nwamd_event_do_not_send(event); 822 return; 823 } 824 if (object->nwamd_object_state == NWAM_STATE_DISABLED) { 825 nlog(LOG_DEBUG, "nwamd_enm_handle_action_event: " 826 "enm %s already disabled, nothing to do", 827 event->event_object); 828 nwamd_object_release(object); 829 return; 830 } 831 nwamd_object_release(object); 832 833 nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM, 834 event->event_object, NWAM_STATE_ONLINE_TO_OFFLINE, 835 NWAM_AUX_STATE_MANUAL_DISABLE); 836 break; 837 case NWAM_ACTION_ADD: 838 case NWAM_ACTION_REFRESH: 839 nwamd_enm_handle_init_event(event); 840 break; 841 case NWAM_ACTION_DESTROY: 842 nwamd_enm_handle_fini_event(event); 843 break; 844 default: 845 nlog(LOG_INFO, "nwam_enm_handle_action_event: " 846 "unexpected action"); 847 nwamd_event_do_not_send(event); 848 break; 849 } 850 } 851 852 void 853 nwamd_enm_handle_state_event(nwamd_event_t event) 854 { 855 nwamd_object_t object; 856 nwam_state_t new_state; 857 nwam_aux_state_t new_aux_state; 858 859 if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, 860 event->event_object)) == NULL) { 861 nlog(LOG_ERR, "nwamd_enm_handle_state_event: " 862 "state event for nonexistent ENM %s", event->event_object); 863 nwamd_event_do_not_send(event); 864 return; 865 } 866 new_state = event->event_msg->nwe_data.nwe_object_state.nwe_state; 867 new_aux_state = 868 event->event_msg->nwe_data.nwe_object_state.nwe_aux_state; 869 870 if (new_state == object->nwamd_object_state && 871 new_aux_state == object->nwamd_object_aux_state) { 872 nlog(LOG_DEBUG, "nwamd_enm_handle_state_event: " 873 "ENM %s already in state (%s , %s)", 874 object->nwamd_object_name, nwam_state_to_string(new_state), 875 nwam_aux_state_to_string(new_aux_state)); 876 nwamd_object_release(object); 877 return; 878 } 879 880 object->nwamd_object_state = new_state; 881 object->nwamd_object_aux_state = new_aux_state; 882 883 nlog(LOG_DEBUG, "nwamd_enm_handle_state_event: changing state for ENM " 884 "%s to (%s , %s)", object->nwamd_object_name, 885 nwam_state_to_string(object->nwamd_object_state), 886 nwam_aux_state_to_string(object->nwamd_object_aux_state)); 887 888 nwamd_object_release(object); 889 890 /* 891 * State machine for ENMs. 892 */ 893 switch (new_state) { 894 case NWAM_STATE_OFFLINE_TO_ONLINE: 895 nwamd_enm_activate(event->event_object); 896 break; 897 case NWAM_STATE_ONLINE_TO_OFFLINE: 898 nwamd_enm_deactivate(event->event_object); 899 break; 900 case NWAM_STATE_DISABLED: 901 case NWAM_STATE_OFFLINE: 902 case NWAM_STATE_UNINITIALIZED: 903 case NWAM_STATE_MAINTENANCE: 904 case NWAM_STATE_DEGRADED: 905 default: 906 /* do nothing */ 907 break; 908 } 909 } 910