libnwam_ncp.c revision 69b43529e65fb6eb0c88e6b7b42025e9bf025b8a
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <assert.h>
#include <ctype.h>
#include <libgen.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <libdladm.h>
#include "libnwam_impl.h"
#include <libnwam_priv.h>
#include <libnwam.h>
/*
* Functions to support creating, modifying, destroying, querying the
* state of and changing the state of NCP (Network Configuration Profiles)
* and the NCUs (Network Configuration Units) that are contained in those
* NCP objects. An NCP is simply a container for a set of NCUs which represent
* the datalink and interface configuration preferences for the system.
* An NCP can consist a set of prioritized link NCUs, e.g. wired links preferred
* of both. Interface NCUs inherit activation from their underlying links,
* so if wired is preferred over wireless and a cable is plugged in,
* the wired link NCU will be active, as will the IP interface NCU above it.
*/
/*
* The NCU property table is used to mapping property types to property name
* strings, their associated value types etc. The table is used for validation
* purposes, and for commit()ing and read()ing NCUs.
*/
struct nwam_prop_table_entry ncu_prop_table_entries[] = {
"specifies the NCU type - valid values are \'datalink\' and \'ip\'",
"specifies the NCU class - valid values are "
"\'phys\' and \'ip\'",
"specifies the parent NCP name",
"specifies the NCU activation mode - valid values are:\n"
"\'prioritized\' and \'manual\'",
"specifies if manual NCU is to be enabled",
"specifies the priority grouping of NCUs - lower values are "
"prioritized, negative values are invalid",
"specifies the mode of prioritization - valid values are:\n"
"\'exclusive\', \'shared\' and \'all\'",
"specifies MAC address of form aa:bb:cc:dd:ee:ff for the link",
"specifies modules to autopush on link",
"specifies MTU for link",
"specifies IP versions for IP NCU - valid values are:\n"
"\'ipv4\' and \'ipv6\'",
"specifies IPv4 address source(s) - valid values are:\n"
"\'dhcp\' and \'static\'",
"specifies static IPv4 host address(es)",
"specifies per-interface default IPv4 route",
"specifies IPv6 address source(s) - valid values are:\n"
"\'dhcp\', \'autoconf\' and \'static\'.\n"
"\'dhcp\' and \'autoconf\' are mandatory values.",
"specifies static IPv6 host address(es)",
"specifies per-interface default IPv6 route",
};
#define NWAM_NUM_NCU_PROPS (sizeof (ncu_prop_table_entries) / \
sizeof (*ncu_prop_table_entries))
struct nwam_prop_table ncu_prop_table =
{
}
static nwam_error_t
{
return (NWAM_NO_MEMORY);
return (NWAM_SUCCESS);
}
/* ARGSUSED1 */
{
char *ncpfile;
!= NWAM_SUCCESS)
return (err);
/* Create empty container for NCUs */
!= NWAM_SUCCESS) {
return (err);
}
}
return (err);
}
/* Used by libnwam_files.c */
{
char path_copy[MAXPATHLEN];
/* Make a copy as basename(3c) may modify string */
return (NWAM_NO_MEMORY);
return (NWAM_ENTITY_INVALID);
}
return (NWAM_ENTITY_INVALID);
}
return (NWAM_ENTITY_INVALID);
}
suffix[0] = '\0';
return (NWAM_SUCCESS);
}
/* ARGSUSED1 */
{
char *filename;
/* try to read the associated ncp configuration */
return (err);
}
return (err);
}
static nwam_error_t
{
char *parentname;
&parentval)) != NWAM_SUCCESS ||
!= NWAM_SUCCESS ||
*parentnamep = NULL;
return (err);
}
return (NWAM_SUCCESS);
}
static int
{
char *oldparent;
/* Get filenames for the new and old NCU's */
!= NWAM_SUCCESS)
return (err);
if (err != NWAM_SUCCESS)
return (err);
!= NWAM_SUCCESS)
goto fail;
/* new NCU name (and typedname) is the same as the old name */
&newncuh)) != NWAM_SUCCESS)
goto fail;
/* Duplicate the old NCU's data */
goto fail;
/* Update the parent property for the new NCU */
!= NWAM_SUCCESS)
goto fail;
if (err != NWAM_SUCCESS)
goto fail;
/* Save the new NCU */
fail:
return (err);
}
{
int cb_ret;
/* check if newname NCP already exists */
return (NWAM_ENTITY_EXISTS);
}
/* create new handle */
return (err);
if (err != NWAM_SUCCESS) {
/* remove the NCP even if any NCU's had already been copied */
(void) nwam_ncp_destroy(*newncphp, 0);
if (err == NWAM_WALK_HALTED)
return (cb_ret);
else
return (err);
}
return (NWAM_SUCCESS);
}
/*
* Convert type to flag
*/
static uint64_t
{
switch (type) {
case NWAM_NCU_TYPE_LINK:
return (NWAM_FLAG_NCU_TYPE_LINK);
case NWAM_NCU_TYPE_INTERFACE:
return (NWAM_FLAG_NCU_TYPE_INTERFACE);
case NWAM_NCU_TYPE_ANY:
return (NWAM_FLAG_NCU_TYPE_ALL);
default:
return (0);
}
}
/*
* Convert class to flag
*/
{
switch (class) {
case NWAM_NCU_CLASS_PHYS:
return (NWAM_FLAG_NCU_CLASS_PHYS);
case NWAM_NCU_CLASS_IP:
return (NWAM_FLAG_NCU_CLASS_IP);
case NWAM_NCU_CLASS_ANY:
return (NWAM_FLAG_NCU_CLASS_ALL);
default:
return (0);
}
}
/*
* Infer NCU type from NCU class
*/
{
switch (class) {
case NWAM_NCU_CLASS_PHYS:
return (NWAM_NCU_TYPE_LINK);
case NWAM_NCU_CLASS_IP:
return (NWAM_NCU_TYPE_INTERFACE);
case NWAM_NCU_CLASS_ANY:
return (NWAM_NCU_TYPE_ANY);
default:
return (NWAM_NCU_TYPE_UNKNOWN);
}
}
/*
* Make ncp active, deactivating any other active ncp.
*/
{
char *name;
if (err == NWAM_ERROR_BIND) {
/*
* nwamd is not running, set active_ncp property so when
* nwamd is next started, this NCP will be used.
*/
return (err);
}
return (err);
}
/* Compare NCP names c1 and c2 using strcasecmp() */
static int
{
}
/* ARGSUSED1 */
{
void *objlist;
uint_t i, num_ncpfiles;
int ret = 0;
return (err);
/*
* To get list of NCP files, call nwam_read_object_from_backend()
* with "parent" argument set to NULL. We get back an object list
* consisting of string arrays for each object type - NCP, ENM
* and location. We retrieve the NCP list, which corresponds to
* the set of NCP backend parent objects (these are files at present).
*/
&objlist)) != NWAM_SUCCESS)
return (err);
!= NWAM_SUCCESS) {
return (err);
}
&num_ncpfiles)) != NWAM_SUCCESS) {
return (err);
}
/* sort the NCP names alphabetically */
for (i = 0; i < num_ncpfiles; i++) {
!= NWAM_SUCCESS)
continue;
&ncph)) != NWAM_SUCCESS) {
break;
}
if (ret != 0) {
break;
}
}
return (err);
}
/*
* Checks if NCP is read-only. Only NWAM_NCP_NAME_AUTOMATIC is read-only
* for all but the netadm user (which nwamd runs as).
*/
{
char *name;
return (err);
if (NWAM_NCP_AUTOMATIC(name))
*readp = !nwam_uid_is_special();
else
return (NWAM_SUCCESS);
}
/* Checks if NCU is writable depending on its parent */
{
return (err);
return (err);
}
/* Returns true if the NCP is active */
static boolean_t
{
char *active_ncp, *name;
/*
* Determine which NCP is active via the nwamd/active_ncp property
* value. This allows us to determine which NCP is active even
* if nwamd is not running.
*/
return (B_FALSE);
return (ret);
}
{
char *filename;
return (err);
if (read_only)
return (NWAM_ENTITY_NOT_DESTROYABLE);
if (nwam_ncp_is_active(ncph))
return (NWAM_ENTITY_IN_USE);
!= NWAM_SUCCESS)
return (err);
return (NWAM_SUCCESS);
}
static nwam_error_t
nwam_ncu_internal_name_to_name(const char *internalname,
{
char *prefixstr;
strlen(NWAM_NCU_LINK_NAME_PRE)) == 0) {
strlen(NWAM_NCU_INTERFACE_NAME_PRE)) == 0) {
} else {
return (NWAM_INVALID_ARG);
}
return (NWAM_NO_MEMORY);
return (NWAM_SUCCESS);
}
/* ARGSUSED2 */
static int
{
!= NWAM_SUCCESS ||
!= NWAM_SUCCESS) {
return (NWAM_INVALID_ARG);
}
return (NWAM_INVALID_ARG);
}
if (matchflags & walkfilter)
return (NWAM_SUCCESS);
return (NWAM_INVALID_ARG);
}
{
char *ncpfile;
return (err);
!= NWAM_SUCCESS)
return (err);
retp, ncu_selectcb);
return (err);
}
void
{
}
/*
* Are ncu type and class compatible?
*/
static boolean_t
{
switch (type) {
case NWAM_NCU_TYPE_LINK:
return (class == NWAM_NCU_CLASS_PHYS);
case NWAM_NCU_TYPE_INTERFACE:
return (class == NWAM_NCU_CLASS_IP);
default:
return (B_FALSE);
}
}
/* Name to validate may be internal name. If so, convert it before validating */
static boolean_t
valid_ncu_name(const char *name)
{
char *n;
ret = dladm_valid_linkname(n);
free(n);
} else {
}
return (ret);
}
{
char *typedname;
if (!valid_ncu_name(name))
return (NWAM_INVALID_ARG);
return (err);
if (read_only)
return (NWAM_ENTITY_READ_ONLY);
return (NWAM_ENTITY_EXISTS);
}
if (!valid_ncu_name(name) ||
return (NWAM_INVALID_ARG);
!= NWAM_SUCCESS)
return (err);
/* Create handle */
!= NWAM_SUCCESS)
return (err);
/*
* Create new object list for NCU. The new NCU is initialized with
* the appropriate type and class.
*/
goto finish;
!= NWAM_SUCCESS ||
!= NWAM_SUCCESS ||
!= NWAM_SUCCESS ||
!= NWAM_SUCCESS) {
goto finish;
}
typeval)) != NWAM_SUCCESS ||
classval)) != NWAM_SUCCESS ||
goto finish;
}
/* Set default IP, datalink properties */
!= NWAM_SUCCESS ||
&v4addrsrc)) != NWAM_SUCCESS ||
&v6addrsrc)) != NWAM_SUCCESS) {
goto finish;
}
}
} else {
&actval)) != NWAM_SUCCESS)
goto finish;
}
if (err != NWAM_SUCCESS) {
}
return (err);
}
{
!= NWAM_SUCCESS)
return (err);
if (type == NWAM_NCU_TYPE_ANY) {
/*
* If we get to this point, we have discovered that no
* NCU type is discernable from name or type arguments.
* Either exactly one NCU called name must exist of either
* type, or the operation should fail.
*/
} else {
if (err_ip == NWAM_SUCCESS) {
} else {
}
err = NWAM_SUCCESS;
}
return (err);
}
NWAM_SUCCESS) {
return (err);
}
return (err);
}
{
}
char **typednamep)
{
char *prefixstr;
switch (type) {
case NWAM_NCU_TYPE_INTERFACE:
break;
case NWAM_NCU_TYPE_LINK:
break;
default:
return (NWAM_INVALID_ARG);
}
return (NWAM_NO_MEMORY);
/* Name may be already qualified by type */
} else {
}
return (NWAM_SUCCESS);
}
char **name)
{
}
void
{
}
{
char *typednewname;
&typeval) != NWAM_SUCCESS) {
return (NWAM_INVALID_ARG);
}
return (NWAM_INVALID_ARG);
}
/* check if newname NCU already exists */
return (err);
return (NWAM_ENTITY_EXISTS);
}
!= NWAM_SUCCESS)
return (err);
if (err != NWAM_SUCCESS)
return (err);
return (err);
}
return (NWAM_SUCCESS);
}
{
void *olddata;
return (err);
return (NWAM_ENTITY_READ_ONLY);
/*
* Duplicate data, remove property and validate. If validation
* fails, revert to data duplicated prior to remove.
*/
!= NWAM_SUCCESS)
return (err);
!= NWAM_SUCCESS) {
return (err);
}
return (err);
}
return (NWAM_SUCCESS);
}
{
return (err);
return (NWAM_ENTITY_READ_ONLY);
/*
* If "parent" property doesn't exist, NWAM_INVALID_ARG
* is returned. Allow the setting to continue.
*/
return (err);
}
/* Need to ensure property, type and value are valid */
!= NWAM_SUCCESS)
return (err);
}
{
}
int (*cb)(const char *, nwam_value_t, void *),
{
}
{
char *parentname = NULL;
!= NWAM_SUCCESS ||
!= NWAM_SUCCESS) {
if (parentname != NULL)
return (err);
}
return (NWAM_SUCCESS);
}
{
return (err);
if (read_only)
return (NWAM_ENTITY_READ_ONLY);
!= NWAM_SUCCESS)
return (err);
return (err);
}
return (err);
}
/* Get the NCU type */
{
!= NWAM_SUCCESS)
return (err);
if (err != NWAM_SUCCESS)
return (err);
return (NWAM_SUCCESS);
}
/* Get the NCU class */
{
&classval)) != NWAM_SUCCESS)
return (err);
if (err != NWAM_SUCCESS)
return (err);
return (NWAM_SUCCESS);
}
/*
* Determine if the NCU has manual activation-mode or not.
*/
{
&actval)) != NWAM_SUCCESS)
return (err);
if (err != NWAM_SUCCESS)
return (err);
else
return (NWAM_SUCCESS);
}
/* Determine if NCU is enabled or not */
static nwam_error_t
{
&enabledval)) != NWAM_SUCCESS)
return (err);
return (err);
}
/* Update the enabled property */
static nwam_error_t
{
!= NWAM_SUCCESS)
return (err);
if (err != NWAM_SUCCESS)
return (err);
}
/*
* Make ncu active; fails if the NCU's parent NCP is not active.
*/
{
/* Don't allow NCUs of Automatic NCP to be enabled */
return (err);
if (read_only)
return (NWAM_ENTITY_NOT_MANUAL);
/* Link NCUs with manual activation-mode or IP NCUs can be enabled */
return (err);
if (type == NWAM_NCU_TYPE_LINK) {
return (err);
if (!manual)
return (NWAM_ENTITY_NOT_MANUAL);
}
/* Make sure NCU is not enabled */
!= NWAM_SUCCESS)
return (err);
if (enabled) {
return (NWAM_SUCCESS);
}
return (err);
}
/* nwamd may not be running, that's okay. */
if (err == NWAM_ERROR_BIND)
return (NWAM_SUCCESS);
else
return (err);
}
/*
* Disable ncu; fails if the NCU's parent NCP is not active, or if the
* NCU is not currently active.
*/
{
/* Don't allow NCUs of Automatic NCP to be disabled */
return (err);
if (read_only)
return (NWAM_ENTITY_NOT_MANUAL);
/* Link NCUs with manual activation-mode or IP NCUs can be disabled */
return (err);
if (type == NWAM_NCU_TYPE_LINK) {
return (err);
if (!manual)
return (NWAM_ENTITY_NOT_MANUAL);
}
/* Make sure NCU is enabled */
!= NWAM_SUCCESS)
return (err);
if (!enabled) {
return (NWAM_SUCCESS);
}
return (err);
}
/* nwamd may not be running, that's okay. */
if (err == NWAM_ERROR_BIND)
return (NWAM_SUCCESS);
else
return (err);
}
{
return (err);
if (read_only)
return (NWAM_ENTITY_NOT_DESTROYABLE);
!= NWAM_SUCCESS)
return (err);
!= NWAM_SUCCESS) {
return (err);
}
return (err);
}
{
descriptionp));
}
/* Get expected property data type */
{
}
{
return (NWAM_SUCCESS);
}
{
}
/*
* Ensure that the properties in the ncu, determined by that ncu's
* type and class, belong there.
*/
static nwam_error_t
{
struct nwam_prop_table_entry *pte;
!= NWAM_SUCCESS)
return (NWAM_ENTITY_INVALID);
return (NWAM_ENTITY_INVALID);
}
!= NWAM_SUCCESS)
return (NWAM_ENTITY_INVALID);
return (NWAM_ENTITY_INVALID);
}
return (NWAM_INVALID_ARG);
return (NWAM_SUCCESS);
} else {
return (NWAM_ENTITY_INVALID_MEMBER);
}
}
/* Validate property's ncu membership and type, number and range of values */
{
/* First, determine if this property is valid for this ncu */
!= NWAM_SUCCESS)
return (err);
}
/* Property-specific value validation functions follow */
static nwam_error_t
{
return (NWAM_ENTITY_INVALID_VALUE);
return (NWAM_SUCCESS);
}
static nwam_error_t
{
return (NWAM_ENTITY_INVALID_VALUE);
return (NWAM_SUCCESS);
}
static nwam_error_t
{
char *ncp;
return (NWAM_ENTITY_INVALID_VALUE);
return (NWAM_SUCCESS);
}
static nwam_error_t
{
return (NWAM_ENTITY_INVALID_VALUE);
return (NWAM_SUCCESS);
}
static nwam_error_t
{
return (NWAM_ENTITY_INVALID_VALUE);
switch (activation_mode) {
return (NWAM_SUCCESS);
}
return (NWAM_ENTITY_INVALID_VALUE);
}
/* ARGSUSED0 */
static nwam_error_t
{
return (NWAM_SUCCESS);
}
static nwam_error_t
{
!= NWAM_SUCCESS)
return (NWAM_ENTITY_INVALID_VALUE);
for (i = 0; i < numvalues; i++) {
if (versions[i] != IPV4_VERSION &&
versions[i] != IPV6_VERSION)
return (NWAM_ENTITY_INVALID_VALUE);
}
return (NWAM_SUCCESS);
}
static nwam_error_t
{
!= NWAM_SUCCESS)
return (NWAM_ENTITY_INVALID_VALUE);
for (i = 0; i < numvalues; i++) {
if (addrsrc[i] != NWAM_ADDRSRC_DHCP &&
addrsrc[i] != NWAM_ADDRSRC_STATIC)
return (NWAM_ENTITY_INVALID_VALUE);
}
return (NWAM_SUCCESS);
}
static nwam_error_t
{
!= NWAM_SUCCESS)
return (NWAM_ENTITY_INVALID_VALUE);
for (i = 0; i < numvalues; i++) {
if (addrsrc[i] != NWAM_ADDRSRC_DHCP &&
addrsrc[i] != NWAM_ADDRSRC_STATIC &&
addrsrc[i] != NWAM_ADDRSRC_AUTOCONF)
return (NWAM_ENTITY_INVALID_VALUE);
if (addrsrc[i] == NWAM_ADDRSRC_DHCP)
dhcp_found = B_TRUE;
if (addrsrc[i] == NWAM_ADDRSRC_AUTOCONF)
}
/*
* DHCP and AUTOCONF need to be specified as v6 address sources
* since there is no way to switch them off in NWAM at present.
*/
if (dhcp_found && autoconf_found)
return (NWAM_SUCCESS);
else
return (NWAM_ENTITY_INVALID_VALUE);
}
/* ARGSUSED0 */
static nwam_error_t
{
return (NWAM_SUCCESS);
}
{
}
/*
* Given the ncu type and ncu class, return the list of properties that needs
* to be set. Note this list is a complete property list that includes both
* the required ones and the optional ones. Caller needs to free prop_list.
*/
{
}
{
}
{
char *ncpname;
return (err);
if (!nwam_ncp_is_active(ncph)) {
return (NWAM_ENTITY_INVALID);
}
!= NWAM_SUCCESS)
return (err);
return (err);
}
{
return (nwam_request_active_priority_group(priorityp));
}