#include <sys/errno.h>
#include <sys/types.h>
#include <sys/param.h>
#include <machine/spl.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/filedesc.h>
#include <sys/fcntl.h>
#include <sys/mbuf.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netat/sysglue.h>
#include <netat/appletalk.h>
#include <netat/ddp.h>
#include <netat/at_pcb.h>
#include <netat/at_var.h>
#include <netat/atp.h>
#include <netat/asp.h>
#include <netat/debug.h>
static void atp_trans_complete(struct atp_trans *);
void atp_x_done_locked(void *);
void atp_treq_event(void *);
void atp_treq_event(void *arg)
{
register gref_t *gref = (gref_t *)arg;
register gbuf_t *m;
register struct atp_state *atp;
atalk_lock();
atp = (struct atp_state *)gref->info;
if (atp->dflag)
atp = (struct atp_state *)atp->atp_msgq;
if (atp->dflag) {
if ((m = gbuf_alloc(sizeof(ioc_t), PRI_HI)) != NULL) {
gbuf_set_type(m, MSG_IOCTL);
gbuf_wset(m,sizeof(ioc_t));
((ioc_t *)gbuf_rptr(m))->ioc_cmd = AT_ATP_GET_POLL;
atp_wput(gref, m);
}
}
else if ((m = gbuf_alloc(1, PRI_HI)) != NULL) {
*gbuf_rptr(m) = 0;
gbuf_wset(m,1);
atalk_putnext(gref, m);
}
if (m == 0)
timeout(atp_treq_event, gref, 10);
atalk_unlock();
}
void atp_rput(gref, m)
gref_t *gref;
gbuf_t *m;
{
register at_atp_t *athp;
register struct atp_state *atp;
gbuf_t *m_asp = NULL;
struct timeval timenow;
u_short temp_net;
atp = (struct atp_state *)gref->info;
if (atp->dflag)
atp = (struct atp_state *)atp->atp_msgq;
switch(gbuf_type(m)) {
case MSG_DATA:
if (((AT_DDP_HDR(m))->type != DDP_ATP) ||
(atp->atp_flags & ATP_CLOSING)) {
gbuf_freem(m);
dPrintf(D_M_ATP_LOW, (D_L_INPUT|D_L_ERROR),
("atp_rput: dropping MSG, not atp\n"));
break;
}
athp = AT_ATP_HDR(m);
dPrintf(D_M_ATP_LOW, D_L_INPUT,
("atp_rput MSG_DATA: %s (%d)\n",
(athp->cmd == ATP_CMD_TRESP)? "TRESP":
(athp->cmd == ATP_CMD_TREL)? "TREL":
(athp->cmd == ATP_CMD_TREQ)? "TREQ": "unknown",
athp->cmd));
trace_mbufs(D_M_ATP_LOW, " r", m);
switch (athp->cmd) {
case ATP_CMD_TRESP:
{
register struct atp_trans *trp;
register int seqno;
register at_ddp_t *ddp;
for (trp = atp->atp_trans_wait.head; trp; trp = trp->tr_list.next) {
if (trp->tr_tid == UAS_VALUE_NTOH(athp->tid))
break;
}
seqno = athp->bitmap;
if (trp == NULL) {
ddp = AT_DDP_HDR(m);
dPrintf(D_M_ATP_LOW, (D_L_INPUT|D_L_ERROR),
("atp_rput: dropping TRESP, no trp,tid=%d,loc=%d,rem=%d.%d,seqno=%d\n",
UAS_VALUE_NTOH(athp->tid),
ddp->dst_socket, ddp->src_node, ddp->src_socket, seqno));
gbuf_freem(m);
return;
}
if (trp->tr_state == TRANS_FAILED) {
ddp = AT_DDP_HDR(m);
dPrintf(D_M_ATP_LOW, (D_L_INPUT|D_L_ERROR),
("atp_rput: dropping TRESP, failed trp,tid=%d,loc=%d,rem=%d.%d\n",
UAS_VALUE_NTOH(athp->tid),
ddp->dst_socket, ddp->src_node, ddp->src_socket));
gbuf_freem(m);
return;
}
if (!(trp->tr_bitmap&atp_mask[seqno]) || trp->tr_rcv[seqno]) {
ddp = AT_DDP_HDR(m);
dPrintf(D_M_ATP_LOW, (D_L_INPUT|D_L_ERROR),
("atp_rput: dropping TRESP, duplicate,tid=%d,loc=%d,rem=%d.%d,seqno=%d\n",
UAS_VALUE_NTOH(athp->tid),
ddp->dst_socket, ddp->src_node, ddp->src_socket, seqno));
gbuf_freem(m);
return;
}
if (athp->eom)
trp->tr_bitmap &= atp_lomask[seqno];
else
trp->tr_bitmap &= ~atp_mask[seqno];
trp->tr_rcv[seqno] = m;
if (seqno)
gbuf_rinc(m,DDP_X_HDR_SIZE);
if (trp->tr_bitmap == 0) {
atp_untimout(atp_req_timeout, trp);
atp_x_done(trp);
return;
}
if (athp->sts) {
atp_untimout(atp_req_timeout, trp);
atp_send(trp);
return;
}
return;
}
case ATP_CMD_TREL:
{ register struct atp_rcb *rcbp;
register at_ddp_t *ddp;
ddp = AT_DDP_HDR(m);
for (rcbp = atp->atp_rcb.head; rcbp; rcbp = rcbp->rc_list.next) {
if (rcbp->rc_tid == UAS_VALUE_NTOH(athp->tid) &&
rcbp->rc_socket.node == ddp->src_node &&
rcbp->rc_socket.net == NET_VALUE(ddp->src_net) &&
rcbp->rc_socket.socket == ddp->src_socket) {
rcbp->rc_not_sent_bitmap = 0;
if (rcbp->rc_state == RCB_SENDING)
rcbp->rc_state = RCB_RELEASED;
else
{
ddp = 0;
atp_rcb_free(rcbp);
}
break;
}
}
gbuf_freem(m);
return;
}
case ATP_CMD_TREQ:
{ register struct atp_rcb *rcbp;
register at_ddp_t *ddp;
gbuf_t *m2;
ddp = AT_DDP_HDR(m);
for (rcbp = atp->atp_rcb.head; rcbp; rcbp = rcbp->rc_list.next) {
if (rcbp->rc_tid == UAS_VALUE_NTOH(athp->tid) &&
rcbp->rc_socket.node == ddp->src_node &&
rcbp->rc_socket.net == NET_VALUE(ddp->src_net) &&
rcbp->rc_socket.socket == ddp->src_socket)
break;
}
if (rcbp == NULL) {
for (rcbp = atp->atp_attached.head; rcbp; rcbp = rcbp->rc_list.next) {
if (rcbp->rc_tid == UAS_VALUE_NTOH(athp->tid) &&
rcbp->rc_socket.node == ddp->src_node &&
rcbp->rc_socket.net == NET_VALUE(ddp->src_net) &&
rcbp->rc_socket.socket == ddp->src_socket) {
gbuf_freem(m);
dPrintf(D_M_ATP_LOW, D_L_INPUT,
("atp_rput: dropping TREQ, matches req queue\n"));
return;
}
}
if ((rcbp = atp_rcb_alloc(atp)) == NULL) {
gbuf_freem(m);
return;
}
rcbp->rc_state = RCB_UNQUEUED;
rcbp->rc_local_node = ddp->dst_node;
temp_net = NET_VALUE(ddp->dst_net);
NET_ASSIGN_NOSWAP(rcbp->rc_local_net, temp_net);
rcbp->rc_socket.socket = ddp->src_socket;
rcbp->rc_socket.node = ddp->src_node;
rcbp->rc_socket.net = NET_VALUE(ddp->src_net);
rcbp->rc_tid = UAS_VALUE_NTOH(athp->tid);
rcbp->rc_bitmap = athp->bitmap;
rcbp->rc_not_sent_bitmap = athp->bitmap;
rcbp->rc_xo = athp->xo;
if (atp->dflag) {
if ((m2 = gbuf_alloc(sizeof(ioc_t), PRI_HI))) {
gbuf_set_type(m2, MSG_DATA);
gbuf_wset(m2,sizeof(ioc_t));
((ioc_t *)gbuf_rptr(m2))->ioc_cmd = AT_ATP_GET_POLL;
m_asp = m2;
}
} else if ((m2 = gbuf_alloc(1, PRI_HI))) {
*gbuf_rptr(m2) = 0;
gbuf_wset(m2,1);
atalk_putnext(gref, m2);
}
if (m2 == 0) {
dPrintf(D_M_ATP,D_L_WARNING,
("atp_rput: out of buffer for TREQ\n"));
timeout(atp_treq_event, gref, 10);
}
rcbp->rc_ioctl = m;
dPrintf(D_M_ATP_LOW, D_L_INPUT,
("atp_rput: moving to attached list\n"));
rcbp->rc_state = RCB_PENDING;
ATP_Q_APPEND(atp->atp_attached, rcbp, rc_list);
if (m_asp != NULL) {
atp_req_ind(atp, m_asp);
return;
}
} else {
dPrintf(D_M_ATP_LOW, D_L_INPUT,
("atp_rput: found match, state:%d\n",
rcbp->rc_state));
switch (rcbp->rc_state) {
case RCB_RESPONDING:
case RCB_RESPONSE_FULL:
getmicrouptime(&timenow);
if (rcbp->rc_timestamp) {
rcbp->rc_timestamp = timenow.tv_sec;
if (rcbp->rc_timestamp == 0)
rcbp->rc_timestamp = 1;
}
rcbp->rc_bitmap = athp->bitmap;
rcbp->rc_not_sent_bitmap = athp->bitmap;
gbuf_freem(m);
atp_reply(rcbp);
return;
case RCB_RELEASED:
default:
gbuf_freem(m);
return;
}
}
return;
}
default:
gbuf_freem(m);
break;
}
break;
case MSG_IOCACK:
if (atp->dflag)
asp_ack_reply(gref, m);
else
atalk_putnext(gref, m);
break;
case MSG_IOCNAK:
if (atp->dflag)
asp_nak_reply(gref, m);
else
atalk_putnext(gref, m);
break;
default:
gbuf_freem(m);
}
}
void
atp_x_done_locked(trp)
void *trp;
{
atalk_lock();
atp_x_done((struct atp_trans *)trp);
atalk_unlock();
}
void
atp_x_done(trp)
register struct atp_trans *trp;
{
struct atp_state *atp;
gbuf_t *m;
if ( !trp->tr_xo)
atp_trans_complete(trp);
else {
if ((m = (gbuf_t *)atp_build_release(trp)) != NULL) {
AT_DDP_HDR(m)->src_socket = ((struct atp_state *)
trp->tr_queue)->atp_socket_no;
DDP_OUTPUT(m);
atp_trans_complete(trp);
} else {
atp = trp->tr_queue;
trp->tr_state = TRANS_RELEASE;
timeout(atp_x_done_locked, trp, 10);
}
}
}
static void
atp_trans_complete(trp)
register struct atp_trans *trp;
{ register gbuf_t *m;
register int type;
struct atp_state *atp;
m = trp->tr_xmt;
trp->tr_xmt = NULL;
trp->tr_state = TRANS_DONE;
if (gbuf_cont(m) == NULL)
type = AT_ATP_ISSUE_REQUEST_NOTE;
else {
type = ((ioc_t *)(gbuf_rptr(m)))->ioc_cmd;
gbuf_freem(gbuf_cont(m));
gbuf_cont(m) = NULL;
}
dPrintf(D_M_ATP_LOW, D_L_INPUT, ("atp_trans_comp: trp=0x%x type = %s\n",
(u_int) trp,
(type==AT_ATP_ISSUE_REQUEST)? "AT_ATP_ISSUE_REQUEST":
(type==AT_ATP_ISSUE_REQUEST_NOTE)? "AT_ATP_ISSUE_REQUEST_NOTE" :
"unknown"));
switch(type) {
case AT_ATP_ISSUE_REQUEST:
atp = trp->tr_queue;
if (atp->dflag) {
((ioc_t *)gbuf_rptr(m))->ioc_count = 0;
((ioc_t *)gbuf_rptr(m))->ioc_error = 0;
((ioc_t *)gbuf_rptr(m))->ioc_rval = trp->tr_tid;
((ioc_t *)gbuf_rptr(m))->ioc_cmd = AT_ATP_REQUEST_COMPLETE;
gbuf_set_type(m, MSG_IOCTL);
atp_rsp_ind(trp, m);
} else {
if (trp->tr_bdsp == NULL) {
gbuf_freem(m);
if (trp->tr_rsp_wait)
wakeup(&trp->tr_event);
} else {
gbuf_set_type(m, MSG_IOCACK);
((ioc_t *)gbuf_rptr(m))->ioc_count = 0;
((ioc_t *)gbuf_rptr(m))->ioc_error = 0;
((ioc_t *)gbuf_rptr(m))->ioc_rval = 0;
atalk_putnext(trp->tr_queue->atp_gref, m);
}
}
break;
case AT_ATP_ISSUE_REQUEST_NOTE:
gbuf_wset(m,1);
*gbuf_rptr(m) = 1;
gbuf_set_type(m, MSG_DATA);
atalk_putnext(trp->tr_queue->atp_gref, m);
break;
}
}