OpenSS7
SS7 for the
Common Man
© Copyright 1997-2007 OpenSS7 Corporation All Rights Reserved.
Last modified: Sat, 16 Aug 2008 00:06:24 GMT
Home TopIndex FirstPrev Next LastMore Download Info FAQ Mail  Home -> Resources -> Browse Source -> /code/strinet/src/drivers/inet.c
Quick Links

Download

SCTP

SIGTRAN

SS7

Hardware

STREAMS

Asterisk

Related

Package

Manual

FAQ

Browse Source

Applications

SS7 Stack

ISDN Stack

SIGTRAN Stack

VoIP Stack

MG Stack

SS7/ISDN Devices

IP Transport

Embedded Systems

Operating System

Resources

Packages

Sys Req

Download

Mailing Lists

Browse Source

CVS Archive

Bug Reports

Library

Hardware

Vendor Links

Home

Overview

Status

Documentation

Resources

About

News

Description: Code

File /code/strinet/src/drivers/inet.c



#ident "@(#) inet.c,v openss7-0_9_2_F(0.9.2.85) 2007/05/17 22:33:00"

static char const ident[] =
    "inet.c,v openss7-0_9_2_F(0.9.2.85) 2007/05/17 22:33:00";

#include <sys/os7/compat.h>

#if defined HAVE_OPENSS7_SCTP
#if !defined CONFIG_SCTP && !defined CONFIG_SCTP_MODULE
#undef HAVE_OPENSS7_SCTP
#endif
#endif

#if !defined HAVE_OPENSS7_SCTP
#undef sctp_addr
#define sctp_addr stupid_sctp_addr_in_the_wrong_place
#endif

#include <linux/bitops.h>

#define t_tst_bit(nr,addr)	test_bit(nr,addr)
#define t_set_bit(nr,addr)	__set_bit(nr,addr)
#define t_clr_bit(nr,addr)	__clear_bit(nr,addr)

#include <linux/net.h>
#include <linux/in.h>
#include <linux/un.h>
#include <linux/ip.h>

#undef ASSERT

#include <net/sock.h>
#include <net/udp.h>
#include <net/tcp.h>
#if defined HAVE_OPENSS7_SCTP
#undef STATIC
#undef INLINE
#include <net/sctp.h>
#endif

#if 0

#undef ensure
#undef assure
#undef assert
#undef printd
#undef swerr
#undef rare
#undef seldom
#undef likely

#define ensure __ensure
#define assure __assure
#define assert __assert
#define printd __printd
#define swerr __swerr
#define rare __rare
#define seldom __seldom
#define _DEBUG
#endif

#ifdef HAVE_OLD_SOCK_STRUCTURE

#define sk_callback_lock	callback_lock
#define sk_user_data		user_data
#define sk_state_change		state_change
#define sk_data_ready		data_ready
#define sk_write_space		write_space
#define sk_error_report		error_report
#define sk_lingertime		lingertime
#define sk_state		state
#define sk_rcvbuf		rcvbuf
#define sk_rcvlowat		rcvlowat
#define sk_sndbuf		sndbuf
#define sk_reuse		reuse
#define sk_localroute		localroute
#define sk_no_check		no_check
#define sk_debug		debug
#define sk_allocation		allocation
#define sk_priority		priority
#define sk_ack_backlog		ack_backlog
#define sk_prot			prot
#define sk_receive_queue	receive_queue
#define sk_rmem_alloc		rmem_alloc

#define sock_tst_dead(_sk)		(((struct sock *)_sk)->dead ? 1 : 0)
#define sock_tst_done(_sk)		(((struct sock *)_sk)->done ? 1 : 0)
#define sock_tst_urginline(_sk)		(((struct sock *)_sk)->urginline ? 1 : 0)
#define sock_tst_keepopen(_sk)		(((struct sock *)_sk)->keepopen ? 1 : 0)
#define sock_tst_linger(_sk)		(((struct sock *)_sk)->linger ? 1 : 0)
#define sock_tst_destroy(_sk)		(((struct sock *)_sk)->destroy ? 1 : 0)
#define sock_tst_broadcast(_sk)		(((struct sock *)_sk)->broadcast ? 1 : 0)
#define sock_tst_localroute(_sk)	(((struct sock *)_sk)->localroute ? 1 : 0)
#define sock_tst_debug(_sk)		(((struct sock *)_sk)->debug ? 1 : 0)

#define sock_set_dead(_sk)		(((struct sock *)_sk)->dead = 1)
#define sock_set_done(_sk)		(((struct sock *)_sk)->done = 1)
#define sock_set_urginline(_sk)		(((struct sock *)_sk)->urginline = 1)
#define sock_set_keepopen(_sk)		(((struct sock *)_sk)->keepopen = 1)
#define sock_set_linger(_sk)		(((struct sock *)_sk)->linger = 1)
#define sock_set_destroy(_sk)		(((struct sock *)_sk)->destroy = 1)
#define sock_set_broadcast(_sk)		(((struct sock *)_sk)->broadcast = 1)
#define sock_set_localroute(_sk)	(((struct sock *)_sk)->localroute = 1)
#define sock_set_debug(_sk)		(((struct sock *)_sk)->debug = 1)

#define sock_clr_dead(_sk)		(((struct sock *)_sk)->dead = 0)
#define sock_clr_done(_sk)		(((struct sock *)_sk)->done = 0)
#define sock_clr_urginline(_sk)		(((struct sock *)_sk)->urginline = 0)
#define sock_clr_keepopen(_sk)		(((struct sock *)_sk)->keepopen = 0)
#define sock_clr_linger(_sk)		(((struct sock *)_sk)->linger = 0)
#define sock_clr_destroy(_sk)		(((struct sock *)_sk)->destroy = 0)
#define sock_clr_broadcast(_sk)		(((struct sock *)_sk)->broadcast = 0)
#define sock_clr_localroute(_sk)	(((struct sock *)_sk)->localroute = 0)
#define sock_clr_debug(_sk)		(((struct sock *)_sk)->debug = 0)

#undef inet_sk
#define inet_sk(_sk)			(&(((struct sock *)_sk)->protinfo.af_inet))
#undef inet_csk
#define inet_csk(_sk)			(&(((struct sock *)_sk)->protinfo.af_inet))
#undef tcp_sk
#define tcp_sk(_sk)			(&(((struct sock *)_sk)->tp_pinfo.af_tcp))
#undef sctp_sk
#define sctp_sk(_sk)			(&(((struct sock *)_sk)->tp_pinfo.af_sctp))

#define sock_saddr(_sk)			(((struct sock *)_sk)->saddr)
#define sock_sport(_sk)			(((struct sock *)_sk)->sport)
#define sock_daddr(_sk)			(((struct sock *)_sk)->daddr)
#define sock_dport(_sk)			(((struct sock *)_sk)->dport)

#define tcp_user_mss(_tp)		((_tp)->user_mss)

#define sock_syn_retries(_sk)		(tcp_sk(_sk)->syn_retries)
#define sock_defer_accept(_sk)		(tcp_sk(_sk)->defer_accept)
#define sock_accept_queue_head(_sk)	(tcp_sk(_sk)->accept_queue)
#define sock_accept_queue_tail(_sk)	(tcp_sk(_sk)->accept_queue_tail)
#define sock_accept_queue_lock(_sk)
#define sock_accept_queue_unlock(_sk)

#else
#ifdef HAVE_TRN_SOCK_STRUCTURE

#define sock_tst_dead(_sk)		(sock_flag(_sk, SOCK_DEAD) ? 1 : 0)
#define sock_tst_done(_sk)		(sock_flag(_sk, SOCK_DONE) ? 1 : 0)
#define sock_tst_urginline(_sk)		(sock_flag(_sk, SOCK_URGINLINE) ? 1 : 0)
#define sock_tst_keepopen(_sk)		(sock_flag(_sk, SOCK_KEEPOPEN) ? 1 : 0)
#define sock_tst_linger(_sk)		(sock_flag(_sk, SOCK_LINGER) ? 1 : 0)
#define sock_tst_destroy(_sk)		(sock_flag(_sk, SOCK_DESTROY) ? 1 : 0)
#define sock_tst_broadcast(_sk)		(sock_flag(_sk, SOCK_BROADCAST) ? 1 : 0)
#define sock_tst_localroute(_sk)	(((struct sock *)_sk)->sk_localroute ? 1 : 0)
#define sock_tst_debug(_sk)		(((struct sock *)_sk)->sk_debug ? 1 : 0)

#define sock_set_dead(_sk)		(sock_set_flag(_sk, SOCK_DEAD))
#define sock_set_done(_sk)		(sock_set_flag(_sk, SOCK_DONE))
#define sock_set_urginline(_sk)		(sock_set_flag(_sk, SOCK_URGINLINE))
#define sock_set_keepopen(_sk)		(sock_set_flag(_sk, SOCK_KEEPOPEN))
#define sock_set_linger(_sk)		(sock_set_flag(_sk, SOCK_LINGER))
#define sock_set_destroy(_sk)		(sock_set_flag(_sk, SOCK_DESTROY))
#define sock_set_broadcast(_sk)		(sock_set_flag(_sk, SOCK_BROADCAST))
#define sock_set_localroute(_sk)	(((struct sock *)_sk)->sk_localroute = 1)
#define sock_set_debug(_sk)		(((struct sock *)_sk)->sk_debug = 1)

#define sock_clr_dead(_sk)		(sock_reset_flag(_sk, SOCK_DEAD))
#define sock_clr_done(_sk)		(sock_reset_flag(_sk, SOCK_DONE))
#define sock_clr_urginline(_sk)		(sock_reset_flag(_sk, SOCK_URGINLINE))
#define sock_clr_keepopen(_sk)		(sock_reset_flag(_sk, SOCK_KEEPOPEN))
#define sock_clr_linger(_sk)		(sock_reset_flag(_sk, SOCK_LINGER))
#define sock_clr_destroy(_sk)		(sock_reset_flag(_sk, SOCK_DESTROY))
#define sock_clr_broadcast(_sk)		(sock_reset_flag(_sk, SOCK_BROADCAST))
#define sock_clr_localroute(_sk)	(((struct sock *)_sk)->sk_localroute = 0)
#define sock_clr_debug(_sk)		(((struct sock *)_sk)->sk_debug = 0)

#define sock_saddr(_sk)			(inet_sk(_sk)->saddr)
#define sock_sport(_sk)			(inet_sk(_sk)->sport)
#define sock_daddr(_sk)			(inet_sk(_sk)->daddr)
#define sock_dport(_sk)			(inet_sk(_sk)->dport)

#define tcp_user_mss(_tp)		((_tp)->user_mss)

#define sock_syn_retries(_sk)		(tcp_sk(_sk)->syn_retries)
#define sock_defer_accept(_sk)		(tcp_sk(_sk)->defer_accept)
#define sock_accept_queue_head(_sk)	(tcp_sk(_sk)->accept_queue)
#define sock_accept_queue_tail(_sk)	(tcp_sk(_sk)->accept_queue_tail)
#define sock_accept_queue_lock(_sk)
#define sock_accept_queue_unlock(_sk)

#else
#ifdef HAVE_NEW_SOCK_STRUCTURE

#define sock_tst_dead(_sk)		(sock_flag(_sk, SOCK_DEAD) ? 1 : 0)
#define sock_tst_done(_sk)		(sock_flag(_sk, SOCK_DONE) ? 1 : 0)
#define sock_tst_urginline(_sk)		(sock_flag(_sk, SOCK_URGINLINE) ? 1 : 0)
#define sock_tst_keepopen(_sk)		(sock_flag(_sk, SOCK_KEEPOPEN) ? 1 : 0)
#define sock_tst_linger(_sk)		(sock_flag(_sk, SOCK_LINGER) ? 1 : 0)
#define sock_tst_destroy(_sk)		(sock_flag(_sk, SOCK_DESTROY) ? 1 : 0)
#define sock_tst_broadcast(_sk)		(sock_flag(_sk, SOCK_BROADCAST) ? 1 : 0)
#ifdef HAVE_KMEMB_STRUCT_SOCK_SK_LOCALROUTE
#define sock_tst_localroute(_sk)	(((struct sock *)_sk)->sk_localroute ? 1 : 0)
#else
#define sock_tst_localroute(_sk)	(sock_flag(_sk, SOCK_LOCALROUTE) ? 1 : 0)
#endif
#ifdef HAVE_KMEMB_STRUCT_SOCK_SK_DEBUG
#define sock_tst_debug(_sk)		(((struct sock *)_sk)->sk_debug ? 1 : 0)
#else
#define sock_tst_debug(_sk)		(sock_flag(_sk, SOCK_DBG) ? 1 : 0)
#endif

#define sock_set_dead(_sk)		(sock_set_flag(_sk, SOCK_DEAD))
#define sock_set_done(_sk)		(sock_set_flag(_sk, SOCK_DONE))
#define sock_set_urginline(_sk)		(sock_set_flag(_sk, SOCK_URGINLINE))
#define sock_set_keepopen(_sk)		(sock_set_flag(_sk, SOCK_KEEPOPEN))
#define sock_set_linger(_sk)		(sock_set_flag(_sk, SOCK_LINGER))
#define sock_set_destroy(_sk)		(sock_set_flag(_sk, SOCK_DESTROY))
#define sock_set_broadcast(_sk)		(sock_set_flag(_sk, SOCK_BROADCAST))
#ifdef HAVE_KMEMB_STRUCT_SOCK_SK_LOCALROUTE
#define sock_set_localroute(_sk)	(((struct sock *)_sk)->sk_localroute = 1)
#else
#define sock_set_localroute(_sk)	(sock_set_flag(_sk, SOCK_LOCALROUTE))
#endif
#ifdef HAVE_KMEMB_STRUCT_SOCK_SK_DEBUG
#define sock_set_debug(_sk)		(((struct sock *)_sk)->sk_debug = 1)
#else
#define sock_set_debug(_sk)		(sock_set_flag(_sk, SOCK_DBG))
#endif

#define sock_clr_dead(_sk)		(sock_reset_flag(_sk, SOCK_DEAD))
#define sock_clr_done(_sk)		(sock_reset_flag(_sk, SOCK_DONE))
#define sock_clr_urginline(_sk)		(sock_reset_flag(_sk, SOCK_URGINLINE))
#define sock_clr_keepopen(_sk)		(sock_reset_flag(_sk, SOCK_KEEPOPEN))
#define sock_clr_linger(_sk)		(sock_reset_flag(_sk, SOCK_LINGER))
#define sock_clr_destroy(_sk)		(sock_reset_flag(_sk, SOCK_DESTROY))
#define sock_clr_broadcast(_sk)		(sock_reset_flag(_sk, SOCK_BROADCAST))
#ifdef HAVE_KMEMB_STRUCT_SOCK_SK_LOCALROUTE
#define sock_clr_localroute(_sk)	(((struct sock *)_sk)->sk_localroute = 0)
#else
#define sock_clr_localroute(_sk)	(sock_reset_flag(_sk, SOCK_LOCALROUTE))
#endif
#ifdef HAVE_KMEMB_STRUCT_SOCK_SK_DEBUG
#define sock_clr_debug(_sk)		(((struct sock *)_sk)->sk_debug = 0)
#else
#define sock_clr_debug(_sk)		(sock_reset_flag(_sk, SOCK_DBG))
#endif

#define sock_saddr(_sk)			(inet_sk(_sk)->saddr)
#define sock_sport(_sk)			(inet_sk(_sk)->sport)
#define sock_daddr(_sk)			(inet_sk(_sk)->daddr)
#define sock_dport(_sk)			(inet_sk(_sk)->dport)

#define inet_opt	inet_sock
#define tcp_opt		tcp_sock

#define tcp_user_mss(_tp)		((_tp)->rx_opt.user_mss)

#ifndef HAVE_KFUNC_INET_CSK
#define sock_syn_retries(_sk)		(tcp_sk(_sk)->syn_retries)
#ifndef HAVE_KINC_NET_REQUEST_SOCK_H
#define sock_defer_accept(_sk)		(tcp_sk(_sk)->defer_accept)
#define sock_accept_queue_head(_sk)	(tcp_sk(_sk)->accept_queue)
#define sock_accept_queue_tail(_sk)	(tcp_sk(_sk)->accept_queue_tail)
#define sock_accept_queue_lock(_sk)
#define sock_accept_queue_unlock(_sk)
#else
#define sock_defer_accept(_sk)		(tcp_sk(_sk)->defer_accept)
#define sock_accept_queue_head(_sk)	(tcp_sk(_sk)->accept_queue.rskq_accept_head)
#define sock_accept_queue_tail(_sk)	(tcp_sk(_sk)->accept_queue.rskq_accept_tail)
#define sock_accept_queue_lock(_sk)	write_lock_bh(&tcp_sk(_sk)->accept_queue.syn_wait_lock)
#define sock_accept_queue_unlock(_sk)	write_unlock_bh(&tcp_sk(_sk)->accept_queue.syn_wait_lock)
#define open_request request_sock
#define tcp_openreq_fastfree(__req)	__reqsk_free(__req)
#endif
#else
#define sock_syn_retries(_sk)		(inet_csk(_sk)->icsk_syn_retries)
#define sock_defer_accept(_sk)		(inet_csk(_sk)->icsk_accept_queue.rskq_defer_accept)
#define sock_accept_queue_head(_sk)	(inet_csk(_sk)->icsk_accept_queue.rskq_accept_head)
#define sock_accept_queue_tail(_sk)	(inet_csk(_sk)->icsk_accept_queue.rskq_accept_tail)
#define sock_accept_queue_lock(_sk)	write_lock_bh(&inet_csk(_sk)->icsk_accept_queue.syn_wait_lock)
#define sock_accept_queue_unlock(_sk)	write_unlock_bh(&inet_csk(_sk)->icsk_accept_queue.syn_wait_lock)
#define open_request request_sock
#define tcp_openreq_fastfree(__req)	__reqsk_free(__req)
#endif

#else
#error One of HAVE_OLD_SOCK_STRUCTURE, HAVE_TRN_SOCK_STRUCTURE or HAVE_NEW_SOCK_STRUCTURE must be defined.
#endif
#endif
#endif

#ifndef SK_WMEM_MAX
#define SK_WMEM_MAX 65535
#endif
#ifndef SK_RMEM_MAX
#define SK_RMEM_MAX 65535
#endif

#if !defined HAVE_OPENSS7_SCTP
#undef sctp_addr
#endif

#ifndef tcp_openreq_cachep
#ifdef HAVE_TCP_OPENREQ_CACHEP_ADDR
#include <linux/slab.h>
static kmem_cachep_t *const _tcp_openreq_cachep_location =
    (typeof(_tcp_openreq_cachep_location)) (HAVE_TCP_OPENREQ_CACHEP_ADDR);

#define tcp_openreq_cachep (*_tcp_openreq_cachep_location)
#endif
#endif

#ifndef tcp_set_keepalive
#ifdef HAVE_TCP_SET_KEEPALIVE_ADDR
void
tcp_set_keepalive(struct sock *sk, int val)
{
	static void (*func) (struct sock *, int) = (typeof(func)) HAVE_TCP_SET_KEEPALIVE_ADDR;

	return func(sk, val);
}
#endif
#endif

#ifndef tcp_sync_mss
#ifdef HAVE_TCP_SYNC_MSS_ADDR
int
tcp_sync_mss(struct sock *sk, u32 pmtu)
{
	static int (*func) (struct sock *, u32) = (typeof(func)) HAVE_TCP_SYNC_MSS_ADDR;

	return func(sk, pmtu);
}
#endif
#endif

#ifndef tcp_write_xmit
#ifdef HAVE_TCP_WRITE_XMIT_ADDR
int
tcp_write_xmit(struct sock *sk, int nonagle)
{
	static int (*func) (struct sock *, int) = (typeof(func)) HAVE_TCP_WRITE_XMIT_ADDR;

	return func(sk, nonagle);
}
#endif
#endif

#ifndef tcp_cwnd_application_limited
#ifdef HAVE_TCP_CWND_APPLICATION_LIMITED_ADDR
void
tcp_cwnd_application_limited(struct sock *sk)
{
	static void (*func) (struct sock *) = (typeof(func)) HAVE_TCP_CWND_APPLICATION_LIMITED_ADDR;

	return func(sk);
}
#endif
#endif

__u8 ip_tos2prio[16] = { 0, 1, 0, 0, 2, 2, 2, 2, 6, 6, 6, 6, 4, 4, 4, 4 };

#ifndef sysctl_rmem_default
#ifdef HAVE_SYSCTL_RMEM_DEFAULT_ADDR
static __u32 *const _sysctl_rmem_default_location =
    (typeof(_sysctl_rmem_default_location)) (HAVE_SYSCTL_RMEM_DEFAULT_ADDR);

#define sysctl_rmem_default (*_sysctl_rmem_default_location)
#else
#define sysctl_rmem_default SK_RMEM_MAX
#endif
#endif

#ifndef sysctl_wmem_default
#ifdef HAVE_SYSCTL_WMEM_DEFAULT_ADDR
static __u32 *const _sysctl_wmem_default_location =
    (typeof(_sysctl_wmem_default_location)) (HAVE_SYSCTL_WMEM_DEFAULT_ADDR);

#define sysctl_wmem_default (*_sysctl_wmem_default_location)
#else
#define sysctl_wmem_default SK_WMEM_MAX
#endif
#endif

#ifndef sysctl_tcp_fin_timeout
#ifdef HAVE_SYSCTL_TCP_FIN_TIMEOUT_ADDR
static __u32 *const _sysctl_tcp_fin_timeout_location =
    (typeof(_sysctl_tcp_fin_timeout_location)) (HAVE_SYSCTL_TCP_FIN_TIMEOUT_ADDR);

#define sysctl_tcp_fin_timeout (*_sysctl_tcp_fin_timeout_location)
#else
#define sysctl_tcp_fin_timeout TCP_FIN_TIMEOUT
#endif
#endif

#ifndef tcp_current_mss
#ifdef HAVE_TCP_CURRENT_MSS_ADDR
unsigned int
tcp_current_mss(struct sock *sk, int large)
{
	static unsigned int (*func) (struct sock *, int) = (typeof(func)) HAVE_TCP_CURRENT_MSS_ADDR;

	return func(sk, large);
}
#endif
#endif

#ifndef sysctl_ip_dynaddr
#ifdef HAVE_SYSCTL_IP_DYNADDR_ADDR
extern int sysctl_ip_dynaddr;

#define sysctl_ip_dynaddr (*((typeof(sysctl_ip_dynaddr) *)HAVE_SYSCTL_IP_DYNADDR_ADDR))
#endif
#endif

#ifndef sysctl_ip_nonlocal_bind
#ifdef HAVE_SYSCTL_IP_NONLOCAL_BIND_ADDR
extern int sysctl_ip_nonlocal_bind;

#define sysctl_ip_nonlocal_bind (*((typeof(sysctl_ip_nonlocal_bind) *)HAVE_SYSCTL_IP_NONLOCAL_BIND_ADDR))
#endif
#endif

#ifndef sysctl_ip_default_ttl
#ifdef HAVE_SYSCTL_IP_DEFAULT_TTL_ADDR
extern int sysctl_ip_default_ttl;

#define sysctl_ip_default_ttl (*((typeof(sysctl_ip_default_ttl) *)HAVE_SYSCTL_IP_DEFAULT_TTL_ADDR))
#endif
#endif

#ifndef tcp_set_skb_tso_segs
#ifdef HAVE_TCP_SET_SKB_TSO_SEGS_ADDR
#ifdef HAVE_KFUNC_TCP_SET_SKB_TSO_SEGS_SOCK
void
tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb)
{
	static void (*func) (struct sock *, struct sk_buff *) =
	    (typeof(func)) HAVE_TCP_SET_SKB_TSO_SEGS_ADDR;

	return func(sk, skb);
}
#else
void
tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_std)
{
	static void (*func) (struct sk_buff *, unsigned int) =
	    (typeof(func)) HAVE_TCP_SET_SKB_TSO_SEGS_ADDR;

	return func(skb, mss_std);
}
#endif
#endif
#endif

#ifndef tcp_set_skb_tso_factor
#ifdef HAVE_TCP_SET_SKB_TSO_FACTOR_ADDR
void
tcp_set_skb_tso_factor(struct sk_buff *skb, unsigned int mss_std)
{
	static void (*func) (struct sk_buff *, unsigned int) =
	    (typeof(func)) HAVE_TCP_SET_SKB_TSO_FACTOR_ADDR;

	return func(skb, mss_std);
}
#endif
#endif

#if defined HAVE_TIHDR_H
#   include <tihdr.h>
#else
#   include <sys/tihdr.h>
#endif

#include <sys/xti.h>
#include <sys/xti_inet.h>
#include <sys/xti_sctp.h>

#define T_ALLLEVELS -1

#define LINUX_2_4 1

#define SS__DESCRIP	"UNIX SYSTEM V RELEASE 4.2 FAST STREAMS FOR LINUX"
#define SS__EXTRA	"Part of the OpenSS7 Stack for Linux Fast-STREAMS."
#define SS__COPYRIGHT	"Copyright (c) 1997-2006 OpenSS7 Corporation.  All Rights Reserved."
#define SS__REVISION	"OpenSS7 inet.c,v openss7-0_9_2_F(0.9.2.85) 2007/05/17 22:33:00"
#define SS__DEVICE	"SVR 4.2 STREAMS INET Drivers (NET4)"
#define SS__CONTACT	"Brian Bidulock <bidulock@openss7.org>"
#define SS__LICENSE	"GPL"
#define SS__BANNER	SS__DESCRIP	"\n" \
			SS__EXTRA	"\n" \
			SS__REVISION	"\n" \
			SS__COPYRIGHT	"\n" \
			SS__DEVICE	"\n" \
			SS__CONTACT
#define SS__SPLASH	SS__DESCRIP	"\n" \
			SS__REVISION

#ifdef LINUX
MODULE_AUTHOR(SS__CONTACT);
MODULE_DESCRIPTION(SS__DESCRIP);
MODULE_SUPPORTED_DEVICE(SS__DEVICE);
#ifdef MODULE_LICENSE
MODULE_LICENSE(SS__LICENSE);
#endif
#if defined MODULE_ALIAS
MODULE_ALIAS("streams-inet");
#endif
#endif

#ifdef LFS
#define SS__DRV_ID	CONFIG_STREAMS_SS__MAJOR
#define SS__DRV_NAME	CONFIG_STREAMS_SS__NAME
#define SS__CMAJORS	CONFIG_STREAMS_SS__NMAJORS
#define SS__CMAJOR_0	CONFIG_STREAMS_SS__MAJOR
#define SS__UNITS	CONFIG_STREAMS_SS__NMINORS
#endif

#define IP_CMINOR	32

#define FIRST_CMINOR	33

#define ICMP_CMINOR	33
#define GGP_CMINOR	34
#define IPIP_CMINOR	35
#define TCP_CMINOR	36
#define EGP_CMINOR	37
#define PUP_CMINOR	38
#define UDP_CMINOR	39
#define IDP_CMINOR	40
#define RAWIP_CMINOR	41

#define TICOTS_ORD_CMINOR	42
#define TICOTS_CMINOR	43
#define TICLTS_CMINOR	44

#if defined HAVE_OPENSS7_SCTP
#define SCTP_CMINOR	45
#define LAST_CMINOR	45
#else
#define LAST_CMINOR	44
#endif

#define FREE_CMINOR	50

#ifdef LINUX
#ifdef MODULE_ALIAS
#ifdef LFS
MODULE_ALIAS("streams-modid-" __stringify(CONFIG_STREAMS_SS__MAJOR));
MODULE_ALIAS("streams-driver-inet");
MODULE_ALIAS("streams-major-" __stringify(CONFIG_STREAMS_SS__MAJOR));
MODULE_ALIAS("/dev/streams/inet");
MODULE_ALIAS("/dev/streams/inet
#endif
#endif

#define DRV_ID		SS__DRV_ID
#define DRV_NAME	SS__DRV_NAME
#define CMAJORS		SS__CMAJORS
#define CMAJOR_0	SS__CMAJOR_0
#define UNITS		SS__UNITS
#ifdef MODULE
#define DRV_BANNER	SS__BANNER
#else
#define DRV_BANNER	SS__SPLASH
#endif

STATIC struct module_info ss_rinfo = {
	.mi_idnum = DRV_ID,
	.mi_idname = DRV_NAME,
	.mi_minpsz = 0,
	.mi_maxpsz = (1 << 16),
	.mi_hiwat = SHEADHIWAT << 5,
	.mi_lowat = 0,
};

STATIC struct module_stat ss_rstat __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
STATIC struct module_stat ss_wstat __attribute__ ((__aligned__(SMP_CACHE_BYTES)));

STATIC streamscall int ss_open(queue_t *, dev_t *, int, int, cred_t *);
STATIC streamscall int ss_close(queue_t *, int, cred_t *);

STATIC streamscall int ss_rput(queue_t *, mblk_t *);
STATIC streamscall int ss_rsrv(queue_t *);

STATIC struct qinit ss_rinit = {
	.qi_putp = ss_rput,
	.qi_srvp = ss_rsrv,
	.qi_qopen = ss_open,
	.qi_qclose = ss_close,
	.qi_minfo = &ss_rinfo,
	.qi_mstat = &ss_rstat,
};

STATIC struct module_info ss_winfo = {
	.mi_idnum = DRV_ID,
	.mi_idname = DRV_NAME,
	.mi_minpsz = 0,
	.mi_maxpsz = (1 << 16),
	.mi_hiwat = (SHEADHIWAT >> 1),
	.mi_lowat = 0,
};

STATIC streamscall int ss_wput(queue_t *, mblk_t *);
STATIC streamscall int ss_wsrv(queue_t *);

STATIC struct qinit ss_winit = {
	.qi_putp = ss_wput,
	.qi_srvp = ss_wsrv,
	.qi_minfo = &ss_winfo,
	.qi_mstat = &ss_wstat,
};

MODULE_STATIC struct streamtab ss_info = {
	.st_rdinit = &ss_rinit,
	.st_wrinit = &ss_winit,
};

#define TSF_UNBND	( 1 << TS_UNBND		)
#define TSF_WACK_BREQ	( 1 << TS_WACK_BREQ	)
#define TSF_WACK_UREQ	( 1 << TS_WACK_UREQ	)
#define TSF_IDLE	( 1 << TS_IDLE		)
#ifdef TS_WACK_OPTREQ
#define TSF_WACK_OPTREQ	( 1 << TS_WACK_OPTREQ	)
#endif
#define TSF_WACK_CREQ	( 1 << TS_WACK_CREQ	)
#define TSF_WCON_CREQ	( 1 << TS_WCON_CREQ	)
#define TSF_WRES_CIND	( 1 << TS_WRES_CIND	)
#define TSF_WACK_CRES	( 1 << TS_WACK_CRES	)
#define TSF_DATA_XFER	( 1 << TS_DATA_XFER	)
#define TSF_WIND_ORDREL	( 1 << TS_WIND_ORDREL	)
#define TSF_WREQ_ORDREL	( 1 << TS_WREQ_ORDREL	)
#define TSF_WACK_DREQ6	( 1 << TS_WACK_DREQ6	)
#define TSF_WACK_DREQ7	( 1 << TS_WACK_DREQ7	)
#define TSF_WACK_DREQ9	( 1 << TS_WACK_DREQ9	)
#define TSF_WACK_DREQ10	( 1 << TS_WACK_DREQ10	)
#define TSF_WACK_DREQ11	( 1 << TS_WACK_DREQ11	)
#define TSF_NOSTATES	( 1 << TS_NOSTATES	)
#define TSM_WACK_DREQ	(TSF_WACK_DREQ6 \
			|TSF_WACK_DREQ7 \
			|TSF_WACK_DREQ9 \
			|TSF_WACK_DREQ10 \
			|TSF_WACK_DREQ11)
#define TSM_LISTEN	(TSF_IDLE \
			|TSF_WRES_CIND)
#define TSM_CONNECTED	(TSF_WCON_CREQ\
			|TSF_WRES_CIND\
			|TSF_DATA_XFER\
			|TSF_WIND_ORDREL\
			|TSF_WREQ_ORDREL)
#define TSM_DISCONN	(TSF_IDLE\
			|TSF_UNBND)
#define TSM_INDATA	(TSF_DATA_XFER\
			|TSF_WIND_ORDREL)
#define TSM_OUTDATA	(TSF_DATA_XFER\
			|TSF_WREQ_ORDREL)
#ifndef T_PROVIDER
#define T_PROVIDER  0
#define T_USER	    1
#endif

#define TCPM_CLOSING	(TCPF_CLOSE\
			|TCPF_TIME_WAIT\
			|TCPF_CLOSE_WAIT)
#define TCPM_CONNIND	(TCPF_SYN_RECV\
			|TCPF_ESTABLISHED\
			|TCPF_LISTEN)

typedef struct ss_options {
#if 0
	unsigned char flags[12];
#else
	unsigned long flags[3];
#endif
	struct {
		t_uscalar_t debug[4];
		struct t_linger linger;
		t_uscalar_t rcvbuf;
		t_uscalar_t rcvlowat;
		t_uscalar_t sndbuf;
		t_uscalar_t sndlowat;
	} xti;
	struct {
		unsigned char options[40];
		unsigned char tos;
		unsigned char ttl;
		unsigned int reuseaddr;
		unsigned int dontroute;
		unsigned int broadcast;
		uint32_t addr;
	} ip;
	struct {
		t_uscalar_t checksum;
	} udp;
	struct {
		t_uscalar_t nodelay;
		t_uscalar_t maxseg;
		struct t_kpalive keepalive;
		t_uscalar_t cork;
		t_uscalar_t keepidle;
		t_uscalar_t keepitvl;
		t_uscalar_t keepcnt;
		t_uscalar_t syncnt;
		t_uscalar_t linger2;
		t_uscalar_t defer_accept;
		t_uscalar_t window_clamp;
		struct t_tcp_info info;
		t_uscalar_t quickack;
	} tcp;
#if defined HAVE_OPENSS7_SCTP
	struct {
		t_uscalar_t nodelay;
		t_uscalar_t maxseg;
		t_uscalar_t cork;
		t_uscalar_t ppi;
		t_uscalar_t sid;
		t_uscalar_t ssn;
		t_uscalar_t tsn;
		t_uscalar_t recvopt;
		t_uscalar_t cookie_life;
		t_uscalar_t sack_delay;
		t_uscalar_t path_max_retrans;
		t_uscalar_t assoc_max_retrans;
		t_uscalar_t max_init_retries;
		t_uscalar_t heartbeat_itvl;
		t_uscalar_t rto_initial;
		t_uscalar_t rto_min;
		t_uscalar_t rto_max;
		t_uscalar_t ostreams;
		t_uscalar_t istreams;
		t_uscalar_t cookie_inc;
		t_uscalar_t throttle_itvl;
		t_uscalar_t mac_type;
		t_uscalar_t cksum_type;
		struct t_sctp_hb hb;
		struct t_sctp_rto rto;
		struct {
			struct t_sctp_status status;
			struct t_sctp_dest_status dest_status;
		} status;
		t_uscalar_t debug;
#if defined CONFIG_SCTP_ECN
		t_uscalar_t ecn;
#endif
#if defined CONFIG_SCTP_ADD_IP || defined CONFIG_SCTP_ADAPTATION_LAYER_INFO
		t_uscalar_t ali;
#endif
#if defined CONFIG_SCTP_ADD_IP
		t_uscalar_t add;
		t_uscalar_t set;
		struct sockaddr_in add_ip;
		struct sockaddr_in del_ip;
		struct sockaddr_in set_ip;
#endif
#if defined CONFIG_SCTP_PARTIAL_RELIABILITY
		t_uscalar_t pr;
#endif
#if defined CONFIG_SCTP_LIFETIMES || defined CONFIG_SCTP_PARTIAL_RELIABILITY
		t_uscalar_t lifetime;
#endif
		t_uscalar_t disposition;
		t_uscalar_t max_burst;
	} sctp;
#endif
} ss_options_t;

typedef struct ss_profile {
	struct {
		uint family;
		uint type;
		uint protocol;
	} prot;
	struct T_info_ack info;
} ss_profile_t;

typedef struct ss_protocol {
	struct ss_protocol *next;
	struct ss_protocol **prev;
	atomic_t refcnt;
	spinlock_t lock;
	void (*put) (struct ss_protocol *);
	struct ss_protocol *(*get) (struct ss_protocol *);
	uint type;
	uint id;
	uint state;
	uint flags;
	int ps_family;
	int ps_type;
	int ps_protocol;
	dev_t ps_dev;
	int ps_flags;
} ss_protocol_t;

struct ss_protocol *ss_protosw = NULL;

typedef struct inet {
	struct inet *next;
	struct inet **prev;
	size_t refcnt;
	spinlock_t lock;
	major_t cmajor;
	minor_t cminor;
	queue_t *rq;
	queue_t *wq;
	cred_t cred;
	spinlock_t qlock;
	queue_t *rwait;
	queue_t *wwait;
	long users;
	uint rbid;
	uint wbid;
	ushort port;
	int tcp_state;
	ss_profile_t p;
	struct {
		void (*sk_state_change) (struct sock *);
		void (*sk_data_ready) (struct sock *, int);
		void (*sk_write_space) (struct sock *);
		void (*sk_error_report) (struct sock *);
	} cb_save;
	struct sockaddr src;
	struct sockaddr dst;
	ss_options_t options;
	unsigned char _pad[40];
	bufq_t conq;
	uint conind;
	struct socket *sock;
} ss_t;

#define PRIV(__q) ((ss_t *)((__q)->q_ptr))
#define SOCK_PRIV(__sk) ((__sk)->sk_user_data)

#define xti_default_debug		{ 0, }
#define xti_default_linger		(struct t_linger){T_YES, 120}
#define xti_default_rcvbuf		SK_RMEM_MAX
#define xti_default_rcvlowat		1
#define xti_default_sndbuf		SK_WMEM_MAX
#define xti_default_sndlowat		1

#define ip_default_options		{ 0, }
#define ip_default_tos			0
#define ip_default_ttl			64
#define ip_default_reuseaddr		T_NO
#define ip_default_dontroute		T_NO
#define ip_default_broadcast		T_NO

#define udp_default_checksum		T_YES

#define tcp_default_nodelay		T_NO
#define tcp_default_maxseg		536
#define tcp_default_keepalive		(struct t_kpalive){ T_YES, 1 }

#define sctp_default_nodelay		T_NO
#define sctp_default_maxseg		536
#define sctp_default_cork		T_NO
#define sctp_default_ppi		0
#define sctp_default_sid		0
#define sctp_default_ssn		T_UNSPEC
#define sctp_default_tsn		T_UNSPEC
#define sctp_default_recvopt		T_YES
#define sctp_default_cookie_life	60
#define sctp_default_sack_delay		200
#define sctp_default_path_max_retrans	5
#define sctp_default_assoc_max_retrans	10
#define sctp_default_max_init_retries	8
#define sctp_default_heartbeat_itvl	30
#define sctp_default_rto_initial	3000
#define sctp_default_rto_min		1000
#define sctp_default_rto_max		60000
#define sctp_default_ostreams		1
#define sctp_default_istreams		33
#define sctp_default_cookie_inc		1000
#define sctp_default_throttle_itvl	50
#ifdef CONFIG_SCTP_HMAC_MD5
#define sctp_default_mac_type		T_SCTP_HMAC_MD5
#else
#ifdef CONFIG_SCTP_HMAC_SHA1
#define sctp_default_mac_type		T_SCTP_HMAC_SHA1
#else
#define sctp_default_mac_type		T_SCTP_HMAC_NONE
#endif
#endif
#if defined CONFIG_SCTP_CRC32C
#define sctp_default_cksum_type		T_SCTP_CSUM_CRC32C
#else
#define sctp_default_cksum_type		T_SCTP_CSUM_ADLER32
#endif
#define sctp_default_hb			(struct t_sctp_hb){ INADDR_ANY, T_YES, sctp_default_heartbeat_itvl }
#define sctp_default_rto		(struct t_sctp_rto){ INADDR_ANY, sctp_default_rto_initial, sctp_default_rto_min, sctp_default_rto_max, sctp_default_path_max_retrans }
#define sctp_default_sctp_status	(struct t_sctp_status){ 0, }
#define sctp_default_dest_status	(struct t_sctp_dest_status){ INADDR_ANY, }
#define sctp_default_status		{ { 0, }, { INADDR_ANY, } }
#define sctp_default_debug		0
#if defined CONFIG_SCTP_ECN
#define sctp_default_ecn		T_YES
#else
#define sctp_default_ecn		T_NO
#endif
#define sctp_default_ali		0
#define sctp_default_add		T_NO
#define sctp_default_set		T_NO
#define sctp_default_add_ip		INADDR_ANY
#define sctp_default_del_ip		INADDR_ANY
#define sctp_default_set_ip		INADDR_ANY
#define sctp_default_pr			T_NO
#define sctp_default_lifetime		T_UNSPEC
#define sctp_default_disposition	T_UNSPEC
#define sctp_default_max_burst		4

enum {
	_T_BIT_XTI_DEBUG = 0,
	_T_BIT_XTI_LINGER,
	_T_BIT_XTI_RCVBUF,
	_T_BIT_XTI_RCVLOWAT,
	_T_BIT_XTI_SNDBUF,
	_T_BIT_XTI_SNDLOWAT,
	_T_BIT_IP_OPTIONS,
	_T_BIT_IP_TOS,
	_T_BIT_IP_TTL,
	_T_BIT_IP_REUSEADDR,
	_T_BIT_IP_DONTROUTE,
	_T_BIT_IP_BROADCAST,
	_T_BIT_IP_ADDR,
	_T_BIT_IP_RETOPTS,
	_T_BIT_TCP_NODELAY,
	_T_BIT_TCP_MAXSEG,
	_T_BIT_TCP_KEEPALIVE,
	_T_BIT_TCP_CORK,
	_T_BIT_TCP_KEEPIDLE,
	_T_BIT_TCP_KEEPINTVL,
	_T_BIT_TCP_KEEPCNT,
	_T_BIT_TCP_SYNCNT,
	_T_BIT_TCP_LINGER2,
	_T_BIT_TCP_DEFER_ACCEPT,
	_T_BIT_TCP_WINDOW_CLAMP,
	_T_BIT_TCP_INFO,
	_T_BIT_TCP_QUICKACK,
	_T_BIT_UDP_CHECKSUM,
#if defined HAVE_OPENSS7_SCTP
	_T_BIT_SCTP_NODELAY,
	_T_BIT_SCTP_MAXSEG,
	_T_BIT_SCTP_CORK,
	_T_BIT_SCTP_PPI,
	_T_BIT_SCTP_SID,
	_T_BIT_SCTP_SSN,
	_T_BIT_SCTP_TSN,
	_T_BIT_SCTP_RECVOPT,
	_T_BIT_SCTP_COOKIE_LIFE,
	_T_BIT_SCTP_SACK_DELAY,
	_T_BIT_SCTP_PATH_MAX_RETRANS,
	_T_BIT_SCTP_ASSOC_MAX_RETRANS,
	_T_BIT_SCTP_MAX_INIT_RETRIES,
	_T_BIT_SCTP_HEARTBEAT_ITVL,
	_T_BIT_SCTP_RTO_INITIAL,
	_T_BIT_SCTP_RTO_MIN,
	_T_BIT_SCTP_RTO_MAX,
	_T_BIT_SCTP_OSTREAMS,
	_T_BIT_SCTP_ISTREAMS,
	_T_BIT_SCTP_COOKIE_INC,
	_T_BIT_SCTP_THROTTLE_ITVL,
	_T_BIT_SCTP_MAC_TYPE,
	_T_BIT_SCTP_CKSUM_TYPE,
	_T_BIT_SCTP_HB,
	_T_BIT_SCTP_RTO,
	_T_BIT_SCTP_STATUS,
	_T_BIT_SCTP_DEBUG,
	_T_BIT_SCTP_ECN,
	_T_BIT_SCTP_ALI,
	_T_BIT_SCTP_ADD,
	_T_BIT_SCTP_SET,
	_T_BIT_SCTP_ADD_IP,
	_T_BIT_SCTP_DEL_IP,
	_T_BIT_SCTP_SET_IP,
	_T_BIT_SCTP_PR,
	_T_BIT_SCTP_LIFETIME,
	_T_BIT_SCTP_DISPOSITION,
	_T_BIT_SCTP_MAX_BURST,
#endif
};

typedef struct ss_event {
	struct sock *sk;
	int state;
} ss_event_t;

STATIC spinlock_t ss_lock = SPIN_LOCK_UNLOCKED;
STATIC ss_t *ss_opens = NULL;

#if 0

STATIC ss_t *ss_dflt_dest = NULL;
STATIC ss_t *ss_dflt_lstn = NULL;
#endif

STATIC void ss_state_change(struct sock *sk);
STATIC void ss_write_space(struct sock *sk);
STATIC void ss_error_report(struct sock *sk);
STATIC void ss_data_ready(struct sock *sk, int len);
STATIC void
ss_socket_put(struct socket *sock)
{
	unsigned long flags;
	struct sock *sk;

	ensure(sock, return);
	if ((sk = sock->sk)) {

		write_lock_irqsave(&sk->sk_callback_lock, flags);
		{
			ss_t *ss;

			if ((ss = SOCK_PRIV(sk))) {
				SOCK_PRIV(sk) = NULL;
				ss->refcnt--;
				sk->sk_state_change = ss->cb_save.sk_state_change;
				sk->sk_data_ready = ss->cb_save.sk_data_ready;
				sk->sk_write_space = ss->cb_save.sk_write_space;
				sk->sk_error_report = ss->cb_save.sk_error_report;
			} else
				assure(ss);
		}
		write_unlock_irqrestore(&sock->sk->sk_callback_lock, flags);

		sock_set_keepopen(sk);
		sk->sk_lingertime = 0;
	} else
		assure(sk);
	sock_release(sock);
}
STATIC void
ss_socket_get(struct socket *sock, ss_t *ss)
{
	unsigned long flags;
	struct sock *sk;

	ensure(sock, return);
	if ((sk = sock->sk)) {

		write_lock_irqsave(&sock->sk->sk_callback_lock, flags);
		{
			SOCK_PRIV(sk) = ss;
			ss->refcnt++;
			ss->cb_save.sk_state_change = sk->sk_state_change;
			ss->cb_save.sk_data_ready = sk->sk_data_ready;
			ss->cb_save.sk_write_space = sk->sk_write_space;
			ss->cb_save.sk_error_report = sk->sk_error_report;
			sk->sk_state_change = ss_state_change;
			sk->sk_data_ready = ss_data_ready;
			sk->sk_write_space = ss_write_space;
			sk->sk_error_report = ss_error_report;
#ifdef LINUX_2_4
			inet_sk(sk)->recverr = 1;
#else
			sk->ip_recverr = 1;
#endif
			ss->tcp_state = sk->sk_state;
		}
		write_unlock_irqrestore(&sock->sk->sk_callback_lock, flags);
	} else
		assure(sk);
}

#if 0
STATIC int
ss_trylockq(queue_t *q)
{
	unsigned long flags;
	int res;
	ss_t *ss = PRIV(q);

	spin_lock_irqsave(&ss->qlock, flags);
	if (!(res = !ss->users++)) {
		if (q == ss->rq)
			ss->rwait = q;
		if (q == ss->wq)
			ss->wwait = q;
		--ss->users;
	}
	spin_unlock_irqrestore(&ss->qlock, flags);
	return (res);
}
STATIC void
ss_unlockq(queue_t *q)
{
	unsigned long flags;
	ss_t *ss = PRIV(q);

	spin_lock_irqsave(&ss->qlock, flags);
	if (ss->rwait)
		qenable(xchg(&ss->rwait, NULL));
	if (ss->wwait)
		qenable(xchg(&ss->wwait, NULL));
	ss->users = 0;
	spin_unlock_irqrestore(&ss->qlock, flags);
}
#else
STATIC inline fastcall int
ss_trylockq(queue_t *q)
{
	return (!test_and_set_bit(0, &PRIV(q)->users));
}
STATIC inline fastcall void
ss_unlockq(queue_t *q)
{
	clear_bit(0, &PRIV(q)->users);
}
#endif

STATIC void streamscall
ss_bufsrv(long data)
{
	queue_t *q = (queue_t *) data;

	if (q) {
		ss_t *ss = PRIV(q);
		unsigned long flags;

		spin_lock_irqsave(&ss->lock, flags);
		if (q == ss->rq) {
			if (ss->rbid) {
				ss->rbid = 0;
				ss->refcnt--;
			}
		} else if (q == ss->wq) {
			if (ss->wbid) {
				ss->wbid = 0;
				ss->refcnt--;
			}
		} else
			swerr();
		spin_unlock_irqrestore(&ss->lock, flags);
		qenable(q);
	}
}

STATIC void
__ss_unbufcall(queue_t *q)
{
	ss_t *ss = PRIV(q);

	if (ss->rbid) {
		unbufcall(xchg(&ss->rbid, 0));
		ss->refcnt--;
	}
	if (ss->wbid) {
		unbufcall(xchg(&ss->wbid, 0));
		ss->refcnt--;
	}
}

STATIC mblk_t *
ss_allocb(queue_t *q, size_t size, int prior)
{
	mblk_t *mp;

	if ((mp = allocb(size, prior)))
		return (mp);
	else {
		ss_t *ss = PRIV(q);
		unsigned long flags;

		spin_lock_irqsave(&ss->lock, flags);
		if (q == ss->rq) {
			if (!ss->rbid) {
				ss->rbid = bufcall(size, prior, &ss_bufsrv, (long) q);
				ss->refcnt++;
			}
		} else if (q == ss->wq) {
			if (!ss->wbid) {
				ss->wbid = bufcall(size, prior, &ss_bufsrv, (long) q);
				ss->refcnt++;
			}
		} else
			swerr();
		spin_unlock_irqrestore(&ss->lock, flags);
		return (NULL);
	}
}

#if 0

STATIC mblk_t *
ss_esballoc(queue_t *q, unsigned char *base, size_t size, int prior, frtn_t *frtn)
{
	mblk_t *mp;

	if ((mp = esballoc(base, size, prior, frtn)))
		return (mp);
	else {
		ss_t *ss = PRIV(q);

		if (q == ss->rq) {
			if (!ss->rbid) {
				ss->rbid = esbbcall(prior, &ss_bufsrv, (long) q);
				ss->refcnt++;
			}
			return (NULL);
		}
		if (q == ss->wq) {
			if (!ss->wbid) {
				ss->wbid = esbbcall(prior, &ss_bufsrv, (long) q);
				ss->refcnt++;
			}
			return (NULL);
		}
		swerr();
		return (NULL);
	}
}
#endif

#define T_SPACE(len) \
	(sizeof(struct t_opthdr) + T_ALIGN(len))

#define T_LENGTH(len) \
	(sizeof(struct t_opthdr) + len)

#define _T_SPACE_SIZEOF(s) \
	T_SPACE(sizeof(s))

#define _T_LENGTH_SIZEOF(s) \
	T_LENGTH(sizeof(s))

STATIC ss_options_t ss_defaults = {
	{0,}
	,
	{
	 xti_default_debug,
	 xti_default_linger,
	 xti_default_rcvbuf,
	 xti_default_rcvlowat,
	 xti_default_sndbuf,
	 xti_default_sndlowat,
	 }
	,
	{
	 ip_default_options,
	 ip_default_tos,
	 ip_default_ttl,
	 ip_default_reuseaddr,
	 ip_default_dontroute,
	 ip_default_broadcast,
	 }
	,
	{
	 udp_default_checksum,
	 }
	,
	{
	 tcp_default_nodelay,
	 tcp_default_maxseg,
	 tcp_default_keepalive,
	 }
#if defined HAVE_OPENSS7_SCTP
	,
	{
	 sctp_default_nodelay,
	 sctp_default_maxseg,
	 sctp_default_cork,
	 sctp_default_ppi,
	 sctp_default_sid,
	 sctp_default_ssn,
	 sctp_default_tsn,
	 sctp_default_recvopt,
	 sctp_default_cookie_life,
	 sctp_default_sack_delay,
	 sctp_default_path_max_retrans,
	 sctp_default_assoc_max_retrans,
	 sctp_default_max_init_retries,
	 sctp_default_heartbeat_itvl,
	 sctp_default_rto_initial,
	 sctp_default_rto_min,
	 sctp_default_rto_max,
	 sctp_default_ostreams,
	 sctp_default_istreams,
	 sctp_default_cookie_inc,
	 sctp_default_throttle_itvl,
	 sctp_default_mac_type,
	 sctp_default_cksum_type,
	 sctp_default_hb,
	 sctp_default_rto,
	 sctp_default_status,
	 sctp_default_debug,
#if defined CONFIG_SCTP_ECN
	 sctp_default_ecn,
#endif
#if defined CONFIG_SCTP_ADD_IP || defined CONFIG_SCTP_ADAPTATION_LAYER_INFO
	 sctp_default_ali,
#endif
#if defined CONFIG_SCTP_ADD_IP
	 sctp_default_add,
	 sctp_default_set,
	 sctp_default_add_ip,
	 sctp_default_del_ip,
	 sctp_default_set_ip,
#endif
#if defined CONFIG_SCTP_PARTIAL_RELIABILITY
	 sctp_default_pr,
#endif
#if defined CONFIG_SCTP_LIFETIMES || defined CONFIG_SCTP_PARTIAL_RELIABILITY
	 sctp_default_lifetime,
#endif
	 sctp_default_disposition,
	 sctp_default_max_burst,
	 }
#endif
};

#define t_defaults ss_defaults

STATIC int
ss_size_conn_opts(ss_t *ss)
{
	int size = 0;

	if (t_tst_bit(_T_BIT_XTI_DEBUG, ss->options.flags))
		size += _T_SPACE_SIZEOF(ss->options.xti.debug);
	if (t_tst_bit(_T_BIT_XTI_LINGER, ss->options.flags))
		size += _T_SPACE_SIZEOF(ss->options.xti.linger);
	if (t_tst_bit(_T_BIT_XTI_RCVBUF, ss->options.flags))
		size += _T_SPACE_SIZEOF(ss->options.xti.rcvbuf);
	if (t_tst_bit(_T_BIT_XTI_RCVLOWAT, ss->options.flags))
		size += _T_SPACE_SIZEOF(ss->options.xti.rcvlowat);
	if (t_tst_bit(_T_BIT_XTI_SNDBUF, ss->options.flags))
		size += _T_SPACE_SIZEOF(ss->options.xti.sndbuf);
	if (t_tst_bit(_T_BIT_XTI_SNDLOWAT, ss->options.flags))
		size += _T_SPACE_SIZEOF(ss->options.xti.sndlowat);
	if (ss->p.prot.family == PF_INET) {
		{

#if 0
			if (t_tst_bit(_T_BIT_IP_OPTIONS, ss->options.flags))
#endif
				size += _T_SPACE_SIZEOF(ss->options.ip.options);
#if 0
			if (t_tst_bit(_T_BIT_IP_TOS, ss->options.flags))
#endif
				size += _T_SPACE_SIZEOF(ss->options.ip.tos);
		}
		if (t_tst_bit(_T_BIT_IP_TTL, ss->options.flags))
			size += _T_SPACE_SIZEOF(ss->options.ip.ttl);
		if (t_tst_bit(_T_BIT_IP_REUSEADDR, ss->options.flags))
			size += _T_SPACE_SIZEOF(ss->options.ip.reuseaddr);
		if (t_tst_bit(_T_BIT_IP_DONTROUTE, ss->options.flags))
			size += _T_SPACE_SIZEOF(ss->options.ip.dontroute);
		if (t_tst_bit(_T_BIT_IP_BROADCAST, ss->options.flags))
			size += _T_SPACE_SIZEOF(ss->options.ip.broadcast);
		if (t_tst_bit(_T_BIT_IP_ADDR, ss->options.flags))
			size += _T_SPACE_SIZEOF(ss->options.ip.addr);
		switch (ss->p.prot.protocol) {
		case T_INET_TCP:
			if (t_tst_bit(_T_BIT_TCP_NODELAY, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.tcp.nodelay);
			if (t_tst_bit(_T_BIT_TCP_MAXSEG, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.tcp.maxseg);
			if (t_tst_bit(_T_BIT_TCP_KEEPALIVE, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.tcp.keepalive);
			if (t_tst_bit(_T_BIT_TCP_CORK, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.tcp.cork);
			if (t_tst_bit(_T_BIT_TCP_KEEPIDLE, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.tcp.keepidle);
			if (t_tst_bit(_T_BIT_TCP_KEEPINTVL, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.tcp.keepitvl);
			if (t_tst_bit(_T_BIT_TCP_KEEPCNT, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.tcp.keepcnt);
			if (t_tst_bit(_T_BIT_TCP_SYNCNT, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.tcp.syncnt);
			if (t_tst_bit(_T_BIT_TCP_LINGER2, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.tcp.linger2);
			if (t_tst_bit(_T_BIT_TCP_DEFER_ACCEPT, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.tcp.defer_accept);
			if (t_tst_bit(_T_BIT_TCP_WINDOW_CLAMP, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.tcp.window_clamp);
#if 0

			if (t_tst_bit(_T_BIT_TCP_INFO, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.tcp.info);
#endif
			if (t_tst_bit(_T_BIT_TCP_QUICKACK, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.tcp.quickack);
			break;
#if defined HAVE_OPENSS7_SCTP
		case T_INET_SCTP:
			if (t_tst_bit(_T_BIT_SCTP_NODELAY, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.nodelay);
			if (t_tst_bit(_T_BIT_SCTP_MAXSEG, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.maxseg);
			if (t_tst_bit(_T_BIT_SCTP_CORK, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.cork);
			if (t_tst_bit(_T_BIT_SCTP_PPI, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.ppi);
			if (t_tst_bit(_T_BIT_SCTP_SID, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.sid);
			if (t_tst_bit(_T_BIT_SCTP_SSN, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.ssn);
			if (t_tst_bit(_T_BIT_SCTP_TSN, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.tsn);
			if (t_tst_bit(_T_BIT_SCTP_RECVOPT, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.recvopt);
			if (t_tst_bit(_T_BIT_SCTP_COOKIE_LIFE, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.cookie_life);
			if (t_tst_bit(_T_BIT_SCTP_SACK_DELAY, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.sack_delay);
			if (t_tst_bit(_T_BIT_SCTP_PATH_MAX_RETRANS, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.path_max_retrans);
			if (t_tst_bit(_T_BIT_SCTP_ASSOC_MAX_RETRANS, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.assoc_max_retrans);
			if (t_tst_bit(_T_BIT_SCTP_MAX_INIT_RETRIES, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.max_init_retries);
			if (t_tst_bit(_T_BIT_SCTP_HEARTBEAT_ITVL, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.heartbeat_itvl);
			if (t_tst_bit(_T_BIT_SCTP_RTO_INITIAL, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.rto_initial);
			if (t_tst_bit(_T_BIT_SCTP_RTO_MIN, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.rto_min);
			if (t_tst_bit(_T_BIT_SCTP_RTO_MAX, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.rto_max);
			{

#if 0
				if (t_tst_bit(_T_BIT_SCTP_OSTREAMS, ss->options.flags))
#endif
					size += _T_SPACE_SIZEOF(ss->options.sctp.ostreams);
#if 0
				if (t_tst_bit(_T_BIT_SCTP_ISTREAMS, ss->options.flags))
#endif
					size += _T_SPACE_SIZEOF(ss->options.sctp.istreams);
			}
			if (t_tst_bit(_T_BIT_SCTP_COOKIE_INC, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.cookie_inc);
			if (t_tst_bit(_T_BIT_SCTP_THROTTLE_ITVL, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.throttle_itvl);
			if (t_tst_bit(_T_BIT_SCTP_MAC_TYPE, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.mac_type);
			if (t_tst_bit(_T_BIT_SCTP_HB, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.hb);
			if (t_tst_bit(_T_BIT_SCTP_RTO, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.rto);
			if (t_tst_bit(_T_BIT_SCTP_STATUS, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.status);
			if (t_tst_bit(_T_BIT_SCTP_DEBUG, ss->options.flags))
				size += _T_SPACE_SIZEOF(ss->options.sctp.debug);
			break;
#endif
		}
	}
	return (size);
}

STATIC int
t_build_conn_opts(ss_t *ss, unsigned char *op, size_t olen)
{
	struct t_opthdr *oh;
	struct sock *sk;

	if (op == NULL || olen == 0)
		return (0);
	if (!ss || !ss->sock || !(sk = ss->sock->sk))
		goto eproto;
	oh = _T_OPT_FIRSTHDR_OFS(op, olen, 0);
	if (t_tst_bit(_T_BIT_XTI_DEBUG, ss->options.flags)) {
		if (oh == NULL)
			goto efault;
		oh->len = _T_LENGTH_SIZEOF(ss->options.xti.debug);
		oh->level = XTI_GENERIC;
		oh->name = XTI_DEBUG;
		oh->status = T_SUCCESS;
		bcopy(ss->options.xti.debug, T_OPT_DATA(oh), sizeof(ss->options.xti.debug));
		oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
	}
	if (t_tst_bit(_T_BIT_XTI_LINGER, ss->options.flags)) {
		if (oh == NULL)
			goto efault;
		oh->len = _T_LENGTH_SIZEOF(ss->options.xti.linger);
		oh->level = XTI_GENERIC;
		oh->name = XTI_LINGER;
		oh->status = T_SUCCESS;
		if ((sock_tst_linger(sk) == 1) != (ss->options.xti.linger.l_onoff == T_YES)) {
			ss->options.xti.linger.l_onoff = sock_tst_linger(sk) ? T_YES : T_NO;
		}
		if (ss->options.xti.linger.l_onoff == T_YES) {
			if (ss->options.xti.linger.l_linger != sk->sk_lingertime / HZ) {
				if (ss->options.xti.linger.l_linger != T_UNSPEC
				    && ss->options.xti.linger.l_linger < sk->sk_lingertime / HZ)
					oh->status = T_PARTSUCCESS;
				ss->options.xti.linger.l_linger = sk->sk_lingertime / HZ;
			}
		} else
			ss->options.xti.linger.l_linger = T_UNSPEC;
		*((struct t_linger *) T_OPT_DATA(oh)) = ss->options.xti.linger;
		oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
	}
	if (t_tst_bit(_T_BIT_XTI_RCVBUF, ss->options.flags)) {
		if (oh == NULL)
			goto efault;
		oh->len = _T_LENGTH_SIZEOF(ss->options.xti.rcvbuf);
		oh->level = XTI_GENERIC;
		oh->name = XTI_RCVBUF;
		oh->status = T_SUCCESS;
		if (ss->options.xti.rcvbuf != sk->sk_rcvbuf / 2) {
			if (ss->options.xti.rcvbuf != T_UNSPEC
			    && ss->options.xti.rcvbuf < sk->sk_rcvbuf / 2)
				oh->status = T_PARTSUCCESS;
			ss->options.xti.rcvbuf = sk->sk_rcvbuf / 2;
		}
		*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.xti.rcvbuf;
		oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
	}
	if (t_tst_bit(_T_BIT_XTI_RCVLOWAT, ss->options.flags)) {
		if (oh == NULL)
			goto efault;
		oh->len = _T_LENGTH_SIZEOF(ss->options.xti.rcvlowat);
		oh->level = XTI_GENERIC;
		oh->name = XTI_RCVLOWAT;
		oh->status = T_SUCCESS;
		if (ss->options.xti.rcvlowat != sk->sk_rcvlowat) {
			if (ss->options.xti.rcvlowat != T_UNSPEC
			    && ss->options.xti.rcvlowat < sk->sk_rcvlowat)
				oh->status = T_PARTSUCCESS;
			ss->options.xti.rcvlowat = sk->sk_rcvlowat;
		}
		*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.xti.rcvlowat;
		oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
	}
	if (t_tst_bit(_T_BIT_XTI_SNDBUF, ss->options.flags)) {
		if (oh == NULL)
			goto efault;
		oh->len = _T_LENGTH_SIZEOF(ss->options.xti.sndbuf);
		oh->level = XTI_GENERIC;
		oh->name = XTI_SNDBUF;
		oh->status = T_SUCCESS;
		if (ss->options.xti.sndbuf != sk->sk_sndbuf / 2) {
			if (ss->options.xti.sndbuf != T_UNSPEC
			    && ss->options.xti.sndbuf < sk->sk_sndbuf / 2)
				oh->status = T_PARTSUCCESS;
			ss->options.xti.sndbuf = sk->sk_sndbuf / 2;
		}
		*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.xti.sndbuf;
		oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
	}
	if (t_tst_bit(_T_BIT_XTI_SNDLOWAT, ss->options.flags)) {
		if (oh == NULL)
			goto efault;
		oh->len = _T_LENGTH_SIZEOF(ss->options.xti.sndlowat);
		oh->level = XTI_GENERIC;
		oh->name = XTI_SNDLOWAT;
		oh->status = T_SUCCESS;
		if (ss->options.xti.sndlowat != 1) {
			if (ss->options.xti.sndlowat != T_UNSPEC && ss->options.xti.sndlowat < 1)
				oh->status = T_PARTSUCCESS;
			ss->options.xti.sndlowat = 1;
		}
		*((t_uscalar_t *) T_OPT_DATA(oh)) = t_defaults.xti.sndlowat;
		oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
	}
	if (ss->p.prot.family == PF_INET) {
		struct inet_opt *np = inet_sk(sk);

#if 0
		if (t_tst_bit(_T_BIT_IP_OPTIONS, ss->options.flags))
#endif
		{
			if (oh == NULL)
				goto efault;
			oh->len = _T_LENGTH_SIZEOF(ss->options.ip.options);
			oh->level = T_INET_IP;
			oh->name = T_IP_OPTIONS;
			oh->status = T_SUCCESS;
			oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
		}
#if 0
		if (t_tst_bit(_T_BIT_IP_TOS, ss->options.flags))
#endif
		{
			if (oh == NULL)
				goto efault;
			oh->len = _T_LENGTH_SIZEOF(ss->options.ip.tos);
			oh->level = T_INET_IP;
			oh->name = T_IP_TOS;
			oh->status = T_SUCCESS;
			if (ss->options.ip.tos != np->tos) {
				if (ss->options.ip.tos > np->tos)
					oh->status = T_PARTSUCCESS;
				ss->options.ip.tos = np->tos;
			}
			*((unsigned char *) T_OPT_DATA(oh)) = ss->options.ip.tos;
			oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
		}
		if (t_tst_bit(_T_BIT_IP_TTL, ss->options.flags)) {
			if (oh == NULL)
				goto efault;
			oh->len = _T_LENGTH_SIZEOF(ss->options.ip.ttl);
			oh->level = T_INET_IP;
			oh->name = T_IP_TTL;
			oh->status = T_SUCCESS;
#ifdef HAVE_STRUCT_SOCK_PROTINFO_AF_INET_TTL
			if (ss->options.ip.ttl != np->ttl) {
				if (ss->options.ip.ttl > np->ttl)
					oh->status = T_PARTSUCCESS;
				ss->options.ip.ttl = np->ttl;
			}
#else
#ifdef HAVE_STRUCT_SOCK_PROTINFO_AF_INET_UC_TTL
			if (ss->options.ip.ttl != np->uc_ttl) {
				if (ss->options.ip.ttl > np->uc_ttl)
					oh->status = T_PARTSUCCESS;
				ss->options.ip.ttl = np->uc_ttl;
			}
#endif
#endif
			*((unsigned char *) T_OPT_DATA(oh)) = ss->options.ip.ttl;
			oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
		}
		if (t_tst_bit(_T_BIT_IP_REUSEADDR, ss->options.flags)) {
			if (oh == NULL)
				goto efault;
			oh->len = _T_LENGTH_SIZEOF(unsigned int);

			oh->level = T_INET_IP;
			oh->name = T_IP_REUSEADDR;
			oh->status = T_SUCCESS;
			if ((ss->options.ip.reuseaddr == T_NO) != (sk->sk_reuse == 0)) {
				oh->status = T_PARTSUCCESS;
				ss->options.ip.reuseaddr = sk->sk_reuse ? T_YES : T_NO;
			}
			*((unsigned int *) T_OPT_DATA(oh)) = ss->options.ip.reuseaddr;
			oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
		}
		if (t_tst_bit(_T_BIT_IP_DONTROUTE, ss->options.flags)) {
			if (oh == NULL)
				goto efault;
			oh->len = _T_LENGTH_SIZEOF(unsigned int);

			oh->level = T_INET_IP;
			oh->name = T_IP_DONTROUTE;
			oh->status = T_SUCCESS;
			if ((ss->options.ip.dontroute == T_NO) != (sock_tst_localroute(sk) == 0)) {
				oh->status = T_PARTSUCCESS;
				ss->options.ip.dontroute = sock_tst_localroute(sk) ? T_YES : T_NO;
			}
			*((unsigned int *) T_OPT_DATA(oh)) = ss->options.ip.dontroute;
			oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
		}
		if (t_tst_bit(_T_BIT_IP_BROADCAST, ss->options.flags)) {
			if (oh == NULL)
				goto efault;
			oh->len = _T_LENGTH_SIZEOF(unsigned int);

			oh->level = T_INET_IP;
			oh->name = T_IP_BROADCAST;
			oh->status = T_SUCCESS;
			if ((ss->options.ip.broadcast == T_NO) != (sock_tst_broadcast(sk) == 0)) {
				oh->status = T_PARTSUCCESS;
				ss->options.ip.broadcast = sock_tst_broadcast(sk) ? T_YES : T_NO;
			}
			*((unsigned int *) T_OPT_DATA(oh)) = ss->options.ip.broadcast;
			oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
		}
		if (t_tst_bit(_T_BIT_IP_ADDR, ss->options.flags)) {
			if (oh == NULL)
				goto efault;
			oh->len = _T_LENGTH_SIZEOF(uint32_t);

			oh->level = T_INET_IP;
			oh->name = T_IP_ADDR;
			oh->status = T_SUCCESS;
			*((uint32_t *) T_OPT_DATA(oh)) = ss->options.ip.addr;
			oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
		}
		switch (ss->p.prot.protocol) {
		case T_INET_TCP:
		{
			struct tcp_opt *tp = tcp_sk(sk);

			if (t_tst_bit(_T_BIT_TCP_NODELAY, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_TCP;
				oh->name = T_TCP_NODELAY;
				oh->status = T_SUCCESS;
				if ((ss->options.tcp.nodelay == T_NO) != (tp->nonagle == 0)) {
					oh->status = T_PARTSUCCESS;
					ss->options.tcp.nodelay = tp->nonagle ? T_YES : T_NO;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.tcp.nodelay;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_TCP_MAXSEG, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_TCP;
				oh->name = T_TCP_MAXSEG;
				oh->status = T_SUCCESS;
				if (ss->options.tcp.maxseg != tcp_user_mss(tp)) {
					if (ss->options.tcp.maxseg > tcp_user_mss(tp))
						oh->status = T_PARTSUCCESS;
					ss->options.tcp.maxseg = tcp_user_mss(tp);
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.tcp.maxseg;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_TCP_KEEPALIVE, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(struct t_kpalive);

				oh->level = T_INET_TCP;
				oh->name = T_TCP_KEEPALIVE;
				oh->status = T_SUCCESS;
				if ((ss->options.tcp.keepalive.kp_onoff != T_NO) !=
				    (sock_tst_keepopen(sk) != 0)) {
					ss->options.tcp.keepalive.kp_onoff =
					    sock_tst_keepopen(sk) ? T_YES : T_NO;
				}
				if (ss->options.tcp.keepalive.kp_onoff == T_YES) {
					if (ss->options.tcp.keepalive.kp_timeout !=
					    tp->keepalive_time / 60 / HZ) {
						if (ss->options.tcp.keepalive.kp_timeout != T_UNSPEC
						    && ss->options.tcp.keepalive.kp_timeout >
						    tp->keepalive_time / 60 / HZ)
							oh->status = T_PARTSUCCESS;
						ss->options.tcp.keepalive.kp_timeout =
						    tp->keepalive_time / 60 / HZ;
					}
				} else
					ss->options.tcp.keepalive.kp_timeout = T_UNSPEC;
				*((struct t_kpalive *) T_OPT_DATA(oh)) = ss->options.tcp.keepalive;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_TCP_CORK, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_TCP;
				oh->name = T_TCP_CORK;
				oh->status = T_SUCCESS;
				if ((ss->options.tcp.cork == T_YES) != (tp->nonagle == 2)) {
					oh->status = T_FAILURE;
					ss->options.tcp.cork = (tp->nonagle == 2) ? T_YES : T_NO;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.tcp.cork;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_TCP_KEEPIDLE, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_TCP;
				oh->name = T_TCP_KEEPIDLE;
				oh->status = T_SUCCESS;
				if (ss->options.tcp.keepidle == T_UNSPEC)
					ss->options.tcp.keepidle = tp->keepalive_time / HZ;
				else if (ss->options.tcp.keepidle != tp->keepalive_time / HZ) {
					oh->status = T_PARTSUCCESS;
					ss->options.tcp.keepidle = tp->keepalive_time / HZ;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.tcp.keepidle;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_TCP_KEEPINTVL, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_TCP;
				oh->name = T_TCP_KEEPINTVL;
				oh->status = T_SUCCESS;
				if (ss->options.tcp.keepitvl == T_UNSPEC)
					ss->options.tcp.keepitvl = tp->keepalive_intvl / HZ;
				else if (ss->options.tcp.keepitvl != tp->keepalive_intvl / HZ) {
					oh->status = T_PARTSUCCESS;
					ss->options.tcp.keepcnt = tp->keepalive_intvl / HZ;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.tcp.keepcnt;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_TCP_KEEPCNT, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_TCP;
				oh->name = T_TCP_KEEPCNT;
				oh->status = T_SUCCESS;
				if (ss->options.tcp.keepcnt == T_UNSPEC)
					ss->options.tcp.keepcnt = tp->keepalive_probes;
				else if (ss->options.tcp.keepcnt != tp->keepalive_probes) {
					oh->status = T_FAILURE;
					ss->options.tcp.keepcnt = tp->keepalive_probes;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.tcp.keepcnt;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_TCP_SYNCNT, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_TCP;
				oh->name = T_TCP_SYNCNT;
				oh->status = T_SUCCESS;
				if (ss->options.tcp.syncnt == T_UNSPEC)
					ss->options.tcp.syncnt = sock_syn_retries(sk);
				else if (ss->options.tcp.syncnt != sock_syn_retries(sk)) {
					oh->status = T_FAILURE;
					ss->options.tcp.syncnt = sock_syn_retries(sk);
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.tcp.syncnt;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_TCP_LINGER2, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_TCP;
				oh->name = T_TCP_LINGER2;
				oh->status = T_SUCCESS;
				if (ss->options.tcp.linger2 == T_UNSPEC)
					ss->options.tcp.linger2 = tp->linger2 / HZ;
				else if (ss->options.tcp.linger2 != tp->linger2 / HZ) {
					oh->status = T_PARTSUCCESS;
					ss->options.tcp.linger2 = tp->linger2 / HZ;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.tcp.linger2;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_TCP_DEFER_ACCEPT, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_TCP;
				oh->name = T_TCP_DEFER_ACCEPT;
				oh->status = T_SUCCESS;
				if (ss->options.tcp.defer_accept == T_UNSPEC)
					ss->options.tcp.defer_accept =
					    (TCP_TIMEOUT_INIT / HZ) << sock_defer_accept(sk);
				else if (ss->options.tcp.defer_accept !=
					 ((TCP_TIMEOUT_INIT / HZ) << sock_defer_accept(sk))) {
					oh->status = T_PARTSUCCESS;
					ss->options.tcp.defer_accept =
					    ((TCP_TIMEOUT_INIT / HZ) << sock_defer_accept(sk));
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.tcp.defer_accept;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_TCP_WINDOW_CLAMP, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_TCP;
				oh->name = T_TCP_WINDOW_CLAMP;
				oh->status = T_SUCCESS;
				if (ss->options.tcp.window_clamp == T_UNSPEC)
					ss->options.tcp.window_clamp = tp->window_clamp;
				else if (ss->options.tcp.window_clamp != tp->window_clamp) {
					oh->status = T_PARTSUCCESS;
					ss->options.tcp.window_clamp = tp->window_clamp;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.tcp.window_clamp;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_TCP_INFO, ss->options.flags)) {

			}
			if (t_tst_bit(_T_BIT_TCP_QUICKACK, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_TCP;
				oh->name = T_TCP_QUICKACK;
				oh->status = T_SUCCESS;
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.tcp.quickack;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			break;
		}
#if defined HAVE_OPENSS7_SCTP
		case T_INET_SCTP:
		{
			struct sctp_opt *sp = sctp_sk(sk);

			if (t_tst_bit(_T_BIT_SCTP_NODELAY, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_NODELAY;
				oh->status = T_SUCCESS;
				if ((ss->options.sctp.nodelay != T_NO) != (sp->nonagle != 0)) {
					oh->status = T_PARTSUCCESS;
					ss->options.sctp.nodelay = sp->nonagle ? T_YES : T_NO;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.nodelay;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_MAXSEG, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_MAXSEG;
				oh->status = T_SUCCESS;
				if (ss->options.sctp.maxseg != sp->user_amps) {
					if (ss->options.sctp.maxseg > sp->user_amps)
						oh->status = T_PARTSUCCESS;
					ss->options.sctp.maxseg = sp->user_amps;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.maxseg;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_CORK, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_CORK;
				oh->status = T_SUCCESS;
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.cork;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_PPI, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_PPI;
				oh->status = T_SUCCESS;
				ss->options.sctp.ppi = sp->ppi;
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.ppi;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_SID, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_SID;
				oh->status = T_SUCCESS;
				ss->options.sctp.sid = sp->sid;
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.sid;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_SSN, ss->options.flags)) {

			}
			if (t_tst_bit(_T_BIT_SCTP_TSN, ss->options.flags)) {

			}
			if (t_tst_bit(_T_BIT_SCTP_RECVOPT, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_RECVOPT;
				oh->status = T_SUCCESS;

				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.recvopt;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_COOKIE_LIFE, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_COOKIE_LIFE;
				oh->status = T_SUCCESS;
				if (ss->options.sctp.cookie_life != sp->ck_life / HZ * 1000) {
					if (ss->options.sctp.cookie_life < sp->ck_life / HZ * 1000)
						oh->status = T_PARTSUCCESS;
					ss->options.sctp.cookie_life = sp->ck_life / HZ * 1000;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.cookie_life;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_SACK_DELAY, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_SACK_DELAY;
				oh->status = T_SUCCESS;
				if (ss->options.sctp.sack_delay != sp->max_sack / HZ * 1000) {
					if (ss->options.sctp.sack_delay < sp->max_sack / HZ * 1000)
						oh->status = T_PARTSUCCESS;
					ss->options.sctp.sack_delay = sp->max_sack / HZ * 1000;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.sack_delay;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_PATH_MAX_RETRANS, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_PATH_MAX_RETRANS;
				oh->status = T_SUCCESS;

				*((t_uscalar_t *) T_OPT_DATA(oh)) =
				    ss->options.sctp.path_max_retrans;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_ASSOC_MAX_RETRANS, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_ASSOC_MAX_RETRANS;
				oh->status = T_SUCCESS;

				*((t_uscalar_t *) T_OPT_DATA(oh)) =
				    ss->options.sctp.assoc_max_retrans;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_MAX_INIT_RETRIES, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_MAX_INIT_RETRIES;
				oh->status = T_SUCCESS;

				*((t_uscalar_t *) T_OPT_DATA(oh)) =
				    ss->options.sctp.max_init_retries;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_HEARTBEAT_ITVL, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_HEARTBEAT_ITVL;
				oh->status = T_SUCCESS;
				if (ss->options.sctp.heartbeat_itvl != sp->hb_itvl / HZ * 1000) {
					if (ss->options.sctp.heartbeat_itvl <
					    sp->hb_itvl / HZ * 1000)
						oh->status = T_PARTSUCCESS;
					ss->options.sctp.heartbeat_itvl = sp->hb_itvl / HZ * 1000;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.heartbeat_itvl;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_RTO_INITIAL, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_RTO_INITIAL;
				oh->status = T_SUCCESS;
				if (ss->options.sctp.rto_initial != sp->rto_ini / HZ * 1000) {
					if (ss->options.sctp.rto_initial < sp->rto_ini / HZ * 1000)
						oh->status = T_PARTSUCCESS;
					ss->options.sctp.rto_initial = sp->rto_ini / HZ * 1000;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.rto_initial;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_RTO_MIN, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_RTO_MIN;
				oh->status = T_SUCCESS;
				if (ss->options.sctp.rto_min != sp->rto_min / HZ * 1000) {
					if (ss->options.sctp.rto_min < sp->rto_min / HZ * 1000)
						oh->status = T_PARTSUCCESS;
					ss->options.sctp.rto_min = sp->rto_min / HZ * 1000;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.rto_min;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_RTO_MAX, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_RTO_MAX;
				oh->status = T_SUCCESS;
				if (ss->options.sctp.rto_max != sp->rto_max / HZ * 1000) {
					if (ss->options.sctp.rto_max < sp->rto_max / HZ * 1000)
						oh->status = T_PARTSUCCESS;
					ss->options.sctp.rto_max = sp->rto_max / HZ * 1000;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.rto_max;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
#if 0
			if (t_tst_bit(_T_BIT_SCTP_OSTREAMS, ss->options.flags))
#endif
			{
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_OSTREAMS;
				oh->status = T_SUCCESS;
				if (ss->options.sctp.ostreams != sp->req_ostr) {
					if (ss->options.sctp.ostreams > sp->req_ostr)
						oh->status = T_PARTSUCCESS;
					ss->options.sctp.ostreams = sp->req_ostr;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.ostreams;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
#if 0
			if (t_tst_bit(_T_BIT_SCTP_ISTREAMS, ss->options.flags))
#endif
			{
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_ISTREAMS;
				oh->status = T_SUCCESS;
				if (ss->options.sctp.istreams != sp->max_istr) {
					if (ss->options.sctp.istreams > sp->max_istr)
						oh->status = T_PARTSUCCESS;
					ss->options.sctp.istreams = sp->max_istr;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.istreams;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_COOKIE_INC, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_COOKIE_INC;
				oh->status = T_SUCCESS;
				if (ss->options.sctp.cookie_inc != sp->ck_inc / HZ * 1000) {
					if (ss->options.sctp.cookie_inc < sp->ck_inc / HZ * 1000)
						oh->status = T_PARTSUCCESS;
					ss->options.sctp.cookie_inc = sp->ck_inc / HZ * 1000;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.cookie_inc;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_THROTTLE_ITVL, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_THROTTLE_ITVL;
				oh->status = T_SUCCESS;
				if (ss->options.sctp.throttle_itvl != sp->throttle / HZ * 1000) {
					if (ss->options.sctp.throttle_itvl <
					    sp->throttle / HZ * 1000)
						oh->status = T_PARTSUCCESS;
					ss->options.sctp.throttle_itvl = sp->throttle / HZ * 1000;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.throttle_itvl;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_MAC_TYPE, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_MAC_TYPE;
				oh->status = T_SUCCESS;
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.mac_type;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_CKSUM_TYPE, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_CKSUM_TYPE;
				oh->status = T_SUCCESS;
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.cksum_type;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_HB, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(struct t_sctp_hb);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_HB;
				oh->status = T_SUCCESS;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_RTO, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(struct t_sctp_rto);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_RTO;
				oh->status = T_SUCCESS;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_STATUS, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len =
				    T_SPACE(sizeof(struct t_sctp_status) +
					    sizeof(struct t_sctp_dest_status));
				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_STATUS;
				oh->status = T_SUCCESS;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_DEBUG, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_DEBUG;
				oh->status = T_SUCCESS;
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.debug;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
#if defined CONFIG_SCTP_ECN
			if (t_tst_bit(_T_BIT_SCTP_ECN, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_ECN;
				oh->status = T_SUCCESS;
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.ecn;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
#endif
#if defined CONFIG_SCTP_ADD_IP || defined CONFIG_SCTP_ADAPTATION_LAYER_INFO
			if (t_tst_bit(_T_BIT_SCTP_ALI, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_ALI;
				oh->status = T_SUCCESS;
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.ali;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
#endif
#if defined CONFIG_SCTP_ADD_IP
			if (t_tst_bit(_T_BIT_SCTP_ADD, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_ADD;
				oh->status = T_SUCCESS;

				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.add;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_SET, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_SET;
				oh->status = T_SUCCESS;

				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.set;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_ADD_IP, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_ADD_IP;
				oh->status = T_SUCCESS;

				*((struct sockaddr_in *) T_OPT_DATA(oh)) = ss->options.sctp.add_ip;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_DEL_IP, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_DEL_IP;
				oh->status = T_SUCCESS;

				*((struct sockaddr_in *) T_OPT_DATA(oh)) = ss->options.sctp.del_ip;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_SET_IP, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_SET_IP;
				oh->status = T_SUCCESS;

				*((struct sockaddr_in *) T_OPT_DATA(oh)) = ss->options.sctp.set_ip;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
#endif
#if defined CONFIG_SCTP_PARTIAL_RELIABILITY
			if (t_tst_bit(_T_BIT_SCTP_PR, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_PR;
				oh->status = T_SUCCESS;

				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.pr;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
#endif
#if defined CONFIG_SCTP_LIFETIMES || defined CONFIG_SCTP_PARTIAL_RELIABILITY
			if (t_tst_bit(_T_BIT_SCTP_LIFETIME, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_LIFETIME;
				oh->status = T_SUCCESS;
				if (ss->options.sctp.lifetime != sp->life / HZ * 1000) {
					if (ss->options.sctp.lifetime < sp->life / HZ * 1000)
						oh->status = T_PARTSUCCESS;
					ss->options.sctp.lifetime = sp->life / HZ * 1000;
				}
				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.lifetime;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
#endif
			if (t_tst_bit(_T_BIT_SCTP_DISPOSITION, ss->options.flags)) {
				if (oh == NULL)
					goto efault;

				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_DISPOSITION;
				oh->status = T_SUCCESS;

				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.disposition;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			if (t_tst_bit(_T_BIT_SCTP_MAX_BURST, ss->options.flags)) {
				if (oh == NULL)
					goto efault;
				oh->len = _T_LENGTH_SIZEOF(t_uscalar_t);

				oh->level = T_INET_SCTP;
				oh->name = T_SCTP_MAX_BURST;
				oh->status = T_SUCCESS;

				*((t_uscalar_t *) T_OPT_DATA(oh)) = ss->options.sctp.max_burst;
				oh = _T_OPT_NEXTHDR_OFS(op, olen, oh, 0);
			}
			break;
		}
#endif
		}
	}

	assure(oh == NULL);
	return (olen);
	// return ((unsigned char *) oh - op);
      eproto:
	swerr();
	return (-EPROTO);
      efault:
	swerr();
	return (-EFAULT);
}

#ifdef __LP64__
#undef MAX_SCHEDULE_TIMEOUT
#define MAX_SCHEDULE_TIMEOUT INT_MAX
#endif

STATIC int
t_set_options(ss_t *ss)
{
	struct sock *sk;

	if (!ss || !ss->sock || !(sk = ss->sock->sk))
		goto eproto;
	if (t_tst_bit(_T_BIT_XTI_DEBUG, ss->options.flags)) {

	}
	if (t_tst_bit(_T_BIT_XTI_LINGER, ss->options.flags)) {
		struct t_linger *valp = &ss->options.xti.linger;

		if (valp->l_onoff == T_NO)
			valp->l_linger = T_UNSPEC;
		else {
			if (valp->l_linger == T_UNSPEC)
				valp->l_linger = t_defaults.xti.linger.l_linger;
			if (valp->l_linger == T_INFINITE)
				valp->l_linger = MAX_SCHEDULE_TIMEOUT / HZ;
			if (valp->l_linger >= MAX_SCHEDULE_TIMEOUT / HZ)
				valp->l_linger = MAX_SCHEDULE_TIMEOUT / HZ;
		}
		if (valp->l_onoff == T_YES) {
			sock_set_linger(sk);
			sk->sk_lingertime = valp->l_linger * HZ;
		} else {
			sock_clr_linger(sk);
			sk->sk_lingertime = 0;
		}
	}
	if (t_tst_bit(_T_BIT_XTI_RCVBUF, ss->options.flags)) {
		t_uscalar_t *valp = &ss->options.xti.rcvbuf;

		if (*valp > sysctl_rmem_max)
			*valp = sysctl_rmem_max;
		if (*valp < SOCK_MIN_RCVBUF / 2)
			*valp = SOCK_MIN_RCVBUF / 2;
		sk->sk_rcvbuf = *valp * 2;
	}
	if (t_tst_bit(_T_BIT_XTI_RCVLOWAT, ss->options.flags)) {
		t_uscalar_t *valp = &ss->options.xti.rcvlowat;

		if (*valp < 1)
			*valp = 1;
		if (*valp > INT_MAX)
			*valp = INT_MAX;
		sk->sk_rcvlowat = *valp;
	}
	if (t_tst_bit(_T_BIT_XTI_SNDBUF, ss->options.flags)) {
		t_uscalar_t *valp = &ss->options.xti.sndbuf;

		if (*valp > sysctl_wmem_max)
			*valp = sysctl_wmem_max;
		if (*valp < SOCK_MIN_SNDBUF / 2)
			*valp = SOCK_MIN_SNDBUF / 2;
		sk->sk_sndbuf = *valp * 2;
	}
	if (t_tst_bit(_T_BIT_XTI_SNDLOWAT, ss->options.flags)) {
		t_uscalar_t *valp = &ss->options.xti.sndlowat;

		if (*valp < 1)
			*valp = 1;
		if (*valp > 1)
			*valp = 1;
	}
	if (ss->p.prot.family == PF_INET) {
		struct inet_opt *np = inet_sk(sk);

		if (t_tst_bit(_T_BIT_IP_OPTIONS, ss->options.flags)) {
			unsigned char *valp = ss->options.ip.options;

			(void) valp;
		}
		if (t_tst_bit(_T_BIT_IP_TOS, ss->options.flags)) {
			unsigned char *valp = &ss->options.ip.tos;

			np->tos = *valp;
		}
		if (t_tst_bit(_T_BIT_IP_TTL, ss->options.flags)) {
			unsigned char *valp = &ss->options.ip.ttl;

			if (*valp < 1)
				*valp = 1;
#ifdef HAVE_STRUCT_SOCK_PROTINFO_AF_INET_TTL
			np->ttl = *valp;
#else
#ifdef HAVE_STRUCT_SOCK_PROTINFO_AF_INET_UC_TTL
			np->uc_ttl = *valp;
#endif
#endif
		}
		if (t_tst_bit(_T_BIT_IP_REUSEADDR, ss->options.flags)) {
			unsigned int *valp = &ss->options.ip.reuseaddr;

			sk->sk_reuse = (*valp == T_YES) ? 1 : 0;
		}
		if (t_tst_bit(_T_BIT_IP_DONTROUTE, ss->options.flags)) {
			unsigned int *valp = &ss->options.ip.dontroute;

			if (*valp == T_YES)
				sock_set_localroute(sk);
			else
				sock_clr_localroute(sk);
		}
		if (t_tst_bit(_T_BIT_IP_BROADCAST, ss->options.flags)) {
			unsigned int *valp = &ss->options.ip.broadcast;

			if (*valp == T_YES)
				sock_set_broadcast(sk);
			else
				sock_clr_broadcast(sk);
		}
		if (t_tst_bit(_T_BIT_IP_ADDR, ss->options.flags)) {
			uint32_t *valp = &ss->options.ip.addr;

			sock_saddr(sk) = *valp;
		}
		switch (ss->p.prot.protocol) {
		case T_INET_UDP:
			if (t_tst_bit(_T_BIT_UDP_CHECKSUM, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.udp.checksum;

				sk->sk_no_check =
				    (*valp == T_YES) ? UDP_CSUM_DEFAULT : UDP_CSUM_NOXMIT;
			}
			break;
		case T_INET_TCP:
		{
			struct tcp_opt *tp = tcp_sk(sk);

			if (t_tst_bit(_T_BIT_TCP_NODELAY, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.tcp.nodelay;

				tp->nonagle = (*valp == T_YES) ? 1 : 0;
			}
			if (t_tst_bit(_T_BIT_TCP_MAXSEG, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.tcp.maxseg;

				if (*valp < 8)
					*valp = 8;
				if (*valp > MAX_TCP_WINDOW)
					*valp = MAX_TCP_WINDOW;
				tcp_user_mss(tp) = *valp;
			}
			if (t_tst_bit(_T_BIT_TCP_KEEPALIVE, ss->options.flags)) {
				struct t_kpalive *valp = &ss->options.tcp.keepalive;

				if (valp->kp_onoff == T_NO)
					valp->kp_timeout = T_UNSPEC;
				else {
					if (valp->kp_timeout == T_UNSPEC)
						valp->kp_timeout =
						    t_defaults.tcp.keepalive.kp_timeout;
					if (valp->kp_timeout < 1)
						valp->kp_timeout = 1;
					if (valp->kp_timeout > MAX_SCHEDULE_TIMEOUT / 60 / HZ)
						valp->kp_timeout = MAX_SCHEDULE_TIMEOUT / 60 / HZ;
				}
				if (valp->kp_onoff == T_YES)
					tp->keepalive_time = valp->kp_timeout * 60 * HZ;
#if defined HAVE_TCP_SET_KEEPALIVE_ADDR
				tcp_set_keepalive(sk, valp->kp_onoff == T_YES ? 1 : 0);
#endif
				if (valp->kp_onoff == T_YES)
					sock_set_keepopen(sk);
				else
					sock_clr_keepopen(sk);
			}
			if (t_tst_bit(_T_BIT_TCP_CORK, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.tcp.cork;

				(void) valp;
			}
			if (t_tst_bit(_T_BIT_TCP_KEEPIDLE, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.tcp.keepidle;

				(void) valp;
			}
			if (t_tst_bit(_T_BIT_TCP_KEEPINTVL, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.tcp.keepitvl;

				(void) valp;
			}
			if (t_tst_bit(_T_BIT_TCP_KEEPCNT, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.tcp.keepcnt;

				(void) valp;
			}
			if (t_tst_bit(_T_BIT_TCP_SYNCNT, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.tcp.syncnt;

				(void) valp;
			}
			if (t_tst_bit(_T_BIT_TCP_LINGER2, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.tcp.linger2;

				(void) valp;
			}
			if (t_tst_bit(_T_BIT_TCP_DEFER_ACCEPT, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.tcp.defer_accept;

				(void) valp;
			}
			if (t_tst_bit(_T_BIT_TCP_WINDOW_CLAMP, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.tcp.window_clamp;

				(void) valp;
			}
			if (t_tst_bit(_T_BIT_TCP_INFO, ss->options.flags)) {

			}
			if (t_tst_bit(_T_BIT_TCP_QUICKACK, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.tcp.quickack;

				(void) valp;
			}
			break;
		}
#if defined HAVE_OPENSS7_SCTP
		case T_INET_SCTP:
		{
			struct sctp_opt *sp = sctp_sk(sk);

			if (t_tst_bit(_T_BIT_SCTP_NODELAY, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.nodelay;

				(void) *valp;
			}
			if (t_tst_bit(_T_BIT_SCTP_MAXSEG, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.maxseg;

				if (*valp < 1)
					*valp = 1;
				if (*valp > MAX_TCP_WINDOW)
					*valp = MAX_TCP_WINDOW;
				sp->user_amps = *valp;
			}
			if (t_tst_bit(_T_BIT_SCTP_CORK, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.cork;

				if (sp->nonagle != 1)
					sp->nonagle = (*valp == T_YES) ? 2 : 0;
			}
			if (t_tst_bit(_T_BIT_SCTP_PPI, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.ppi;

				sp->ppi = *valp;
			}
			if (t_tst_bit(_T_BIT_SCTP_SID, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.sid;

				sp->sid = *valp;
			}
#if 0

			if (t_tst_bit(_T_BIT_SCTP_SSN, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.ssn;
			}
			if (t_tst_bit(_T_BIT_SCTP_TSN, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.tsn;
			}
#endif
			if (t_tst_bit(_T_BIT_SCTP_RECVOPT, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.recvopt;

				if (*valp == T_YES)
					sp->cmsg_flags |=
					    (SCTP_CMSGF_RECVSID | SCTP_CMSGF_RECVPPI |
					     SCTP_CMSGF_RECVSSN | SCTP_CMSGF_RECVTSN);
				else
					sp->cmsg_flags &=
					    ~(SCTP_CMSGF_RECVSID | SCTP_CMSGF_RECVPPI |
					      SCTP_CMSGF_RECVSSN | SCTP_CMSGF_RECVTSN);
			}
			if (t_tst_bit(_T_BIT_SCTP_COOKIE_LIFE, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.cookie_life;

				if (*valp == T_INFINITE)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				sp->ck_life = *valp / 1000 * HZ;
			}
			if (t_tst_bit(_T_BIT_SCTP_SACK_DELAY, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.sack_delay;

				if (*valp == T_INFINITE)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				sp->max_sack = *valp / 1000 * HZ;
			}
			if (t_tst_bit(_T_BIT_SCTP_PATH_MAX_RETRANS, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.path_max_retrans;

				sp->rtx_path = *valp;
			}
			if (t_tst_bit(_T_BIT_SCTP_ASSOC_MAX_RETRANS, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.assoc_max_retrans;

				sp->max_retrans = *valp;
			}
			if (t_tst_bit(_T_BIT_SCTP_MAX_INIT_RETRIES, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.max_init_retries;

				sp->max_inits = *valp;
			}
			if (t_tst_bit(_T_BIT_SCTP_HEARTBEAT_ITVL, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.heartbeat_itvl;

				if (*valp == T_INFINITE)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				sp->hb_itvl = *valp / 1000 * HZ;
#if defined CONFIG_SCTP_THROTTLE_HEARTBEATS
				sp->hb_tint = (*valp >> 1) + 1;
#endif
			}
			if (t_tst_bit(_T_BIT_SCTP_RTO_INITIAL, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.rto_initial;

				if (*valp == T_INFINITE)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (*valp > sp->rto_max / HZ * 1000)
					*valp = sp->rto_max / HZ * 1000;
				if (*valp < sp->rto_min / HZ * 1000)
					*valp = sp->rto_min / HZ * 1000;
				if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				sp->rto_ini = *valp / 1000 * HZ;
			}
			if (t_tst_bit(_T_BIT_SCTP_RTO_MIN, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.rto_min;

				if (*valp == T_INFINITE)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (*valp > sp->rto_max / HZ * 1000)
					*valp = sp->rto_max / HZ * 1000;
				if (*valp > sp->rto_ini / HZ * 1000)
					*valp = sp->rto_ini / HZ * 1000;
				if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				sp->rto_min = *valp / 1000 * HZ;
			}
			if (t_tst_bit(_T_BIT_SCTP_RTO_MAX, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.rto_max;

				if (*valp == T_INFINITE)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (*valp < sp->rto_min / HZ * 1000)
					*valp = sp->rto_min / HZ * 1000;
				if (*valp < sp->rto_ini / HZ * 1000)
					*valp = sp->rto_ini / HZ * 1000;
				if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				sp->rto_max = *valp / 1000 * HZ;
			}
			if (t_tst_bit(_T_BIT_SCTP_OSTREAMS, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.ostreams;

				sp->req_ostr = *valp;
			}
			if (t_tst_bit(_T_BIT_SCTP_ISTREAMS, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.istreams;

				sp->max_istr = *valp;
			}
			if (t_tst_bit(_T_BIT_SCTP_COOKIE_INC, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.cookie_inc;

				if (*valp == T_INFINITE)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				sp->ck_inc = *valp / 1000 * HZ;
			}
			if (t_tst_bit(_T_BIT_SCTP_THROTTLE_ITVL, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.throttle_itvl;

				if (*valp == T_INFINITE)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				sp->throttle = *valp / 1000 * HZ;
			}
			if (t_tst_bit(_T_BIT_SCTP_MAC_TYPE, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.mac_type;

				sp->hmac = *valp;
			}
			if (t_tst_bit(_T_BIT_SCTP_CKSUM_TYPE, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.cksum_type;

				sp->cksum = *valp;
			}
			if (t_tst_bit(_T_BIT_SCTP_HB, ss->options.flags)) {
				struct t_sctp_hb *valp = &ss->options.sctp.hb;

				if (valp->hb_itvl == T_UNSPEC)
					valp->hb_itvl = t_defaults.sctp.hb.hb_itvl;
				if (valp->hb_itvl == T_INFINITE)
					valp->hb_itvl = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (valp->hb_itvl / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
					valp->hb_itvl = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (valp->hb_itvl < 1000 / HZ)
					valp->hb_itvl = 1000 / HZ;

			}
			if (t_tst_bit(_T_BIT_SCTP_RTO, ss->options.flags)) {
				struct t_sctp_rto *valp = &ss->options.sctp.rto;

				if (valp->rto_initial == T_INFINITE)
					valp->rto_initial = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (valp->rto_initial / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
					valp->rto_initial = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (valp->rto_min == T_INFINITE)
					valp->rto_min = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (valp->rto_min / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
					valp->rto_min = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (valp->rto_max == T_INFINITE)
					valp->rto_max = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (valp->rto_max / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
					valp->rto_max = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;

			}
			if (t_tst_bit(_T_BIT_SCTP_STATUS, ss->options.flags)) {

			}
			if (t_tst_bit(_T_BIT_SCTP_DEBUG, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.debug;

				sp->options = *valp;
			}
#if defined CONFIG_SCTP_ECN
			if (t_tst_bit(_T_BIT_SCTP_ECN, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.ecn;

				if (*valp == T_YES)
					sp->l_caps |= SCTP_CAPS_ECN;
				else
					sp->l_caps &= ~SCTP_CAPS_ECN;
			}
#endif
#if defined CONFIG_SCTP_ADD_IP || defined CONFIG_SCTP_ADAPTATION_LAYER_INFO
			if (t_tst_bit(_T_BIT_SCTP_ALI, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.ali;

				if (*valp)
					sp->l_caps |= SCTP_CAPS_ALI;
				else
					sp->l_caps &= ~SCTP_CAPS_ALI;
			}
#endif
#if defined CONFIG_SCTP_ADD_IP
			if (t_tst_bit(_T_BIT_SCTP_ADD, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.add;

				if (*valp == T_YES)
					sp->l_caps |= SCTP_CAPS_ADD_IP;
				else
					sp->l_caps &= ~SCTP_CAPS_ADD_IP;
			}
			if (t_tst_bit(_T_BIT_SCTP_SET, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.set;

				if (*valp == T_YES)
					sp->l_caps |= SCTP_CAPS_SET_IP;
				else
					sp->l_caps &= ~SCTP_CAPS_SET_IP;
			}
#if 0
			if (t_tst_bit(_T_BIT_SCTP_ADD_IP, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.add_ip;

				sctp_add_ip(sk, valp);
			}
			if (t_tst_bit(_T_BIT_SCTP_DEL_IP, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.del_ip;

				sctp_del_ip(sk, valp);
			}
			if (t_tst_bit(_T_BIT_SCTP_SET_IP, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.set_ip;

				sctp_set_ip(sk, valp);
			}
#endif
#endif
#if defined CONFIG_SCTP_PARTIAL_RELIABILITY
			if (t_tst_bit(_T_BIT_SCTP_PR, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.pr;

				sp->prel = *valp;
			}
#endif
#if defined CONFIG_SCTP_LIFETIMES || defined CONFIG_SCTP_PARTIAL_RELIABILITY
			if (t_tst_bit(_T_BIT_SCTP_LIFETIME, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.lifetime;

				if (*valp == T_INFINITE)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
					*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
				sp->life = *valp / 1000 * HZ;
			}
#endif
			if (t_tst_bit(_T_BIT_SCTP_DISPOSITION, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.disposition;

				sp->disp = *valp;
			}
			if (t_tst_bit(_T_BIT_SCTP_MAX_BURST, ss->options.flags)) {
				t_uscalar_t *valp = &ss->options.sctp.max_burst;

				sp->max_burst = *valp;
			}
			break;
		}
#endif
		}
	}
	return (0);
      eproto:
	swerr();
	return (-EPROTO);
}

STATIC int
t_parse_conn_opts(ss_t *ss, const unsigned char *ip, size_t ilen, int request)
{
	const struct t_opthdr *ih;
	struct sock *sk;

	bzero(ss->options.flags, sizeof(ss->options.flags));
	if (ip == NULL || ilen == 0)
		return (0);
	if (!ss || !ss->sock || !(sk = ss->sock->sk))
		goto eproto;

	for (ih = _T_OPT_FIRSTHDR_OFS(ip, ilen, 0); ih; ih = _T_OPT_NEXTHDR_OFS(ip, ilen, ih, 0)) {
		if (ih->len < sizeof(*ih))
			goto einval;
		switch (ih->level) {
		case XTI_GENERIC:
			switch (ih->name) {
			case XTI_DEBUG:
			{
				t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

				if (((ih->len - sizeof(*ih)) % sizeof(t_uscalar_t)) != 0)
					goto einval;
				if (ih->len >= sizeof(*ih) + 4 * sizeof(t_uscalar_t))
					ss->options.xti.debug[3] = valp[3];
				else
					ss->options.xti.debug[3] = 0;
				if (ih->len >= sizeof(*ih) + 3 * sizeof(t_uscalar_t))
					ss->options.xti.debug[2] = valp[2];
				else
					ss->options.xti.debug[2] = 0;
				if (ih->len >= sizeof(*ih) + 2 * sizeof(t_uscalar_t))
					ss->options.xti.debug[1] = valp[1];
				else
					ss->options.xti.debug[1] = 0;
				if (ih->len >= sizeof(*ih) + 1 * sizeof(t_uscalar_t))
					ss->options.xti.debug[0] = valp[0];
				else
					ss->options.xti.debug[1] = 0;
				t_set_bit(_T_BIT_XTI_DEBUG, ss->options.flags);
				continue;
			}
			case XTI_LINGER:
			{
				struct t_linger *valp = (struct t_linger *) T_OPT_DATA(ih);

				if (ih->len - sizeof(*ih) != sizeof(*valp))
					goto einval;
				if (valp->l_onoff != T_NO && valp->l_onoff != T_YES)
					goto einval;
				if (valp->l_linger != T_INFINITE && valp->l_linger != T_UNSPEC
				    && valp->l_linger < 0)
					goto einval;
				ss->options.xti.linger = *valp;
				t_set_bit(_T_BIT_XTI_LINGER, ss->options.flags);
				if (!request)
					continue;
				if (valp->l_onoff == T_NO)
					valp->l_linger = T_UNSPEC;
				else {
					if (valp->l_linger == T_UNSPEC)
						valp->l_linger = t_defaults.xti.linger.l_linger;
					if (valp->l_linger == T_INFINITE)
						valp->l_linger = MAX_SCHEDULE_TIMEOUT / HZ;
					if (valp->l_linger >= MAX_SCHEDULE_TIMEOUT / HZ)
						valp->l_linger = MAX_SCHEDULE_TIMEOUT / HZ;
				}
				if (valp->l_onoff == T_YES) {
					sock_set_linger(sk);
					sk->sk_lingertime = valp->l_linger * HZ;
				} else {
					sock_clr_linger(sk);
					sk->sk_lingertime = 0;
				}
				continue;
			}
			case XTI_RCVBUF:
			{
				t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

				if (ih->len - sizeof(*ih) != sizeof(*valp))
					goto einval;
				ss->options.xti.rcvbuf = *valp;
				t_set_bit(_T_BIT_XTI_RCVBUF, ss->options.flags);
				if (!request)
					continue;
				if (*valp > sysctl_rmem_max)
					*valp = sysctl_rmem_max;
				if (*valp < SOCK_MIN_RCVBUF / 2)
					*valp = SOCK_MIN_RCVBUF / 2;
				sk->sk_rcvbuf = *valp * 2;
				continue;
			}
			case XTI_RCVLOWAT:
			{
				t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

				if (ih->len - sizeof(*ih) != sizeof(*valp))
					goto einval;
				ss->options.xti.rcvlowat = *valp;
				t_set_bit(_T_BIT_XTI_RCVLOWAT, ss->options.flags);
				if (!request)
					continue;
				if (*valp < 1)
					*valp = 1;
				if (*valp > INT_MAX)
					*valp = INT_MAX;
				sk->sk_rcvlowat = *valp;
				continue;
			}
			case XTI_SNDBUF:
			{
				t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

				if (ih->len - sizeof(*ih) != sizeof(*valp))
					goto einval;
				ss->options.xti.sndbuf = *valp;
				t_set_bit(_T_BIT_XTI_SNDBUF, ss->options.flags);
				if (!request)
					continue;
				if (*valp > sysctl_wmem_max)
					*valp = sysctl_wmem_max;
				if (*valp < SOCK_MIN_SNDBUF / 2)
					*valp = SOCK_MIN_SNDBUF / 2;
				sk->sk_sndbuf = *valp * 2;
				continue;
			}
			case XTI_SNDLOWAT:
			{
				t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

				if (ih->len - sizeof(*ih) != sizeof(*valp))
					goto einval;
				ss->options.xti.sndlowat = *valp;
				t_set_bit(_T_BIT_XTI_SNDLOWAT, ss->options.flags);
				if (!request)
					continue;
				if (*valp < 1)
					*valp = 1;
				if (*valp > 1)
					*valp = 1;
				continue;
			}
			}
			continue;
		case T_INET_IP:
			if (ss->p.prot.family == PF_INET) {
				struct inet_opt *np = inet_sk(sk);

				switch (ih->name) {
				case T_IP_OPTIONS:
				{
					unsigned char *valp = (unsigned char *) T_OPT_DATA(ih);

					(void) valp;
					t_set_bit(_T_BIT_IP_OPTIONS, ss->options.flags);
					continue;
				}
				case T_IP_TOS:
				{
					unsigned char *valp = (unsigned char *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.ip.tos = *valp;
					t_set_bit(_T_BIT_IP_TOS, ss->options.flags);
					if (!request)
						continue;
					np->tos = *valp;
					continue;
				}
				case T_IP_TTL:
				{
					unsigned char *valp = (unsigned char *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.ip.ttl = *valp;
					t_set_bit(_T_BIT_IP_TTL, ss->options.flags);
					if (!request)
						continue;
					if (*valp < 1)
						*valp = 1;
#ifdef HAVE_STRUCT_SOCK_PROTINFO_AF_INET_TTL
					np->ttl = *valp;
#else
#ifdef HAVE_STRUCT_SOCK_PROTINFO_AF_INET_UC_TTL
					np->uc_ttl = *valp;
#endif
#endif
					continue;
				}
				case T_IP_REUSEADDR:
				{
					unsigned int *valp = (unsigned int *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					if (*valp != T_NO && *valp != T_YES)
						goto einval;
					ss->options.ip.reuseaddr = *valp;
					t_set_bit(_T_BIT_IP_REUSEADDR, ss->options.flags);
					if (!request)
						continue;
					sk->sk_reuse = (*valp == T_YES) ? 1 : 0;
					continue;
				}
				case T_IP_DONTROUTE:
				{
					unsigned int *valp = (unsigned int *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					if (*valp != T_NO && *valp != T_YES)
						goto einval;
					ss->options.ip.dontroute = *valp;
					t_set_bit(_T_BIT_IP_DONTROUTE, ss->options.flags);
					if (!request)
						continue;
					if (*valp == T_YES)
						sock_set_localroute(sk);
					else
						sock_clr_localroute(sk);
					continue;
				}
				case T_IP_BROADCAST:
				{
					unsigned int *valp = (unsigned int *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					if (*valp != T_NO && *valp != T_YES)
						goto einval;
					ss->options.ip.broadcast = *valp;
					t_set_bit(_T_BIT_IP_BROADCAST, ss->options.flags);
					if (!request)
						continue;
					if (*valp == T_YES)
						sock_set_broadcast(sk);
					else
						sock_clr_broadcast(sk);
					continue;
				}
				case T_IP_ADDR:
				{
					uint32_t *valp = (unsigned int *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.ip.addr = *valp;
					t_set_bit(_T_BIT_IP_ADDR, ss->options.flags);
					if (!request)
						continue;
					sock_saddr(sk) = *valp;
					continue;
				}
				}
			}
			continue;
		case T_INET_UDP:
			if (ss->p.prot.family == PF_INET && ss->p.prot.protocol == T_INET_UDP) {
				switch (ih->name) {
				case T_UDP_CHECKSUM:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					if (*valp != T_NO && *valp != T_YES)
						goto einval;
					ss->options.udp.checksum = *valp;
					t_set_bit(_T_BIT_UDP_CHECKSUM, ss->options.flags);
					if (!request)
						continue;
					sk->sk_no_check =
					    (*valp == T_YES) ? UDP_CSUM_DEFAULT : UDP_CSUM_NOXMIT;
					continue;
				}
				}
			}
			continue;
		case T_INET_TCP:
			if (ss->p.prot.family == PF_INET && ss->p.prot.protocol == T_INET_TCP) {
				struct tcp_opt *tp = tcp_sk(sk);

				switch (ih->name) {
				case T_TCP_NODELAY:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					if (*valp != T_NO && *valp != T_YES)
						goto einval;
					ss->options.tcp.nodelay = *valp;
					t_set_bit(_T_BIT_TCP_NODELAY, ss->options.flags);
					if (!request)
						continue;
					tp->nonagle = (*valp == T_YES) ? 1 : 0;
					continue;
				}
				case T_TCP_MAXSEG:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.tcp.maxseg = *valp;
					t_set_bit(_T_BIT_TCP_MAXSEG, ss->options.flags);
					if (!request)
						continue;
					if (*valp < 8)
						*valp = 8;
					if (*valp > MAX_TCP_WINDOW)
						*valp = MAX_TCP_WINDOW;
					tcp_user_mss(tp) = *valp;
					continue;
				}
				case T_TCP_KEEPALIVE:
				{
					struct t_kpalive *valp =
					    (struct t_kpalive *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					if (valp->kp_onoff != T_YES && valp->kp_onoff != T_NO)
						goto einval;
					if (valp->kp_timeout != T_INFINITE
					    && valp->kp_timeout != T_UNSPEC && valp->kp_timeout < 0)
						goto einval;
					ss->options.tcp.keepalive = *valp;
					t_set_bit(_T_BIT_TCP_KEEPALIVE, ss->options.flags);
					if (!request)
						continue;
					if (valp->kp_onoff == T_NO)
						valp->kp_timeout = T_UNSPEC;
					else {
						if (valp->kp_timeout == T_UNSPEC)
							valp->kp_timeout =
							    t_defaults.tcp.keepalive.kp_timeout;
						if (valp->kp_timeout < 1)
							valp->kp_timeout = 1;
						if (valp->kp_timeout >
						    MAX_SCHEDULE_TIMEOUT / 60 / HZ)
							valp->kp_timeout =
							    MAX_SCHEDULE_TIMEOUT / 60 / HZ;
					}
					if (valp->kp_onoff == T_YES)
						tp->keepalive_time = valp->kp_timeout * 60 * HZ;
#if defined HAVE_TCP_SET_KEEPALIVE_ADDR
					tcp_set_keepalive(sk, valp->kp_onoff == T_YES ? 1 : 0);
#endif
					if (valp->kp_onoff == T_YES)
						sock_set_keepopen(sk);
					else
						sock_clr_keepopen(sk);
					continue;
				}
				case T_TCP_CORK:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len != sizeof(*ih) + sizeof(*valp))
						goto einval;
					if (*valp != T_YES && *valp != T_NO)
						goto einval;
					ss->options.tcp.cork = *valp;
					t_set_bit(_T_BIT_TCP_CORK, ss->options.flags);
					if (!request)
						continue;
					if (*valp == T_YES && tp->nonagle == 0)
						tp->nonagle = 2;
					if (*valp == T_NO && tp->nonagle == 2)
						tp->nonagle = 0;
					continue;
				}
				case T_TCP_KEEPIDLE:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len != sizeof(*ih) + sizeof(*valp))
						goto einval;
					ss->options.tcp.keepidle = *valp;
					t_set_bit(_T_BIT_TCP_KEEPIDLE, ss->options.flags);
					if (!request)
						continue;
					if (*valp < 1)
						*valp = 1;
					if (*valp > MAX_TCP_KEEPIDLE)
						*valp = MAX_TCP_KEEPIDLE;
					tp->keepalive_time = *valp * HZ;

					continue;
				}
				case T_TCP_KEEPINTVL:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len != sizeof(*ih) + sizeof(*valp))
						goto einval;
					ss->options.tcp.keepitvl = *valp;
					t_set_bit(_T_BIT_TCP_KEEPINTVL, ss->options.flags);
					if (!request)
						continue;
					if (*valp < 1)
						*valp = 1;
					if (*valp > MAX_TCP_KEEPINTVL)
						*valp = MAX_TCP_KEEPINTVL;
					tp->keepalive_intvl = *valp * HZ;
					continue;
				}
				case T_TCP_KEEPCNT:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len != sizeof(*ih) + sizeof(*valp))
						goto einval;
					ss->options.tcp.keepcnt = *valp;
					t_set_bit(_T_BIT_TCP_KEEPCNT, ss->options.flags);
					if (!request)
						continue;
					if (*valp < 1)
						*valp = 1;
					if (*valp > MAX_TCP_KEEPCNT)
						*valp = MAX_TCP_KEEPCNT;
					tp->keepalive_probes = *valp;
					continue;
				}
				case T_TCP_SYNCNT:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len != sizeof(*ih) + sizeof(*valp))
						goto einval;
					ss->options.tcp.syncnt = *valp;
					t_set_bit(_T_BIT_TCP_SYNCNT, ss->options.flags);
					if (!request)
						continue;
					if (*valp < 1)
						*valp = 1;
					if (*valp > MAX_TCP_SYNCNT)
						*valp = MAX_TCP_SYNCNT;
					sock_syn_retries(sk) = *valp;
					continue;
				}
				case T_TCP_LINGER2:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len != sizeof(*ih) + sizeof(*valp))
						goto einval;
					ss->options.tcp.linger2 = *valp;
					t_set_bit(_T_BIT_TCP_LINGER2, ss->options.flags);
					if (!request)
						continue;
					if (*valp < 0)
						tp->linger2 = -1;
					else if (*valp > sysctl_tcp_fin_timeout / HZ)
						tp->linger2 = 0;
					else
						tp->linger2 = *valp * HZ;
					continue;
				}
				case T_TCP_DEFER_ACCEPT:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len != sizeof(*ih) + sizeof(*valp))
						goto einval;
					ss->options.tcp.defer_accept = *valp;
					t_set_bit(_T_BIT_TCP_DEFER_ACCEPT, ss->options.flags);
					if (!request)
						continue;
					if (*valp == 0)
						sock_defer_accept(sk) = 0;
					else {
						for (sock_defer_accept(sk) = 0;
						     sock_defer_accept(sk) < 32
						     && *valp >
						     ((TCP_TIMEOUT_INIT /
						       HZ) << sock_defer_accept(sk));
						     sock_defer_accept(sk)++) ;
						sock_defer_accept(sk)++;
					}
					continue;
				}
				case T_TCP_WINDOW_CLAMP:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len != sizeof(*ih) + sizeof(*valp))
						goto einval;
					ss->options.tcp.window_clamp = *valp;
					t_set_bit(_T_BIT_TCP_WINDOW_CLAMP, ss->options.flags);
					if (!request)
						continue;
					if (*valp < SOCK_MIN_RCVBUF / 2)
						*valp = SOCK_MIN_RCVBUF / 2;
					tp->window_clamp = *valp;
					continue;
				}
#if 0
				case T_TCP_INFO:
				{

				}
				case T_TCP_QUICKACK:
				{

				}
#endif
				}
			}
			continue;
#if defined HAVE_OPENSS7_SCTP
		case T_INET_SCTP:
			if (ss->p.prot.family == PF_INET && ss->p.prot.protocol == T_INET_SCTP) {
				struct sctp_opt *sp = sctp_sk(sk);

				switch (ih->name) {
				case T_SCTP_NODELAY:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					if (*valp != T_NO && *valp != T_YES)
						goto einval;
					ss->options.sctp.nodelay = *valp;
					t_set_bit(_T_BIT_SCTP_NODELAY, ss->options.flags);
					if (!request)
						continue;
					continue;
				}
				case T_SCTP_MAXSEG:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.sctp.maxseg = *valp;
					t_set_bit(_T_BIT_SCTP_MAXSEG, ss->options.flags);
					if (!request)
						continue;
					if (*valp < 1)
						*valp = 1;
					if (*valp > MAX_TCP_WINDOW)
						*valp = MAX_TCP_WINDOW;
					sp->user_amps = *valp;
					continue;
				}
				case T_SCTP_CORK:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					if (*valp != T_NO && *valp != T_YES)
						goto einval;
					ss->options.sctp.cork = *valp;
					t_set_bit(_T_BIT_SCTP_CORK, ss->options.flags);
					if (!request)
						continue;
					if (sp->nonagle != 1)
						sp->nonagle = (*valp == T_YES) ? 2 : 0;
					continue;
				}
				case T_SCTP_PPI:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.sctp.ppi = *valp;
					t_set_bit(_T_BIT_SCTP_PPI, ss->options.flags);
					if (!request)
						continue;
					sp->ppi = *valp;
					continue;
				}
				case T_SCTP_SID:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					if (*valp > sp->n_ostr)
						goto einval;
					ss->options.sctp.sid = *valp;
					t_set_bit(_T_BIT_SCTP_SID, ss->options.flags);
					if (!request)
						continue;
					sp->sid = *valp;
					continue;
				}
				case T_SCTP_SSN:
				{

					goto einval;
				}
				case T_SCTP_TSN:
				{

					goto einval;
				}
				case T_SCTP_RECVOPT:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					if (*valp != T_NO && *valp != T_YES)
						goto einval;
					ss->options.sctp.recvopt = *valp;
					t_set_bit(_T_BIT_SCTP_RECVOPT, ss->options.flags);
					if (!request)
						continue;
					if (*valp == T_YES)
						sp->cmsg_flags |=
						    (SCTP_CMSGF_RECVSID | SCTP_CMSGF_RECVPPI |
						     SCTP_CMSGF_RECVSSN | SCTP_CMSGF_RECVTSN);
					else
						sp->cmsg_flags &=
						    ~(SCTP_CMSGF_RECVSID | SCTP_CMSGF_RECVPPI |
						      SCTP_CMSGF_RECVSSN | SCTP_CMSGF_RECVTSN);
					continue;
				}
				case T_SCTP_COOKIE_LIFE:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.sctp.cookie_life = *valp;
					t_set_bit(_T_BIT_SCTP_COOKIE_LIFE, ss->options.flags);
					if (!request)
						continue;
					if (*valp == T_INFINITE)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					sp->ck_life = *valp / 1000 * HZ;
					continue;
				}
				case T_SCTP_SACK_DELAY:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.sctp.sack_delay = *valp;
					t_set_bit(_T_BIT_SCTP_SACK_DELAY, ss->options.flags);
					if (!request)
						continue;
					if (*valp == T_INFINITE)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					sp->max_sack = *valp / 1000 * HZ;
					continue;
				}
				case T_SCTP_PATH_MAX_RETRANS:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.sctp.path_max_retrans = *valp;
					t_set_bit(_T_BIT_SCTP_PATH_MAX_RETRANS, ss->options.flags);
					if (!request)
						continue;
					sp->rtx_path = *valp;
					continue;
				}
				case T_SCTP_ASSOC_MAX_RETRANS:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.sctp.assoc_max_retrans = *valp;
					t_set_bit(_T_BIT_SCTP_ASSOC_MAX_RETRANS, ss->options.flags);
					if (!request)
						continue;
					sp->max_retrans = *valp;
					continue;
				}
				case T_SCTP_MAX_INIT_RETRIES:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.sctp.max_init_retries = *valp;
					t_set_bit(_T_BIT_SCTP_MAX_INIT_RETRIES, ss->options.flags);
					if (!request)
						continue;
					sp->max_inits = *valp;
					continue;
				}
				case T_SCTP_HEARTBEAT_ITVL:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.sctp.heartbeat_itvl = *valp;
					t_set_bit(_T_BIT_SCTP_HEARTBEAT_ITVL, ss->options.flags);
					if (!request)
						continue;
					if (*valp == T_INFINITE)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					sp->hb_itvl = *valp / 1000 * HZ;
#if defined CONFIG_SCTP_THROTTLE_HEARTBEATS
					sp->hb_tint = (*valp >> 1) + 1;
#endif
					continue;
				}
				case T_SCTP_RTO_INITIAL:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.sctp.rto_initial = *valp;
					t_set_bit(_T_BIT_SCTP_RTO_INITIAL, ss->options.flags);
					if (!request)
						continue;
					if (*valp == T_INFINITE)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					if (*valp > sp->rto_max / HZ * 1000)
						*valp = sp->rto_max / HZ * 1000;
					if (*valp < sp->rto_min / HZ * 1000)
						*valp = sp->rto_min / HZ * 1000;
					if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					sp->rto_ini = *valp / 1000 * HZ;
					continue;
				}
				case T_SCTP_RTO_MIN:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.sctp.rto_min = *valp;
					t_set_bit(_T_BIT_SCTP_RTO_MIN, ss->options.flags);
					if (!request)
						continue;
					if (*valp == T_INFINITE)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					if (*valp > sp->rto_max / HZ * 1000)
						*valp = sp->rto_max / HZ * 1000;
					if (*valp > sp->rto_ini / HZ * 1000)
						*valp = sp->rto_ini / HZ * 1000;
					if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					sp->rto_min = *valp / 1000 * HZ;
					continue;
				}
				case T_SCTP_RTO_MAX:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.sctp.rto_max = *valp;
					t_set_bit(_T_BIT_SCTP_RTO_MAX, ss->options.flags);
					if (!request)
						continue;
					if (*valp == T_INFINITE)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					if (*valp < sp->rto_min / HZ * 1000)
						*valp = sp->rto_min / HZ * 1000;
					if (*valp < sp->rto_ini / HZ * 1000)
						*valp = sp->rto_ini / HZ * 1000;
					if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					sp->rto_max = *valp / 1000 * HZ;
					continue;
				}
				case T_SCTP_OSTREAMS:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					if (*valp < 1 || *valp > 0x0ffff)
						goto einval;
					ss->options.sctp.ostreams = *valp;
					t_set_bit(_T_BIT_SCTP_OSTREAMS, ss->options.flags);
					if (!request)
						continue;
					sp->req_ostr = *valp;
					continue;
				}
				case T_SCTP_ISTREAMS:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					if (*valp < 1 || *valp > 0x0ffff)
						goto einval;
					ss->options.sctp.istreams = *valp;
					t_set_bit(_T_BIT_SCTP_ISTREAMS, ss->options.flags);
					if (!request)
						continue;
					sp->max_istr = *valp;
					continue;
				}
				case T_SCTP_COOKIE_INC:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.sctp.cookie_inc = *valp;
					t_set_bit(_T_BIT_SCTP_COOKIE_INC, ss->options.flags);
					if (!request)
						continue;
					if (*valp == T_INFINITE)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					sp->ck_inc = *valp / 1000 * HZ;
					continue;
				}
				case T_SCTP_THROTTLE_ITVL:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					ss->options.sctp.throttle_itvl = *valp;
					t_set_bit(_T_BIT_SCTP_THROTTLE_ITVL, ss->options.flags);
					if (!request)
						continue;
					if (*valp == T_INFINITE)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					if (*valp / HZ > MAX_SCHEDULE_TIMEOUT / 1000)
						*valp = MAX_SCHEDULE_TIMEOUT / 1000 * HZ;
					sp->throttle = *valp / 1000 * HZ;
					continue;
				}
				case T_SCTP_MAC_TYPE:
				{
					t_uscalar_t *valp = (t_uscalar_t *) T_OPT_DATA(ih);

					if (ih->len - sizeof(*ih) != sizeof(*valp))
						goto einval;
					if (*valp != T_SCTP_HMAC_NO