#include <sys/types.h>
#include <inet/common.h>
#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/strsun.h>
#include <sys/sysmacros.h>
#include <sys/stropts.h>
#include <sys/strsubr.h>
#include <sys/tpicommon.h>
#include <sys/socket_proto.h>
#include <sys/policy.h>
#include <inet/optcom.h>
#include <inet/ipclassifier.h>
boolean_t
proto_set_rx_hiwat(queue_t *q, conn_t *connp, size_t size)
{
if (connp != NULL && IPCL_IS_NONSTR(connp)) {
struct sock_proto_props sopp;
sopp.sopp_flags = SOCKOPT_RCVHIWAT;
sopp.sopp_rxhiwat = size;
(*connp->conn_upcalls->su_set_proto_props)
(connp->conn_upper_handle, &sopp);
} else {
MBLKP mp;
struct stroptions *stropt;
if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
return (B_FALSE);
mp->b_datap->db_type = M_SETOPTS;
mp->b_wptr += sizeof (*stropt);
stropt = (struct stroptions *)mp->b_rptr;
stropt->so_flags = SO_HIWAT;
stropt->so_hiwat = size;
putnext(q, mp);
}
return (B_TRUE);
}
boolean_t
proto_set_rx_lowat(queue_t *q, conn_t *connp, size_t size)
{
if (connp != NULL && IPCL_IS_NONSTR(connp)) {
struct sock_proto_props sopp;
sopp.sopp_flags = SOCKOPT_RCVLOWAT;
sopp.sopp_rxlowat = size;
(*connp->conn_upcalls->su_set_proto_props)
(connp->conn_upper_handle, &sopp);
} else {
MBLKP mp;
struct stroptions *stropt;
if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
return (B_FALSE);
mp->b_datap->db_type = M_SETOPTS;
mp->b_wptr += sizeof (*stropt);
stropt = (struct stroptions *)mp->b_rptr;
stropt->so_flags = SO_LOWAT;
stropt->so_lowat = size;
putnext(q, mp);
}
return (B_TRUE);
}
boolean_t
proto_set_maxpsz(queue_t *q, conn_t *connp, size_t size)
{
if (connp != NULL && IPCL_IS_NONSTR(connp)) {
struct sock_proto_props sopp;
sopp.sopp_flags = SOCKOPT_MAXPSZ;
sopp.sopp_maxpsz = size;
(*connp->conn_upcalls->su_set_proto_props)
(connp->conn_upper_handle, &sopp);
return (B_TRUE);
} else {
struct stdata *stp;
queue_t *wq;
stp = STREAM(q);
if (stp == NULL || stp->sd_flag & STPLEX)
return (B_FALSE);
claimstr(stp->sd_wrq);
wq = stp->sd_wrq->q_next;
ASSERT(wq != NULL);
(void) strqset(wq, QMAXPSZ, 0, size);
releasestr(stp->sd_wrq);
return (B_TRUE);
}
}
boolean_t
proto_set_tx_maxblk(queue_t *q, conn_t *connp, ssize_t size)
{
if (connp != NULL && IPCL_IS_NONSTR(connp)) {
struct sock_proto_props sopp;
sopp.sopp_flags = SOCKOPT_MAXBLK;
sopp.sopp_maxblk = size;
(*connp->conn_upcalls->su_set_proto_props)
(connp->conn_upper_handle, &sopp);
} else {
MBLKP mp;
struct stroptions *stropt;
if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
return (B_FALSE);
mp->b_datap->db_type = M_SETOPTS;
mp->b_wptr += sizeof (*stropt);
stropt = (struct stroptions *)mp->b_rptr;
stropt->so_flags = SO_MAXBLK;
stropt->so_maxblk = size;
putnext(q, mp);
}
return (B_TRUE);
}
boolean_t
proto_set_tx_copyopt(queue_t *q, conn_t *connp, int copyopt)
{
if (connp != NULL && IPCL_IS_NONSTR(connp)) {
struct sock_proto_props sopp;
sopp.sopp_flags = SOCKOPT_ZCOPY;
sopp.sopp_zcopyflag = (ushort_t)copyopt;
(*connp->conn_upcalls->su_set_proto_props)
(connp->conn_upper_handle, &sopp);
} else {
MBLKP mp;
struct stroptions *stropt;
if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
return (B_FALSE);
mp->b_datap->db_type = M_SETOPTS;
mp->b_wptr += sizeof (*stropt);
stropt = (struct stroptions *)mp->b_rptr;
stropt->so_flags = SO_COPYOPT;
stropt->so_copyopt = (ushort_t)copyopt;
putnext(q, mp);
}
return (B_TRUE);
}
boolean_t
proto_set_tx_wroff(queue_t *q, conn_t *connp, size_t size)
{
if (connp != NULL && IPCL_IS_NONSTR(connp)) {
struct sock_proto_props sopp;
sopp.sopp_flags = SOCKOPT_WROFF;
sopp.sopp_wroff = size;
if (connp->conn_upper_handle != NULL)
(*connp->conn_upcalls->su_set_proto_props)
(connp->conn_upper_handle, &sopp);
} else {
MBLKP mp;
struct stroptions *stropt;
if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
return (B_FALSE);
mp->b_datap->db_type = M_SETOPTS;
mp->b_wptr += sizeof (*stropt);
stropt = (struct stroptions *)mp->b_rptr;
stropt->so_flags = SO_WROFF;
stropt->so_wroff = (ushort_t)size;
putnext(q, mp);
}
return (B_TRUE);
}
void
proto_set_rx_oob_opt(conn_t *connp, boolean_t onoff)
{
struct sock_proto_props sopp;
ASSERT(IPCL_IS_NONSTR(connp));
sopp.sopp_flags = SOCKOPT_OOBINLINE;
sopp.sopp_oobinline = onoff;
(*connp->conn_upcalls->su_set_proto_props)
(connp->conn_upper_handle, &sopp);
}
static const int tli_errs[] = {
0,
EADDRNOTAVAIL,
ENOPROTOOPT,
EACCES,
EBADF,
EADDRNOTAVAIL,
EPROTO,
ECONNABORTED,
0,
EPROTO,
EMSGSIZE,
EMSGSIZE,
EPROTO,
EWOULDBLOCK,
EPROTO,
EPROTO,
EINVAL,
EPROTO,
EOPNOTSUPP,
EPROTO,
EPROTO,
EPROTO,
EPROTO,
EADDRINUSE,
EBADF,
EBADF,
EBADF,
EBADF,
EPROTO,
EPROTO,
};
int
proto_tlitosyserr(int terr)
{
ASSERT(terr != TSYSERR);
if (terr >= (sizeof (tli_errs) / sizeof (tli_errs[0])))
return (EPROTO);
else
return (tli_errs[terr]);
}
int
proto_verify_ip_addr(int family, const struct sockaddr *name, socklen_t namelen)
{
if (name == NULL || !OK_32PTR((char *)name))
return (EINVAL);
switch (family) {
case AF_INET:
if (name->sa_family != AF_INET) {
return (EAFNOSUPPORT);
}
if (namelen != (socklen_t)sizeof (struct sockaddr_in)) {
return (EINVAL);
}
break;
case AF_INET6: {
#ifdef DEBUG
struct sockaddr_in6 *sin6;
#endif
if (name->sa_family != AF_INET6) {
return (EAFNOSUPPORT);
}
if (namelen != (socklen_t)sizeof (struct sockaddr_in6)) {
return (EINVAL);
}
#ifdef DEBUG
sin6 = (struct sockaddr_in6 *)name;
if (sin6->sin6_scope_id != 0 &&
!IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) {
zcmn_err(getzoneid(), CE_WARN,
"connect/send* with uninitialized sin6_scope_id "
"(%d) on socket. Pid = %d\n",
(int)sin6->sin6_scope_id, (int)curproc->p_pid);
}
#endif
break;
}
default:
return (EINVAL);
}
return (0);
}
opdes_t *
proto_opt_lookup(t_uscalar_t level, t_uscalar_t name, opdes_t *opt_arr,
uint_t opt_arr_cnt)
{
opdes_t *optd;
for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt];
optd++) {
if (level == (uint_t)optd->opdes_level &&
name == (uint_t)optd->opdes_name)
return (optd);
}
return (NULL);
}
int
proto_opt_check(int level, int name, int len, t_uscalar_t *max_len,
opdes_t *opt_arr, uint_t opt_arr_cnt, boolean_t negotiate, boolean_t check,
cred_t *cr)
{
opdes_t *optd;
optd = proto_opt_lookup(level, name, opt_arr, opt_arr_cnt);
if (optd == NULL)
return (-TBADOPT);
if (negotiate) {
ASSERT(check == B_FALSE);
if (!OA_WRITE_OR_EXECUTE(optd, cr)) {
if (!(OA_MATCHED_PRIV(optd, cr)) &&
OA_WX_ANYPRIV(optd)) {
return (-TACCES);
} else {
return (-TBADOPT);
}
}
if (!(optd->opdes_props & OP_VARLEN)) {
if (len != optd->opdes_size) {
return (EINVAL);
}
}
} else {
if (check) {
if (!OA_RWX_ANYPRIV(optd))
return (-TBADOPT);
}
if (!OA_READ_PERMISSION(optd, cr)) {
if (!(OA_MATCHED_PRIV(optd, cr)) &&
OA_R_ANYPRIV(optd)) {
return (-TACCES);
} else {
return (-TBADOPT);
}
}
}
if (max_len != NULL)
*max_len = optd->opdes_size;
return (0);
}