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 <assert.h> 28 #include <ctype.h> 29 #include <libgen.h> 30 #include <netdb.h> 31 #include <sys/param.h> 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <sys/socket.h> 35 #include <netinet/in.h> 36 #include <arpa/inet.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <strings.h> 40 #include <unistd.h> 41 #include <libdladm.h> 42 43 #include "libnwam_impl.h" 44 #include <libnwam_priv.h> 45 #include <libnwam.h> 46 47 /* 48 * Functions to support creating, modifying, destroying, querying the 49 * state of and changing the state of NCP (Network Configuration Profiles) 50 * and the NCUs (Network Configuration Units) that are contained in those 51 * NCP objects. An NCP is simply a container for a set of NCUs which represent 52 * the datalink and interface configuration preferences for the system. 53 * An NCP can consist a set of prioritized link NCUs, e.g. wired links preferred 54 * over wireless, a set of manually enabled/diasbled NCUs, or a combination 55 * of both. Interface NCUs inherit activation from their underlying links, 56 * so if wired is preferred over wireless and a cable is plugged in, 57 * the wired link NCU will be active, as will the IP interface NCU above it. 58 */ 59 60 /* 61 * The NCU property table is used to mapping property types to property name 62 * strings, their associated value types etc. The table is used for validation 63 * purposes, and for commit()ing and read()ing NCUs. 64 */ 65 66 static nwam_error_t valid_type(nwam_value_t); 67 static nwam_error_t valid_class(nwam_value_t); 68 static nwam_error_t valid_ncp(nwam_value_t); 69 static nwam_error_t valid_priority_mode(nwam_value_t); 70 static nwam_error_t valid_ncu_activation_mode(nwam_value_t); 71 static nwam_error_t valid_link_autopush(nwam_value_t); 72 static nwam_error_t valid_link_mtu(nwam_value_t); 73 static nwam_error_t valid_ip_version(nwam_value_t); 74 static nwam_error_t valid_addrsrc_v4(nwam_value_t); 75 static nwam_error_t valid_addrsrc_v6(nwam_value_t); 76 77 struct nwam_prop_table_entry ncu_prop_table_entries[] = { 78 {NWAM_NCU_PROP_TYPE, NWAM_VALUE_TYPE_UINT64, B_FALSE, 1, 1, valid_type, 79 "specifies the NCU type - valid values are \'datalink\' and \'ip\'", 80 NWAM_FLAG_NCU_TYPE_ALL, NWAM_FLAG_NCU_CLASS_ALL}, 81 {NWAM_NCU_PROP_CLASS, NWAM_VALUE_TYPE_UINT64, B_FALSE, 1, 1, 82 valid_class, 83 "specifies the NCU class - valid values are " 84 "\'phys\' and \'ip\'", 85 NWAM_FLAG_NCU_TYPE_ALL, NWAM_FLAG_NCU_CLASS_ALL}, 86 {NWAM_NCU_PROP_PARENT_NCP, NWAM_VALUE_TYPE_STRING, B_FALSE, 1, 1, 87 valid_ncp, 88 "specifies the parent NCP name", 89 NWAM_FLAG_NCU_TYPE_ALL, NWAM_FLAG_NCU_CLASS_ALL}, 90 {NWAM_NCU_PROP_ACTIVATION_MODE, NWAM_VALUE_TYPE_UINT64, B_FALSE, 1, 1, 91 valid_ncu_activation_mode, 92 "specifies the NCU activation mode - valid values are:\n" 93 "\'prioritized\' and \'manual\'", 94 NWAM_FLAG_NCU_TYPE_LINK, NWAM_FLAG_NCU_CLASS_ALL_LINK}, 95 {NWAM_NCU_PROP_ENABLED, NWAM_VALUE_TYPE_BOOLEAN, B_TRUE, 0, 1, 96 nwam_valid_boolean, 97 "specifies if manual NCU is to be enabled", 98 NWAM_FLAG_NCU_TYPE_ALL, NWAM_FLAG_NCU_CLASS_ALL}, 99 {NWAM_NCU_PROP_PRIORITY_GROUP, NWAM_VALUE_TYPE_UINT64, B_FALSE, 0, 1, 100 nwam_valid_uint64, 101 "specifies the priority grouping of NCUs - lower values are " 102 "prioritized, negative values are invalid", 103 NWAM_FLAG_NCU_TYPE_LINK, NWAM_FLAG_NCU_CLASS_ALL_LINK}, 104 {NWAM_NCU_PROP_PRIORITY_MODE, NWAM_VALUE_TYPE_UINT64, B_FALSE, 0, 1, 105 valid_priority_mode, 106 "specifies the mode of prioritization - valid values are:\n" 107 "\'exclusive\', \'shared\' and \'all\'", 108 NWAM_FLAG_NCU_TYPE_LINK, NWAM_FLAG_NCU_CLASS_ALL_LINK}, 109 {NWAM_NCU_PROP_LINK_MAC_ADDR, NWAM_VALUE_TYPE_STRING, B_FALSE, 0, 1, 110 nwam_valid_mac_addr, 111 "specifies MAC address of form aa:bb:cc:dd:ee:ff for the link", 112 NWAM_FLAG_NCU_TYPE_LINK, NWAM_FLAG_NCU_CLASS_ALL_LINK}, 113 {NWAM_NCU_PROP_LINK_AUTOPUSH, NWAM_VALUE_TYPE_STRING, B_FALSE, 0, 114 NWAM_MAX_NUM_VALUES, valid_link_autopush, 115 "specifies modules to autopush on link", 116 NWAM_FLAG_NCU_TYPE_LINK, NWAM_FLAG_NCU_CLASS_ALL_LINK}, 117 {NWAM_NCU_PROP_LINK_MTU, NWAM_VALUE_TYPE_UINT64, B_FALSE, 0, 1, 118 valid_link_mtu, 119 "specifies MTU for link", 120 NWAM_FLAG_NCU_TYPE_LINK, NWAM_FLAG_NCU_CLASS_ALL_LINK}, 121 {NWAM_NCU_PROP_IP_VERSION, NWAM_VALUE_TYPE_UINT64, B_FALSE, 0, 122 NWAM_MAX_NUM_VALUES, valid_ip_version, 123 "specifies IP versions for IP NCU - valid values are:\n" 124 "\'ipv4\' and \'ipv6\'", 125 NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE}, 126 {NWAM_NCU_PROP_IPV4_ADDRSRC, NWAM_VALUE_TYPE_UINT64, B_FALSE, 0, 127 NWAM_MAX_NUM_VALUES, valid_addrsrc_v4, 128 "specifies IPv4 address source(s) - valid values are:\n" 129 "\'dhcp\' and \'static\'", 130 NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE}, 131 {NWAM_NCU_PROP_IPV4_ADDR, NWAM_VALUE_TYPE_STRING, B_FALSE, 0, 132 NWAM_MAX_NUM_VALUES, nwam_valid_host_v4, 133 "specifies static IPv4 host address(es)", 134 NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE}, 135 {NWAM_NCU_PROP_IPV4_DEFAULT_ROUTE, NWAM_VALUE_TYPE_STRING, B_FALSE, 0, 136 1, nwam_valid_route_v4, 137 "specifies per-interface default IPv4 route", 138 NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE}, 139 {NWAM_NCU_PROP_IPV6_ADDRSRC, NWAM_VALUE_TYPE_UINT64, B_FALSE, 0, 140 NWAM_MAX_NUM_VALUES, valid_addrsrc_v6, 141 "specifies IPv6 address source(s) - valid values are:\n" 142 "\'dhcp\', \'autoconf\' and \'static\'.\n" 143 "\'dhcp\' and \'autoconf\' are mandatory values.", 144 NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE}, 145 {NWAM_NCU_PROP_IPV6_ADDR, NWAM_VALUE_TYPE_STRING, B_FALSE, 0, 146 NWAM_MAX_NUM_VALUES, nwam_valid_host_v6, 147 "specifies static IPv6 host address(es)", 148 NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE}, 149 {NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE, NWAM_VALUE_TYPE_STRING, B_FALSE, 0, 150 1, nwam_valid_route_v6, 151 "specifies per-interface default IPv6 route", 152 NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE} 153 }; 154 155 #define NWAM_NUM_NCU_PROPS (sizeof (ncu_prop_table_entries) / \ 156 sizeof (*ncu_prop_table_entries)) 157 158 struct nwam_prop_table ncu_prop_table = 159 { NWAM_NUM_NCU_PROPS, ncu_prop_table_entries }; 160 161 nwam_error_t 162 nwam_ncp_get_name(nwam_ncp_handle_t ncph, char **namep) 163 { 164 return (nwam_get_name(ncph, namep)); 165 } 166 167 static nwam_error_t 168 nwam_ncp_name_to_file(const char *name, char **filename) 169 { 170 assert(name != NULL && filename != NULL); 171 172 if ((*filename = malloc(MAXPATHLEN)) == NULL) 173 return (NWAM_NO_MEMORY); 174 175 (void) snprintf(*filename, MAXPATHLEN, "%s%s%s%s", NWAM_CONF_DIR, 176 NWAM_NCP_CONF_FILE_PRE, name, NWAM_NCP_CONF_FILE_SUF); 177 178 return (NWAM_SUCCESS); 179 } 180 181 /* ARGSUSED1 */ 182 nwam_error_t 183 nwam_ncp_create(const char *name, uint64_t flags, nwam_ncp_handle_t *ncphp) 184 { 185 nwam_error_t err; 186 char *ncpfile; 187 188 if ((err = nwam_handle_create(NWAM_OBJECT_TYPE_NCP, name, ncphp)) 189 != NWAM_SUCCESS) 190 return (err); 191 192 /* Create empty container for NCUs */ 193 if ((err = nwam_ncp_name_to_file(name, &ncpfile)) 194 != NWAM_SUCCESS) { 195 nwam_free(*ncphp); 196 *ncphp = NULL; 197 return (err); 198 } 199 200 if ((err = nwam_commit(ncpfile, *ncphp, flags)) != NWAM_SUCCESS) { 201 nwam_free(*ncphp); 202 *ncphp = NULL; 203 } 204 205 free(ncpfile); 206 207 return (err); 208 } 209 210 /* Used by libnwam_files.c */ 211 nwam_error_t 212 nwam_ncp_file_to_name(const char *path, char **name) 213 { 214 char path_copy[MAXPATHLEN]; 215 char *filename, *suffix; 216 217 assert(path != NULL && name != NULL); 218 219 /* Make a copy as basename(3c) may modify string */ 220 (void) strlcpy(path_copy, path, MAXPATHLEN); 221 222 if ((*name = malloc(NWAM_MAX_NAME_LEN)) == NULL) 223 return (NWAM_NO_MEMORY); 224 225 if ((filename = basename(path_copy)) == NULL) { 226 free(*name); 227 return (NWAM_ENTITY_INVALID); 228 } 229 230 /* Ensure filename begins/ends with right prefix/suffix */ 231 if (sscanf(filename, NWAM_NCP_CONF_FILE_PRE "%256[^\n]s", *name) < 1) { 232 free(*name); 233 return (NWAM_ENTITY_INVALID); 234 } 235 suffix = *name + strlen(*name) - strlen(NWAM_NCP_CONF_FILE_SUF); 236 if (strstr(*name, NWAM_NCP_CONF_FILE_SUF) != suffix) { 237 free(*name); 238 return (NWAM_ENTITY_INVALID); 239 } 240 suffix[0] = '\0'; 241 242 return (NWAM_SUCCESS); 243 } 244 245 /* ARGSUSED1 */ 246 nwam_error_t 247 nwam_ncp_read(const char *name, uint64_t flags, nwam_ncp_handle_t *ncphp) 248 { 249 char *filename; 250 nwam_error_t err; 251 252 assert(name != NULL && ncphp != NULL); 253 254 /* try to read the associated ncp configuration */ 255 if ((err = nwam_ncp_name_to_file(name, &filename)) != NWAM_SUCCESS) { 256 *ncphp = NULL; 257 return (err); 258 } 259 260 err = nwam_read(NWAM_OBJECT_TYPE_NCP, filename, name, flags, ncphp); 261 free(filename); 262 return (err); 263 } 264 265 static nwam_error_t 266 nwam_ncu_get_parent_ncp_name(nwam_ncu_handle_t ncuh, char **parentnamep) 267 { 268 nwam_value_t parentval = NULL; 269 char *parentname; 270 nwam_error_t err; 271 272 if ((err = nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_PARENT_NCP, 273 &parentval)) != NWAM_SUCCESS || 274 (err = nwam_value_get_string(parentval, &parentname)) 275 != NWAM_SUCCESS || 276 (*parentnamep = strdup(parentname)) == NULL) { 277 if (parentval != NULL) 278 nwam_value_free(parentval); 279 *parentnamep = NULL; 280 return (err); 281 } 282 nwam_value_free(parentval); 283 284 return (NWAM_SUCCESS); 285 } 286 287 static int 288 nwam_ncp_copy_callback(nwam_ncu_handle_t oldncuh, void *arg) 289 { 290 nwam_error_t err; 291 nwam_ncu_handle_t newncuh = NULL; 292 char *oldparent; 293 char *oldfilename = NULL, *newfilename = NULL; 294 nwam_ncp_handle_t newncph = (nwam_ncp_handle_t)arg; 295 nwam_value_t newparentval; 296 297 /* Get filenames for the new and old NCU's */ 298 if ((err = nwam_ncu_get_parent_ncp_name(oldncuh, &oldparent)) 299 != NWAM_SUCCESS) 300 return (err); 301 err = nwam_ncp_name_to_file(oldparent, &oldfilename); 302 free(oldparent); 303 if (err != NWAM_SUCCESS) 304 return (err); 305 if ((err = nwam_ncp_name_to_file(newncph->nwh_name, &newfilename)) 306 != NWAM_SUCCESS) 307 goto fail; 308 309 /* new NCU name (and typedname) is the same as the old name */ 310 if ((err = nwam_handle_create(NWAM_OBJECT_TYPE_NCU, oldncuh->nwh_name, 311 &newncuh)) != NWAM_SUCCESS) 312 goto fail; 313 /* Duplicate the old NCU's data */ 314 if ((err = nwam_dup_object_list(oldncuh->nwh_data, 315 &(newncuh->nwh_data))) != NWAM_SUCCESS) 316 goto fail; 317 318 /* Update the parent property for the new NCU */ 319 if ((err = nwam_value_create_string(newncph->nwh_name, &newparentval)) 320 != NWAM_SUCCESS) 321 goto fail; 322 err = nwam_set_prop_value(newncuh->nwh_data, NWAM_NCU_PROP_PARENT_NCP, 323 newparentval); 324 nwam_value_free(newparentval); 325 if (err != NWAM_SUCCESS) 326 goto fail; 327 328 /* Save the new NCU */ 329 err = nwam_commit(newfilename, newncuh, 0); 330 331 fail: 332 free(oldfilename); 333 free(newfilename); 334 nwam_ncu_free(newncuh); 335 return (err); 336 } 337 338 nwam_error_t 339 nwam_ncp_copy(nwam_ncp_handle_t oldncph, const char *newname, 340 nwam_ncp_handle_t *newncphp) 341 { 342 nwam_ncp_handle_t ncph; 343 nwam_error_t err; 344 int cb_ret; 345 346 assert(oldncph != NULL && newname != NULL && newncphp != NULL); 347 348 /* check if newname NCP already exists */ 349 if (nwam_ncp_read(newname, 0, &ncph) == NWAM_SUCCESS) { 350 nwam_ncp_free(ncph); 351 *newncphp = NULL; 352 return (NWAM_ENTITY_EXISTS); 353 } 354 355 /* create new handle */ 356 if ((err = nwam_ncp_create(newname, 0, newncphp)) != NWAM_SUCCESS) 357 return (err); 358 359 err = nwam_ncp_walk_ncus(oldncph, nwam_ncp_copy_callback, *newncphp, 360 NWAM_FLAG_NCU_TYPE_CLASS_ALL, &cb_ret); 361 if (err != NWAM_SUCCESS) { 362 /* remove the NCP even if any NCU's had already been copied */ 363 (void) nwam_ncp_destroy(*newncphp, 0); 364 *newncphp = NULL; 365 if (err == NWAM_WALK_HALTED) 366 return (cb_ret); 367 else 368 return (err); 369 } 370 371 return (NWAM_SUCCESS); 372 } 373 374 /* 375 * Convert type to flag 376 */ 377 static uint64_t 378 nwam_ncu_type_to_flag(nwam_ncu_type_t type) 379 { 380 switch (type) { 381 case NWAM_NCU_TYPE_LINK: 382 return (NWAM_FLAG_NCU_TYPE_LINK); 383 case NWAM_NCU_TYPE_INTERFACE: 384 return (NWAM_FLAG_NCU_TYPE_INTERFACE); 385 case NWAM_NCU_TYPE_ANY: 386 return (NWAM_FLAG_NCU_TYPE_ALL); 387 default: 388 return (0); 389 } 390 } 391 392 /* 393 * Convert class to flag 394 */ 395 uint64_t 396 nwam_ncu_class_to_flag(nwam_ncu_class_t class) 397 { 398 switch (class) { 399 case NWAM_NCU_CLASS_PHYS: 400 return (NWAM_FLAG_NCU_CLASS_PHYS); 401 case NWAM_NCU_CLASS_IP: 402 return (NWAM_FLAG_NCU_CLASS_IP); 403 case NWAM_NCU_CLASS_ANY: 404 return (NWAM_FLAG_NCU_CLASS_ALL); 405 default: 406 return (0); 407 } 408 } 409 410 /* 411 * Infer NCU type from NCU class 412 */ 413 nwam_ncu_type_t 414 nwam_ncu_class_to_type(nwam_ncu_class_t class) 415 { 416 switch (class) { 417 case NWAM_NCU_CLASS_PHYS: 418 return (NWAM_NCU_TYPE_LINK); 419 case NWAM_NCU_CLASS_IP: 420 return (NWAM_NCU_TYPE_INTERFACE); 421 case NWAM_NCU_CLASS_ANY: 422 return (NWAM_NCU_TYPE_ANY); 423 default: 424 return (NWAM_NCU_TYPE_UNKNOWN); 425 } 426 } 427 428 /* 429 * Make ncp active, deactivating any other active ncp. 430 */ 431 nwam_error_t 432 nwam_ncp_enable(nwam_ncp_handle_t ncph) 433 { 434 nwam_error_t err; 435 char *name; 436 437 assert(ncph != NULL); 438 439 err = nwam_enable(NULL, ncph); 440 441 if (err == NWAM_ERROR_BIND) { 442 /* 443 * nwamd is not running, set active_ncp property so when 444 * nwamd is next started, this NCP will be used. 445 */ 446 if ((err = nwam_ncp_get_name(ncph, &name)) != NWAM_SUCCESS) 447 return (err); 448 449 err = nwam_set_smf_string_property(NWAM_FMRI, NWAM_PG, 450 NWAM_PROP_ACTIVE_NCP, name); 451 free(name); 452 } 453 454 return (err); 455 } 456 457 /* Compare NCP names c1 and c2 using strcasecmp() */ 458 static int 459 ncpname_cmp(const void *c1, const void *c2) 460 { 461 return (strcasecmp(*(const char **)c1, *(const char **)c2)); 462 } 463 464 /* ARGSUSED1 */ 465 nwam_error_t 466 nwam_walk_ncps(int (*cb)(nwam_ncp_handle_t, void *), void *data, 467 uint64_t flags, int *retp) 468 { 469 char *ncpname, **ncpfiles; 470 nwam_ncp_handle_t ncph; 471 nwam_error_t err; 472 nwam_value_t value; 473 void *objlist; 474 uint_t i, num_ncpfiles; 475 int ret = 0; 476 477 assert(cb != NULL); 478 479 if ((err = nwam_valid_flags(flags, NWAM_FLAG_BLOCKING)) != NWAM_SUCCESS) 480 return (err); 481 /* 482 * To get list of NCP files, call nwam_read_object_from_backend() 483 * with "parent" argument set to NULL. We get back an object list 484 * consisting of string arrays for each object type - NCP, ENM 485 * and location. We retrieve the NCP list, which corresponds to 486 * the set of NCP backend parent objects (these are files at present). 487 */ 488 if ((err = nwam_read_object_from_backend(NULL, NULL, flags, 489 &objlist)) != NWAM_SUCCESS) 490 return (err); 491 492 if ((err = nwam_get_prop_value(objlist, NWAM_NCP_OBJECT_STRING, &value)) 493 != NWAM_SUCCESS) { 494 nwam_free_object_list(objlist); 495 return (err); 496 } 497 if ((err = nwam_value_get_string_array(value, &ncpfiles, 498 &num_ncpfiles)) != NWAM_SUCCESS) { 499 nwam_value_free(value); 500 nwam_free_object_list(objlist); 501 return (err); 502 } 503 504 /* sort the NCP names alphabetically */ 505 qsort(ncpfiles, num_ncpfiles, sizeof (char *), ncpname_cmp); 506 507 for (i = 0; i < num_ncpfiles; i++) { 508 if (nwam_ncp_file_to_name(ncpfiles[i], &ncpname) 509 != NWAM_SUCCESS) 510 continue; 511 if ((err = nwam_handle_create(NWAM_OBJECT_TYPE_NCP, ncpname, 512 &ncph)) != NWAM_SUCCESS) { 513 free(ncpname); 514 break; 515 } 516 ret = cb(ncph, data); 517 free(ncph); 518 free(ncpname); 519 if (ret != 0) { 520 err = NWAM_WALK_HALTED; 521 break; 522 } 523 } 524 nwam_value_free(value); 525 nwam_free_object_list(objlist); 526 527 if (retp != NULL) 528 *retp = ret; 529 return (err); 530 } 531 532 /* 533 * Checks if NCP is read-only. Only NWAM_NCP_NAME_AUTOMATIC is read-only 534 * for all but the netadm user (which nwamd runs as). 535 */ 536 nwam_error_t 537 nwam_ncp_get_read_only(nwam_ncp_handle_t ncph, boolean_t *readp) 538 { 539 nwam_error_t err; 540 char *name; 541 542 assert(ncph != NULL && readp != NULL); 543 544 if ((err = nwam_ncp_get_name(ncph, &name)) != NWAM_SUCCESS) 545 return (err); 546 547 if (NWAM_NCP_AUTOMATIC(name)) 548 *readp = !nwam_uid_is_netadm(); 549 else 550 *readp = B_FALSE; 551 552 free(name); 553 return (NWAM_SUCCESS); 554 } 555 556 /* Checks if NCU is writable depending on its parent */ 557 nwam_error_t 558 nwam_ncu_get_read_only(nwam_ncu_handle_t ncuh, boolean_t *readp) 559 { 560 nwam_error_t err; 561 nwam_ncp_handle_t ncph; 562 563 assert(ncuh != NULL && readp != NULL); 564 565 if ((err = nwam_ncu_get_ncp(ncuh, &ncph)) != NWAM_SUCCESS) 566 return (err); 567 568 err = nwam_ncp_get_read_only(ncph, readp); 569 nwam_ncp_free(ncph); 570 return (err); 571 } 572 573 /* Returns true if the NCP is active */ 574 static boolean_t 575 nwam_ncp_is_active(nwam_ncp_handle_t ncph) 576 { 577 char *active_ncp, *name; 578 boolean_t ret; 579 580 assert(ncph != NULL); 581 582 /* 583 * Determine which NCP is active via the nwamd/active_ncp property 584 * value. This allows us to determine which NCP is active even 585 * if nwamd is not running. 586 */ 587 if (nwam_ncp_get_name(ncph, &name) != NWAM_SUCCESS || 588 nwam_get_smf_string_property(NWAM_FMRI, NWAM_PG, 589 NWAM_PROP_ACTIVE_NCP, &active_ncp) != NWAM_SUCCESS) 590 return (B_FALSE); 591 592 ret = (strcmp(name, active_ncp) == 0); 593 594 free(active_ncp); 595 free(name); 596 597 return (ret); 598 } 599 600 nwam_error_t 601 nwam_ncp_destroy(nwam_ncp_handle_t ncph, uint64_t flags) 602 { 603 char *filename; 604 nwam_error_t err; 605 boolean_t read_only; 606 607 assert(ncph != NULL); 608 609 if ((err = nwam_ncp_get_read_only(ncph, &read_only)) != NWAM_SUCCESS) 610 return (err); 611 if (read_only) 612 return (NWAM_ENTITY_NOT_DESTROYABLE); 613 614 if (nwam_ncp_is_active(ncph)) 615 return (NWAM_ENTITY_IN_USE); 616 617 if ((err = nwam_ncp_name_to_file(ncph->nwh_name, &filename)) 618 != NWAM_SUCCESS) 619 return (err); 620 621 err = nwam_destroy(filename, ncph, flags); 622 free(filename); 623 624 return (NWAM_SUCCESS); 625 } 626 627 static nwam_error_t 628 nwam_ncu_internal_name_to_name(const char *internalname, 629 nwam_ncu_type_t *typep, char **namep) 630 { 631 char *prefixstr; 632 633 assert(internalname != NULL && namep != NULL); 634 635 if (strncasecmp(internalname, NWAM_NCU_LINK_NAME_PRE, 636 strlen(NWAM_NCU_LINK_NAME_PRE)) == 0) { 637 prefixstr = NWAM_NCU_LINK_NAME_PRE; 638 *typep = NWAM_NCU_TYPE_LINK; 639 } else if (strncasecmp(internalname, NWAM_NCU_INTERFACE_NAME_PRE, 640 strlen(NWAM_NCU_INTERFACE_NAME_PRE)) == 0) { 641 prefixstr = NWAM_NCU_INTERFACE_NAME_PRE; 642 *typep = NWAM_NCU_TYPE_INTERFACE; 643 } else { 644 return (NWAM_INVALID_ARG); 645 } 646 647 *namep = strdup(internalname + strlen(prefixstr)); 648 if (*namep == NULL) 649 return (NWAM_NO_MEMORY); 650 return (NWAM_SUCCESS); 651 } 652 653 /* ARGSUSED2 */ 654 static int 655 ncu_selectcb(struct nwam_handle *hp, uint64_t flags, void *data) 656 { 657 nwam_ncu_handle_t ncuh = hp; 658 nwam_value_t typeval = NULL, classval = NULL; 659 uint64_t type, class, matchflags, walkfilter; 660 661 if (nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_TYPE, &typeval) 662 != NWAM_SUCCESS || 663 nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_CLASS, &classval) 664 != NWAM_SUCCESS) { 665 if (typeval != NULL) 666 nwam_value_free(typeval); 667 return (NWAM_INVALID_ARG); 668 } 669 if (nwam_value_get_uint64(typeval, &type) != NWAM_SUCCESS || 670 nwam_value_get_uint64(classval, &class) != NWAM_SUCCESS) { 671 nwam_value_free(typeval); 672 nwam_value_free(classval); 673 return (NWAM_INVALID_ARG); 674 } 675 676 matchflags = nwam_ncu_type_to_flag(type) | 677 nwam_ncu_class_to_flag(class); 678 nwam_value_free(typeval); 679 nwam_value_free(classval); 680 681 if ((walkfilter = (flags & NWAM_WALK_FILTER_MASK)) == 0) 682 walkfilter = NWAM_FLAG_NCU_TYPE_CLASS_ALL; 683 684 if (matchflags & walkfilter) 685 return (NWAM_SUCCESS); 686 return (NWAM_INVALID_ARG); 687 } 688 689 nwam_error_t 690 nwam_ncp_walk_ncus(nwam_ncp_handle_t ncph, 691 int(*cb)(nwam_ncu_handle_t, void *), void *data, uint64_t flags, int *retp) 692 { 693 char *ncpfile; 694 nwam_error_t err; 695 696 assert(ncph != NULL && cb != NULL); 697 698 if ((err = nwam_valid_flags(flags, 699 NWAM_FLAG_NCU_TYPE_CLASS_ALL | NWAM_FLAG_BLOCKING)) != NWAM_SUCCESS) 700 return (err); 701 702 if ((err = nwam_ncp_name_to_file(ncph->nwh_name, &ncpfile)) 703 != NWAM_SUCCESS) 704 return (err); 705 706 err = nwam_walk(NWAM_OBJECT_TYPE_NCU, ncpfile, cb, data, flags, 707 retp, ncu_selectcb); 708 free(ncpfile); 709 710 return (err); 711 } 712 713 void 714 nwam_ncp_free(nwam_ncp_handle_t ncph) 715 { 716 nwam_free(ncph); 717 } 718 719 /* 720 * Are ncu type and class compatible? 721 */ 722 static boolean_t 723 nwam_ncu_type_class_compatible(nwam_ncu_type_t type, nwam_ncu_class_t class) 724 { 725 switch (type) { 726 case NWAM_NCU_TYPE_LINK: 727 return (class == NWAM_NCU_CLASS_PHYS); 728 case NWAM_NCU_TYPE_INTERFACE: 729 return (class == NWAM_NCU_CLASS_IP); 730 default: 731 return (B_FALSE); 732 } 733 } 734 735 /* Name to validate may be internal name. If so, convert it before validating */ 736 static boolean_t 737 valid_ncu_name(const char *name) 738 { 739 char *n; 740 boolean_t ret; 741 nwam_ncu_type_t type; 742 743 if (nwam_ncu_internal_name_to_name(name, &type, &n) == NWAM_SUCCESS) { 744 745 ret = dladm_valid_linkname(n); 746 free(n); 747 } else { 748 ret = dladm_valid_linkname(name); 749 } 750 751 return (ret); 752 } 753 754 nwam_error_t 755 nwam_ncu_create(nwam_ncp_handle_t ncph, const char *name, 756 nwam_ncu_type_t type, nwam_ncu_class_t class, nwam_ncu_handle_t *ncuhp) 757 { 758 nwam_ncu_handle_t ncuh; 759 nwam_value_t typeval = NULL, classval = NULL, parentval = NULL; 760 nwam_value_t enabledval = NULL; 761 nwam_error_t err; 762 boolean_t read_only; 763 char *typedname; 764 765 assert(ncph != NULL && name != NULL && ncuhp != NULL); 766 767 if (!valid_ncu_name(name)) 768 return (NWAM_INVALID_ARG); 769 770 if ((err = nwam_ncp_get_read_only(ncph, &read_only)) != NWAM_SUCCESS) 771 return (err); 772 if (read_only) 773 return (NWAM_ENTITY_READ_ONLY); 774 775 if (nwam_ncu_read(ncph, name, type, 0, &ncuh) == NWAM_SUCCESS) { 776 nwam_ncu_free(ncuh); 777 return (NWAM_ENTITY_EXISTS); 778 } 779 780 if (!valid_ncu_name(name) || 781 !nwam_ncu_type_class_compatible(type, class)) 782 return (NWAM_INVALID_ARG); 783 784 if ((err = nwam_ncu_name_to_typed_name(name, type, &typedname)) 785 != NWAM_SUCCESS) 786 return (err); 787 788 /* Create handle */ 789 if ((err = nwam_handle_create(NWAM_OBJECT_TYPE_NCU, typedname, ncuhp)) 790 != NWAM_SUCCESS) 791 return (err); 792 free(typedname); 793 794 /* 795 * Create new object list for NCU. The new NCU is initialized with 796 * the appropriate type and class. 797 */ 798 if ((err = nwam_alloc_object_list(&(*ncuhp)->nwh_data)) != NWAM_SUCCESS) 799 goto finish; 800 801 if ((err = nwam_value_create_uint64(type, &typeval)) 802 != NWAM_SUCCESS || 803 (err = nwam_value_create_uint64(class, &classval)) 804 != NWAM_SUCCESS || 805 (err = nwam_value_create_string(ncph->nwh_name, &parentval)) 806 != NWAM_SUCCESS || 807 (err = nwam_value_create_boolean(B_TRUE, &enabledval)) 808 != NWAM_SUCCESS) { 809 goto finish; 810 } 811 if ((err = nwam_set_prop_value((*ncuhp)->nwh_data, NWAM_NCU_PROP_TYPE, 812 typeval)) != NWAM_SUCCESS || 813 (err = nwam_set_prop_value((*ncuhp)->nwh_data, NWAM_NCU_PROP_CLASS, 814 classval)) != NWAM_SUCCESS || 815 (err = nwam_set_prop_value((*ncuhp)->nwh_data, 816 NWAM_NCU_PROP_PARENT_NCP, parentval)) != NWAM_SUCCESS || 817 (err = nwam_set_prop_value((*ncuhp)->nwh_data, 818 NWAM_NCU_PROP_ENABLED, enabledval)) != NWAM_SUCCESS) { 819 goto finish; 820 } 821 822 /* Set default IP, datalink properties */ 823 if (type == NWAM_NCU_TYPE_INTERFACE && class == NWAM_NCU_CLASS_IP) { 824 825 uint64_t ver[] = { IPV4_VERSION, IPV6_VERSION }; 826 uint64_t v6src[] = { NWAM_ADDRSRC_DHCP, NWAM_ADDRSRC_AUTOCONF }; 827 uint_t vercnt = 2, v6srccnt = 2; 828 nwam_value_t ipver = NULL, v4addrsrc = NULL, v6addrsrc = NULL; 829 830 if ((err = nwam_value_create_uint64_array(ver, vercnt, &ipver)) 831 != NWAM_SUCCESS || 832 (err = nwam_value_create_uint64(NWAM_ADDRSRC_DHCP, 833 &v4addrsrc)) != NWAM_SUCCESS || 834 (err = nwam_value_create_uint64_array(v6src, v6srccnt, 835 &v6addrsrc)) != NWAM_SUCCESS) { 836 nwam_value_free(ipver); 837 nwam_value_free(v4addrsrc); 838 goto finish; 839 } 840 if ((err = nwam_set_prop_value((*ncuhp)->nwh_data, 841 NWAM_NCU_PROP_IP_VERSION, ipver)) == NWAM_SUCCESS && 842 (err = nwam_set_prop_value((*ncuhp)->nwh_data, 843 NWAM_NCU_PROP_IPV4_ADDRSRC, v4addrsrc)) == NWAM_SUCCESS) { 844 err = nwam_set_prop_value((*ncuhp)->nwh_data, 845 NWAM_NCU_PROP_IPV6_ADDRSRC, v6addrsrc); 846 } 847 nwam_value_free(ipver); 848 nwam_value_free(v4addrsrc); 849 nwam_value_free(v6addrsrc); 850 } else { 851 nwam_value_t actval = NULL; 852 if ((err = nwam_value_create_uint64(NWAM_ACTIVATION_MODE_MANUAL, 853 &actval)) != NWAM_SUCCESS) 854 goto finish; 855 err = nwam_set_prop_value((*ncuhp)->nwh_data, 856 NWAM_NCU_PROP_ACTIVATION_MODE, actval); 857 nwam_value_free(actval); 858 } 859 860 finish: 861 nwam_value_free(typeval); 862 nwam_value_free(classval); 863 nwam_value_free(parentval); 864 nwam_value_free(enabledval); 865 if (err != NWAM_SUCCESS) { 866 nwam_ncu_free(*ncuhp); 867 *ncuhp = NULL; 868 } 869 return (err); 870 } 871 872 nwam_error_t 873 nwam_ncu_read(nwam_ncp_handle_t ncph, const char *name, 874 nwam_ncu_type_t type, uint64_t flags, nwam_ncu_handle_t *ncuhp) 875 { 876 char *ncpfile, *typedname; 877 nwam_error_t err, err_ip, err_link; 878 nwam_ncu_handle_t ncuh_ip, ncuh_link; 879 880 assert(ncph != NULL && name != NULL && ncuhp != NULL); 881 882 if ((err = nwam_ncp_name_to_file(ncph->nwh_name, &ncpfile)) 883 != NWAM_SUCCESS) 884 return (err); 885 886 if (type == NWAM_NCU_TYPE_ANY) { 887 888 free(ncpfile); 889 890 /* 891 * If we get to this point, we have discovered that no 892 * NCU type is discernable from name or type arguments. 893 * Either exactly one NCU called name must exist of either 894 * type, or the operation should fail. 895 */ 896 err_ip = nwam_ncu_read(ncph, name, NWAM_NCU_TYPE_INTERFACE, 897 flags, &ncuh_ip); 898 err_link = nwam_ncu_read(ncph, name, NWAM_NCU_TYPE_LINK, 899 flags, &ncuh_link); 900 901 *ncuhp = NULL; 902 903 if (err_ip == NWAM_SUCCESS && err_link == NWAM_SUCCESS) { 904 nwam_ncu_free(ncuh_ip); 905 nwam_ncu_free(ncuh_link); 906 err = NWAM_ENTITY_MULTIPLE_VALUES; 907 } else if (err_ip != NWAM_SUCCESS && err_link != NWAM_SUCCESS) { 908 err = NWAM_ENTITY_NOT_FOUND; 909 } else { 910 if (err_ip == NWAM_SUCCESS) { 911 *ncuhp = ncuh_ip; 912 } else { 913 *ncuhp = ncuh_link; 914 } 915 err = NWAM_SUCCESS; 916 } 917 918 return (err); 919 } 920 if ((err = nwam_ncu_name_to_typed_name(name, type, &typedname)) != 921 NWAM_SUCCESS) { 922 free(ncpfile); 923 return (err); 924 } 925 err = nwam_read(NWAM_OBJECT_TYPE_NCU, ncpfile, typedname, flags, ncuhp); 926 927 free(typedname); 928 free(ncpfile); 929 930 return (err); 931 } 932 933 nwam_error_t 934 nwam_ncu_get_name(nwam_ncu_handle_t ncuh, char **namep) 935 { 936 nwam_ncu_type_t type; 937 938 assert(ncuh != NULL && namep != NULL); 939 940 return (nwam_ncu_internal_name_to_name(ncuh->nwh_name, &type, namep)); 941 } 942 943 nwam_error_t 944 nwam_ncu_name_to_typed_name(const char *name, nwam_ncu_type_t type, 945 char **typednamep) 946 { 947 char *prefixstr; 948 size_t typednamesz; 949 950 assert(name != NULL && typednamep != NULL); 951 952 switch (type) { 953 case NWAM_NCU_TYPE_INTERFACE: 954 prefixstr = NWAM_NCU_INTERFACE_NAME_PRE; 955 break; 956 case NWAM_NCU_TYPE_LINK: 957 prefixstr = NWAM_NCU_LINK_NAME_PRE; 958 break; 959 default: 960 return (NWAM_INVALID_ARG); 961 } 962 typednamesz = strlen(name) + strlen(prefixstr) + 1; 963 if ((*typednamep = malloc(typednamesz)) == NULL) 964 return (NWAM_NO_MEMORY); 965 966 /* Name may be already qualified by type */ 967 if (strncasecmp(prefixstr, name, strlen(prefixstr)) == 0) { 968 (void) snprintf(*typednamep, typednamesz, "%s", name); 969 } else { 970 (void) snprintf(*typednamep, typednamesz, "%s%s", 971 prefixstr, name); 972 } 973 974 return (NWAM_SUCCESS); 975 } 976 977 nwam_error_t 978 nwam_ncu_typed_name_to_name(const char *typed_name, nwam_ncu_type_t *typep, 979 char **name) 980 { 981 return (nwam_ncu_internal_name_to_name(typed_name, typep, name)); 982 } 983 984 void 985 nwam_ncu_free(nwam_ncu_handle_t ncuh) 986 { 987 nwam_free(ncuh); 988 } 989 990 nwam_error_t 991 nwam_ncu_copy(nwam_ncu_handle_t oldncuh, const char *newname, 992 nwam_ncu_handle_t *newncuhp) 993 { 994 nwam_ncp_handle_t ncph; 995 nwam_ncu_handle_t ncuh; 996 nwam_error_t err; 997 nwam_value_t typeval; 998 uint64_t type; 999 char *typednewname; 1000 1001 assert(oldncuh != NULL && newname != NULL && newncuhp != NULL); 1002 1003 if (nwam_ncu_get_prop_value(oldncuh, NWAM_NCU_PROP_TYPE, 1004 &typeval) != NWAM_SUCCESS) { 1005 return (NWAM_INVALID_ARG); 1006 } 1007 if (nwam_value_get_uint64(typeval, &type) != NWAM_SUCCESS) { 1008 nwam_value_free(typeval); 1009 return (NWAM_INVALID_ARG); 1010 } 1011 nwam_value_free(typeval); 1012 1013 /* check if newname NCU already exists */ 1014 if ((err = nwam_ncu_get_ncp(oldncuh, &ncph)) != NWAM_SUCCESS) 1015 return (err); 1016 if (nwam_ncu_read(ncph, newname, type, 0, &ncuh) == NWAM_SUCCESS) { 1017 nwam_ncu_free(ncuh); 1018 nwam_ncp_free(ncph); 1019 return (NWAM_ENTITY_EXISTS); 1020 } 1021 nwam_ncp_free(ncph); 1022 1023 if ((err = nwam_ncu_name_to_typed_name(newname, type, &typednewname)) 1024 != NWAM_SUCCESS) 1025 return (err); 1026 1027 err = nwam_handle_create(NWAM_OBJECT_TYPE_NCU, typednewname, newncuhp); 1028 free(typednewname); 1029 if (err != NWAM_SUCCESS) 1030 return (err); 1031 if ((err = nwam_dup_object_list(oldncuh->nwh_data, 1032 &((*newncuhp)->nwh_data))) != NWAM_SUCCESS) { 1033 free(*newncuhp); 1034 *newncuhp = NULL; 1035 return (err); 1036 } 1037 1038 return (NWAM_SUCCESS); 1039 } 1040 1041 nwam_error_t 1042 nwam_ncu_delete_prop(nwam_ncu_handle_t ncuh, const char *propname) 1043 { 1044 boolean_t ro_ncu, ro_prop; 1045 nwam_error_t err; 1046 void *olddata; 1047 1048 assert(ncuh != NULL && propname != NULL); 1049 1050 if ((err = nwam_ncu_get_read_only(ncuh, &ro_ncu)) != NWAM_SUCCESS || 1051 (err = nwam_ncu_prop_read_only(propname, &ro_prop)) != NWAM_SUCCESS) 1052 return (err); 1053 if (ro_ncu || ro_prop) 1054 return (NWAM_ENTITY_READ_ONLY); 1055 1056 /* 1057 * Duplicate data, remove property and validate. If validation 1058 * fails, revert to data duplicated prior to remove. 1059 */ 1060 if ((err = nwam_dup_object_list(ncuh->nwh_data, &olddata)) 1061 != NWAM_SUCCESS) 1062 return (err); 1063 if ((err = nwam_delete_prop(ncuh->nwh_data, propname)) 1064 != NWAM_SUCCESS) { 1065 nwam_free_object_list(ncuh->nwh_data); 1066 ncuh->nwh_data = olddata; 1067 return (err); 1068 } 1069 if ((err = nwam_ncu_validate(ncuh, NULL)) != NWAM_SUCCESS) { 1070 nwam_free_object_list(ncuh->nwh_data); 1071 ncuh->nwh_data = olddata; 1072 return (err); 1073 } 1074 nwam_free_object_list(olddata); 1075 1076 return (NWAM_SUCCESS); 1077 } 1078 1079 nwam_error_t 1080 nwam_ncu_set_prop_value(nwam_ncu_handle_t ncuh, const char *propname, 1081 nwam_value_t value) 1082 { 1083 boolean_t ro_ncu, ro_prop; 1084 nwam_error_t err; 1085 nwam_ncp_handle_t ncph; 1086 1087 assert(ncuh != NULL && propname != NULL && value != NULL); 1088 1089 if ((err = nwam_ncu_get_read_only(ncuh, &ro_ncu)) != NWAM_SUCCESS || 1090 (err = nwam_ncu_prop_read_only(propname, &ro_prop)) != NWAM_SUCCESS) 1091 return (err); 1092 if (ro_ncu || ro_prop) 1093 return (NWAM_ENTITY_READ_ONLY); 1094 1095 err = nwam_ncu_get_ncp(ncuh, &ncph); 1096 if (err != NWAM_SUCCESS && err != NWAM_INVALID_ARG) { 1097 /* 1098 * If "parent" property doesn't exist, NWAM_INVALID_ARG 1099 * is returned. Allow the setting to continue. 1100 */ 1101 return (err); 1102 } 1103 nwam_ncp_free(ncph); 1104 1105 /* Need to ensure property, type and value are valid */ 1106 if ((err = nwam_ncu_validate_prop(ncuh, propname, value)) 1107 != NWAM_SUCCESS) 1108 return (err); 1109 1110 return (nwam_set_prop_value(ncuh->nwh_data, propname, value)); 1111 } 1112 1113 nwam_error_t 1114 nwam_ncu_get_prop_value(nwam_ncu_handle_t ncuh, const char *propname, 1115 nwam_value_t *valuep) 1116 { 1117 assert(ncuh != NULL && propname != NULL && valuep != NULL); 1118 1119 return (nwam_get_prop_value(ncuh->nwh_data, propname, valuep)); 1120 } 1121 1122 nwam_error_t 1123 nwam_ncu_walk_props(nwam_ncu_handle_t ncuh, 1124 int (*cb)(const char *, nwam_value_t, void *), 1125 void *data, uint64_t flags, int *retp) 1126 { 1127 return (nwam_walk_props(ncuh, cb, data, flags, retp)); 1128 } 1129 1130 nwam_error_t 1131 nwam_ncu_get_ncp(nwam_ncu_handle_t ncuh, nwam_ncp_handle_t *ncphp) 1132 { 1133 nwam_error_t err; 1134 char *parentname = NULL; 1135 1136 if ((err = nwam_ncu_get_parent_ncp_name(ncuh, &parentname)) 1137 != NWAM_SUCCESS || 1138 (err = nwam_handle_create(NWAM_OBJECT_TYPE_NCP, parentname, ncphp)) 1139 != NWAM_SUCCESS) { 1140 if (parentname != NULL) 1141 free(parentname); 1142 return (err); 1143 } 1144 free(parentname); 1145 1146 return (NWAM_SUCCESS); 1147 } 1148 1149 nwam_error_t 1150 nwam_ncu_commit(nwam_ncu_handle_t ncuh, uint64_t flags) 1151 { 1152 nwam_error_t err; 1153 boolean_t read_only; 1154 char *ncpfile, *ncpname; 1155 1156 assert(ncuh != NULL && ncuh->nwh_data != NULL); 1157 1158 if ((err = nwam_ncu_get_read_only(ncuh, &read_only)) != NWAM_SUCCESS) 1159 return (err); 1160 if (read_only) 1161 return (NWAM_ENTITY_READ_ONLY); 1162 1163 if ((err = nwam_ncu_validate(ncuh, NULL)) != NWAM_SUCCESS || 1164 (err = nwam_ncu_get_parent_ncp_name(ncuh, &ncpname)) 1165 != NWAM_SUCCESS) 1166 return (err); 1167 1168 if ((err = nwam_ncp_name_to_file(ncpname, &ncpfile)) != NWAM_SUCCESS) { 1169 free(ncpname); 1170 return (err); 1171 } 1172 1173 err = nwam_commit(ncpfile, ncuh, flags); 1174 1175 free(ncpname); 1176 free(ncpfile); 1177 1178 return (err); 1179 } 1180 /* Get the NCU type */ 1181 nwam_error_t 1182 nwam_ncu_get_ncu_type(nwam_ncu_handle_t ncuh, nwam_ncu_type_t *typep) 1183 { 1184 nwam_error_t err; 1185 nwam_value_t typeval; 1186 uint64_t type; 1187 1188 if ((err = nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_TYPE, &typeval)) 1189 != NWAM_SUCCESS) 1190 return (err); 1191 err = nwam_value_get_uint64(typeval, &type); 1192 nwam_value_free(typeval); 1193 if (err != NWAM_SUCCESS) 1194 return (err); 1195 1196 *typep = type; 1197 return (NWAM_SUCCESS); 1198 } 1199 1200 /* Get the NCU class */ 1201 nwam_error_t 1202 nwam_ncu_get_ncu_class(nwam_ncu_handle_t ncuh, nwam_ncu_class_t *classp) 1203 { 1204 nwam_error_t err; 1205 nwam_value_t classval; 1206 uint64_t class; 1207 1208 if ((err = nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_CLASS, 1209 &classval)) != NWAM_SUCCESS) 1210 return (err); 1211 err = nwam_value_get_uint64(classval, &class); 1212 nwam_value_free(classval); 1213 if (err != NWAM_SUCCESS) 1214 return (err); 1215 1216 *classp = class; 1217 return (NWAM_SUCCESS); 1218 } 1219 1220 /* 1221 * Determine if the NCU has manual activation-mode or not. 1222 */ 1223 nwam_error_t 1224 nwam_ncu_is_manual(nwam_ncu_handle_t ncuh, boolean_t *manualp) 1225 { 1226 nwam_error_t err; 1227 nwam_value_t actval; 1228 uint64_t activation; 1229 1230 assert(ncuh != NULL); 1231 1232 if ((err = nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_ACTIVATION_MODE, 1233 &actval)) != NWAM_SUCCESS) 1234 return (err); 1235 err = nwam_value_get_uint64(actval, &activation); 1236 nwam_value_free(actval); 1237 if (err != NWAM_SUCCESS) 1238 return (err); 1239 1240 if (activation == NWAM_ACTIVATION_MODE_MANUAL) 1241 *manualp = B_TRUE; 1242 else 1243 *manualp = B_FALSE; 1244 return (NWAM_SUCCESS); 1245 } 1246 1247 /* Determine if NCU is enabled or not */ 1248 static nwam_error_t 1249 nwam_ncu_is_enabled(nwam_ncu_handle_t ncuh, boolean_t *enabledp) 1250 { 1251 nwam_error_t err; 1252 nwam_value_t enabledval; 1253 1254 assert(ncuh != NULL); 1255 1256 if ((err = nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_ENABLED, 1257 &enabledval)) != NWAM_SUCCESS) 1258 return (err); 1259 err = nwam_value_get_boolean(enabledval, enabledp); 1260 nwam_value_free(enabledval); 1261 return (err); 1262 } 1263 1264 /* Update the enabled property */ 1265 static nwam_error_t 1266 nwam_ncu_update_enabled(nwam_ncu_handle_t ncuh, boolean_t enabled) 1267 { 1268 nwam_error_t err; 1269 nwam_value_t enabledval; 1270 1271 if ((err = nwam_value_create_boolean(enabled, &enabledval)) 1272 != NWAM_SUCCESS) 1273 return (err); 1274 err = nwam_set_prop_value(ncuh->nwh_data, NWAM_NCU_PROP_ENABLED, 1275 enabledval); 1276 nwam_value_free(enabledval); 1277 if (err != NWAM_SUCCESS) 1278 return (err); 1279 return (nwam_ncu_commit(ncuh, NWAM_FLAG_ENTITY_ENABLE)); 1280 } 1281 1282 /* 1283 * Make ncu active; fails if the NCU's parent NCP is not active. 1284 */ 1285 nwam_error_t 1286 nwam_ncu_enable(nwam_ncu_handle_t ncuh) 1287 { 1288 char *ncpname = NULL; 1289 nwam_error_t err; 1290 nwam_ncu_type_t type; 1291 boolean_t read_only, enabled, manual; 1292 1293 assert(ncuh != NULL); 1294 1295 /* Don't allow NCUs of Automatic NCP to be enabled */ 1296 if ((err = nwam_ncu_get_read_only(ncuh, &read_only)) != NWAM_SUCCESS) 1297 return (err); 1298 if (read_only) 1299 return (NWAM_ENTITY_NOT_MANUAL); 1300 1301 /* Link NCUs with manual activation-mode or IP NCUs can be enabled */ 1302 if ((err = nwam_ncu_get_ncu_type(ncuh, &type)) != NWAM_SUCCESS) 1303 return (err); 1304 1305 if (type == NWAM_NCU_TYPE_LINK) { 1306 if ((err = nwam_ncu_is_manual(ncuh, &manual)) != NWAM_SUCCESS) 1307 return (err); 1308 if (!manual) 1309 return (NWAM_ENTITY_NOT_MANUAL); 1310 } 1311 1312 /* Make sure NCU is not enabled */ 1313 if ((err = nwam_ncu_is_enabled(ncuh, &enabled)) != NWAM_SUCCESS || 1314 (err = nwam_ncu_get_parent_ncp_name(ncuh, &ncpname)) 1315 != NWAM_SUCCESS) 1316 return (err); 1317 1318 if (enabled) { 1319 free(ncpname); 1320 return (NWAM_SUCCESS); 1321 } 1322 1323 if ((err = nwam_ncu_update_enabled(ncuh, B_TRUE)) != NWAM_SUCCESS) { 1324 free(ncpname); 1325 return (err); 1326 } 1327 1328 err = nwam_enable(ncpname, ncuh); 1329 free(ncpname); 1330 1331 /* nwamd may not be running, that's okay. */ 1332 if (err == NWAM_ERROR_BIND) 1333 return (NWAM_SUCCESS); 1334 else 1335 return (err); 1336 } 1337 1338 /* 1339 * Disable ncu; fails if the NCU's parent NCP is not active, or if the 1340 * NCU is not currently active. 1341 */ 1342 nwam_error_t 1343 nwam_ncu_disable(nwam_ncu_handle_t ncuh) 1344 { 1345 char *ncpname = NULL; 1346 nwam_error_t err; 1347 nwam_ncu_type_t type; 1348 boolean_t read_only, enabled, manual; 1349 1350 assert(ncuh != NULL); 1351 1352 /* Don't allow NCUs of Automatic NCP to be disabled */ 1353 if ((err = nwam_ncu_get_read_only(ncuh, &read_only)) != NWAM_SUCCESS) 1354 return (err); 1355 if (read_only) 1356 return (NWAM_ENTITY_NOT_MANUAL); 1357 1358 /* Link NCUs with manual activation-mode or IP NCUs can be disabled */ 1359 if ((err = nwam_ncu_get_ncu_type(ncuh, &type)) != NWAM_SUCCESS) 1360 return (err); 1361 1362 if (type == NWAM_NCU_TYPE_LINK) { 1363 if ((err = nwam_ncu_is_manual(ncuh, &manual)) != NWAM_SUCCESS) 1364 return (err); 1365 if (!manual) 1366 return (NWAM_ENTITY_NOT_MANUAL); 1367 } 1368 1369 /* Make sure NCU is enabled */ 1370 if ((err = nwam_ncu_is_enabled(ncuh, &enabled)) != NWAM_SUCCESS || 1371 (err = nwam_ncu_get_parent_ncp_name(ncuh, &ncpname)) 1372 != NWAM_SUCCESS) 1373 return (err); 1374 1375 if (!enabled) { 1376 free(ncpname); 1377 return (NWAM_SUCCESS); 1378 } 1379 1380 if ((err = nwam_ncu_update_enabled(ncuh, B_FALSE)) != NWAM_SUCCESS) { 1381 free(ncpname); 1382 return (err); 1383 } 1384 1385 err = nwam_disable(ncpname, ncuh); 1386 free(ncpname); 1387 1388 /* nwamd may not be running, that's okay. */ 1389 if (err == NWAM_ERROR_BIND) 1390 return (NWAM_SUCCESS); 1391 else 1392 return (err); 1393 } 1394 1395 nwam_error_t 1396 nwam_ncu_destroy(nwam_ncu_handle_t ncuh, uint64_t flags) 1397 { 1398 char *ncpname, *ncpfile; 1399 boolean_t read_only; 1400 nwam_error_t err; 1401 1402 assert(ncuh != NULL); 1403 1404 if ((err = nwam_ncu_get_read_only(ncuh, &read_only)) != NWAM_SUCCESS) 1405 return (err); 1406 if (read_only) 1407 return (NWAM_ENTITY_NOT_DESTROYABLE); 1408 1409 if ((err = nwam_ncu_get_parent_ncp_name(ncuh, &ncpname)) 1410 != NWAM_SUCCESS) 1411 return (err); 1412 if ((err = nwam_ncp_name_to_file(ncpname, &ncpfile)) 1413 != NWAM_SUCCESS) { 1414 free(ncpname); 1415 return (err); 1416 } 1417 1418 err = nwam_destroy(ncpfile, ncuh, flags); 1419 1420 free(ncpname); 1421 free(ncpfile); 1422 1423 return (err); 1424 } 1425 1426 nwam_error_t 1427 nwam_ncu_get_prop_description(const char *propname, const char **descriptionp) 1428 { 1429 return (nwam_get_prop_description(ncu_prop_table, propname, 1430 descriptionp)); 1431 } 1432 1433 /* Get expected property data type */ 1434 nwam_error_t 1435 nwam_ncu_get_prop_type(const char *propname, nwam_value_type_t *typep) 1436 { 1437 return (nwam_get_prop_type(ncu_prop_table, propname, typep)); 1438 } 1439 1440 nwam_error_t 1441 nwam_ncu_prop_read_only(const char *propname, boolean_t *readp) 1442 { 1443 if ((*readp = NWAM_NCU_PROP_SETONCE(propname)) == B_TRUE) 1444 return (NWAM_SUCCESS); 1445 1446 return (nwam_prop_read_only(ncu_prop_table, propname, readp)); 1447 } 1448 1449 nwam_error_t 1450 nwam_ncu_prop_multivalued(const char *propname, boolean_t *multip) 1451 { 1452 return (nwam_prop_multivalued(ncu_prop_table, propname, multip)); 1453 } 1454 1455 /* 1456 * Ensure that the properties in the ncu, determined by that ncu's 1457 * type and class, belong there. 1458 */ 1459 static nwam_error_t 1460 nwam_ncu_validate_prop_membership(nwam_ncu_handle_t ncuh, const char *propname) 1461 { 1462 struct nwam_prop_table_entry *pte; 1463 nwam_value_t typeval, classval; 1464 uint64_t type, class; 1465 uint64_t typeflags = 0, classflags = 0; 1466 1467 /* Get type/class from ncu */ 1468 if (nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_TYPE, &typeval) 1469 != NWAM_SUCCESS) 1470 return (NWAM_ENTITY_INVALID); 1471 if (nwam_value_get_uint64(typeval, &type) != NWAM_SUCCESS) { 1472 nwam_value_free(typeval); 1473 return (NWAM_ENTITY_INVALID); 1474 } 1475 typeflags = nwam_ncu_type_to_flag((nwam_ncu_type_t)type); 1476 nwam_value_free(typeval); 1477 1478 if (nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_CLASS, &classval) 1479 != NWAM_SUCCESS) 1480 return (NWAM_ENTITY_INVALID); 1481 if (nwam_value_get_uint64(classval, &class) != NWAM_SUCCESS) { 1482 nwam_value_free(classval); 1483 return (NWAM_ENTITY_INVALID); 1484 } 1485 classflags = nwam_ncu_class_to_flag((nwam_ncu_class_t)class); 1486 nwam_value_free(classval); 1487 1488 if ((pte = nwam_get_prop_table_entry(ncu_prop_table, propname)) == NULL) 1489 return (NWAM_INVALID_ARG); 1490 1491 if (typeflags & pte->prop_type_membership && 1492 classflags & pte->prop_class_membership) { 1493 return (NWAM_SUCCESS); 1494 } else { 1495 return (NWAM_ENTITY_INVALID_MEMBER); 1496 } 1497 } 1498 1499 /* Validate property's ncu membership and type, number and range of values */ 1500 nwam_error_t 1501 nwam_ncu_validate_prop(nwam_ncu_handle_t ncuh, const char *propname, 1502 nwam_value_t value) 1503 { 1504 nwam_error_t err; 1505 1506 assert(ncuh != NULL && propname != NULL); 1507 1508 /* First, determine if this property is valid for this ncu */ 1509 if ((err = nwam_ncu_validate_prop_membership(ncuh, propname)) 1510 != NWAM_SUCCESS) 1511 return (err); 1512 1513 return (nwam_validate_prop(ncu_prop_table, ncuh, propname, value)); 1514 } 1515 1516 /* Property-specific value validation functions follow */ 1517 1518 static nwam_error_t 1519 valid_type(nwam_value_t value) 1520 { 1521 uint64_t type; 1522 1523 if (nwam_value_get_uint64(value, &type) != NWAM_SUCCESS || 1524 type > NWAM_NCU_TYPE_INTERFACE) 1525 return (NWAM_ENTITY_INVALID_VALUE); 1526 return (NWAM_SUCCESS); 1527 } 1528 1529 static nwam_error_t 1530 valid_class(nwam_value_t value) 1531 { 1532 uint64_t class; 1533 1534 if (nwam_value_get_uint64(value, &class) != NWAM_SUCCESS || 1535 class > NWAM_NCU_CLASS_IP) 1536 return (NWAM_ENTITY_INVALID_VALUE); 1537 return (NWAM_SUCCESS); 1538 } 1539 1540 static nwam_error_t 1541 valid_ncp(nwam_value_t value) 1542 { 1543 char *ncp; 1544 1545 if (nwam_value_get_string(value, &ncp) != NWAM_SUCCESS) 1546 return (NWAM_ENTITY_INVALID_VALUE); 1547 return (NWAM_SUCCESS); 1548 } 1549 1550 static nwam_error_t 1551 valid_priority_mode(nwam_value_t value) 1552 { 1553 uint64_t priority_mode; 1554 1555 if (nwam_value_get_uint64(value, &priority_mode) != NWAM_SUCCESS || 1556 priority_mode > NWAM_PRIORITY_MODE_ALL) 1557 return (NWAM_ENTITY_INVALID_VALUE); 1558 return (NWAM_SUCCESS); 1559 } 1560 1561 static nwam_error_t 1562 valid_ncu_activation_mode(nwam_value_t value) 1563 { 1564 uint64_t activation_mode; 1565 1566 if (nwam_value_get_uint64(value, &activation_mode) != NWAM_SUCCESS) 1567 return (NWAM_ENTITY_INVALID_VALUE); 1568 1569 switch (activation_mode) { 1570 case NWAM_ACTIVATION_MODE_MANUAL: 1571 case NWAM_ACTIVATION_MODE_PRIORITIZED: 1572 return (NWAM_SUCCESS); 1573 } 1574 return (NWAM_ENTITY_INVALID_VALUE); 1575 } 1576 1577 /* ARGSUSED0 */ 1578 static nwam_error_t 1579 valid_link_autopush(nwam_value_t value) 1580 { 1581 return (NWAM_SUCCESS); 1582 } 1583 1584 static nwam_error_t 1585 valid_ip_version(nwam_value_t value) 1586 { 1587 uint64_t *versions; 1588 uint_t i, numvalues; 1589 1590 if (nwam_value_get_uint64_array(value, &versions, &numvalues) 1591 != NWAM_SUCCESS) 1592 return (NWAM_ENTITY_INVALID_VALUE); 1593 1594 for (i = 0; i < numvalues; i++) { 1595 if (versions[i] != IPV4_VERSION && 1596 versions[i] != IPV6_VERSION) 1597 return (NWAM_ENTITY_INVALID_VALUE); 1598 } 1599 return (NWAM_SUCCESS); 1600 } 1601 1602 static nwam_error_t 1603 valid_addrsrc_v4(nwam_value_t value) 1604 { 1605 uint64_t *addrsrc; 1606 uint_t i, numvalues; 1607 1608 if (nwam_value_get_uint64_array(value, &addrsrc, &numvalues) 1609 != NWAM_SUCCESS) 1610 return (NWAM_ENTITY_INVALID_VALUE); 1611 1612 for (i = 0; i < numvalues; i++) { 1613 if (addrsrc[i] != NWAM_ADDRSRC_DHCP && 1614 addrsrc[i] != NWAM_ADDRSRC_STATIC) 1615 return (NWAM_ENTITY_INVALID_VALUE); 1616 } 1617 return (NWAM_SUCCESS); 1618 } 1619 1620 static nwam_error_t 1621 valid_addrsrc_v6(nwam_value_t value) 1622 { 1623 uint64_t *addrsrc; 1624 uint_t i, numvalues; 1625 boolean_t dhcp_found = B_FALSE, autoconf_found = B_FALSE; 1626 1627 if (nwam_value_get_uint64_array(value, &addrsrc, &numvalues) 1628 != NWAM_SUCCESS) 1629 return (NWAM_ENTITY_INVALID_VALUE); 1630 1631 for (i = 0; i < numvalues; i++) { 1632 if (addrsrc[i] != NWAM_ADDRSRC_DHCP && 1633 addrsrc[i] != NWAM_ADDRSRC_STATIC && 1634 addrsrc[i] != NWAM_ADDRSRC_AUTOCONF) 1635 return (NWAM_ENTITY_INVALID_VALUE); 1636 if (addrsrc[i] == NWAM_ADDRSRC_DHCP) 1637 dhcp_found = B_TRUE; 1638 if (addrsrc[i] == NWAM_ADDRSRC_AUTOCONF) 1639 autoconf_found = B_TRUE; 1640 } 1641 /* 1642 * DHCP and AUTOCONF need to be specified as v6 address sources 1643 * since there is no way to switch them off in NWAM at present. 1644 */ 1645 if (dhcp_found && autoconf_found) 1646 return (NWAM_SUCCESS); 1647 else 1648 return (NWAM_ENTITY_INVALID_VALUE); 1649 } 1650 1651 /* ARGSUSED0 */ 1652 static nwam_error_t 1653 valid_link_mtu(nwam_value_t value) 1654 { 1655 return (NWAM_SUCCESS); 1656 } 1657 1658 nwam_error_t 1659 nwam_ncu_validate(nwam_ncu_handle_t ncuh, const char **errpropp) 1660 { 1661 return (nwam_validate(ncu_prop_table, ncuh, errpropp)); 1662 } 1663 1664 /* 1665 * Given the ncu type and ncu class, return the list of properties that needs 1666 * to be set. Note this list is a complete property list that includes both 1667 * the required ones and the optional ones. Caller needs to free prop_list. 1668 */ 1669 nwam_error_t 1670 nwam_ncu_get_default_proplist(nwam_ncu_type_t type, nwam_ncu_class_t class, 1671 const char ***prop_list, uint_t *numvalues) 1672 { 1673 uint64_t typeflags = nwam_ncu_type_to_flag(type); 1674 uint64_t classflags = nwam_ncu_class_to_flag(class); 1675 1676 return (nwam_get_default_proplist(ncu_prop_table, typeflags, 1677 classflags, prop_list, numvalues)); 1678 } 1679 1680 nwam_error_t 1681 nwam_ncp_get_state(nwam_ncp_handle_t ncph, nwam_state_t *statep, 1682 nwam_aux_state_t *auxp) 1683 { 1684 return (nwam_get_state(ncph->nwh_name, ncph, statep, auxp)); 1685 } 1686 1687 nwam_error_t 1688 nwam_ncu_get_state(nwam_ncu_handle_t ncuh, nwam_state_t *statep, 1689 nwam_aux_state_t *auxp) 1690 { 1691 nwam_ncp_handle_t ncph; 1692 char *ncpname; 1693 nwam_error_t err; 1694 1695 assert(ncuh != NULL); 1696 1697 if ((err = nwam_ncu_get_ncp(ncuh, &ncph)) != NWAM_SUCCESS) 1698 return (err); 1699 if (!nwam_ncp_is_active(ncph)) { 1700 nwam_ncp_free(ncph); 1701 return (NWAM_ENTITY_INVALID); 1702 } 1703 nwam_ncp_free(ncph); 1704 1705 if ((err = nwam_ncu_get_parent_ncp_name(ncuh, &ncpname)) 1706 != NWAM_SUCCESS) 1707 return (err); 1708 1709 err = nwam_request_state(NWAM_OBJECT_TYPE_NCU, ncuh->nwh_name, ncpname, 1710 statep, auxp); 1711 free(ncpname); 1712 return (err); 1713 } 1714 1715 nwam_error_t 1716 nwam_ncp_get_active_priority_group(int64_t *priorityp) 1717 { 1718 return (nwam_request_active_priority_group(priorityp)); 1719 } 1720