home *** CD-ROM | disk | FTP | other *** search
- /* io.c
- * I/O routines for MacPPP
- *
- * Copyright 1992-1993 Merit Network, Inc. and The Regents of the
- * University of Michigan. Usage of this source code is restricted
- * to non-profit, non-commercial purposes. The source is provided
- * "as-is", without warranty.
- */
- #include "ppp.h"
-
- /* macro to calculate new fcs */
- #define pppfcs(fcs, c) ((fcs >> 8) ^ lap->fcstab[(fcs ^ c) & 0x00ff])
-
- /*
- * Pass the completed IP packet up to the IP layer.
- */
- void rcvip(register LapInfo *lap, struct bufheader *bufptr)
- {
- long oldA5;
-
- if (lap->rds.rdsparm.lnb.lnb_ptr != nil) { /* MacTCP doesn't always call ReadRest */
- /* DebugStr("\pIPPH not ready"); */
- release((struct bufheader *)lap->rds.rdsparm.lnb.lnb_ptr); /* free un-copied data */
- }
-
- lap->idle_timer = 0; /* clear idle timer */
- tcp_window_fix(lap, bufptr); /* TCP window hack */
-
- lap->rds.laphdr.ptr = nil;
- lap->rds.laphdr.length = 0;
- lap->rds.lapBroadcast = FALSE;
- lap->rds.lap = lap;
- lap->rds.ph_rp = (ProcPtr) readpkt; /* set up ptr's to */
- lap->rds.ph_rr = (ProcPtr) readrest; /* mysterious rtn's */
- lap->rds.rdsparm.lnb.lnb_ptr = (b_8 *) bufptr; /* ptr to packet */
- lap->rds.ph_bytesleft = bufptr->length; /* length of packet */
-
- /* pass pkt to IP layer in a rdStruct */
- if (lap->ip_ph != nil) {
- oldA5 = seta5((long)lap->ipGlobals); /* setup apps A5 */
- (*(lap->ip_ph))(&(lap->rds));
- seta5(oldA5); /* restore old A5 */
- } else
- PPP_DEBUG_CHECKS("\pNo ip_ph to call!");
- }
-
- OSErr readpkt(struct rdStruct *rds, Ptr bufp, long buflen)
- {
- #ifdef LOG
- log(GetLAPPtr(),0x3, (int) TickCount(),(int)( rds->rdsparm.lnb.lnb_ptr), (int) buflen);
- #endif
- /*
- * It's against the rules to have ReadPacket read in the remainder
- * of the packet. You have to call ReadRest for that
- * Too bad nobody plays by the rules. ReadPacket can't return an error
- * if bytesleft exactly equals buflen, or else the higher layer gets
- * an error on a packet with 0 bytes of data, which breaks everything.
- */
- if (rds->ph_bytesleft >= buflen) { /* will this buffer fill up? */
- yankbuf((struct bufheader *)rds->rdsparm.lnb.lnb_ptr,
- (b_8 *) bufp,(short) buflen); /* copy data */
- rds->ph_bytesleft -= buflen; /* update len */
- return (0); /* buffer has data */
- }
- return (-1); /* call ReadRest instead */
- }
- /*
- * ReadRest is called to read the remainder of a packet. It must be
- * called exactly once per packet.
- */
- long readrest(register struct rdStruct *rds, Ptr bufp, long buflen)
- {
- long rc;
- #ifdef LOG
- log(GetLAPPtr(),0x4, (int) TickCount(),(int)( rds->rdsparm.lnb.lnb_ptr), (int) buflen);
- #endif
- if (rds->ph_bytesleft > buflen) { /* packet won't fit Truncate */
- yankbuf((struct bufheader *)rds->rdsparm.lnb.lnb_ptr,
- (b_8 *) bufp, (short) buflen);
- rds->ph_bytesleft -= buflen; /* update # of bytes truncated */
- rc = -(rds->ph_bytesleft);
- } else {
- yankbuf((struct bufheader *)rds->rdsparm.lnb.lnb_ptr,
- (b_8 *) bufp, (short) rds->ph_bytesleft);
- rc = buflen - rds->ph_bytesleft;
- rds->ph_bytesleft = 0; /* the entire packet is copied */
- }
- release((struct bufheader *) rds->rdsparm.lnb.lnb_ptr);
- rds->rdsparm.lnb.lnb_ptr = (b_8 *) nil;
- return rc; /* return value */
- }
-
- /*
- * ProcFrame - process a PPP frame in an MBUF
- */
-
- void
- ProcFrame(register LapInfo *lap, register struct bufheader *bufptr)
- {
- register b_16 proto;
- register short RecvByte;
-
- /* pull off header */
- if ((RecvByte = yankbyte(bufptr)) < 0)
- goto error;
-
- if (RecvByte == HDLC_ALL_ADDR) {
- if ((RecvByte = yankbyte(bufptr)) < 0)
- goto error;
-
- if (RecvByte == HDLC_UI) {
- if ((RecvByte = yankbyte(bufptr)) < 0)
- goto error;
-
- if ((RecvByte & 0x01) != 0) {
- proto = RecvByte;
- } else {
- proto = RecvByte << 8;
-
- if ((RecvByte = yankbyte(bufptr)) < 0)
- goto no_error;
-
- if ((RecvByte & 0x01) == 0)
- goto error;
-
- proto += RecvByte;
- }
- } else {
- goto error;
- }
- } else {
- if (RecvByte & 0x01) {
- proto = RecvByte;
- } else {
- proto = RecvByte << 8;
-
- if ((RecvByte = yankbyte(bufptr)) < 0)
- goto no_error;
-
- proto += RecvByte;
- }
- }
-
- /* handle frame */
-
- switch (proto) {
- case PPP_IP_PROTOCOL:
- if (lap->ppp_fsm[IPcp].state != fsmOPENED) {
- PPP_DEBUG_CHECKS("\pnot open for IP traffic");
- goto in_error;
- }
- rcvip(lap, bufptr);
- break;
-
- case PPP_VJ_COMP_PROTOCOL:
- if (lap->ppp_fsm[IPcp].state != fsmOPENED) {
- PPP_DEBUG_CHECKS("\pnot open for Compressed TCP/IP traffic");
- goto in_error;
- }
- if (!(lap->ipcp_i.local.work_negotiate & IPCP_N_COMPRESS)) {
- PPP_DEBUG_CHECKS("\pCompressed TCP/IP not enabled");
- goto in_error;
- }
- if (slhc_uncompress(lap, bufptr) <= 0) {
- PPP_DEBUG_CHECKS("\pCompressed TCP/IP packet error");
- goto in_error;
- }
- rcvip(lap, bufptr);
- break;
-
- case PPP_VJ_UNCOMP_PROTOCOL:
- if (lap->ppp_fsm[IPcp].state != fsmOPENED) {
- PPP_DEBUG_CHECKS("\pnot open for Uncompressed TCP/IP traffic");
- goto in_error;
- }
- if (!(lap->ipcp_i.local.work_negotiate & IPCP_N_COMPRESS)) {
- PPP_DEBUG_CHECKS("\pUncompressed TCP/IP not enabled");
- goto in_error;
- }
- if (slhc_remember(lap, bufptr) <= 0) {
- PPP_DEBUG_CHECKS("\pUncompressed TCP/IP packet error");
- goto in_error;
- }
- rcvip(lap, bufptr);
- break;
-
- case PPP_LCP_PROTOCOL:
- fsm_proc(&(lap->ppp_fsm[Lcp]), bufptr);
- break;
-
- case PPP_PAP_PROTOCOL:
- if (lap->ppp_phase != pppAUTHENTICATE
- && lap->ppp_phase != pppNETWORK) {
- PPP_DEBUG_CHECKS("\pNot ready for Authentication");
- goto in_error;
- }
- pap_proc(&(lap->ppp_fsm[Pap]), bufptr);
- break;
-
- case PPP_IPCP_PROTOCOL:
- if (lap->ppp_phase != pppNETWORK) {
- PPP_DEBUG_CHECKS("\pNot ready for IPCP traffic");
- goto in_error;
- }
- fsm_proc(&(lap->ppp_fsm[IPcp]), bufptr);
- break;
-
- default:
- lap->InUnknown++; /* count unknown protocol */
- if (lap->ppp_fsm[Lcp].state == fsmOPENED) {
- makeroom(bufptr, 2);
- put16(bufptr->dataptr, proto); /* put protocol field back on */
- fsm_send(&(lap->ppp_fsm[Lcp]), PROT_REJ, 0, bufptr); /* send protocol reject */
- } else
- release(bufptr);
- break;
- }
- return;
-
- /* finish up */
- in_error:
- lap->InError++;
- goto no_error;
- error:
- lap->InHeader++;
- PPP_DEBUG_CHECKS("\pPPP header error");
- no_error:
- release(bufptr); /* release the buffer */
- return;
- }
-
- long
- GetQSize(register LapInfo *lap) {
- register long qcount;
-
- lap->stat_pb.csCode = 2; /* call SerGetBuf routine */
- PBStatusImmed((ParmBlkPtr) &lap->stat_pb);
- qcount = *( (long *) lap->stat_pb.csParam);
- if (qcount > RXBUFSIZE)
- qcount = RXBUFSIZE;
- lap->r_iopb.iop.ioReqCount = qcount;
- return qcount;
- }
-
- void RcvDeferred(void)
- {
- asm {
- lea OFFSET(LapInfo, r_iopb.iop)(a1),a0
- _PBRead ASYNC /* read the data */
- }
- }
-
- void
- ProcRcvPPP(void){
-
- register LapInfo *lap;
- register long qcount;
- struct TMprocess *tmprocp;
-
- asm {
- move.l a1,tmprocp
- }
- lap = tmprocp->tmsavptr.lap;
- if (GetQSize(lap) == 0)
- PrimeTime( (QElemPtr) &lap->rxp_task, 4L); /* no data, try again in 4 ms */
- else {
- if (lap->HasDeferredTasks)
- DTInstall((QElemPtr) &lap->defer_rx);
- else
- PBReadAsync((ParmBlkPtr) &lap->r_iopb.iop);
- }
- }
-
- #define RXHILIMIT 32 /* Hi-water mark for Reading data immediately */
- void
- SerReadDone(void){
-
- typedef enum
- {
- c_Flag, /* PPP opening/closing flag */
- c_Escape, /* PPP escape char */
- c_Normal, /* A normal data character */
- c_Ignore, /* Character to be ignored */
- c_Error /* Errored char received */
- } class_t;
-
- register LapInfo *lap;
- sdiopb *pb;
- struct bufheader *tempbuf;
- register short *cntptr;
- b_8 *dataptr;
- register b_8 *rbufptr;
- register b_8 *rbufend;
- register class_t RecvClass;
- register b_8 RecvByte;
- register HDLCState RecvState;
- register b_8 StatusByte;
- long qcount;
- OSErr rc;
-
- asm {
- move.l a0,pb ; set up paramblkptr
- };
-
- lap = pb->lap;
-
- if ((rc = pb->iop.ioResult) != noErr) {
- lap->readerr++;
- lap->lasterr = rc;
- PPP_DEBUG_CHECKS("\pSerial driver rx. error");
- goto rcvexit;
- }
- qcount = pb->iop.ioActCount;
-
- lap->InRxOctetCount += qcount; /* count the octets */
- rbufptr = lap->rxbuf;
- rbufend = rbufptr + qcount;
- dataptr = lap->bufptr->dataptr; /* pointer to start of data in mbuf */
- cntptr = &(lap->bufptr->length);
- while (rbufptr < rbufend) {
- RecvByte = *rbufptr++;
- RecvState = lap->read_state;
-
- if (lap->bufptr == nil) {
- if ( (lap->bufptr = getbuffer() ) != nil ) {
- dataptr = lap->rddata = lap->bufptr->dataptr;
- cntptr = &(lap->bufptr->length);
- } else {
- PPP_DEBUG_CHECKS("\pNo rbufs");
- goto rcvexit;
- }
- }
- /* figure equivalence class of input char/err */
- if (RecvByte == PPP_FLAG)
- RecvClass = c_Flag;
- else if (RecvByte == PPP_ESCAPE)
- RecvClass = c_Escape;
- else if ((RecvByte & 0xE0) != 0)
- RecvClass = c_Normal;
- else {
- if (((1L << RecvByte) & lap->PPP_RecvACM) != 0) {
- RecvClass = c_Ignore;
- } else
- RecvClass = c_Normal;
- }
-
- /*
- * "I feel the need, the need for speed" The C switch()
- * statement is too slow for use here, so we just use a
- * carefully organized if...elseif...elseif... statement to
- * optimize this routine for speed. --ejs
- */
- /* handle receive states
- * Taken from KA9Q and re-arranged for better performance
- * also changed to if else style per ejs suggestion. --ljb
- */
- if (RecvState == s_Data) {
- if (RecvClass == c_Normal) {
- if ((*cntptr)++ <= PPP_BUFSIZE) {
- lap->RecvFCS = pppfcs(lap->RecvFCS, RecvByte);
- *(lap->rddata)++ = RecvByte;
- } else {
- (*cntptr)--;
- lap->InFrameOvr++;
- lap->read_state = s_Idle;
- }
- }
- else if (RecvClass == c_Escape)
- lap->read_state = s_Escape;
- else if (RecvClass == c_Flag) {
- if (lap->RecvFCS == FCS_TERM) {
- lap->RecvFCS = FCS_INIT; /* reset FCS */
- lap->InOpenFlag++; /* count good frame */
- tempbuf = lap->bufptr; /* get pointer to current mbuf */
- /* must make copy due to possible re-entrancy */
- lap->bufptr = nil; /* need new buffer next time */
- tempbuf->length -= 2; /* trim FCS bytes */
- ProcFrame(lap, tempbuf); /* process the PPP frame */
- } else if (*cntptr > 0) {
- PPP_DEBUG_CHECKS("\pGot a bad FCS");
- lap->InCheckSeq++;
- slhc_toss(&lap->comp); /* let VJ compression engine know */
- *cntptr = 0;
- lap->rddata = dataptr;
- lap->RecvFCS = FCS_INIT;
- lap->stat_pb.csCode = 8; /* call SerStatus routine */
- PBStatusImmed((ParmBlkPtr) &lap->stat_pb);
- StatusByte = *( (b_8 *) lap->stat_pb.csParam);
- if (StatusByte & swOverrunErr)
- lap->InSoftOvr++;
- if (StatusByte & hwOverrunErr)
- lap->InHardOvr++;
- if (StatusByte & framingErr)
- lap->InFramingErr++;
- }
- }
- }
- else if (RecvState == s_Escape) {
- if (RecvClass == c_Normal) {
- if (*cntptr <= PPP_BUFSIZE) {
- RecvByte ^= 0x20;
- lap->RecvFCS = pppfcs(lap->RecvFCS, RecvByte);
- *(lap->rddata)++ = RecvByte;
- (*cntptr)++;
- lap->read_state = s_Data;
- } else {
- lap->InFrameOvr++;
- lap->read_state = s_Idle;
- }
- }
- else if (RecvClass == c_Flag)
- lap->read_state = s_Idle;
- }
- else if (RecvState == s_Idle) {
- if (RecvClass == c_Flag) {
- lap->RecvFCS = FCS_INIT;
- lap->read_state = s_Data;
- lap->rddata = dataptr;
- *cntptr = 0;
- } else
- lap->InIdleToss++;
- }
- else if (RecvState == s_Init) {
- RecvByte &= 0x7f; /* clear high bit */
- if (!lap->term_mode || ( RecvByte != 0x0a && RecvByte != 0x08) ) {
- if (*cntptr >= PPP_BUFSIZE) {
- lap->rddata = dataptr; /* wrap around */
- *cntptr = 0;
- }
- *(lap->rddata)++ = RecvByte; /* buffer and hi bit */
- (*cntptr)++;
- } else if (RecvByte == 0x08 && *cntptr > 0) {
- (*cntptr)--; /* decrement counter */
- lap->rddata--; /* decrement pointer */
- }
- }
- }
-
- rcvexit:
- if (GetQSize(lap) > RXHILIMIT) {
- PrimeTime( (QElemPtr) &lap->rxp_task, 0L);
- }
- else
- PrimeTime( (QElemPtr) &lap->rxp_task, 2L);
-
- }
-
- /* queue a frame to transmitted */
- OSErr QueueFrame (LapInfo *lap, struct bufheader *bufptr, struct ipbuf *ipbp)
- {
- PPPiopb *pb;
-
- /* try to get a free transmit queue element */
-
- if ((pb = (PPPiopb *)lap->pppbq.qHead) != nil) {
- Dequeue( (QElemPtr) pb, (QHdrPtr) &lap->pppbq);
- }
- if (pb != nil) {
- if ((pb->ipbuf = ipbp) != nil) { /* check if from MacTCP */
- #ifdef LOG
- log(lap, 0x1,(int) TickCount(),(int) ipbp, (int)ipbp->iop.ioCompletion );
- #endif
- ipbp->iop.ioResult = inProgress; /* mark i/o as async */
- }
- pb->bufptr = bufptr; /* point to mbuf (if available) */
- Enqueue((QElemPtr) pb, (QHdrPtr) &lap->out_q); /* queue for xmit */
- } else {
- /* we're out of Q elements (very bad) */
- lap->outofiopbs++;
- PPP_DEBUG_CHECKS("\pOut of ioParam blocks");
- IOCompleted(lap, ipbp);
- return(noErr);
- }
-
- /* Prime transmitter (if needed) */
- if (lap->needTxPrime) {
- lap->needTxPrime = false;
- ProcXmtPPP(lap); /* start transmitter */
- }
-
- return(noErr);
- }
-
- void IOCompleted(LapInfo *lap, struct ipbuf *ipbp)
- {
- long oldA5;
-
- #ifdef LOG
- log(lap, 0x2, (int) TickCount(), (int) ipbp, 0);
- #endif
-
- if (ipbp->iop.ioCompletion != nil) { /* check if completion routine */
- oldA5 = seta5((long)lap->ipGlobals);
- ipbp->iop.ioResult = noErr; /* always return no error */
- asm {
- movea.l ipbp,a0 /* set pointer to iop */
- move.l noErr,d0 /* result code */
- move.l a0,-(a7)
- movea.l IOParam.ioCompletion(a0),a1 /* completion routine*/
- tst.w d0
- jsr (a1)
- addq.l #4,a7
- }
- seta5(oldA5);
- }
- }
-
- void IOfinish(register LapInfo *lap, PPPiopb *pb)
- {
- struct ipbuf *ipbp = pb->ipbuf;
-
- Enqueue( (QElemPtr) pb, (QHdrPtr) &lap->pppbq); /* give back iopb to pool */
- IOCompleted(lap, ipbp); /* call the completion routine */
- }
-
- PPPiopb *Getxmitpb(LapInfo *lap)
- {
- PPPiopb *pb;
- struct bufheader *bufptr;
- struct ipbuf *ipb;
- struct wdsEntry *wdsp;
- b_8 *datap;
- short n, protocol = PPP_IP_PROTOCOL;
- b_16 proto;
-
- if ((pb = (PPPiopb *)lap->out_q.qHead) != nil)
- Dequeue( (QElemPtr) pb, (QHdrPtr) &lap->out_q); /* Dequeue a xmit buffer */
- else
- return nil;
-
- if (pb->bufptr != nil) { /* check if from MacTCP or LAP */
- if (pb->ipbuf != nil) { /* special case for LCP echos */
- pb->ipbuf = nil;
- if ((bufptr = getbuffer()) == nil) /* get a buffer */
- return nil;
- bufptr->length = pb->bufptr->length;
- BlockMove(pb->bufptr->dataptr, bufptr->dataptr, (long) bufptr->length);
- pb->bufptr = bufptr;
- /* prime lcp echo routine */
- PrimeTime((QElemPtr)&lap->echo_task, (long)lap->prefdata.echo * 1000L);
- return pb;
- }
- } else {
- if ((ipb = pb->ipbuf) == nil) { /* shouldn't happen */
- PPP_DEBUG_CHECKS("\pip buffer ptr nil");
- return nil;
- }
-
- if ((bufptr = getbuffer()) == nil){ /* get a buffer */
- IOfinish(lap, pb);
- return nil;
- }
- wdsp = &(ipb->ip); /* point to wds entries (@ip header) */
- datap = bufptr->dataptr;
-
- /* copy packet into a buffer */
-
- while ( (n = wdsp->length) != 0 ) {
- BlockMove(wdsp->ptr, datap, (long) n);
- bufptr->length += n;
- datap += n;
- wdsp++;
- }
- tcp_window_fix(lap, bufptr); /* chop down TCP window size */
-
- if (lap->ipcp_i.remote.work_negotiate & IPCP_N_COMPRESS) {
- /* Attempt IP/TCP header compression */
- switch (slhc_compress(lap, bufptr,
- lap->ipcp_i.remote.work.ipcp_option.slot_compress)) {
- case SL_TYPE_IP:
- protocol = PPP_IP_PROTOCOL;
- break;
- case SL_TYPE_COMPRESSED_TCP:
- protocol = PPP_COMPR_PROTOCOL;
- break;
- case SL_TYPE_UNCOMPRESSED_TCP:
- protocol = PPP_UNCOMP_PROTOCOL;
- break;
- default:
- lap->OutError++;
- PPP_DEBUG_CHECKS("\pVJ compress error");
- release(bufptr);
- IOfinish(lap, pb);
- return nil;
- }
- }
- if (lap->ppp_phase == pppDEAD) {
- lap->OutError++;
- PPP_DEBUG_CHECKS("\pDead link output error");
- release(bufptr);
- IOfinish(lap, pb);
- return nil;
- }
-
- htonppp(lap, protocol, bufptr);
- pb->bufptr = bufptr;
- }
- return pb; /* pointer to transmit iopb */
- }
-
- /* routine to transmit some characters from the transmit fifo
- * This is executed as part of the transmit IO completion routine.
- * TXBUFSIZE controls the maximum number of characters to transmit.
- * Don't make this too large as it may result in receive overruns
- * because this will often be executed during level 2 interrupt time.
- */
- void xmitout(register LapInfo *lap)
- {
- register unsigned short maxsend;
- register ioParam *iop = &(lap->w_iopb.iop);
-
- if (lap->ok_to_xmit && (lap->XmitQSize > 0)) {
- lap->ok_to_xmit = false;
- if ( (maxsend = XMITQLEN - lap->XmitQHead) > MAXXMIT)
- maxsend = MAXXMIT;
- iop->ioReqCount = lap->XmitQSize > maxsend ? maxsend : lap->XmitQSize;
- iop->ioBuffer = (Ptr) &lap->XmitQ[lap->XmitQHead];
- asm {
- movea.l iop, a0
- _PBWrite ASYNC
- }
- }
- }
-
- /* routine to place some chars in the transmit fifo */
- void xmitfifo(register LapInfo *lap, short len)
- {
- short i;
- register Byte *bufptr = lap->xbuf;
-
- for ( i = 0 ; i < len ; ++i ) {
- if (lap->XmitQSize >= XMITQLEN) {
- PPP_DEBUG_CHECKS("\pOverflowed xmit fifo"); /* this shouldn't happen */
- break;
- }
- lap->XmitQ[lap->XmitQTail++] = *bufptr++;
- lap->XmitQTail &= (XMITQLEN - 1);
- lap->XmitQSize++;
- }
- xmitout(lap); /* try to xmit some characters in the fifo */
- }
-
- void TxCDeferred(void)
- {
- LapInfo *lap;
-
- asm {
- move.l a1,lap
- }
- lap->ok_to_xmit = true; /* okay to transmit some more */
- xmitout(lap); /* transmit some more bytes */
- }
-
- /*
- * This is the serial write i/o completion routine. All it does is call
- * the xmitout routine to transmit some chars from the fifo.
- */
- ProcPtr hdlcwioc()
- {
- register LapInfo *lap;
- sdiopb *pb;
- register unsigned short count;
-
- /* We are allowed to trash a0,a1,d0-d2 */
- asm {
- move.l a0,pb ; set up paramblkptr
- };
-
- lap = pb->lap;
-
- count = pb->iop.ioActCount;
-
- if (count > pb->iop.ioReqCount) {
- lap->writerr++;
- PPP_DEBUG_CHECKS("\pwrite: Tx berserk");
- }
-
- if (pb->iop.ioResult != noErr) {
- if (pb->iop.ioResult == abortErr) {
- lap->XmitQSize = lap->XmitQHead = lap->XmitQTail = 0;
- lap->ok_to_xmit = true;
- return;
- }
- lap->writerr++; /* count bad writes */
- }
-
- lap->OutTxOctetCount += count; /* add to total out count */
- lap->XmitQSize -= count;
- if ( (lap->XmitQHead += count) >= XMITQLEN)
- lap->XmitQHead = 0;
-
- if (lap->HasDeferredTasks)
- DTInstall((QElemPtr) &lap->defer_txcomplete);
- else {
- lap->ok_to_xmit = true;
- xmitout(lap);
- }
- }
-
- void XmtDeferred(void)
- {
- LapInfo *lap;
-
- asm {
- move.l a1,lap
- }
- ProcXmtPPP(lap);
- }
-
- /* time manager routine to re-start transmitter */
- void XmtTMProc(void)
- {
- LapInfo *lap;
- struct TMprocess *tmprocp;
-
- asm {
- move.l a1,tmprocp
- };
- lap = tmprocp->tmsavptr.lap;
- if (lap->HasDeferredTasks)
- DTInstall((QElemPtr) &lap->defer_tx);
- else
- ProcXmtPPP(lap);
- }
-
- void ProcXmtPPP(register LapInfo *lap)
- {
- register short XmitByte;
- short sreg;
- ProcPtr ioc;
- register HDLCState wstate;
- PPPiopb *pb;
- register b_8 *xbufp;
-
- /* we loop through this routine until either it is done handling the
- output or the xmit fifo is too full. In the latter case, we re-prime the
- routine to execute later (when there will be more room in the fifo)
- */
- while (TRUE) {
- if ( lap->XmitQSize > (XMITQLEN - 8) ) {
- if (!(lap->txp_task.atm.qType & TASK_QUEUED)) /* check if task in q */
- PrimeTime((QElemPtr) &lap->txp_task, 16L);
- break;
- }
-
- wstate = lap->write_state; /* put in register for speed */
- xbufp = lap->xbuf;
- if (wstate == s_Data) { /* we're in the middle of a packet */
- if ((XmitByte = yankbyte(lap->active->bufptr)) == -1 ) {/* get byte */
- lap->write_state = s_SendFCS; /* move to FCS state */
- release(lap->active->bufptr);
- lap->active->bufptr = nil;
- } else {
- lap->XmitFCS = pppfcs(lap->XmitFCS, XmitByte);
- /* escape ESC, FLAG, and all characters in escape map */
- if (((XmitByte < 0x20) && (lap->PPP_activeACM & (1L << XmitByte)))
- || (XmitByte == PPP_FLAG) || (XmitByte == PPP_ESCAPE)) {
- *xbufp++ = PPP_ESCAPE; /* send ESC */
- XmitByte ^= 0x20; /* encoded character */
- }
- *xbufp++ = (Byte) XmitByte; /* un-escaped character */
- xmitfifo(lap, xbufp - lap->xbuf); /* fifo the data */
- }
- } else if (wstate == s_Idle) { /* just sitting around */
- if ((lap->active = Getxmitpb(lap)) != nil) {
- /* something on queue */
- if (lap->active->ipbuf == nil) /* escape LCP, NCP's for safety */
- lap->PPP_activeACM = 0xFFFFFFFFL;
- else {
- /* check for packet sent to our IP address */
- if (lap->cur_ip_addr ==
- get32((b_8 *)lap->active->ipbuf->ip.ptr + IP_DEST_OFFSET)) {
- lap->write_state = s_Loopback;
- /* need exclusivity from receiver */
- PrimeTime((QElemPtr) &lap->txp_task, 0L);
- break;
- }
- lap->PPP_activeACM = lap->PPP_XmitACM; /* use current ACCM */
-
- }
- lap->write_state = s_Data;
- lap->OutOpenFlag++; /* about to send an open flag */
- lap->XmitFCS = FCS_INIT; /* start new FCS calculation */
- if (lap->ok_to_xmit) { /* see if already xmitting */
- *xbufp = PPP_FLAG; /* no, so send a flag */
- xmitfifo(lap, 1);
- }
- } else {
- sreg = set_sr(0x2300); /* disable ints */
- /* possible for another datagram to have been added */
- if (lap->out_q.qHead != nil) {
- set_sr(sreg);
- continue;
- } else {
- lap->needTxPrime = true;
- set_sr(sreg);
- break;
- }
- }
- } else if (wstate == s_SendFCS) { /* Packet is done */
- lap->write_state = s_Finish; /* done with pkt */
-
- /* The FCS is complemented before transmitting. It is also
- * transmitted low byte first, then high byte, which is a real
- * pain in the butt.
- */
- lap->XmitFCS ^= 0xffff; /* send one's compl. */
- XmitByte = lap->XmitFCS & 0xFF;
- wstate = 2;
- while (wstate != 0) {
- if ( ( ( XmitByte < 0x20 ) && ( lap->PPP_activeACM & ( 1L << XmitByte ) ) ) ||
- ( XmitByte == PPP_FLAG ) || ( XmitByte == PPP_ESCAPE ) ) {
- *xbufp++ = PPP_ESCAPE;
- XmitByte ^= 0x20;
- }
- *xbufp++ = (Byte) XmitByte;
- XmitByte = lap->XmitFCS >> 8;
- wstate--;
- }
-
- /* do closing flag */
-
- *xbufp++ = PPP_FLAG;
- xmitfifo(lap, xbufp - lap->xbuf); /* send it along */
-
- } else if (wstate == s_Finish || wstate == s_Loopback) {
- /*
- * If the buffer just sent was an IP datagram, let the
- * IP layer know we finished the write.
- */
- pb = lap->active; /* store pointer to current iopb */
- lap->active = nil; /* make current nil */
- lap->write_state = s_Idle; /* Idle state */
- if ( pb->ipbuf != nil) {
- if (wstate == s_Loopback)
- ProcFrame(lap, pb->bufptr); /* loopback packet around */
- pb->ipbuf->iop.ioResult = noErr; /* i/o is complete */
- IOfinish(lap, pb); /* call completion routine */
- } else
- /* not an IP packet, just put iopb on free queue */
- Enqueue((QElemPtr) pb, (QHdrPtr) &lap->pppbq); /* put on free Q */
- } else if (wstate == s_Init)
- break;
- else {
- lap->OutError++;
- PPP_DEBUG_CHECKS("\pPPP Tx: bad state");
- }
- }
- }
-