/*
* 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 (c) 2013 by Delphix. All rights reserved.
*/
/*
* interface property values. It also holds all the supported properties for
* both IP interface and protocols in `ipadm_prop_desc_t'. Following protocols
* are supported: IP, IPv4, IPv6, TCP, SCTP, UDP and ICMP.
*
* This file also contains walkers, which walks through the property table and
* calls the callback function, of the form `ipadm_prop_wfunc_t' , for every
* property in the table.
*/
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <fcntl.h>
#include <strings.h>
#include <stdlib.h>
#include <assert.h>
#include <libdllink.h>
#include <zone.h>
#include "libipadm_impl.h"
#include <inet/tunables.h>
/*
* Callback functions to retrieve property values from the kernel. These
* functions, when required, translate the values from the kernel to a format
* suitable for printing. For example: boolean values will be translated
* a given property.
*/
/*
* Callback function to set property values. These functions translate the
* values to a format suitable for kernel consumption, allocates the necessary
* ioctl buffers and then invokes ioctl().
*/
/* array of protocols we support */
/*
* Supported IP protocol properties.
*/
};
/* possible values for TCP properties `ecn' and `sack' */
/* Supported TCP protocol properties */
};
/* Supported UDP protocol properties */
};
/* Supported SCTP protocol properties */
};
/* Supported ICMP protocol properties */
};
/*
* A dummy private property structure, used while handling private
* protocol properties (properties not yet supported by libipadm).
*/
/*
* Returns the property description table, for the given protocol
*/
static ipadm_prop_desc_t *
{
switch (proto) {
case MOD_PROTO_IP:
case MOD_PROTO_IPV4:
case MOD_PROTO_IPV6:
return (ipadm_ip_prop_table);
case MOD_PROTO_RAWIP:
return (ipadm_icmp_prop_table);
case MOD_PROTO_TCP:
return (ipadm_tcp_prop_table);
case MOD_PROTO_UDP:
return (ipadm_udp_prop_table);
case MOD_PROTO_SCTP:
return (ipadm_sctp_prop_table);
}
return (NULL);
}
static ipadm_prop_desc_t *
{
int err = 0;
goto ret;
}
break;
}
}
/* if we matched name, but failed protocol check */
if (matched_name)
}
ret:
return (ipdp);
}
char *
{
switch (proto) {
case MOD_PROTO_IP:
return ("ip");
case MOD_PROTO_IPV4:
return ("ipv4");
case MOD_PROTO_IPV6:
return ("ipv6");
case MOD_PROTO_RAWIP:
return ("icmp");
case MOD_PROTO_TCP:
return ("tcp");
case MOD_PROTO_UDP:
return ("udp");
case MOD_PROTO_SCTP:
return ("sctp");
}
return (NULL);
}
{
return (MOD_PROTO_NONE);
return (MOD_PROTO_TCP);
return (MOD_PROTO_UDP);
return (MOD_PROTO_IP);
return (MOD_PROTO_IPV4);
return (MOD_PROTO_IPV6);
return (MOD_PROTO_RAWIP);
return (MOD_PROTO_SCTP);
return (MOD_PROTO_IP);
return (MOD_PROTO_NONE);
}
/* ARGSUSED */
static ipadm_status_t
{
char *endp;
int s;
/* to reset MTU first retrieve the default MTU and then set it */
if (flags & IPADM_OPT_DEFAULT) {
if (status != IPADM_SUCCESS)
return (status);
}
errno = 0;
return (IPADM_INVALID_ARG);
return (ipadm_errno2status(errno));
return (IPADM_SUCCESS);
}
/* ARGSUSED */
static ipadm_status_t
{
char *endp;
int metric;
int s;
/* if we are resetting, set the value to its default value */
if (flags & IPADM_OPT_DEFAULT) {
} else {
errno = 0;
return (IPADM_INVALID_ARG);
}
return (ipadm_errno2status(errno));
return (IPADM_SUCCESS);
}
/* ARGSUSED */
static ipadm_status_t
{
int s;
/* if we are resetting, set the value to its default value */
if (flags & IPADM_OPT_DEFAULT)
/*
* cannot specify logical interface name. We can also filter out other
* bogus interface names here itself through i_ipadm_validate_ifname().
*/
return (IPADM_INVALID_ARG);
return (ipadm_errno2status(errno));
} else {
return (ipadm_errno2status(errno));
lifr.lifr_index = 0;
}
return (ipadm_errno2status(errno));
return (IPADM_SUCCESS);
}
static struct hostmodel_strval {
char *esm_str;
} esm_arr[] = {
{"weak", IP_WEAK_ES},
{"src-priority", IP_SRC_PRI_ES},
{"strong", IP_STRONG_ES},
{"custom", IP_MAXVAL_ES}
};
static ip_hostmodel_t
{
int i;
}
}
return (IP_MAXVAL_ES);
}
static char *
{
int i;
}
return (NULL);
}
/* ARGSUSED */
static ipadm_status_t
{
if ((flags & IPADM_OPT_DEFAULT) == 0) {
if (hostmodel == IP_MAXVAL_ES)
return (IPADM_INVALID_ARG);
}
}
/* ARGSUSED */
static ipadm_status_t
{
char *cp;
switch (valtype) {
case MOD_PROP_PERM:
break;
case MOD_PROP_DEFAULT:
break;
case MOD_PROP_ACTIVE:
valtype);
if (status != IPADM_SUCCESS)
return (status);
break;
case MOD_PROP_POSSIBLE:
break;
default:
return (IPADM_INVALID_ARG);
}
/* insufficient buffer space */
return (IPADM_NO_BUFS);
}
return (IPADM_SUCCESS);
}
/* ARGSUSED */
static ipadm_status_t
{
/* if we are resetting, set the value to its default value */
if (flags & IPADM_OPT_DEFAULT) {
pval = IPADM_ONSTR;
pval = IPADM_OFFSTR;
} else {
return (IPADM_PROP_UNKNOWN);
}
}
else
return (IPADM_INVALID_ARG);
if (on)
else
if (on)
else
if (on)
else
if (on)
else
}
}
return (status);
}
/* ARGSUSED */
static ipadm_status_t
{
int err;
if (flags & IPADM_OPT_DEFAULT) {
}
return (ipadm_errno2status(err));
/* count the number of ports */
++count;
}
} else if (count > 1) {
/*
* We allow only one port to be added, removed or
* assigned at a time.
*
* However on reboot, while initializing protocol
* properties, extra_priv_ports might have multiple
* values. Only in that case we allow setting multiple
* values.
*/
return (IPADM_INVALID_ARG);
}
if (status != IPADM_SUCCESS)
break;
}
return (status);
}
/* ARGSUSED */
static ipadm_status_t
{
/*
* if interface name is provided, then set forwarding using the
* IFF_ROUTER flag
*/
} else {
/*
* if the caller is IPH_LEGACY, `pval' already contains
* numeric values.
*/
if (!(flags & IPADM_OPT_DEFAULT) &&
val = "1";
val = "0";
else
return (IPADM_INVALID_ARG);
}
}
return (status);
}
/* ARGSUSED */
static ipadm_status_t
{
uint_t i;
/* if IPH_LEGACY is set, `pval' already contains numeric values */
for (i = 0; ecn_sack_vals[i] != NULL; i++) {
break;
}
if (ecn_sack_vals[i] == NULL)
return (IPADM_INVALID_ARG);
}
}
/* ARGSUSED */
{
switch (valtype) {
case MOD_PROP_POSSIBLE:
for (i = 0; ecn_sack_vals[i] != NULL; i++) {
if (i == 0)
else
break;
}
break;
case MOD_PROP_PERM:
case MOD_PROP_DEFAULT:
case MOD_PROP_ACTIVE:
valtype);
/*
* If IPH_LEGACY is set, do not convert the value returned
* from kernel,
*/
break;
/*
* For current and default value, convert the value returned
* from kernel to more discrete representation.
*/
valtype == MOD_PROP_DEFAULT)) {
assert(i < 3);
ecn_sack_vals[i]);
}
break;
default:
return (IPADM_INVALID_ARG);
}
/* insufficient buffer space */
return (IPADM_NO_BUFS);
}
return (status);
}
/* ARGSUSED */
static ipadm_status_t
{
/*
* if interface name is provided, then get forwarding status using
* SIOCGLIFFLAGS
*/
} else {
/*
* If IPH_LEGACY is set, do not convert the value returned
* from kernel,
*/
goto ret;
valtype == MOD_PROP_DEFAULT)) {
}
}
ret:
return (status);
}
/* ARGSUSED */
static ipadm_status_t
{
int s;
switch (valtype) {
case MOD_PROP_PERM:
break;
case MOD_PROP_DEFAULT:
case MOD_PROP_POSSIBLE:
case MOD_PROP_ACTIVE:
return (ipadm_errno2status(errno));
break;
default:
return (IPADM_INVALID_ARG);
}
/* insufficient buffer space */
return (IPADM_NO_BUFS);
}
return (IPADM_SUCCESS);
}
/* ARGSUSED */
static ipadm_status_t
{
int s, val;
switch (valtype) {
case MOD_PROP_PERM:
break;
case MOD_PROP_DEFAULT:
break;
case MOD_PROP_ACTIVE:
return (ipadm_errno2status(errno));
break;
default:
return (IPADM_INVALID_ARG);
}
/* insufficient buffer space */
return (IPADM_NO_BUFS);
}
return (IPADM_SUCCESS);
}
/* ARGSUSED */
static ipadm_status_t
{
int s;
switch (valtype) {
case MOD_PROP_PERM:
break;
case MOD_PROP_DEFAULT:
break;
case MOD_PROP_ACTIVE:
return (ipadm_errno2status(errno));
if (lifr.lifr_index == 0) {
/* no src address was set, so print 'none' */
sizeof (if_name));
return (ipadm_errno2status(errno));
}
break;
default:
return (IPADM_INVALID_ARG);
}
/* insufficient buffer space */
return (IPADM_NO_BUFS);
}
return (IPADM_SUCCESS);
}
/* ARGSUSED */
static ipadm_status_t
{
char *val;
switch (valtype) {
case MOD_PROP_PERM:
break;
case MOD_PROP_DEFAULT:
val = IPADM_ONSTR;
val = IPADM_OFFSTR;
} else {
return (IPADM_PROP_UNKNOWN);
}
break;
case MOD_PROP_ACTIVE:
if (status != IPADM_SUCCESS)
return (status);
val = IPADM_OFFSTR;
if (!(intf_flags & IFF_NORTEXCH))
val = IPADM_ONSTR;
if (intf_flags & IFF_ROUTER)
val = IPADM_ONSTR;
if (!(intf_flags & IFF_NOARP))
val = IPADM_ONSTR;
if (!(intf_flags & IFF_NONUD))
val = IPADM_ONSTR;
}
break;
default:
return (IPADM_INVALID_ARG);
}
/* insufficient buffer space */
}
return (status);
}
static void
{
}
/* ARGSUSED */
static ipadm_status_t
{
/* allocate sufficient ioctl buffer to retrieve value */
return (IPADM_NO_BUFS);
sizeof (mip->mpr_ifname));
}
iocsize) < 0) {
else
} else {
}
return (status);
}
/*
* Populates the ipmgmt_prop_arg_t based on the class of property.
*
* For private protocol properties, while persisting information in ipadm
* data store, to ensure there is no collision of namespace between ipadm
* private nvpair names (which also starts with '_', see ipadm_ipmgmt.h)
* and private protocol property names, we will prepend IPADM_PRIV_PROP_PREFIX
* to property names.
*/
static void
{
switch (class) {
case IPADMPROP_CLASS_MODULE:
/* if it's a private property then add the prefix. */
}
break;
case IPADMPROP_CLASS_MODIF:
/* check if object is protostr or an ifname */
break;
}
/* it's an interface property, fall through */
/* FALLTHRU */
case IPADMPROP_CLASS_IF:
break;
case IPADMPROP_CLASS_ADDR:
sizeof (pargp->ia_aobjname));
break;
}
}
/*
* Common function to retrieve property value for a given interface `ifname' or
* for a given protocol `proto'. The property name is in `pname'.
*
* `valtype' determines the type of value that will be retrieved.
* IPADM_OPT_ACTIVE - current value of the property (active config)
* IPADM_OPT_PERSIST - value of the property from persistent store
* IPADM_OPT_DEFAULT - default hard coded value (boot-time value)
* IPADM_OPT_POSSIBLE - range of values
*/
static ipadm_status_t
{
int err = 0;
return (IPADM_BAD_PROTOCOL);
/* there are no private interface properties */
return (IPADM_PROP_UNKNOWN);
/*
* check whether the property can be
* applied on an interface
*/
return (IPADM_INVALID_ARG);
/*
* check whether the property can be
* applied on a module
*/
return (IPADM_INVALID_ARG);
} else {
/* private protocol properties, pass it to kernel directly */
pdp = &ipadm_privprop;
}
switch (valtype) {
case IPADM_OPT_PERM:
if (status == IPADM_SUCCESS)
break;
case IPADM_OPT_ACTIVE:
break;
case IPADM_OPT_DEFAULT:
break;
case IPADM_OPT_POSSIBLE:
break;
}
buf[0] = '\0';
break;
case IPADM_OPT_PERSIST:
/* retrieve from database */
if (is_if)
else
break;
default:
break;
}
return (status);
}
/*
* Get protocol property of the specified protocol.
*/
{
/*
* validate the arguments of the function.
*/
return (IPADM_INVALID_ARG);
}
/*
* Do we support this proto, if not return error.
*/
return (IPADM_NOTSUP);
}
/*
* Get interface property of the specified interface.
*/
{
/* validate the arguments of the function. */
return (IPADM_INVALID_ARG);
}
/* Do we support this proto, if not return error. */
return (IPADM_NOTSUP);
/*
* check if interface name is provided for interface property and
* is valid.
*/
return (IPADM_INVALID_ARG);
}
/*
* Allocates sufficient ioctl buffers and copies property name and the
* value, among other things. If the flag IPADM_OPT_DEFAULT is set, then
* `pval' will be NULL and it instructs the kernel to reset the current
* value to property's default value.
*/
static ipadm_status_t
{
if (flags & IPADM_OPT_DEFAULT) {
} else if (flags & IPADM_OPT_ACTIVE) {
if (flags & IPADM_OPT_APPEND)
else if (flags & IPADM_OPT_REMOVE)
}
} else {
valsize = 0;
iocsize = sizeof (mod_ioc_prop_t);
}
return (IPADM_NO_BUFS);
sizeof (mip->mpr_ifname));
}
iocsize) < 0) {
else
}
return (status);
}
/*
*
* If:
* IPADM_OPT_PERSIST is set then the value is persisted.
* IPADM_OPT_DEFAULT is set then the default value for the property will
* be applied.
*/
static ipadm_status_t
{
int err = 0;
/* Check that property value is within the allowed size */
return (IPADM_INVALID_ARG);
return (IPADM_BAD_PROTOCOL);
/* there are no private interface properties */
return (IPADM_PROP_UNKNOWN);
/* do some sanity checks */
if (is_if) {
return (IPADM_INVALID_ARG);
} else {
return (IPADM_INVALID_ARG);
}
/*
* if the property is not multi-valued and IPADM_OPT_APPEND or
* IPADM_OPT_REMOVE is specified, return IPADM_INVALID_ARG.
*/
return (IPADM_INVALID_ARG);
}
} else {
/* private protocol property, pass it to kernel directly */
pdp = &ipadm_privprop;
}
if (status != IPADM_SUCCESS)
return (status);
if (persist) {
if (is_if)
pflags);
else
}
return (status);
}
/*
* Sets the property value of the specified interface
*/
{
/* check for solaris.network.interface.config authorization */
if (!ipadm_check_auth())
return (IPADM_EAUTH);
/*
* validate the arguments of the function.
*/
return (IPADM_INVALID_ARG);
}
/*
* Do we support this protocol, if not return error.
*/
return (IPADM_NOTSUP);
/*
* Validate the interface and check if a persistent
* operation is performed on a temporary object.
*/
if (status != IPADM_SUCCESS)
return (status);
pflags));
}
/*
* Sets the property value of the specified protocol.
*/
{
/* check for solaris.network.interface.config authorization */
if (!ipadm_check_auth())
return (IPADM_EAUTH);
/*
* validate the arguments of the function.
*/
return (IPADM_INVALID_ARG);
}
/*
* Do we support this proto, if not return error.
*/
return (IPADM_NOTSUP);
pflags));
}
/* helper function for ipadm_walk_proptbl */
static void
{
continue;
continue;
/*
* we found a class specific match, call the
* user callback function.
*/
break;
}
}
/*
* Walks through all the properties, for a given protocol and property class
* (protocol or interface).
*
* Further if proto == MOD_PROTO_NONE, then it walks through all the supported
* protocol property tables.
*/
void *arg)
{
int i;
return (IPADM_INVALID_ARG);
switch (class) {
case IPADMPROP_CLASS_ADDR:
break;
case IPADMPROP_CLASS_IF:
case IPADMPROP_CLASS_MODULE:
return (IPADM_INVALID_ARG);
break;
default:
return (IPADM_INVALID_ARG);
}
/*
* proto will be MOD_PROTO_NONE in the case of
* IPADMPROP_CLASS_ADDR.
*/
} else {
/* Walk thru all the protocol tables, we support */
for (i = 0; i < count; i++) {
arg);
}
}
return (status);
}
/*
* Given a property name, walks through all the instances of a property name.
* Some properties have two instances one for v4 interfaces and another for v6
* interfaces. For example: MTU. MTU can have different values for v4 and v6.
* Therefore there are two properties for 'MTU'.
*
* This function invokes `func' for every instance of property `pname'
*/
{
return (IPADM_INVALID_ARG);
switch (class) {
case IPADMPROP_CLASS_ADDR:
break;
case IPADMPROP_CLASS_IF:
case IPADMPROP_CLASS_MODULE:
break;
default:
return (IPADM_INVALID_ARG);
}
return (IPADM_INVALID_ARG);
continue;
continue;
/* we found a match, call the callback function */
break;
}
if (!matched)
return (status);
}
/* ARGSUSED */
{
return (IPADM_SUCCESS);
}
/*
* Makes a door call to ipmgmtd to retrieve the persisted property value
*/
{
int err = 0;
if (err == 0) {
/* assert that rvalp was not reallocated */
/* `ir_pval' contains the property value */
/* insufficient buffer space */
}
}
return (ipadm_errno2status(err));
}
/*
* Persists the property value for a given property in the data store
*/
{
int err = 0;
/*
* Check if value to be persisted need to be appended or removed. This
* is required for multi-valued property.
*/
if (flags & IPADM_OPT_APPEND)
if (flags & IPADM_OPT_REMOVE)
else
/*
* its fine if there were no entry in the DB to delete. The user
* might be changing property value, which was not changed
* persistently.
*/
err = 0;
return (ipadm_errno2status(err));
}
/*
* This is called from ipadm_set_ifprop() to validate the set operation.
* It does the following steps:
* 1. Validates the interface name.
* 2. Fails if it is an IPMP meta-interface or an underlying interface.
* 3. In case of a persistent operation, verifies that the
* interface is persistent.
*/
static ipadm_status_t
{
/* Check if the interface name is valid. */
return (IPADM_INVALID_ARG);
/*
* Setting properties on an IPMP meta-interface or underlying
* interface is not supported.
*/
return (IPADM_NOTSUP);
/* Check if interface exists in the persistent configuration. */
if (status != IPADM_SUCCESS)
return (status);
/* Check if interface exists in the active configuration. */
return (IPADM_OP_DISABLE_OBJ);
if (!af_exists)
return (IPADM_ENXIO);
/*
* If a persistent operation is requested, check if the underlying
* IP interface is persistent.
*/
return (IPADM_TEMPORARY_OBJ);
return (IPADM_SUCCESS);
}
/*
* Private protocol properties namespace scheme:
*
* PSARC 2010/080 identified the private protocol property names to be the
* leading protocol names. For e.g. tcp_strong_iss, ip_strict_src_multihoming,
* et al,. However to be consistent with private data-link property names,
* which starts with '_', private protocol property names will start with '_'.
* For e.g. _strong_iss, _strict_src_multihoming, et al,.
*/
/* maps new private protocol property name to the old private property name */
typedef struct ipadm_oname2nname_map {
char *iom_oname;
char *iom_nname;
/*
* IP is a special case. It isn't straight forward to derive the legacy name
* from the new name and vice versa. No set standard was followed in naming
* the properties and hence we need a table to capture the mapping.
*/
{ "arp_probe_delay", "_arp_probe_delay",
MOD_PROTO_IP },
{ "arp_fastprobe_delay", "_arp_fastprobe_delay",
MOD_PROTO_IP },
{ "arp_probe_interval", "_arp_probe_interval",
MOD_PROTO_IP },
{ "arp_fastprobe_interval", "_arp_fastprobe_interval",
MOD_PROTO_IP },
{ "arp_probe_count", "_arp_probe_count",
MOD_PROTO_IP },
{ "arp_fastprobe_count", "_arp_fastprobe_count",
MOD_PROTO_IP },
{ "arp_defend_interval", "_arp_defend_interval",
MOD_PROTO_IP },
{ "arp_defend_rate", "_arp_defend_rate",
MOD_PROTO_IP },
{ "arp_defend_period", "_arp_defend_period",
MOD_PROTO_IP },
{ "ndp_defend_interval", "_ndp_defend_interval",
MOD_PROTO_IP },
{ "ndp_defend_rate", "_ndp_defend_rate",
MOD_PROTO_IP },
{ "ndp_defend_period", "_ndp_defend_period",
MOD_PROTO_IP },
{ "igmp_max_version", "_igmp_max_version",
MOD_PROTO_IP },
{ "mld_max_version", "_mld_max_version",
MOD_PROTO_IP },
{ "ipsec_override_persocket_policy", "_ipsec_override_persocket_policy",
MOD_PROTO_IP },
{ "ipsec_policy_log_interval", "_ipsec_policy_log_interval",
MOD_PROTO_IP },
{ "icmp_accept_clear_messages", "_icmp_accept_clear_messages",
MOD_PROTO_IP },
{ "igmp_accept_clear_messages", "_igmp_accept_clear_messages",
MOD_PROTO_IP },
{ "pim_accept_clear_messages", "_pim_accept_clear_messages",
MOD_PROTO_IP },
{ "ip_respond_to_echo_multicast", "_respond_to_echo_multicast",
{ "ip_send_redirects", "_send_redirects",
{ "ip_forward_src_routed", "_forward_src_routed",
{ "ip_icmp_return_data_bytes", "_icmp_return_data_bytes",
{ "ip_ignore_redirect", "_ignore_redirect",
{ "ip_strict_dst_multihoming", "_strict_dst_multihoming",
{ "ip_reasm_timeout", "_reasm_timeout",
{ "ip_strict_src_multihoming", "_strict_src_multihoming",
{ "ipv4_dad_announce_interval", "_dad_announce_interval",
{ "ipv4_icmp_return_pmtu", "_icmp_return_pmtu",
{ "ipv6_dad_announce_interval", "_dad_announce_interval",
{ "ipv6_icmp_return_pmtu", "_icmp_return_pmtu",
};
/*
* Following API returns a new property name in `nname' for the given legacy
* property name in `oname'.
*/
int
{
const char *str;
/* if it's a public property, there is nothing to return */
return (-1);
/*
* we didn't find the `oname' in the table, check if the property
* name begins with a leading protocol.
*/
switch (*proto) {
case MOD_PROTO_TCP:
break;
case MOD_PROTO_SCTP:
break;
case MOD_PROTO_UDP:
break;
case MOD_PROTO_RAWIP:
break;
case MOD_PROTO_IP:
case MOD_PROTO_IPV4:
case MOD_PROTO_IPV6:
*proto = MOD_PROTO_IPV6;
} else {
ionmp++) {
break;
}
}
break;
*proto = MOD_PROTO_IP;
}
}
break;
default:
return (-1);
}
return (0);
}
/*
* Following API is required for ndd.c alone. To maintain backward
* compatibility with ndd output, we need to print the legacy name
* for the new name.
*/
int
{
char *prefix;
/* if it's a public property, there is nothing to prepend */
return (-1);
switch (proto) {
case MOD_PROTO_TCP:
prefix = "tcp";
break;
case MOD_PROTO_SCTP:
prefix = "sctp";
break;
case MOD_PROTO_UDP:
prefix = "udp";
break;
case MOD_PROTO_RAWIP:
prefix = "icmp";
break;
case MOD_PROTO_IP:
case MOD_PROTO_IPV4:
case MOD_PROTO_IPV6:
/* handle special case for IP */
nnamelen);
return (0);
}
}
if (proto == MOD_PROTO_IPV6)
prefix = "ip6";
else
prefix = "ip";
break;
default:
return (-1);
}
return (0);
}