#include <sys/param.h>
#include <sys/types.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/filio.h>
#include <sys/user.h>
#include <sys/vnode.h>
#include <sys/cmn_err.h>
#include <sys/errno.h>
#include <sys/kmem.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stream.h>
#include <sys/strsubr.h>
#include <sys/strsun.h>
#include <sys/tihdr.h>
#include <sys/timod.h>
#include <sys/tiuser.h>
#include <sys/t_kuser.h>
#include <errno.h>
#include <stropts.h>
#include <unistd.h>
#include <tiuser.h>
#include "fake_fio.h"
#define FKTLI_RCV_SZ 4096
static const int tli_errs[] = {
0,
EADDRNOTAVAIL,
ENOPROTOOPT,
EACCES,
EBADF,
EADDRNOTAVAIL,
EPROTO,
EPROTO,
ENOSYS,
EPROTO,
EMSGSIZE,
EMSGSIZE,
EPROTO,
EWOULDBLOCK,
EPROTO,
EPROTO,
EINVAL,
EPROTO,
EOPNOTSUPP,
EPROTO,
};
static int
tlitosyserr(int terr)
{
if (terr < 0 || (terr >= (sizeof (tli_errs) / sizeof (tli_errs[0]))))
return (EPROTO);
else
return (tli_errs[terr]);
}
int
t_kopen(file_t *fp, dev_t rdev, int flags, TIUSER **tiptr, cred_t *cr)
{
boolean_t madefp = B_FALSE;
TIUSER *tiu;
int fd;
int rc;
*tiptr = NULL;
if (fp == NULL) {
char *devnm;
switch (rdev) {
case AF_INET:
devnm = "/dev/tcp";
break;
case AF_INET6:
devnm = "/dev/tcp6";
break;
default:
cmn_err(CE_NOTE, "t_kopen: bad device");
return (EINVAL);
}
fd = t_open(devnm, O_RDWR, NULL);
if (fd < 0) {
rc = t_errno;
cmn_err(CE_NOTE, "t_kopen: t_open terr=%d", rc);
return (tlitosyserr(rc));
}
fp = file_getf(fd);
madefp = B_TRUE;
}
fd = file_getfd(fp);
tiu = kmem_zalloc(sizeof (*tiu), KM_SLEEP);
rc = t_getinfo(fd, &tiu->tp_info);
if (rc < 0) {
rc = t_errno;
cmn_err(CE_NOTE, "t_kopen: t_getinfo terr=%d", rc);
kmem_free(tiu, sizeof (*tiu));
if (madefp) {
file_releasef(fd);
(void) t_close(fd);
}
return (tlitosyserr(rc));
}
tiu->fp = fp;
tiu->flags = madefp ? MADE_FP : 0;
*tiptr = tiu;
return (0);
}
int
t_kclose(TIUSER *tiptr, int callclosef)
{
file_t *fp;
fp = (tiptr->flags & MADE_FP) ? tiptr->fp : NULL;
kmem_free(tiptr, TIUSERSZ);
if (fp != NULL) {
int fd = file_getfd(fp);
file_releasef(fd);
(void) t_close(fd);
}
return (0);
}
int
t_kbind(TIUSER *tiptr, struct t_bind *req, struct t_bind *ret)
{
file_t *fp = tiptr->fp;
int fd = file_getfd(fp);
int rc;
if (t_bind(fd, req, ret) < 0) {
rc = t_errno;
cmn_err(CE_NOTE, "t_kbind: t_bind terr=%d", rc);
return (tlitosyserr(rc));
}
return (0);
}
int
t_kunbind(TIUSER *tiptr)
{
file_t *fp = tiptr->fp;
int fd = file_getfd(fp);
int rc;
if (t_unbind(fd) < 0) {
rc = t_errno;
cmn_err(CE_NOTE, "t_kunbind: t_unbind terr=%d", rc);
return (tlitosyserr(rc));
}
return (0);
}
int
t_kconnect(TIUSER *tiptr, struct t_call *sndcall, struct t_call *rcvcall)
{
file_t *fp = tiptr->fp;
int fd = file_getfd(fp);
int rc;
if (t_connect(fd, sndcall, rcvcall) < 0) {
rc = t_errno;
cmn_err(CE_NOTE, "t_kconnect: t_connect terr=%d", rc);
if (rc == TLOOK) {
rc = ECONNREFUSED;
} else {
rc = tlitosyserr(rc);
}
return (rc);
}
return (0);
}
int
t_koptmgmt(TIUSER *tiptr, struct t_optmgmt *req, struct t_optmgmt *ret)
{
file_t *fp = tiptr->fp;
int fd = file_getfd(fp);
int rc;
if (t_optmgmt(fd, req, ret) < 0) {
rc = t_errno;
cmn_err(CE_NOTE, "t_koptmgmt: t_optmgmt terr=%d", rc);
return (tlitosyserr(rc));
}
return (0);
}
int
t_kspoll(TIUSER *tiptr, int timo, int waitflg, int *events)
{
struct pollfd pfds[1];
file_t *fp = tiptr->fp;
int fd = file_getfd(fp);
clock_t timout;
int n;
if (events == NULL || ((waitflg & READWAIT) == 0))
return (EINVAL);
if (timo < 0)
timout = -1;
else
timout = TICK_TO_MSEC(timo);
pfds[0].fd = fd;
pfds[0].events = POLLIN;
pfds[0].revents = 0;
errno = 0;
n = poll(pfds, 1, timout);
if (n < 0)
return (errno);
if (n == 0)
return (ETIME);
*events = pfds[0].revents;
return (0);
}
int
tli_send(TIUSER *tiptr, mblk_t *bp, int fmode)
{
struct strbuf ctlbuf;
struct strbuf databuf;
mblk_t *m;
int flg, n, rc;
file_t *fp = tiptr->fp;
int fd = file_getfd(fp);
if (bp == NULL)
return (0);
switch (bp->b_datap->db_type) {
case M_DATA:
for (m = bp; m != NULL; m = m->b_cont) {
n = MBLKL(m);
flg = (m->b_cont != NULL) ? T_MORE : 0;
rc = t_snd(fd, (void *) m->b_rptr, n, flg);
if (rc != n) {
rc = EIO;
goto out;
}
}
rc = 0;
break;
case M_PROTO:
case M_PCPROTO:
ctlbuf.len = MBLKL(bp);
ctlbuf.maxlen = MBLKL(bp);
ctlbuf.buf = (char *)bp->b_rptr;
if (bp->b_cont == NULL) {
bzero(&databuf, sizeof (databuf));
} else {
m = bp->b_cont;
databuf.len = MBLKL(m);
databuf.maxlen = MBLKL(m);
databuf.buf = (char *)m->b_rptr;
}
if (putmsg(fd, &ctlbuf, &databuf, 0) < 0) {
rc = errno;
cmn_err(CE_NOTE, "tli_send: putmsg err=%d", rc);
} else {
rc = 0;
}
break;
default:
rc = EIO;
break;
}
out:
freemsg(bp);
return (rc);
}
int
tli_recv(TIUSER *tiptr, mblk_t **bp, int fmode)
{
mblk_t *mtop = NULL;
mblk_t *m;
file_t *fp = tiptr->fp;
int fd = file_getfd(fp);
int error;
int flags;
int nread;
int n;
nread = FKTLI_RCV_SZ;
m = allocb_wait(nread, 0, 0, &error);
ASSERT(m != NULL);
if (mtop == NULL)
mtop = m;
again:
flags = 0;
n = t_rcv(fd, (void *) m->b_rptr, nread, &flags);
if (n < 0) {
n = t_errno;
cmn_err(CE_NOTE, "tli_recv: t_rcv terr=%d", n);
error = tlitosyserr(n);
goto errout;
}
if (n == 0) {
error = ENOTCONN;
goto errout;
}
ASSERT(n > 0 && n <= nread);
m->b_wptr = m->b_rptr + n;
if (flags & T_MORE) {
mblk_t *mtail = m;
m = allocb_wait(nread, 0, 0, &error);
ASSERT(m != NULL);
mtail->b_cont = m;
goto again;
}
*bp = mtop;
return (0);
errout:
if (m == mtop) {
freemsg(mtop);
return (error);
}
return (0);
}