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