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