/* Send and receive IP datagrams on serial lines. Compatible with SL/FP * as used with the Merit Network and MIT. */ #include #include "global.h" #include "mbuf.h" #include "iface.h" #include "timer.h" #include "ip.h" #include "slfp.h" #ifdef UNIX /* BSD or SYS5 */ #include "unix.h" #else # ifdef ATARI_ST # include "st.h" # else # include "pc.h" # include "asy.h" # endif /* ATARI_ST */ #endif /* BSD or SYS5 */ #include "trace.h" int asy_ioctl(); int slfp_send(); int doslfp(); int asy_output(); /* SL/FP level control structure */ struct slfp slfp[ASY_MAX]; char slfp_ack[ACK_LEN] = { SLFP_ACK } ; char slfp_req[REQ_LEN] = { SLFP_REQ } ; char ip_hdr[HDR_LEN] = { 2, 1, 0, 0 } ; /* IP Packet Header */ char ar_hdr[HDR_LEN] = { 2, 3, 0, 0 } ; /* "Addr Req" Packet Header */ struct interface asy_interface = /* Fake interface for "dump" proc */ { NULLIF, "asy" } ; /* Name of "asy" interface */ /* Routine to Initialize the Async line for SL/FP processing. * Mostly involves requesting the IP Address for this host. */ int slfp_init(`nterface,pip_addr,modem_cmd) struct interface *interface ; int32 *pip_addr ; /* pointer to host ip address */ char *modem_cmd ; /* optional command to Modem */ { register struct slfp *sp; register struct timer *ar ; char *modem_line ; int i ; sp = &slfp[interface->dev]; ar = &sp->ar_timer ; sp->ar_pending = 1 ; slfp[interface->dev].req_pending = 0 ; /* If a Modem Command is preseis preseis preseis preseis prese for ACK */ start_timer(rt) ; asy_output(dev, slfp_req, REQ_LEN) ; } } /* Start output, if possible, on asynch device dev */ static slfp_asy_start(dev) int16 dev; { register struct slfp *sp; register struct timer *rt ; /* Timer for REQ-ACK negotiation */ struct mbuf *bp ; if(!stxrdy(dev)) return; /* Transmitter not ready */ sp = &slfp[dev]; bp = sp->tbp ; if(bp != NULLBUF){ /* transmission just completed */ free_p(bp) ; sp->tbp = NULLBUF; } if(sp->sndq == NULLBUF) return; /* No work */ rt = &(sp->req_timer) ; if (sp->req_pending) return ; sp->reqcnt = 0 ; sp->req_pending = 1 ; rt->func = slfp_req_notify ; rt->arg = (char *)dev ; set_timer(rt,2000) ; /* 2-Second Timeout for ACK */ start_timer(rt) ; asy_output(dev, slfp_req, REQ_LEN) ; } /* Encode a packet in SL/FP format */ static struct mbuf * slfp_encode(dev,bp) int16 dev; /* Serial line number */ struct mbuf *bp; { struct mbuf *lbp; /* Mbuf containing line-ready packet */ register char *cp; char c; /* Allocate output mbuf that's twice as long as the packet. * This is a worst-case guess (consider a packet full of SLFP_ENDs!) */ lbp = alloc_mbuf(HDR_LEN + 2*len_mbuf(bp) + 2); if(lbp == NULLBUF){ /* No space; drop */ free_p(bp); return NULLBUF; } cp = lbp->data; /* Prefix packet with the Correct Link-Level Header */ if (slfp[dev].ar_pending) memcpy(cp, ar_hdr, HDR_LEN) ; else memcpy(cp, ip_hdr, HDR_LEN) ; cp += HDR_LEN ; /* Copy input to output, escaping special characters */ while(pullup(&bp,&c,1) == 1){ switch(c & 0xff){ case SLFP_ESC: *cp++ = SLFP_ESC; *cp++ = SLFP_ESC - SLFP_ESC; break; case SLFP_END: *cp++ = SLFP_ESC; *cp++ = SLFP_END - SLFP_ESC; break; case SLFP_ACK: *cp++ = SLFP_ESC; *cp++ = SLFP_ACK - SLFP_ESC; break; case SLFP_REQ: *cp++ = SLFP_ESC; *cp++ = SLFP_REQ - SLFP_ESC; break; default: *cp++ = c; } } *cp++ = SLFP_END; lbp->cnt = cp - lbp->data; return lbp; } #ifdef MSDOS /* Invoked when SLFP_REQ is received during xmit of outgoing packet. * This allows immediate reception of packet from SCP, rather than * forcing it to buffer it until we finish sending the outgoing packet */ static unsigned slfp_urgent(dev) int16 dev; /* SL/FP unit number */ { register struct dma *dp ; dp = &asy[dev].dma ; if (dp->last_octet == SLFP_ESC) return 256 ; else { asy[dev].urgent = NULLCHAR ; return SLFP_ACK ; } } #endif void hndl_rcvd_req(dev, sp) int16 dev; /* SL/FP unit number */ register struct slfp *sp; { char i_state ; if (sp->reqd) { /* REQ before rcv'g END of last Packet! */ sp->missed_ends++ ; free_p(sp->rbp); /* throw away current packet */ sp->rbp = NULLBUF; sp->rcnt = 0; } sp->reqd = 1 ; i_state = disable() ; #ifdef MSDOS if (asy[dev].dma.flags) asy[dev].urgent = slfp_urgent ; else #endif asy_output(dev, slfp_ack, ACK_LEN) ; restore(i_state) ; } void hndl_rcvd_ack(dev, sp) int16 dev; /* SL/FP unit number */ register struct slfp *sp; { char i_state ; i_state = disable() ; if (sp->req_pending == 0) { sp->false_acks++ ; restore(i_state) ; return ; } sp->req_pending = 0 ; stop_timer(&(sp->req_timer)) ; restore(i_state) ; sp->tbp = dequeue(&sp->sndq); sp->sndcnt--; asy_output(dev,sp->tbp->data,sp->tbp->cnt); } /* Process incoming bytes in