/* begincopyright Copyright (c) 1988, 1989 Xerox Corporation. All rights reserved. Use and copying of this software and preparation of derivative works based upon this software are permitted. Any distribution of this software or derivative works must comply with all applicable United States export control laws. This software is made available AS IS, and Xerox Corporation makes no warranty about the software, its performance or its conformity to any specification. Any person obtaining a copy of this software is requested to send their name and post office or electronic mail address to: PCR Coordinator Xerox PARC 3333 Coyote Hill Rd. Palo Alto, CA endcopyright */ /* * ThreadsTLI.c * * Tim Diebert: November 21, 1989 5:59:51 pm PST * Michael Plass: February 18, 1992 9:51:11 am PST * * This module provides an interface to the Mentat XNS implementation * via the AT&T TLI interfaces. This code started life looking * suprisingly like the AT&T stuff except that it maintains no global * state. * */ #include #include #include #include #include /* would you believe NULL is in here */ #include /* queue_t */ #include /* stream ioctl things */ #include #include /* #include included in ThreadsTLI.h */ #define DEFSIZE 2048 extern XR_Pointer GC_malloc(); /* Open and Close */ int XR_T_Open(cd, path, flags, info) struct conn_data * cd; char * path; int flags; register struct t_info * info; { int retval; struct T_info_ack inforeq; int retlen; /* Open up the device. In the case of the Mentat XNS path should be * /dev/xr */ if ((cd->cd_fd = XR_OpenStream(path, flags)) < 0) { cd->cd_errno = TSYSERR; return(-1); } /* * is module already pushed ? */ if ((retval = XR_IOCtl(cd->cd_fd, I_FIND, "timod")) < 0) { cd->cd_errno = TSYSERR; XR_Close(cd->cd_fd); return(-1); } if (!retval) if (XR_IOCtl(cd->cd_fd, I_PUSH, "timod") < 0) { cd->cd_errno = TSYSERR; XR_Close(cd->cd_fd); return(-1); } inforeq.PRIM_type = T_INFO_REQ; if (!DoTIModIOCtl(cd, (caddr_t)&inforeq, sizeof(struct T_info_req), TI_GETINFO, &retlen)) { XR_Close(cd->cd_fd); return(-1); } if (retlen != sizeof(struct T_info_ack)) { cd->cd_errno = TSYSERR; XR_SetErrno(EIO); XR_Close(cd->cd_fd); return(-1); } cd->cd_info.addr = inforeq.ADDR_size; cd->cd_info.options = inforeq.OPT_size; cd->cd_info.tsdu = inforeq.TSDU_size; cd->cd_info.etsdu = inforeq.ETSDU_size; cd->cd_info.connect = inforeq.CDATA_size; cd->cd_info.discon = inforeq.DDATA_size; cd->cd_info.servtype = inforeq.SERV_type; if (info != NULL) { info->addr = inforeq.ADDR_size; info->options = inforeq.OPT_size; info->tsdu = inforeq.TSDU_size; info->etsdu = inforeq.ETSDU_size; info->connect = inforeq.CDATA_size; info->discon = inforeq.DDATA_size; info->servtype = inforeq.SERV_type; } /* * initialize data structure and allocate buffers if needed */ if (!(cd->cd_flags & USED)) { if (AllocateBuffers(cd, inforeq) < 0){ XR_T_Close(cd); cd->cd_errno = TSYSERR; return(-1); } if(XR_IOCtl(cd->cd_fd, I_FLUSH, 3L) < 0) { XR_T_Close(cd); cd->cd_errno = TSYSERR; return(-1); } cd->cd_flags = cd->cd_flags | USED; } return(cd->cd_fd); } int XR_T_Close(cd) struct conn_data * cd; { if (CheckCD(cd)) return(-1); /* don't release the memory, since someone else allocated it. * (void)free(cd->cd_rcvbuf); * (void)free(cd->cd_ctlbuf); * (void)free(cd->cd_lookcbuf); * (void)free(cd->cd_lookdbuf); */ XR_Close(cd->cd_fd); cd->cd_fd = -1; /* mark it as closed */ return(0); } /* Binding */ int XR_T_Bind(cd, req, ret) struct conn_data * cd; register struct t_bind *req; register struct t_bind *ret; { int fd; register char *buf; register struct T_bind_req *ti_bind; int size; if (CheckCD(cd)) return(-1); fd = cd->cd_fd; buf = cd->cd_ctlbuf; ti_bind = (struct T_bind_req *)buf; size = sizeof(struct T_bind_req); ti_bind->PRIM_type = T_BIND_REQ; ti_bind->ADDR_length = (req == NULL? 0: req->addr.len); ti_bind->ADDR_offset = 0; ti_bind->CONIND_number = (req == NULL? 0: req->qlen); if (ti_bind->ADDR_length) { AlignedCopy(buf, (int)ti_bind->ADDR_length, size, req->addr.buf, &ti_bind->ADDR_offset); size = ti_bind->ADDR_offset + ti_bind->ADDR_length; } if (!DoTIModIOCtl(cd, buf, size, TI_BIND, 0L)) { return(-1); } if ((ret != NULL) && (ti_bind->ADDR_length > ret->addr.maxlen)) { cd->cd_errno = TBUFOVFLW; return(-1); } if (ret != NULL) { bcopy((char *)(buf + ti_bind->ADDR_offset), ret->addr.buf, (int)ti_bind->ADDR_length); ret->addr.len = ti_bind->ADDR_length; ret->qlen = ti_bind->CONIND_number; } return(0); } int XR_T_UnBind(cd) struct conn_data * cd; { register struct _ti_user *tiptr; struct T_unbind_req *unbind_req; if (CheckCD(cd)) return(-1); if (IsEvent(cd->cd_fd, tiptr)) { return(-1); } unbind_req = (struct T_unbind_req *)cd->cd_ctlbuf; unbind_req->PRIM_type = T_UNBIND_REQ; if (!DoTIModIOCtl(cd, (caddr_t)unbind_req, sizeof(struct T_unbind_req), TI_UNBIND, 0)) { return(-1); } if (XR_IOCtl(cd->cd_fd, I_FLUSH, FLUSHRW) < 0) { cd->cd_errno = TSYSERR; return(-1); } /* * clear more data in TSDU bit */ cd->cd_flags &= ~MORE; return(0); } /* Listening */ int XR_T_Listen(cd, call) struct conn_data * cd; struct t_call *call; { struct strbuf ctlbuf; struct strbuf rcvbuf; int flg = 0; int retval; register union T_primitives *pptr; if (CheckCD(cd)) return(-1); /* * check if something in look buffer */ if (cd->cd_lookflg) { cd->cd_errno = TLOOK; return(-1); } if (cd->cd_servtype == T_CLTS) { cd->cd_errno = TNOTSUPPORT; return(-1); } ctlbuf.maxlen = cd->cd_ctlsize; ctlbuf.len = 0; ctlbuf.buf = cd->cd_ctlbuf; rcvbuf.maxlen = cd->cd_rcvsize; rcvbuf.len = 0; rcvbuf.buf = cd->cd_rcvbuf; if ((retval = XR_GetMsg(cd->cd_fd, &ctlbuf, &rcvbuf, &flg)) < 0) { if (XR_GetErrno() == EAGAIN) cd->cd_errno = TNODATA; else cd->cd_errno = TSYSERR; return(-1); } if (rcvbuf.len == -1) rcvbuf.len = 0; /* * did I get entire message? */ if (retval) { cd->cd_errno = TSYSERR; XR_SetErrno(EIO); return(-1); } /* * is ctl part large enough to determine type */ if (ctlbuf.len < sizeof(long)) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(-1); } pptr = (union T_primitives *)ctlbuf.buf; switch(pptr->type) { case T_CONN_IND: if ((ctlbuf.len < sizeof(struct T_conn_ind)) || (ctlbuf.len < (pptr->conn_ind.OPT_length + pptr->conn_ind.OPT_offset))) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(-1); } if ((rcvbuf.len > (int)call->udata.maxlen) || (pptr->conn_ind.SRC_length > call->addr.maxlen) || (pptr->conn_ind.OPT_length > call->opt.maxlen)) { cd->cd_errno = TBUFOVFLW; return(-1); } bcopy(ctlbuf.buf + pptr->conn_ind.SRC_offset, call->addr.buf, (int)pptr->conn_ind.SRC_length); call->addr.len = pptr->conn_ind.SRC_length; bcopy(ctlbuf.buf + pptr->conn_ind.OPT_offset, call->opt.buf, (int)pptr->conn_ind.OPT_length); call->opt.len = pptr->conn_ind.OPT_length; bcopy(rcvbuf.buf, call->udata.buf, (int)rcvbuf.len); call->udata.len = rcvbuf.len; call->sequence = pptr->conn_ind.SEQ_number; return(0); case T_DISCON_IND: PutBack(cd, rcvbuf.buf, rcvbuf.len, ctlbuf.buf, ctlbuf.len); cd->cd_errno = TLOOK; return(-1); default: break; } cd->cd_errno = TSYSERR; errno = EPROTO; return(-1); } int XR_T_Accept(cd, rescd, call) struct conn_data * cd; struct conn_data * rescd; struct t_call *call; { char *buf; register struct T_conn_res *cres; struct strfdinsert strfdinsert; int size; int retval; int resfd; if (CheckCD(cd)) return(-1); if (CheckCD(rescd)) return(-1); resfd = rescd->cd_fd; if (cd->cd_servtype == T_CLTS) { cd->cd_errno = TNOTSUPPORT; return(-1); } if (cd->cd_fd != resfd) { if ((retval = XR_IOCtl(resfd, I_NREAD, &size)) < 0) { cd->cd_errno = TSYSERR; return(-1); } if (retval) { cd->cd_errno = TBADF; return(-1); } } if (IsEvent(cd)) { return(-1); } buf = cd->cd_ctlbuf; cres = (struct T_conn_res *)buf; cres->PRIM_type = T_CONN_RES; cres->OPT_length = call->opt.len; cres->OPT_offset = 0; cres->SEQ_number = call->sequence; size = sizeof(struct T_conn_res); if (call->opt.len) { AlignedCopy(buf, call->opt.len, size, call->opt.buf, &cres->OPT_offset); size = cres->OPT_offset + cres->OPT_length; } strfdinsert.ctlbuf.maxlen = cd->cd_ctlsize; strfdinsert.ctlbuf.len = size; strfdinsert.ctlbuf.buf = buf; strfdinsert.databuf.maxlen = call->udata.maxlen; strfdinsert.databuf.len = (call->udata.len? call->udata.len: -1); strfdinsert.databuf.buf = call->udata.buf; strfdinsert.fildes = resfd; strfdinsert.offset = sizeof(long); strfdinsert.flags = 0; /* could be EXPEDITED also */ if (XR_IOCtl(cd->cd_fd, I_FDINSERT, &strfdinsert) < 0) { if (XR_GetErrno() == EAGAIN) cd->cd_errno = TFLOW; else cd->cd_errno = TSYSERR; return(-1); } if (!IsOK(cd, (long)T_CONN_RES)) { return(-1); } return(0); } /* State and Info gathering */ int XR_T_GetInfo(cd, info) struct conn_data * cd; register struct t_info *info; { struct T_info_ack inforeq; int retlen; if (CheckCD(cd)) return(-1); inforeq.PRIM_type = T_INFO_REQ; if (!DoTIModIOCtl(cd, (caddr_t)&inforeq, sizeof(struct T_info_req), TI_GETINFO, &retlen)) { return(-1); } if (retlen != sizeof(struct T_info_ack)) { XR_SetErrno(EIO); cd->cd_errno = TSYSERR; return(-1); } info->addr = inforeq.ADDR_size; info->options = inforeq.OPT_size; info->tsdu = inforeq.TSDU_size; info->etsdu = inforeq.ETSDU_size; info->connect = inforeq.CDATA_size; info->discon = inforeq.DDATA_size; info->servtype = inforeq.SERV_type; return(0); } int XR_T_GetState(cd) struct conn_data * cd; { struct T_info_ack info; int retlen; if (CheckCD(cd)) return(-1); info.PRIM_type = T_INFO_REQ; if (!DoTIModIOCtl(cd, (caddr_t)&info, sizeof(struct T_info_req), TI_GETINFO, &retlen)) { return(-1); } if (retlen != sizeof(struct T_info_ack)) { cd->cd_errno = TSYSERR; XR_SetErrno(EIO); return(-1); } switch (info.CURRENT_state) { case TS_UNBND: return(T_UNBND); case TS_IDLE: return(T_IDLE); case TS_WRES_CIND: return(T_INCON); case TS_WCON_CREQ: return(T_OUTCON); case TS_DATA_XFER: return(T_DATAXFER); case TS_WIND_ORDREL: return(T_OUTREL); case TS_WREQ_ORDREL: return(T_INREL); default: cd->cd_errno = TSTATECHNG; return(-1); } } int XR_T_Look(cd) register struct conn_data * cd; { struct strpeek strpeek; int retval; union T_primitives *pptr; long type; if (CheckCD(cd)) return(-1); strpeek.ctlbuf.maxlen = sizeof(long); strpeek.ctlbuf.len = 0; strpeek.ctlbuf.buf = cd->cd_ctlbuf; strpeek.databuf.maxlen = 0; strpeek.databuf.len = 0; strpeek.databuf.buf = NULL; strpeek.flags = 0; if ((retval = XR_IOCtl(cd->cd_fd, I_PEEK, &strpeek)) < 0) return(T_ERROR); /* * if something there and cnt part also there */ if (cd->cd_lookflg || (retval && (strpeek.ctlbuf.len >= sizeof(long)))) { pptr = (union T_primitives *)strpeek.ctlbuf.buf; if (cd->cd_lookflg) { if (((type = *((long *)cd->cd_lookcbuf)) != T_DISCON_IND) && (retval && (pptr->type == T_DISCON_IND))) { type = pptr->type; cd->cd_lookflg = 0; } } else type = pptr->type; switch(type) { case T_CONN_IND: return(T_LISTEN); case T_CONN_CON: return(T_CONNECT); case T_DISCON_IND: return(T_DISCONNECT); case T_DATA_IND: case T_UNITDATA_IND: return(T_DATA); case T_EXDATA_IND: return(T_EXDATA); case T_UDERROR_IND: return(T_UDERR); case T_ORDREL_IND: return(T_ORDREL); default: cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(-1); } } /* * if something there put no control part * it must be data */ if (retval && (strpeek.ctlbuf.len <= 0)) return(T_DATA); /* * if msg there and control * part not large enough to determine type? * it must be illegal TLI message */ if (retval && (strpeek.ctlbuf.len > 0)) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(-1); } return(0); } /* Reliable streams */ int XR_T_Connect(cd, sndcall, rcvcall) struct conn_data * cd; struct t_call *sndcall; struct t_call *rcvcall; { int fctlflg; if (CheckCD(cd)) return(-1); if (SendConnectionRequest(cd, sndcall) < 0) return(-1); if ((fctlflg = XR_FCntl(cd->cd_fd, F_GETFL, 0)) < 0) { cd->cd_errno = TSYSERR; return(-1); } if (fctlflg & O_NDELAY) { cd->cd_errno = TNODATA; return(-1); } if (ReceiveConnectionConfirmation(cd, rcvcall) < 0) { return(-1); } return(0); } /* * SendConnectionRequest - send connect request message to * transport provider */ int SendConnectionRequest(cd, call) struct conn_data * cd; register struct t_call *call; { register struct T_conn_req *creq; struct strbuf ctlbuf; char *buf; int size; if (CheckCD(cd)) return(-1); if (cd->cd_servtype == T_CLTS) { cd->cd_errno = TNOTSUPPORT; return(-1); } if (IsEvent(cd)) { return(-1); } buf = cd->cd_ctlbuf; creq = (struct T_conn_req *)buf; creq->PRIM_type = T_CONN_REQ; creq->DEST_length = call->addr.len; creq->DEST_offset = 0L; creq->OPT_length = call->opt.len; creq->OPT_offset = 0L; size = sizeof(struct T_conn_req); if (call->addr.len) { AlignedCopy(buf, call->addr.len, size, call->addr.buf, &creq->DEST_offset); size = creq->DEST_offset + creq->DEST_length; } if (call->opt.len) { AlignedCopy(buf, call->opt.len, size, call->opt.buf, &creq->OPT_offset); size = creq->OPT_offset + creq->OPT_length; } ctlbuf.maxlen = cd->cd_ctlsize; ctlbuf.len = size; ctlbuf.buf = buf; if (XR_PutMsg(cd->cd_fd, &ctlbuf, (call->udata.len? &call->udata: 0L), 0) < 0) { cd->cd_errno = TSYSERR; return(-1); } if (!IsOK(cd, (long)T_CONN_REQ)) { return(-1); } return(0); } /* * ReceiveConnectionConfirmation - get connection confirmation off * of read queue */ int ReceiveConnectionConfirmation(cd, call) struct conn_data * cd; register struct t_call *call; { struct strbuf ctlbuf; struct strbuf rcvbuf; int flg = 0; register union T_primitives *pptr; int retval; if (CheckCD(cd)) return(-1); if (cd->cd_servtype == T_CLTS) { cd->cd_errno = TNOTSUPPORT; return(-1); } /* * see if there is something in look buffer */ if (cd->cd_lookflg) { cd->cd_errno = TLOOK; return(-1); } ctlbuf.maxlen = cd->cd_ctlsize; ctlbuf.len = 0; ctlbuf.buf = cd->cd_ctlbuf; rcvbuf.maxlen = cd->cd_rcvsize; rcvbuf.len = 0; rcvbuf.buf = cd->cd_rcvbuf; if ((retval = XR_GetMsg(cd->cd_fd, &ctlbuf, &rcvbuf, &flg)) < 0) { if (XR_GetErrno() == EAGAIN) cd->cd_errno = TNODATA; else cd->cd_errno = TSYSERR; return(-1); } if (rcvbuf.len == -1) rcvbuf.len = 0; /* * did we get entire message */ if (retval) { cd->cd_errno = TSYSERR; XR_SetErrno(EIO); return(-1); } /* * is cntl part large enough to determine message type? */ if (ctlbuf.len < sizeof(long)) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(-1); } pptr = (union T_primitives *)ctlbuf.buf; switch((int)pptr->type) { case T_CONN_CON: if ((ctlbuf.len < sizeof(struct T_conn_con)) || (ctlbuf.len < (pptr->conn_con.OPT_length + pptr->conn_con.OPT_offset))) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(-1); } if (call != NULL) { if ((rcvbuf.len > (int)call->udata.maxlen) || (pptr->conn_con.RES_length > call->addr.maxlen) || (pptr->conn_con.OPT_length > call->opt.maxlen)) { cd->cd_errno = TBUFOVFLW; return(-1); } bcopy(ctlbuf.buf + pptr->conn_con.RES_offset, call->addr.buf, (int)pptr->conn_con.RES_length); call->addr.len = pptr->conn_con.RES_length; bcopy(ctlbuf.buf + pptr->conn_con.OPT_offset, call->opt.buf, (int)pptr->conn_con.OPT_length); call->opt.len = pptr->conn_con.OPT_length; bcopy(rcvbuf.buf, call->udata.buf, (int)rcvbuf.len); call->udata.len = rcvbuf.len; /* * since a confirmation seq number * is -1 by default */ call->sequence = -1; } return(0); case T_DISCON_IND: /* * if disconnect indication then put it in look buf */ PutBack(cd, rcvbuf.buf, rcvbuf.len, ctlbuf.buf, ctlbuf.len); cd->cd_errno = TLOOK; return(-1); default: break; } cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(-1); } int XR_T_Rcv(cd, buf, nbytes, flags) register struct conn_data * cd; register char *buf; unsigned nbytes; int *flags; { struct strbuf ctlbuf, rcvbuf; int retval, flg = 0; int msglen; register union T_primitives *pptr; if (CheckCD(cd)) return(-1); if (cd->cd_servtype == T_CLTS) { cd->cd_errno = TNOTSUPPORT; return(-1); } /* * Check in lookbuf for stuff */ if (cd->cd_lookflg) { /* * Beware - this is right! * If something in lookbuf then check * read queue to see if there is something there. * If there is something there and there is not a * discon in lookbuf, then it must be a discon. * If so, fall through to get it off of queue. * I fall through to make sure it is a discon, * instead of making check here. * * If nothing in read queue then just return TLOOK. */ if ((retval = XR_IOCtl(cd->cd_fd, I_NREAD, &msglen)) < 0) { cd->cd_errno = TSYSERR; return(-1); } if (retval) { if (*((long *)cd->cd_lookcbuf) == T_DISCON_IND) { cd->cd_errno = TLOOK; return(-1); } } else { cd->cd_errno = TLOOK; return(-1); } } ctlbuf.maxlen = cd->cd_ctlsize; ctlbuf.len = 0; ctlbuf.buf = cd->cd_ctlbuf; rcvbuf.maxlen = nbytes; rcvbuf.len = 0; rcvbuf.buf = buf; *flags = 0; /* * data goes right in user buffer */ if ((retval = XR_GetMsg(cd->cd_fd, &ctlbuf, &rcvbuf, &flg)) < 0) { if (XR_GetErrno() == EAGAIN) cd->cd_errno = TNODATA; else cd->cd_errno = TSYSERR; return(-1); } printf("retval returned from XR_GetMsg: %d\n", retval); printf("flg returned from XR_GetMsg: %d\n", flg); if (rcvbuf.len == -1) rcvbuf.len = 0; if (ctlbuf.len > 0) { if (ctlbuf.len < sizeof(long)) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(-1); } pptr = (union T_primitives *)ctlbuf.buf; switch(pptr->type) { case T_EXDATA_IND: *flags |= T_EXPEDITED; /* flow thru */ case T_DATA_IND: if ((ctlbuf.len < sizeof(struct T_data_ind)) || (cd->cd_lookflg)) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(-1); } if ((pptr->data_ind.MORE_flag) || retval) { printf("pptr->data_ind.MORE_flag = %d\n", pptr->data_ind.MORE_flag); *flags |= T_MORE; } if ((pptr->data_ind.MORE_flag) && retval) cd->cd_flags |= MORE; return(rcvbuf.len); case T_ORDREL_IND: if (cd->cd_lookflg) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(-1); } /* flow thru */ case T_DISCON_IND: PutBack(cd, rcvbuf.buf, rcvbuf.len, ctlbuf.buf, ctlbuf.len); if (retval&MOREDATA) { ctlbuf.maxlen = 0; ctlbuf.len = 0; ctlbuf.buf = cd->cd_ctlbuf; rcvbuf.maxlen = cd->cd_rcvsize - rcvbuf.len; rcvbuf.len = 0; rcvbuf.buf = cd->cd_lookdbuf+cd->cd_lookdsize; *flags = 0; if ((retval = XR_GetMsg(cd->cd_fd, &ctlbuf, &rcvbuf, &flg)) < 0) { cd->cd_errno = TSYSERR; return(-1); } if (rcvbuf.len == -1) rcvbuf.len = 0; if (retval) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); cd->cd_lookflg = 0; return(-1); } cd->cd_lookdsize += rcvbuf.len; } cd->cd_errno = TLOOK; return(-1); default: break; } cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(-1); } else { if (!retval && (cd->cd_flags&MORE)) { *flags |= T_MORE; cd->cd_flags &= ~MORE; } if (retval) *flags |= T_MORE; return(rcvbuf.len); } } int XR_T_RcvConnect(cd, call) struct conn_data * cd; struct t_call *call; { return(ReceiveConnectionConfirmation(cd, call)); } int XR_T_RcvDis(cd, discon) struct conn_data * cd; struct t_discon *discon; { struct strbuf ctlbuf; struct strbuf databuf; int retval; int flg = 0; union T_primitives *pptr; if (CheckCD(cd)) return(-1); if (cd->cd_servtype == T_CLTS) { cd->cd_errno = TNOTSUPPORT; return(-1); } /* * is there a discon in look buffer */ if (cd->cd_lookflg && (*((long *)cd->cd_lookcbuf) == T_DISCON_IND)) { ctlbuf.maxlen = cd->cd_lookcsize; ctlbuf.len = cd->cd_lookcsize; ctlbuf.buf = cd->cd_lookcbuf; databuf.maxlen = cd->cd_lookdsize; databuf.len = cd->cd_lookdsize; databuf.buf = cd->cd_lookdbuf; } else { if ((retval = XR_T_Look(cd)) < 0) { return(-1); } if (retval != T_DISCONNECT) { cd->cd_errno = TNODIS; return(-1); } /* * get disconnect off read queue. * use ctl and rcv buffers */ ctlbuf.maxlen = cd->cd_ctlsize; ctlbuf.len = 0; ctlbuf.buf = cd->cd_ctlbuf; databuf.maxlen = cd->cd_rcvsize; databuf.len = 0; databuf.buf = cd->cd_rcvbuf; if ((retval = XR_GetMsg(cd->cd_fd, &ctlbuf, &databuf, &flg)) < 0) { cd->cd_errno = TSYSERR; return(-1); } if (databuf.len == -1) databuf.len = 0; /* * did I get entire message? */ if (retval) { cd->cd_errno = TSYSERR; XR_SetErrno(EIO); return(-1); } } cd->cd_lookflg = 0; pptr = (union T_primitives *)ctlbuf.buf; if ((ctlbuf.len < sizeof(struct T_discon_ind)) || (pptr->type != T_DISCON_IND)) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(-1); } if (discon != NULL) { if (databuf.len > (int)discon->udata.maxlen) { cd->cd_errno = TBUFOVFLW; return(-1); } discon->reason = pptr->discon_ind.DISCON_reason; bcopy(databuf.buf, discon->udata.buf, (int)databuf.len); discon->udata.len = databuf.len; discon->sequence = pptr->discon_ind.SEQ_number; } /* * clear more flag */ cd->cd_flags &= ~MORE; return(0); } int XR_T_RcvRel(cd) struct conn_data * cd; { struct strbuf ctlbuf; struct strbuf databuf; int retval; int flg = 0; union T_primitives *pptr; if (CheckCD(cd)) return(-1); if (cd->cd_servtype != T_COTS_ORD) { cd->cd_errno = TNOTSUPPORT; return(-1); } if ((retval = XR_T_Look(cd)) < 0) { return(-1); } if (retval == T_DISCONNECT) { cd->cd_errno = TLOOK; return(-1); } if (cd->cd_lookflg && (*((long *)cd->cd_lookcbuf) == T_ORDREL_IND)) { cd->cd_lookflg = 0; return(0); } else { if (retval != T_ORDREL) { cd->cd_errno = TNOREL; return(-1); } } /* * get ordrel off read queue. * use ctl and rcv buffers */ ctlbuf.maxlen = cd->cd_ctlsize; ctlbuf.len = 0; ctlbuf.buf = cd->cd_ctlbuf; databuf.maxlen = cd->cd_rcvsize; databuf.len = 0; databuf.buf = cd->cd_rcvbuf; if ((retval = XR_GetMsg(cd->cd_fd, &ctlbuf, &databuf, &flg)) < 0) { cd->cd_errno = TSYSERR; return(-1); } /* * did I get entire message? */ if (retval) { cd->cd_errno = TSYSERR; XR_SetErrno(EIO); return(-1); } pptr = (union T_primitives *)ctlbuf.buf; if ((ctlbuf.len < sizeof(struct T_ordrel_ind)) || (pptr->type != T_ORDREL_IND)) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(-1); } return(0); } int XR_T_Snd(cd, buf, nbytes, flags) struct conn_data * cd; register char *buf; unsigned nbytes; int flags; { struct strbuf ctlbuf, databuf; struct T_data_req *datareq; int flg = 0; int tmpcnt, tmp; char *tmpbuf; if (CheckCD(cd)) return(-1); if (cd->cd_servtype == T_CLTS) { cd->cd_errno = TNOTSUPPORT; return(-1); } datareq = (struct T_data_req *)cd->cd_ctlbuf; if (flags & T_EXPEDITED) { datareq->PRIM_type = T_EXDATA_REQ; } else datareq->PRIM_type = T_DATA_REQ; ctlbuf.maxlen = sizeof(struct T_data_req); ctlbuf.len = sizeof(struct T_data_req); ctlbuf.buf = cd->cd_ctlbuf; tmp = nbytes; tmpbuf = buf; while (tmp) { if ((tmpcnt = tmp) > cd->cd_maxpsz) { datareq->MORE_flag = 1; tmpcnt = cd->cd_maxpsz; } else { if (flags & T_MORE) datareq->MORE_flag = 1; else datareq->MORE_flag = 0; } databuf.maxlen = tmpcnt; databuf.len = tmpcnt; databuf.buf = tmpbuf; if (XR_PutMsg(cd->cd_fd, &ctlbuf, &databuf, flg) < 0) { if (nbytes == tmp) { if (XR_GetErrno() == EAGAIN) cd->cd_errno = TFLOW; else cd->cd_errno = TSYSERR; return(-1); } else return(nbytes - tmp); } tmp = tmp - tmpcnt; tmpbuf = tmpbuf + tmpcnt; } return(nbytes - tmp); } int XR_T_SndDis(cd, call) register struct conn_data * cd; struct t_call *call; { struct T_discon_req dreq; struct strbuf ctlbuf; struct strbuf databuf; if (CheckCD(cd)) return(-1); if (cd->cd_servtype == T_CLTS) { cd->cd_errno = TNOTSUPPORT; return(-1); } /* * look at look buffer to see if there is a discon there */ if (XR_T_Look(cd) == T_DISCONNECT) { cd->cd_errno = TLOOK; return(-1); } cd->cd_lookflg = 0; if (XR_IOCtl(cd->cd_fd, I_FLUSH, FLUSHW) < 0) { cd->cd_errno = TSYSERR; return(-1); } dreq.PRIM_type = T_DISCON_REQ; dreq.SEQ_number = (call? call->sequence: -1); ctlbuf.maxlen = sizeof(struct T_discon_req); ctlbuf.len = sizeof(struct T_discon_req); ctlbuf.buf = (caddr_t)&dreq; databuf.maxlen = (call? call->udata.len: 0); databuf.len = (call? call->udata.len: 0); databuf.buf = (call? call->udata.buf: NULL); if (XR_PutMsg(cd->cd_fd, &ctlbuf, (databuf.len? &databuf: NULL), 0) < 0) { cd->cd_errno = TSYSERR; return(-1); } if (!IsOK(cd, (long)T_DISCON_REQ)) { return(-1); } cd->cd_flags &= ~MORE; return(0); } int XR_T_SndRel(cd) register struct conn_data * cd; { struct T_ordrel_req orreq; struct strbuf ctlbuf; if (CheckCD(cd)) return(-1); if (cd->cd_servtype != T_COTS_ORD) { cd->cd_errno = TNOTSUPPORT; return(-1); } orreq.PRIM_type = T_ORDREL_REQ; ctlbuf.maxlen = sizeof(struct T_ordrel_req); ctlbuf.len = sizeof(struct T_ordrel_req); ctlbuf.buf = (caddr_t)&orreq; if (XR_PutMsg(cd->cd_fd, &ctlbuf, NULL, 0) < 0) { if (XR_GetErrno() == EAGAIN) cd->cd_errno = TFLOW; else cd->cd_errno = TSYSERR; return(-1); } return(0); } /* Datagram things */ int XR_T_RcvUData(cd, unitdata, flags) struct conn_data * cd; register struct t_unitdata *unitdata; int *flags; { struct strbuf ctlbuf; int retval, flg = 0; register union T_primitives *pptr; if (CheckCD(cd)) return(-1); /* because of cd->cd_errno */ if (cd->cd_servtype != T_CLTS) { cd->cd_errno = TNOTSUPPORT; return(-1); } /* * check if there is something in look buffer */ if (cd->cd_lookflg) { cd->cd_errno = TLOOK; return(-1); } ctlbuf.maxlen = cd->cd_ctlsize; ctlbuf.len = 0; ctlbuf.buf = cd->cd_ctlbuf; *flags = 0; /* * data goes right in user buffer */ if ((retval = XR_GetMsg(cd->cd_fd, &ctlbuf, &unitdata->udata, &flg)) < 0) { if (XR_GetErrno() == EAGAIN) cd->cd_errno = TNODATA; else cd->cd_errno = TSYSERR; return(-1); } if (unitdata->udata.len == -1) unitdata->udata.len = 0; /* * is there control piece with data? */ if (ctlbuf.len > 0) { if (ctlbuf.len < sizeof(long)) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); unitdata->udata.len = 0; return(-1); } pptr = (union T_primitives *)ctlbuf.buf; switch(pptr->type) { case T_UNITDATA_IND: if ((ctlbuf.len < sizeof(struct T_unitdata_ind)) || (pptr->unitdata_ind.OPT_length && (ctlbuf.len < (pptr->unitdata_ind.OPT_length + pptr->unitdata_ind.OPT_offset)))) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); unitdata->udata.len = 0; return(-1); } if ((pptr->unitdata_ind.SRC_length > (int)unitdata->addr.maxlen) || (pptr->unitdata_ind.OPT_length > (int)unitdata->opt.maxlen)) { cd->cd_errno = TBUFOVFLW; unitdata->udata.len = 0; return(-1); } if (retval) *flags |= T_MORE; bcopy(ctlbuf.buf + pptr->unitdata_ind.SRC_offset, unitdata->addr.buf, (int)pptr->unitdata_ind.SRC_length); unitdata->addr.len = pptr->unitdata_ind.SRC_length; bcopy(ctlbuf.buf + pptr->unitdata_ind.OPT_offset, unitdata->opt.buf, (int)pptr->unitdata_ind.OPT_length); unitdata->opt.len = pptr->unitdata_ind.OPT_length; return(0); case T_UDERROR_IND: PutBack(cd, unitdata->udata.buf, 0, ctlbuf.buf, ctlbuf.len); unitdata->udata.len = 0; cd->cd_errno = TLOOK; return(-1); default: break; } cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(-1); } else { unitdata->addr.len = 0; unitdata->opt.len = 0; /* * only data in message no control piece */ if (retval) *flags = T_MORE; return(0); } } int XR_T_RcvUDErr(cd, uderr) struct conn_data * cd; struct t_uderr *uderr; { struct strbuf ctlbuf, rcvbuf; int flg; int retval; register union T_primitives *pptr; if (CheckCD(cd)) return(-1); if (cd->cd_servtype != T_CLTS) { cd->cd_errno = TNOTSUPPORT; return(-1); } /* * is there an error indication in look buffer */ if (cd->cd_lookflg) { ctlbuf.maxlen = cd->cd_lookcsize; ctlbuf.len = cd->cd_lookcsize; ctlbuf.buf = cd->cd_lookcbuf; rcvbuf.maxlen = 0; rcvbuf.len = 0; rcvbuf.buf = NULL; } else { if ((retval = XR_T_Look(cd)) < 0) return(-1); if (retval != T_UDERR) { cd->cd_errno = TNOUDERR; return(-1); } ctlbuf.maxlen = cd->cd_ctlsize; ctlbuf.len = 0; ctlbuf.buf = cd->cd_ctlbuf; rcvbuf.maxlen = 0; rcvbuf.len = 0; rcvbuf.buf = NULL; if ((retval = XR_GetMsg(cd->cd_fd, &ctlbuf, &rcvbuf, &flg)) < 0) { cd->cd_errno = TSYSERR; return(-1); } /* * did I get entire message? */ if (retval) { cd->cd_errno = TSYSERR; XR_SetErrno(EIO); return(-1); } } cd->cd_lookflg = 0; pptr = (union T_primitives *)ctlbuf.buf; if ((ctlbuf.len < sizeof(struct T_uderror_ind)) || (pptr->type != T_UDERROR_IND)) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(-1); } if (uderr) { if ((uderr->addr.maxlen < pptr->uderror_ind.DEST_length) || (uderr->opt.maxlen < pptr->uderror_ind.OPT_length)) { cd->cd_errno = TBUFOVFLW; return(-1); } uderr->error = pptr->uderror_ind.ERROR_type; bcopy(ctlbuf.buf + pptr->uderror_ind.DEST_offset, uderr->addr.buf, (int)pptr->uderror_ind.DEST_length); bcopy(ctlbuf.buf + pptr->uderror_ind.OPT_offset, uderr->opt.buf, (int)pptr->uderror_ind.OPT_length); } return(0); } int XR_T_SndUData(cd, unitdata) struct conn_data * cd; register struct t_unitdata *unitdata; { register struct T_unitdata_req *udreq; char *buf; struct strbuf ctlbuf; int size; if (CheckCD(cd)) return(-1); if (cd->cd_servtype != T_CLTS) { cd->cd_errno = TNOTSUPPORT; return(-1); } if ((int)unitdata->udata.len == 0) return(0); if ((int)unitdata->udata.len > cd->cd_maxpsz) { cd->cd_errno = TSYSERR; XR_SetErrno(ERANGE); return(-1); } buf = cd->cd_ctlbuf; udreq = (struct T_unitdata_req *)buf; udreq->PRIM_type = T_UNITDATA_REQ; udreq->DEST_length = unitdata->addr.len; udreq->DEST_offset = 0; udreq->OPT_length = unitdata->opt.len; udreq->OPT_offset = 0; size = sizeof(struct T_unitdata_req); if (unitdata->addr.len) { AlignedCopy(buf, unitdata->addr.len, size, unitdata->addr.buf, &udreq->DEST_offset); size = udreq->DEST_offset + udreq->DEST_length; } if (unitdata->opt.len) { AlignedCopy(buf, unitdata->opt.len, size, unitdata->opt.buf, &udreq->OPT_offset); size = udreq->OPT_offset + udreq->OPT_length; } if (size > cd->cd_ctlsize) { cd->cd_errno = TSYSERR; XR_SetErrno(EIO); return(-1); } ctlbuf.maxlen = cd->cd_ctlsize; ctlbuf.len = size; ctlbuf.buf = buf; if (XR_PutMsg(cd->cd_fd, &ctlbuf, (unitdata->udata.len? &unitdata->udata: NULL), 0) < 0) { if (XR_GetErrno() == EAGAIN) cd->cd_errno = TFLOW; else cd->cd_errno = TSYSERR; return(-1); } return(0); } /* Allocation things */ char * XR_T_Alloc(cd, struct_type, fields) struct conn_data * cd; int struct_type; int fields; { struct strioctl strioc; struct T_info_ack info; union structptrs { char *caddr; struct t_bind *bind; struct t_call *call; struct t_discon *dis; struct t_optmgmt *opt; struct t_unitdata *udata; struct t_uderr *uderr; struct t_info *info; } p; unsigned dsize; if (CheckCD(cd)) return(NULL); /* * Get size info for T_ADDR, T_OPT, and T_UDATA fields */ info.PRIM_type = T_INFO_REQ; strioc.ic_cmd = TI_GETINFO; strioc.ic_timout = -1; strioc.ic_len = sizeof(struct T_info_req); strioc.ic_dp = (char *)&info; if (XR_IOCtl(cd->cd_fd, I_STR, &strioc) < 0) { cd->cd_errno = TSYSERR; return(NULL); } if (strioc.ic_len != sizeof(struct T_info_ack)) { XR_SetErrno(EIO); cd->cd_errno = TSYSERR; return(NULL); } /* * Malloc appropriate structure and the specified * fields within each structure. Initialize the * 'buf' and 'maxlen' fields of each. */ switch (struct_type) { case T_BIND: if ((p.bind = (struct t_bind *) GC_malloc((unsigned)sizeof(struct t_bind))) == NULL) goto out; if (fields & T_ADDR) { if (AllocBuf(&p.bind->addr, info.ADDR_size) < 0) goto out; } return((char *)p.bind); case T_CALL: if ((p.call = (struct t_call *) GC_malloc((unsigned)sizeof(struct t_call))) == NULL) goto out; if (fields & T_ADDR) { if (AllocBuf(&p.call->addr, info.ADDR_size) < 0) goto out; } if (fields & T_OPT) { if (AllocBuf(&p.call->opt, info.OPT_size) < 0) goto out; } if (fields & T_UDATA) { dsize = Max(info.CDATA_size, info.DDATA_size); if (AllocBuf(&p.call->udata, dsize) < 0) goto out; } return((char *)p.call); case T_OPTMGMT: if ((p.opt = (struct t_optmgmt *) GC_malloc((unsigned)sizeof(struct t_optmgmt))) == NULL) goto out; if (fields & T_OPT){ if (AllocBuf(&p.opt->opt, info.OPT_size) < 0) goto out; } return((char *)p.opt); case T_DIS: if ((p.dis = (struct t_discon *) GC_malloc((unsigned)sizeof(struct t_discon))) == NULL) goto out; if (fields & T_UDATA){ if (AllocBuf(&p.dis->udata, info.DDATA_size) < 0) goto out; } return((char *)p.dis); case T_UNITDATA: if ((p.udata = (struct t_unitdata *) GC_malloc((unsigned)sizeof(struct t_unitdata))) == NULL) goto out; if (fields & T_ADDR){ if (AllocBuf(&p.udata->addr, info.ADDR_size) < 0) goto out; } if (fields & T_OPT){ if (AllocBuf(&p.udata->opt, info.OPT_size) < 0) goto out; } if (fields & T_UDATA){ if (AllocBuf(&p.udata->udata, info.TSDU_size) < 0) goto out; } return((char *)p.udata); case T_UDERROR: if ((p.uderr = (struct t_uderr *) GC_malloc((unsigned)sizeof(struct t_uderr))) == NULL) goto out; if (fields & T_ADDR){ if (AllocBuf(&p.uderr->addr, info.ADDR_size) < 0) goto out; } if (fields & T_OPT){ if (AllocBuf(&p.uderr->opt, info.OPT_size) < 0) goto out; } return((char *)p.uderr); case T_INFO: if ((p.info = (struct t_info *) GC_malloc((unsigned)sizeof(struct t_info))) == NULL) goto out; return((char *)p.info); default: XR_SetErrno(EINVAL); cd->cd_errno = TSYSERR; return(NULL); } /* * Clean up. Set errno to ENOMEM if * memory could not be allocated. */ out: if (p.caddr) XR_T_Free(cd, p.caddr, struct_type); cd->cd_errno = TSYSERR; XR_SetErrno(ENOMEM); return(NULL); }; int XR_T_Free(cd, ptr, struct_type) struct conn_data * cd; char *ptr; int struct_type; { union structptrs { struct t_bind *bind; struct t_call *call; struct t_discon *dis; struct t_optmgmt *opt; struct t_unitdata *udata; struct t_uderr *uderr; } p; if (CheckCD(cd)) return(-1); /* because of cd->cd_errno */ /* * Free all the buffers associated with the appropriate * fields of each structure. */ switch (struct_type) { case T_BIND: p.bind = (struct t_bind *)ptr; if (p.bind->addr.buf != NULL) free(p.bind->addr.buf); break; case T_CALL: p.call = (struct t_call *)ptr; if (p.call->addr.buf != NULL) free(p.call->addr.buf); if (p.call->opt.buf != NULL) free(p.call->opt.buf); if (p.call->udata.buf != NULL) free(p.call->udata.buf); break; case T_OPTMGMT: p.opt = (struct t_optmgmt *)ptr; if (p.opt->opt.buf != NULL) free(p.opt->opt.buf); break; case T_DIS: p.dis = (struct t_discon *)ptr; if (p.dis->udata.buf != NULL) free(p.dis->udata.buf); break; case T_UNITDATA: p.udata = (struct t_unitdata *)ptr; if (p.udata->addr.buf != NULL) free(p.udata->addr.buf); if (p.udata->opt.buf != NULL) free(p.udata->opt.buf); if (p.udata->udata.buf != NULL) free(p.udata->udata.buf); break; case T_UDERROR: p.uderr = (struct t_uderr *)ptr; if (p.uderr->addr.buf != NULL) free(p.uderr->addr.buf); if (p.uderr->opt.buf != NULL) free(p.uderr->opt.buf); break; case T_INFO: break; default: XR_SetErrno(EINVAL); cd->cd_errno = TSYSERR; return(-1); } free(ptr); return(0); } /* Other useful stuff */ /* * put data and control info in look buffer * * The only thing that can be in look buffer is a T_discon_ind, * T_ordrel_ind or a T_uderr_ind. */ int PutBack(cd, dptr, dsize, cptr, csize) struct conn_data * cd; caddr_t dptr; int dsize; caddr_t cptr; int csize; { if (CheckCD(cd)) return(-1); bcopy(dptr, cd->cd_lookdbuf, dsize); bcopy(cptr, cd->cd_lookcbuf, csize); cd->cd_lookdsize = dsize; cd->cd_lookcsize = csize; cd->cd_lookflg++; } int AllocBuf(buf, n) struct netbuf *buf; { switch(n) { case -1: if ((buf->buf = (char *) GC_malloc(1024)) == NULL) return(-1); else buf->maxlen = 1024; break; case 0: case -2: buf->buf = NULL; buf->maxlen = 0; break; default: if ((buf->buf = (char *) GC_malloc(n)) == NULL) return(-1); else buf->maxlen = n; break; } return(0); } /* * copy data to output buffer and align it as in input buffer * This is to ensure that if the user wants to align a network * addr on a non-word boundry then it will happen. */ int AlignedCopy(buf, len, init_offset, datap, rtn_offset) char *buf; int len; int init_offset; char *datap; long *rtn_offset; { *rtn_offset = ROUNDUP(init_offset) + ((unsigned)datap&0x03); bcopy(datap, (char *)(buf + *rtn_offset), (int)len); } /* * CheckCD checks to see that the contents of the cd data * structure is good */ int CheckCD(cd) struct conn_data * cd; { if (cd == NULL) return(1); if ((cd->cd_fd < 0) || !(cd->cd_flags & USED)) { cd->cd_errno = TBADF; return(1); }; return(0); }; /* * Max - return max between two ints */ int Max(x, y) int x; int y; { if (x > y) return(x); else return(y); }; /* * Is there something that needs attention? */ int IsEvent(cd) struct conn_data * cd; { int size, retval; if ((retval = XR_IOCtl(cd->cd_fd, I_NREAD, &size)) < 0) { cd->cd_errno = TSYSERR; return(1); } if (retval || cd->cd_lookflg) { cd->cd_errno = TLOOK; return(1); } return(0); } /* * wait for T_OK_ACK */ int IsOK(cd, type) register struct conn_data * cd; long type; { struct strbuf ctlbuf; struct strbuf rcvbuf; register union T_primitives *pptr; int flags, retval, cntlflag; int size; int fd = cd->cd_fd; cntlflag = XR_FCntl(fd, F_GETFL, 0); XR_FCntl(fd, F_SETFL, XR_FCntl(fd, F_GETFL, 0) & ~O_NDELAY); ctlbuf.len = 0; ctlbuf.buf = cd->cd_ctlbuf; ctlbuf.maxlen = cd->cd_ctlsize; rcvbuf.maxlen = cd->cd_rcvsize; rcvbuf.len = 0; rcvbuf.buf = cd->cd_rcvbuf; flags = RS_HIPRI; while ((retval = XR_GetMsg(fd, &ctlbuf, &rcvbuf, &flags)) < 0) { if (XR_GetErrno() == EINTR) continue; cd->cd_errno = TSYSERR; return(0); } /* did I get entire message */ if (retval) { cd->cd_errno = TSYSERR; XR_SetErrno(EIO); return(0); } /* * is ctl part large enough to determine type? */ if (ctlbuf.len < sizeof(long)) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(0); } XR_FCntl(cd->cd_fd, F_SETFL, cntlflag); pptr = (union T_primitives *)ctlbuf.buf; switch((int)pptr->type) { case T_OK_ACK: if ((ctlbuf.len < sizeof(struct T_ok_ack)) || (pptr->ok_ack.CORRECT_prim != type)) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(0); } return(1); case T_ERROR_ACK: if ((ctlbuf.len < sizeof(struct T_error_ack)) || (pptr->error_ack.ERROR_prim != type)) { cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(0); } /* * if error is out of state and there is something * on read queue, then indicate to user that * there is something that needs attention */ if (pptr->error_ack.TLI_error == TOUTSTATE) { if ((retval = XR_IOCtl(fd, I_NREAD, &size)) < 0) { cd->cd_errno = TSYSERR; return(0); } if (retval) cd->cd_errno = TLOOK; else cd->cd_errno = TOUTSTATE; } else { cd->cd_errno = pptr->error_ack.TLI_error; if (cd->cd_errno == TSYSERR) XR_SetErrno(pptr->error_ack.UNIX_error); } return(0); default: cd->cd_errno = TSYSERR; XR_SetErrno(EPROTO); return(0); } } /* * timod XR_IOCtl */ int DoTIModIOCtl(cd, buf, size, cmd, retlen) struct conn_data * cd; char *buf; int size; int cmd; int *retlen; { int fd = cd->cd_fd; int retval; struct strioctl strioc; strioc.ic_cmd = cmd; strioc.ic_timout = -1; strioc.ic_len = size; strioc.ic_dp = buf; if ((retval = XR_IOCtl(fd, I_STR, &strioc)) < 0) { cd->cd_errno = TSYSERR; return(0); } if (retval) { cd->cd_errno = retval&0xff; if (cd->cd_errno == TSYSERR) XR_SetErrno((retval >> 8)&0xff); return(0); } if (retlen){ *retlen = strioc.ic_len; } return(1); } /* * alloc scratch buffers and look buffers */ AllocateBuffers(cd, info) struct conn_data * cd; struct T_info_ack info; { unsigned size1, size2; unsigned csize, dsize, asize, osize; char *ctlbuf, *rcvbuf; char *lookdbuf, *lookcbuf; csize = SetSize(info.CDATA_size); dsize = SetSize(info.DDATA_size); size1 = Max(csize, dsize); if ((rcvbuf = (char *) GC_malloc(size1)) == NULL) { return(-1); } if ((lookdbuf = (char *) GC_malloc(size1)) == NULL) { (void)free(rcvbuf); return(-1); } asize = SetSize(info.ADDR_size); osize = SetSize(info.OPT_size); size2 = sizeof(union T_primitives) + asize + sizeof(long) + osize + sizeof(long); if ((ctlbuf = (char *) GC_malloc(size2)) == NULL) { (void)free(rcvbuf); (void)free(lookdbuf); return(-1); } if ((lookcbuf = (char *) GC_malloc(size2)) == NULL) { (void)free(rcvbuf); (void)free(lookdbuf); (void)free(ctlbuf); return(-1); } cd->cd_rcvsize = size1; cd->cd_rcvbuf = rcvbuf; cd->cd_ctlsize = size2; cd->cd_ctlbuf = ctlbuf; cd->cd_lookcbuf = lookcbuf; cd->cd_lookdbuf = lookdbuf; cd->cd_lookcsize = 0; cd->cd_lookdsize = 0; cd->cd_lookflg = 0; cd->cd_flags = USED; cd->cd_maxpsz = info.TIDU_size; cd->cd_servtype = info.SERV_type; return(0); } /* * set sizes of buffers */ SetSize(infosize) long infosize; { switch((int)infosize) { case -1: return(DEFSIZE); case -2: return(0); default: return(infosize); } }