sctp_opt_data.c revision a215d4eb400e2ff52f7a17e0781964c37aabfc04
/*
* 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
*/
/*
*/
#define _SUN_TPI_VERSION 2
#include <sys/xti_inet.h>
#include <inet/proto_set.h>
#include <inet/ipclassifier.h>
#include <inet/ipsec_impl.h>
#include <inet/sctp_itf.h>
#include "sctp_impl.h"
#include "sctp_asconf.h"
#include "sctp_addr.h"
static int sctp_getpeeraddrs(sctp_t *, void *, int *);
static int
{
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
struct sctp_paddrinfo *sp;
int i;
if (!sctp->sctp_primary) {
goto noprim;
}
} else {
}
sstat->sstat_unackdata = 0;
sstat->sstat_penddata = 0;
sizeof (sctp_data_hdr_t);
/* count unack'd */
if (!SCTP_CHUNK_ISSENT(mp)) {
break;
}
if (!SCTP_CHUNK_ISACKED(mp)) {
sstat->sstat_unackdata++;
}
}
}
/*
* Count penddata chunks. We can only count chunks in SCTP (not
* data already delivered to socket layer).
*/
for (i = 0; i < sctp->sctp_num_istr; i++) {
sstat->sstat_penddata++;
}
}
}
}
}
/* Un-Ordered Frag list */
sstat->sstat_penddata++;
return (sizeof (*sstat));
}
/*
* SCTP_GET_PEER_ADDR_INFO
*/
static int
{
struct sockaddr_in *sin4;
struct sockaddr_in6 *sin6;
case AF_INET:
break;
case AF_INET6:
break;
default:
return (EAFNOSUPPORT);
}
return (EINVAL);
*optlen = sizeof (struct sctp_paddrinfo);
return (0);
}
/*
* SCTP_RTOINFO
*/
static int
{
return (sizeof (*srto));
}
static int
{
const struct sctp_rtoinfo *srto;
/*
* Bounds checking. Priviledged user can set the RTO initial
* outside the ndd boundary.
*/
if (srto->srto_initial != 0 &&
return (EINVAL);
}
return (EINVAL);
}
return (EINVAL);
}
return (EINVAL);
}
if (srto->srto_initial != 0) {
}
/* Ensure that sctp_rto_max will never be zero. */
}
}
return (0);
}
/*
* SCTP_ASSOCINFO
*/
static int
{
uint16_t i;
/*
* Count the number of peer addresses
*/
i++;
}
return (sizeof (*sap));
}
static int
{
if (sap->sasoc_asocmaxrxt) {
if (sctp->sctp_faddrs) {
/*
* Bounds check: as per rfc2960, assoc max retr cannot
* exceed the sum of all individual path max retr's.
*/
}
return (EINVAL);
}
}
/*
* Out of bounds.
*/
return (EINVAL);
}
}
if (sap->sasoc_cookie_life != 0 &&
return (EINVAL);
}
if (sap->sasoc_asocmaxrxt > 0) {
}
if (sap->sasoc_cookie_life > 0) {
}
return (0);
}
/*
* SCTP_INITMSG
*/
static int
{
return (sizeof (*si));
}
static int
{
return (EINVAL);
}
return (EINVAL);
}
if (si->sinit_num_ostreams != 0 &&
/*
* Out of bounds.
*/
return (EINVAL);
}
if (si->sinit_max_instreams != 0 &&
return (EINVAL);
}
if (si->sinit_max_attempts != 0 &&
return (EINVAL);
}
if (si->sinit_max_init_timeo != 0 &&
return (EINVAL);
}
if (si->sinit_num_ostreams != 0)
if (si->sinit_max_instreams != 0)
if (si->sinit_max_attempts != 0)
if (si->sinit_max_init_timeo != 0) {
}
return (0);
}
/*
* SCTP_PEER_ADDR_PARAMS
*/
static int
sctp_faddr_t **fpp)
{
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
return (EAFNOSUPPORT);
}
} else {
return (EINVAL);
}
}
return (0);
}
static int
{
int retval;
if (retval) {
return (retval);
}
if (fp) {
} else {
}
return (sizeof (*spp));
}
static int
{
int retval;
if (retval != 0) {
return (retval);
}
return (EINVAL);
}
if (spp->spp_pathmaxrxt &&
return (EINVAL);
}
} else {
}
}
return (EINVAL);
}
}
now = ddi_get_lbolt64();
/*
* Send heartbeat immediatelly, don't modify the
* current setting.
*/
} else {
/*
* Restart the heartbeat timer using the new intrvl.
* We need to call sctp_heartbeat_timer() to set
* the earliest heartbeat expiry time.
*/
}
if (spp->spp_pathmaxrxt) {
}
} else {
/*
* Send heartbeat immediatelly, don't modify
* the current setting.
*/
} else {
}
if (spp->spp_pathmaxrxt) {
}
}
/* Restart the heartbeat timer using the new intrvl. */
}
if (spp->spp_pathmaxrxt) {
}
}
return (0);
}
/*
* SCTP_DEFAULT_SEND_PARAM
*/
static int
{
sinfo->sinfo_cumtsn = 0;
return (sizeof (*sinfo));
}
static int
{
return (EINVAL);
}
return (0);
}
static int
{
int retval;
if (retval)
return (retval);
return (EINVAL);
return (0);
/* Only switch current if fp is alive */
return (0);
}
return (0);
}
/*
* Table of all known options handled on a SCTP protocol stack.
*
* Note: This table contains options processed by both SCTP and IP levels
* and is the superset of options that can be performed on a SCTP and IP
* stack.
*/
opdes_t sctp_opt_arr[] = {
sizeof (struct linger), 0 },
},
},
0 },
0 },
0 },
sizeof (struct sctp_setadaptation), 0 },
sizeof (int), 0 },
sizeof (struct sctp_assocparams), 0 },
sizeof (struct sctp_sndrcvinfo), 0 },
sizeof (int), 0 },
sizeof (struct sctp_event_subscribe), 0 },
sizeof (int), 0 },
sizeof (int), 0 },
sizeof (struct sctp_paddrinfo), 0 },
sizeof (struct sctp_initmsg), 0 },
sizeof (int), 0 },
sizeof (struct sctp_paddrparams), 0 },
sizeof (struct sctp_setpeerprim), 0 },
sizeof (sctp_assoc_stats_t), 0 },
sizeof (int), 0 },
sizeof (struct sctp_rtoinfo), 0 },
sizeof (struct sctp_setprim), 0 },
sizeof (struct sctp_status), 0 },
sizeof (struct sctp_uc_swap), 0 },
40, -1 /* not initialized */ },
40, -1 /* not initialized */ },
sizeof (int), -1 /* not initialized */ },
sizeof (int), 0 /* no ifindex */ },
sizeof (int), 0 },
sizeof (int), -1 /* not initialized */ },
sizeof (int), 0 /* no ifindex */ },
sizeof (int), 0 },
-1 /* not initialized */ },
-1 /* not initialized */ },
-1 /* not initialized */ },
-1 /* not initialized */ },
sizeof (int), -1 /* not initialized */ },
sizeof (int), 0 },
sizeof (int), 0 },
sizeof (int), 0 },
/* Enable receipt of ancillary data */
sizeof (int), 0 },
sizeof (int), 0 },
sizeof (int), 0 },
sizeof (int), 0 },
sizeof (int), 0 },
sizeof (int), 0 },
sizeof (int), 0 },
sizeof (int), 0 },
sizeof (int), 0 },
sizeof (uint32_t), IPV6_PREFER_SRC_DEFAULT },
};
/* Handy on off switch for socket option processing. */
#define ONOFF(x) ((x) == 0 ? 0 : 1)
/*
* SCTP routine to get the values of options.
*/
int
{
int retval = 0;
/* In most cases, the return buffer is just an int */
return (EINVAL);
}
/*
* Check that the level and name are supported by SCTP, and that
* the length and credentials are ok.
*/
if (retval != 0) {
if (retval < 0) {
}
return (retval);
}
switch (level) {
case IPPROTO_SCTP:
switch (name) {
case SCTP_RTOINFO:
break;
case SCTP_ASSOCINFO:
break;
case SCTP_INITMSG:
break;
case SCTP_NODELAY:
break;
case SCTP_AUTOCLOSE:
break;
case SCTP_ADAPTATION_LAYER:
break;
case SCTP_PEER_ADDR_PARAMS:
break;
case SCTP_DEFAULT_SEND_PARAM:
break;
case SCTP_EVENTS: {
struct sctp_event_subscribe *ev;
*optlen = sizeof (struct sctp_event_subscribe);
break;
}
case SCTP_STATUS:
break;
case SCTP_GET_PEER_ADDR_INFO:
break;
case SCTP_GET_NLADDRS:
break;
case SCTP_GET_LADDRS: {
int addr_cnt;
int addr_size;
addr_size = sizeof (struct sockaddr_in);
else
addr_size = sizeof (struct sockaddr_in6);
if (retval == 0)
break;
}
case SCTP_GET_NPADDRS: {
int i;
;
break;
}
case SCTP_GET_PADDRS: {
int addr_cnt;
int addr_size;
addr_size = sizeof (struct sockaddr_in);
else
addr_size = sizeof (struct sockaddr_in6);
if (retval == 0)
break;
}
case SCTP_PRSCTP:
break;
case SCTP_GET_ASSOC_STATS: {
/*
* Copy the current stats to the stats struct.
* For stats which can be reset by snmp users
* add the cumulative and current stats for
* the raw totals to output to the user.
*/
/*
* Copy out the maximum observed RTO since the
* time this data was last requested
*/
if (sctp->sctp_maxrto == 0) {
/* unchanged during obervation period */
} else {
/* record new period maximum */
}
/* Record the value sent to the user this period */
/* Mark beginning of a new observation period */
sctp->sctp_maxrto = 0;
*optlen = sizeof (sctp_assoc_stats_t);
break;
}
case SCTP_MAXSEG:
case SCTP_DISABLE_FRAGMENTS:
default:
/* Not yet supported. */
break;
}
return (retval);
case IPPROTO_IP:
break;
}
switch (name) {
case IP_OPTIONS:
case T_IP_OPTIONS: {
/*
* This is compatible with BSD in that in only return
* the reverse source route with the final destination
* as the last entry. The first 4 bytes of the option
* will contain the final destination. Allocate a
* buffer large enough to hold all the options, we
* add IP_ADDR_LEN to SCTP_MAX_IP_OPTIONS_LENGTH since
* ip_opt_get_user() adds the final destination
* at the start.
*/
int opt_len;
/* Silently truncate */
}
return (0);
}
default:
break;
}
break;
}
if (retval == -1)
return (EINVAL);
return (0);
}
int
{
coas.coa_changed = 0;
/* In all cases, the size of the option must be bigger than int */
}
retval = 0;
return (EINVAL);
}
/*
* Check that the level and name are supported by SCTP, and that
* the length an credentials are ok.
*/
if (retval != 0) {
if (retval < 0) {
}
goto done;
}
/* Note: both SCTP and TCP interpret l_linger as being in seconds */
switch (level) {
case SOL_SOCKET:
switch (name) {
case SO_SNDBUF:
goto done;
}
if (*i1 < 0) {
goto done;
}
if (sctps->sctps_snd_lowat_fraction != 0) {
}
goto done;
case SO_RCVBUF:
goto done;
}
/* Silently ignore zero */
if (*i1 != 0) {
struct sock_proto_props sopp;
/*
* Insist on a receive window that is at least
* sctp_recv_hiwat_minmss * MSS (default 4*MSS)
* to avoid funny interactions of Nagle
* algorithm, SWS avoidance and delayed
* acknowledgement.
*/
/*
* Note that sctp_rwnd is modified by the
* protocol and here we just whack it.
*/
}
/*
* XXX should we return the rwnd here
* and sctp_opt_get ?
*/
goto done;
case SO_ALLZONES:
goto done;
}
break;
case SO_MAC_EXEMPT:
goto done;
}
break;
}
break;
case IPPROTO_SCTP:
switch (name) {
case SCTP_RTOINFO:
break;
case SCTP_ASSOCINFO:
break;
case SCTP_INITMSG:
break;
case SCTP_NODELAY:
break;
case SCTP_AUTOCLOSE:
if (SEC_TO_TICK(*i1) < 0) {
break;
}
/* Convert the number of seconds to ticks. */
break;
break;
case SCTP_PRIMARY_ADDR:
break;
case SCTP_ADAPTATION_LAYER: {
struct sctp_setadaptation *ssb;
break;
}
case SCTP_PEER_ADDR_PARAMS:
break;
case SCTP_DEFAULT_SEND_PARAM:
break;
case SCTP_EVENTS: {
struct sctp_event_subscribe *ev;
break;
}
case SCTP_ADD_ADDR:
case SCTP_REM_ADDR:
/*
* The sctp_t has to be bound first before
* the address list can be changed.
*/
break;
}
} else {
}
if (name == SCTP_ADD_ADDR) {
} else {
B_TRUE);
}
break;
case SCTP_UC_SWAP: {
struct sctp_uc_swap *us;
/*
* Change handle & upcalls.
*/
break;
}
case SCTP_PRSCTP:
break;
case SCTP_MAXSEG:
case SCTP_DISABLE_FRAGMENTS:
/* Not yet supported. */
break;
}
goto done;
case IPPROTO_IP:
goto done;
}
switch (name) {
case IP_SEC_OPT:
/*
* We should not allow policy setting after
* we start listening for connections.
*/
goto done;
}
break;
}
break;
case IPPROTO_IPV6:
goto done;
}
switch (name) {
case IPV6_RECVPKTINFO:
/* Send it with the next msg */
sctp->sctp_recvifindex = 0;
break;
case IPV6_RECVTCLASS:
/* Force it to be sent up with the next msg */
break;
case IPV6_RECVHOPLIMIT:
/* Force it to be sent up with the next msg */
break;
case IPV6_SEC_OPT:
/*
* We should not allow policy setting after
* we start listening for connections.
*/
goto done;
}
break;
case IPV6_V6ONLY:
/*
* After the bound state, setting the v6only option
* is too late.
*/
goto done;
}
break;
}
break;
}
if (retval != 0)
goto done;
/*
* We recache the information which might pick a different
* source and redo IPsec as a result.
*/
}
if (retval != 0)
goto done;
}
/*
* Could be setting options before setting up
* connection.
*/
}
}
done:
return (retval);
}
/*
* SCTP exported kernel interface for geting the first source address of
* a sctp_t. The parameter addr is assumed to have enough space to hold
* one socket address.
*/
int
{
int err = 0;
int addrcnt = 1;
switch (connp->conn_family) {
case AF_INET:
} else {
if (err != 0) {
*addrlen = 0;
break;
}
}
*addrlen = sizeof (struct sockaddr_in);
break;
case AF_INET6:
} else {
if (err != 0) {
*addrlen = 0;
break;
}
}
*addrlen = sizeof (struct sockaddr_in6);
/* Note that flowinfo is only returned for getpeername */
break;
}
return (err);
}
/*
* SCTP exported kernel interface for geting the primary peer address of
* a sctp_t. The parameter addr is assumed to have enough space to hold
* one socket address.
*/
int
{
int err = 0;
int addrcnt = 1;
switch (connp->conn_family) {
case AF_INET:
if (err != 0) {
*addrlen = 0;
break;
}
*addrlen = sizeof (struct sockaddr_in);
break;
case AF_INET6:
if (err != 0) {
*addrlen = 0;
break;
}
*addrlen = sizeof (struct sockaddr_in6);
break;
}
return (err);
}
/*
* Return a list of IP addresses of the peer endpoint of this sctp_t.
* The parameter paddrs is supposed to be either (struct sockaddr_in *) or
* (struct sockaddr_in6 *) depending on the address family of the sctp_t.
*/
int
{
int family;
struct sockaddr_in *sin4;
struct sockaddr_in6 *sin6;
int max;
int cnt;
return (ENOTCONN);
/* If we want only one, give the primary */
if (max == 1) {
switch (family) {
case AF_INET:
break;
case AF_INET6:
if (IN6_IS_ADDR_LINKSCOPE(&addr) &&
IXAF_SCOPEID_SET)) {
} else {
sin6->sin6_scope_id = 0;
}
sin6->__sin6_src_id = 0;
break;
}
return (0);
}
switch (family) {
case AF_INET:
break;
case AF_INET6:
if (IN6_IS_ADDR_LINKSCOPE(&addr) &&
else
sin6->sin6_scope_id = 0;
sin6->__sin6_src_id = 0;
break;
}
}
return (0);
}