Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1338 lines
50 KiB

/***************************************************************************
Name : ECM.C
Comment : Contains the ECM T30 routines
Revision Log
Date Name Description
-------- ----- ---------------------------------------------------------
***************************************************************************/
#include "prep.h"
#include "efaxcb.h"
#include "t30.h"
#include "hdlc.h"
#include "debug.h"
///RSL
#include "glbproto.h"
#define faxTlog(m) DEBUGMSG(ZONE_ECM, m)
#define FILEID FILEID_ECM
typedef enum
{
ECMRECVOK_OK,
ECMRECVOK_BADFR,
ECMRECVOK_ABORT
}
ECMRECVOK;
/****************** begin prototypes from ecm.c *****************/
IFR RNR_RRLoop(PThrdGlbl pTG);
IFR CTC_RespRecvd(PThrdGlbl pTG, USHORT uBaud);
BOOL Recv_NotReadyLoop(PThrdGlbl pTG, IFR ifrFirst, IFR ifrLast);
BOOL FillInFrames(PThrdGlbl pTG, USHORT N, LONG sBufSize, USHORT uDataSize);
ECMRECVOK ECMRecvOK(PThrdGlbl pTG);
/***************** end of prototypes from ecm.c *****************/
BYTE RCP[3] = { 0xFF, 0x03, 0x86 };
ET30ACTION ECMPhaseC(PThrdGlbl pTG, BOOL fReTx)
{
USHORT uFrameNum, uFramesSent, uLim;
SWORD swRet;
ULONG lTotalLen=0;
LPBYTE lpPPRMask;
LPBUFFER lpbf=0;
USHORT uMod;
/******** Transmitter ECM Phase C. Fig A-7/T.30 (sheet 1) ********/
/***
switch(action = Params.lpfnWhatNext(pTG, eventSTARTSEND))
{
case actionCONTINUE: break;
case actionDCN:
case actionHANGUP: return action;
case actionERROR: return action; // goto PhaseLoop & exit
default: return BadAction(action);
}
***/
pTG->ECM.uFrameSize = ProtGetECMFrameSize(pTG);
BG_CHK(pTG->ECM.uFrameSize==6 || pTG->ECM.uFrameSize==8);
// already done in WhatNext
// uSize = (1 << pTG->ECM.uFrameSize);
// ICommSetSendMode(TRUE, uSize+ECM_EXTRA, uSize, TRUE);
if(fReTx)
{
lpPPRMask = ProtGetRetransmitMask(pTG);
}
else
{
pTG->ECM.uPPRCount = 0;
if(pTG->ECM.fEndOfPage)
{
pTG->ECM.SendPageCount++;
pTG->ECM.SendBlockCount = 1;
pTG->ECM.dwPageSize=0;
faxTlog((SZMOD "Waiting for Startpage in ECM at 0x%08lx\r\n", GetTickCount()));
DEBUGSTMT(IFProcProfile((HTASK)(-1), TRUE));
// Callback to open file to send. Doesn't return any data
if((swRet=GetSendBuf(pTG, 0, SEND_STARTPAGE)) != SEND_OK)
{
ERRMSG((SZMOD "<<ERROR>> Nonzero return %d from SendProc at Start Page\r\n", swRet));
// return actionDCN;
return actionERROR;
}
DEBUGSTMT(IFProcProfile((HTASK)(-1), FALSE));
faxTlog((SZMOD "Got Startpage in ECM at 0x%08lx\r\n", GetTickCount()));
}
else
{
pTG->ECM.SendBlockCount++;
faxTlog((SZMOD "Waiting for Startblock in ECM at 0x%08lx\r\n", GetTickCount()));
DEBUGSTMT(IFProcProfile((HTASK)(-1), TRUE));
// Callback to open file to send. Doesn't return any data
if((swRet=GetSendBuf(pTG, 0, SEND_STARTBLOCK)) != SEND_OK)
{
ERRMSG((SZMOD "<<ERROR>> Nonzero return %d from SendProc at Start Page\r\n", swRet));
// return actionDCN;
return actionERROR;
}
DEBUGSTMT(IFProcProfile((HTASK)(-1), FALSE));
faxTlog((SZMOD "Got Startblock in ECM at 0x%08lx\r\n", GetTickCount()));
}
}
faxTlog((SZMOD "Starting ECM Partial Page SEND.......P=%d B=%d ReTx=%d\r\n",
pTG->ECM.SendPageCount, pTG->ECM.SendBlockCount, fReTx));
if(fReTx)
ICommStatus(pTG, T30STATS_RESEND_ECM, pTG->ECM.SendPageCount, 0, pTG->ECM.SendBlockCount);
uMod = ProtGetSendMod(pTG);
if(uMod >= V17_START && !pTG->ECM.fSentCTC) uMod |= ST_FLAG;
pTG->ECM.fSentCTC = FALSE;
// here we should use a small timeout (100ms?) and if it fails,
// should go back to sending the previous V21 frame (which could be DCS
// or MPS or whatever, which is why it gets complicated & we havn't
// done it!). Meanwhile use a long timeout, ignore return value
// and send anyway.
if(!ModemRecvSilence(pTG, pTG->Params.hModem, RECV_PHASEC_PAUSE, LONG_RECVSILENCE_TIMEOUT))
{
ERRMSG((SZMOD "<<ERROR>> ECM Pix RecvSilence(%d, %d) FAILED!!!\r\n", RECV_PHASEC_PAUSE, LONG_RECVSILENCE_TIMEOUT));
}
if(!ModemSendMode(pTG, pTG->Params.hModem, uMod, TRUE, ifrECMPIX))
{
ERRMSG((SZMOD "<<ERROR>> ModemSendMode failed in Tx ECM PhaseC\r\n"));
ICommFailureCode(pTG, T30FAILSE_SENDMODE_PHASEC);
BG_CHK(FALSE);
return actionERROR;
}
#ifdef IFAX
BroadcastMessage(pTG, IF_PSIFAX_DATAMODE, (PSIFAX_SEND|PSIFAX_ECM|(fReTx ? PSIFAX_RESEND : 0)), (uMod & (~ST_FLAG)));
#endif
faxTlog((SZMOD "SENDING ECM Page Data.....\r\n"));
FComCriticalNeg(pTG, FALSE);
uLim = (fReTx ? pTG->ECM.SendFrameCount : 256);
BG_CHK(uLim);
BG_CHK(lpbf == 0);
for(uFrameNum=0, uFramesSent=0, lTotalLen=0, swRet=0; uFrameNum<uLim; uFrameNum++)
{
if(!fReTx || (lpPPRMask[uFrameNum/8] & (1 << (uFrameNum%8))))
{
BG_CHK(uFrameNum < 256 && pTG->ECM.uFrameSize <=8); // shift below won't ovf 16 bits
BG_CHK(lpbf == 0);
swRet = GetSendBuf(pTG, &lpbf, (fReTx ? ((SLONG)(uFrameNum << pTG->ECM.uFrameSize)) : SEND_SEQ));
if(swRet == SEND_ERROR)
{
ERRMSG((SZMOD "<<ERROR>> Error return from SendProc in ECM retransmit\r\n"));
BG_CHK(lpbf == 0);
// return actionDCN; // goto NodeC;
return actionERROR;
}
else if(swRet == SEND_EOF)
{
BG_CHK(lpbf == 0);
if(!fReTx)
break;
else
{
BG_CHK(FALSE);
ICommFailureCode(pTG, T30FAILSE_PHASEC_RETX_EOF);
return actionDCN;
}
}
BG_CHK(swRet == SEND_OK);
BG_CHK(lpbf);
BG_CHK(lpbf->lpbBegBuf+4 == lpbf->lpbBegData);
lpbf->lpbBegBuf[0] = 0xFF;
lpbf->lpbBegBuf[1] = 0x03;
lpbf->lpbBegBuf[2] = 0x06;
lpbf->lpbBegBuf[3] = (BYTE) uFrameNum;
lpbf->lpbBegData -= 4;
lpbf->wLengthData += 4;
lTotalLen += lpbf->wLengthData;
if(!ModemSendMem(pTG, pTG->Params.hModem, lpbf->lpbBegData, lpbf->wLengthData, SEND_ENDFRAME))
{
ERRMSG((SZMOD "<<ERROR>> DataWrite Timeout in ECM Phase C\r\n"));
ICommFailureCode(pTG, T30FAILSE_MODEMSEND_PHASEC);
BG_CHK(FALSE);
return actionERROR; // goto error;
}
// faxTlog((SZMOD "Freeing 0x%08lx in ECM\r\n", lpbf));
if(!MyFreeBuf(pTG, lpbf))
{
ERRMSG((SZMOD "<<ERROR>> FReeBuf failed in ECM Phase C\r\n"));
ICommFailureCode(pTG, T30FAILSE_FREEBUF_PHASEC);
BG_CHK(FALSE);
return actionERROR; // goto error;
}
lpbf = 0;
uFramesSent++;
}
}
if( !ModemSendMem(pTG, pTG->Params.hModem, RCP, 3, SEND_ENDFRAME) ||
!ModemSendMem(pTG, pTG->Params.hModem, RCP, 3, SEND_ENDFRAME) ||
!ModemSendMem(pTG, pTG->Params.hModem, RCP, 3, SEND_ENDFRAME|SEND_FINAL))
{
ERRMSG((SZMOD "<<ERROR>> DataWrite Timeout on RCPs\r\n"));
ICommFailureCode(pTG, T30FAILSE_MODEMSEND_ENDPHASEC);
BG_CHK(FALSE);
return actionERROR; // goto error;
}
/***
if(!ModemDrain())
return FALSE;
***/
FComCriticalNeg(pTG, TRUE);
faxTlog((SZMOD "Page Send Done.....len=(%ld, 0x%08x)\r\n", lTotalLen, lTotalLen));
pTG->ECM.FramesSent = uFramesSent;
if(!fReTx)
{
BG_CHK(lTotalLen>=(ULONG)uFramesSent*4);
pTG->ECM.dwPageSize+= (lTotalLen-uFramesSent*4); // 4-bytes of framing data
pTG->ECM.SendFrameCount = uFrameNum;
switch(GetSendBuf(pTG, 0, SEND_QUERYENDPAGE))
{
case SEND_OK: pTG->ECM.fEndOfPage = FALSE; break;
case SEND_EOF: pTG->ECM.fEndOfPage = TRUE; break;
default: ERRMSG((SZMOD "<<ERROR>> Got SEND_ERROR from GetSendBuf at end of page\r\n"));
return actionERROR;
}
}
if(!pTG->ECM.FramesSent)
{
ERRMSG((SZMOD "<<ERROR>> Sent 0 frames--Bad PPR recvd or bad send file\r\n"));
ICommFailureCode(pTG, T30FAILSE_BADPPR);
return actionERROR;
}
pTG->T30.fSendAfterSend = TRUE; // ECM PhaseC/PIX--PPS-X
return actionGONODE_V;
}
ET30ACTION ECMPhaseD(PThrdGlbl pTG)
{
USHORT uTryCount, i;
ET30ACTION action;
BYTE bPPSfif[3];
LPBYTE lpPPR;
/******** Transmitter ECM Phase D. Fig A-8 to A-17/T.30 ********/
if(!pTG->ECM.fEndOfPage)
{
pTG->T30.ifrSend = ifrPPS_NULL;
}
else
{
switch(action = pTG->Params.lpfnWhatNext(pTG, eventPOSTPAGE))
{
case actionSENDMPS: pTG->T30.ifrSend = ifrPPS_MPS; break;
case actionSENDEOM: pTG->T30.ifrSend = ifrPPS_EOM; break;
case actionSENDEOP: pTG->T30.ifrSend = ifrPPS_EOP; break;
#ifdef PRI
case actionSENDPRIMPS: pTG->T30.ifrSend = ifrPPS_PRI_MPS; break;
case actionSENDPRIEOM: pTG->T30.ifrSend = ifrPPS_PRI_EOM; break;
case actionSENDPRIEOP: pTG->T30.ifrSend = ifrPPS_PRI_EOP; break;
#endif
case actionERROR: return action; // goto PhaseLoop & exit
default: return BadAction(pTG, action);
}
}
bPPSfif[0] = pTG->ECM.SendPageCount-1;
bPPSfif[1] = pTG->ECM.SendBlockCount-1;
BG_CHK(pTG->ECM.FramesSent && pTG->ECM.FramesSent<=256);
// bPPSfif[2] = pTG->ECM.SendFrameCount-1; // don't know which one..!!
bPPSfif[2] = pTG->ECM.FramesSent-1; // this one! For sure
for(uTryCount=0 ;;)
{
SendSingleFrame(pTG, pTG->T30.ifrSend, bPPSfif, 3, 1);
echoretry:
pTG->T30.ifrResp = GetResponse(pTG, ifrPPSresponse);
// if we hear our own frame, try to recv again. DONT retransmit!
if(pTG->T30.ifrResp==pTG->T30.ifrSend) { ECHOMSG(pTG->T30.ifrResp); goto echoretry; }
if(pTG->T30.ifrResp != ifrNULL && pTG->T30.ifrResp != ifrBAD)
break;
if(++uTryCount >= 3)
{
ERRMSG((SZMOD "<<ERROR>> ECM 3 PostPages, No reply\r\n"));
ICommFailureCode(pTG, T30FAILSE_3POSTPAGE_NOREPLY);
return actionDCN;
}
}
switch(pTG->T30.ifrResp)
{
case ifrBAD:
case ifrNULL: BG_CHK(FALSE); // should never get here
ICommFailureCode(pTG, T30FAILSE_BUG2);
return actionERROR; // in case they do :-)
case ifrDCN: ERRMSG((SZMOD "<<ERROR>> Got ifrDCN from GetResponse after sending post-page command\r\n"));
ICommFailureCode(pTG, T30FAILSE_POSTPAGE_DCN);
return actionHANGUP;
case ifrPPR: faxTlog((SZMOD "PPR (P=%d B=%d F=%d) Received: ", pTG->ECM.SendPageCount-1, pTG->ECM.SendBlockCount-1, pTG->ECM.FramesSent-1));
lpPPR = ProtGetRetransmitMask(pTG);
#ifdef DEBUG
for(i=0; i<32; i++)
faxTlog((" %02x", lpPPR[i]));
faxTlog(("]\r\n"));
#endif //DEBUG
if(++pTG->ECM.uPPRCount >= 4)
goto FourthPPR;
return actionGONODE_ECMRETRANSMIT;
case ifrRNR: if((pTG->T30.ifrResp=RNR_RRLoop(pTG)) == ifrDCN)
{
ERRMSG((SZMOD "<<ERROR>> RR_RNR loop failed\r\n"));
// ICommFailureCode already called in RR_RNRLoop()
return actionDCN;
}
faxTlog((SZMOD "Got %d from RNR\r\n", pTG->T30.ifrResp));
break;
}
switch(pTG->T30.ifrResp)
{
case ifrPIP:
case ifrPIN:
# ifdef PRI
return GONODE_E;
# else
ERRMSG((SZMOD "<<WARNING>> Procedure interrupts not supported\r\n"));
// return actionERROR;
// fallthru and treat like MCF
pTG->T30.ifrResp = ifrMCF;
# endif
case ifrMCF:
{
WORD wSize = (WORD) (pTG->ECM.dwPageSize>>10); //Units are KB
ICommStatus(pTG, T30STATS_CONFIRM_ECM,
(USHORT) LOBYTE(wSize),
(USHORT) HIBYTE(wSize),
(USHORT)(pTG->ECM.SendPageCount&0xff));
ERRMSG((SZMOD "Sending T30STATS_CONFIRM_pTG->ECM. wSize=%u\r\n",
(unsigned) wSize));
}
action=pTG->Params.lpfnWhatNext(pTG, eventGOT_ECM_PPS_RESP,
(UWORD)pTG->T30.ifrResp, (LPVOID)((DWORD)pTG->T30.ifrSend));
if(pTG->T30.ifrSend==ifrPPS_EOP && pTG->T30.ifrResp==ifrMCF && action==actionDCN)
{
ICommFailureCode(pTG, T30FAILSE_SUCCESS);
return actionDCN_SUCCESS;
}
else
return action;
default: ERRMSG((SZMOD "<<ERROR>> Got UNKNOWN from GetResponse after sending post-page command\r\n"));
ICommFailureCode(pTG, T30FAILSE_POSTPAGE_UNKNOWN);
return actionDCN;
}
FourthPPR:
action = pTG->Params.lpfnWhatNext(pTG, event4THPPR, (WORD)pTG->ECM.SendFrameCount, (DWORD)pTG->ECM.FramesSent);
switch(action)
{
case actionGONODE_ECMRETRANSMIT:
if(CTC_RespRecvd(pTG, ProtGetSendMod(pTG)) == ifrCTR)
{
pTG->ECM.uPPRCount = 0;
pTG->ECM.fSentCTC = TRUE;
return actionGONODE_ECMRETRANSMIT;
}
else
{
ERRMSG((SZMOD "<<ERROR>> CTC-CTR failed\r\n"));
// ICommFailureCode already called in CTC_RespRecvd(pTG)
return actionDCN;
}
case actionSENDEOR_EOP:
case actionDCN:
case actionERROR:
return action;
default:
return BadAction(pTG, action);
// none of the EOR stuff
// return actionDCN;
}
}
ET30ACTION ECMSendEOR_EOP(PThrdGlbl pTG)
{
// dont set new ICommFailure codes in this function. We have already
// set the 'too many retries' code
USHORT uTryCount;
for(uTryCount=0 ;;)
{
RETAILMSG((SZMOD "<<WARNING>> Sending EOR-EOP\r\n"));
pTG->T30.ifrSend = ifrEOR_EOP;
SendEOR_EOP(pTG);
echoretry:
pTG->T30.ifrResp = GetResponse(pTG, ifrEORresponse);
// if we hear our own frame, try to recv again. DONT retransmit!
if(pTG->T30.ifrResp==pTG->T30.ifrSend) { ECHOMSG(pTG->T30.ifrResp); goto echoretry; }
if(pTG->T30.ifrResp != ifrNULL && pTG->T30.ifrResp != ifrBAD)
break;
if(++uTryCount >= 3)
{
ERRMSG((SZMOD "<<ERROR>> ECM 3 EORs, No reply\r\n"));
return actionDCN;
}
}
switch(pTG->T30.ifrResp)
{
case ifrBAD:
case ifrNULL: BG_CHK(FALSE); // should never get here
return actionERROR; // in case they do :-)
case ifrDCN: ERRMSG((SZMOD "<<ERROR>> Got ifrDCN from GetResponse after sending EOR\r\n"));
return actionHANGUP;
case ifrRNR: RETAILMSG((SZMOD "<<WARNING>> Sent EOR-EOP, got RNR\r\n"));
if((pTG->T30.ifrResp=RNR_RRLoop(pTG)) == ifrDCN)
{
ERRMSG((SZMOD "<<ERROR>> RR_RNR loop failed\r\n"));
// ICommFailureCode already called in RR_RNRLoop(pTG)
return actionDCN;
}
faxTlog((SZMOD "Got %d from RNR\r\n", pTG->T30.ifrResp));
break;
}
switch(pTG->T30.ifrResp)
{
case ifrERR: RETAILMSG((SZMOD "<<WARNING>> Sent EOR-EOP. Got ERR. Sending DCN\r\n"));
return actionDCN;
default: ERRMSG((SZMOD "<<ERROR>> Got UNKNOWN from GetResponse after sending EOR\r\n"));
return actionDCN;
}
}
// reduce this so that when externally measured it always ends up less
// then the specified max of 65s, so we pass protocol conformance tests
#define T5_TIMEOUT 62000L // 60s + 5s
IFR RNR_RRLoop(PThrdGlbl pTG)
{
/** Flowchart is:- Enter this on getting an RNR. Then start T5,
send RR, get response (standard ResponseRecvd routine). If
no response, send RR again. Repeat 3 times. If RNR response
recvd, send RR again & repeat, until T5 expires, upon which
send DCN & hangup.
This routine returns ifrDCN, implying teh caller should
go to NodeC, or ifrXXX, which is used as the response to be
analysed further down the chart. Never returns ifrNULL
**/
UWORD i;
IFR ifr;
TstartTimeOut(pTG, &(pTG->ECM.toT5), T5_TIMEOUT);
do
{
for(i=0; i<3; i++)
{
if(!TcheckTimeOut(pTG, &(pTG->ECM.toT5)))
{
ERRMSG((SZMOD "<<ERROR>> T5 timeout on Sender\r\n"));
ICommFailureCode(pTG, T30FAILSE_RR_T5);
return ifrDCN; // T5 timed out
}
SendRR(pTG);
echoretry:
ifr = GetResponse(pTG, ifrRRresponse);
// if we hear our own frame, try to recv again. DONT retransmit!
if(ifr==ifrRR) { ECHOMSG(ifr); goto echoretry; }
if(ifr!=ifrNULL && ifr!=ifrBAD)
break;
// on ifrNULL (T4 timeout) we resend RR & try again -- 3 times
}
}
while(ifr == ifrRNR);
// BG_CHK(ifr!=ifrRNR && ifr!=ifrNULL && ifr!=ifrBAD && ifr!=ifrTIMEOUT);
// can get BAD or NULL here when i=3
BG_CHK(ifr!=ifrRNR && ifr!=ifrTIMEOUT);
if(ifr == ifrDCN)
{
ERRMSG((SZMOD "<<ERROR>> Got DCN in response to RR\r\n"));
ICommFailureCode(pTG, T30FAILSE_RR_DCN);
}
if(ifr==ifrBAD || ifr==ifrNULL)
{
BG_CHK(i==3);
ERRMSG((SZMOD "<<ERROR>> No response to RR 3 times\r\n"));
ICommFailureCode(pTG, T30FAILSE_RR_3xT4);
ifr=ifrDCN; // same as T5 timeout
}
return ifr; // finally got a non-RNR response
// return ifrDCN or ifrXXXX (not RNR)
}
IFR CTC_RespRecvd(PThrdGlbl pTG, USHORT uBaud)
{
UWORD i;
IFR ifr = ifrDCN;
BYTE bCTCfif[2];
BG_CHK((uBaud & (~0x0F)) == 0);
bCTCfif[0] = 0;
bCTCfif[1] = (uBaud << 2);
for(i=0; i<3; i++)
{
SendCTC (pTG, bCTCfif);
echoretry:
ifr = GetResponse(pTG, ifrCTCresponse);
// if we hear our own frame, try to recv again. DONT retransmit!
if(ifr==ifrCTC) { ECHOMSG(ifr); goto echoretry; }
if(ifr!=ifrNULL && ifr!=ifrBAD)
break;
// on ifrNULL (T4 timeout) we resend RR & try again -- 3 times
}
if(ifr==ifrNULL || ifr==ifrBAD)
{
BG_CHK(i == 3);
ERRMSG((SZMOD "<<ERROR>> No response to CTC 3 times\r\n"));
ICommFailureCode(pTG, T30FAILSE_CTC_3xT4);
ifr = ifrDCN;
}
else if(ifr != ifrCTR)
{
ERRMSG((SZMOD "<<ERROR>> Bad response CTC\r\n"));
ICommFailureCode(pTG, T30FAILSE_CTC_UNKNOWN);
}
return ifr; // return ifrDCN or ifrXXXX
}
ET30ACTION ECMRecvPhaseD ( PThrdGlbl pTG)
{
DWORD CurrPPS;
ET30ACTION action;
switch(pTG->T30.ifrCommand)
{
case ifrPRI_MPS:
case ifrPRI_EOM:
case ifrPRI_EOP:
# ifdef PRI
return actionGONODE_RECVPRIQ;
# else
pTG->T30.ifrCommand = pTG->T30.ifrCommand-ifrPRI_MPS+ifrMPS;
break;
# endif
case ifrPPS_PRI_MPS:
case ifrPPS_PRI_EOM:
case ifrPPS_PRI_EOP:
# ifdef PRI
goto RecvPPSPRIQ;
# else
pTG->T30.ifrCommand = pTG->T30.ifrCommand-ifrPPS_PRI_MPS+ifrPPS_MPS;
break;
# endif
case ifrEOR_PRI_MPS:
case ifrEOR_PRI_EOM:
case ifrEOR_PRI_EOP:
# ifdef PRI
goto RecvEORPRIQ;
# else
pTG->T30.ifrCommand = pTG->T30.ifrCommand-ifrEOR_PRI_MPS+ifrEOR_MPS;
break;
# endif
}
UsePrevCommand:
switch(pTG->T30.ifrCommand)
{
case ifrCTC:
EnterPageCrit(); //start CTR--PAGE critsection
pTG->ECM.fRecvdCTC = TRUE;
SendCTR(pTG);
ECHOPROTECT(ifrCTR, modeECMRETX);
return actionGONODE_RECVECMRETRANSMIT;
case ifrPPS_NULL:
case ifrPPS_MPS:
case ifrPPS_EOM:
case ifrPPS_EOP:
// saved for PPS--RNR--RR--MCF(missed)--RR--MCF sequences
pTG->ECM.ifrPrevCommand = pTG->T30.ifrCommand;
//////BugFix 396//////
CurrPPS = ProtGetPPS(pTG);
if(pTG->ECM.ifrPrevResponse==ifrMCF && _fmemcmp(pTG->ECM.bPrevPPS, (LPBYTE)(&CurrPPS), 4)==0)
goto GoSendMCF;
_fmemcpy(pTG->ECM.bPrevPPS, (LPBYTE)(&CurrPPS), 4);
pTG->ECM.ifrPrevResponse = 0;
//////BugFix 396//////
switch(ECMRecvOK(pTG))
{
default:
case ECMRECVOK_ABORT: return actionERROR;
case ECMRECVOK_OK: break;
case ECMRECVOK_BADFR:
EnterPageCrit(); //start PPR--PAGE critsection
SendPPR(pTG, pTG->ECM.bRecvBadFrameMask);
ECHOPROTECT(ifrPPR, modeECMRETX);
return actionGONODE_RECVECMRETRANSMIT;
}
// now we can mark eop here
// #ifdef PRI is on, this won't work (e.g. if the guy sends
// PRI_MPS at end of page, then this needs to be called but it won't.
if(pTG->T30.ifrCommand != ifrPPS_NULL
&& !pTG->ECM.fRecvEndOfPage) // so we won't call this twice
{
// RECV_ENDDOC if PPS_EOP or PPS_EOM
PutRecvBuf(pTG, NULL, ((pTG->T30.ifrCommand==ifrPPS_MPS) ? RECV_ENDPAGE : RECV_ENDDOC));
// ignore error/abort. We'll catch it soon enough
pTG->ECM.fRecvEndOfPage = TRUE;
}
if(!Recv_NotReadyLoop(pTG, ifrPPS_FIRST, ifrPPS_LAST))
{
ICommFailureCode(pTG, T30FAILRE_PPS_RNR_LOOP);
return actionHANGUP;
}
if(pTG->T30.ifrCommand == ifrPPS_NULL)
{
action = actionSENDMCF;
}
else switch(action = pTG->Params.lpfnWhatNext(pTG, eventRECVPOSTPAGECMD,(WORD)pTG->T30.ifrCommand))
{
case actionSENDMCF: break;
case actionSENDRTN:
case actionHANGUP:
case actionERROR:
default: return BadAction(pTG, action);
}
#ifdef PRI
if(pTG->T30.ifrCommand != ifrPPS_NULL)
{
if((action = pTG->Params.lpfnWhatNext(pTG, eventQUERYLOCALINT))==actionTRUE)
{
ECHOPROTECT(ifrPIP, 0);
SendPIP(pTG);
break;
}
else if(action == actionERROR)
return action;
}
#endif //PRI
GoSendMCF:
pTG->ECM.ifrPrevResponse = ifrMCF;
if(pTG->T30.ifrCommand == ifrPPS_NULL || pTG->T30.ifrCommand == ifrPPS_MPS)
{
EnterPageCrit(); //start ECM MCF--PAGE critsection
ECHOPROTECT(ifrMCF, modeECM);
SendMCF(pTG);
return actionGONODE_RECVPHASEC;
}
ECHOPROTECT(ifrMCF, 0);
SendMCF(pTG);
if(pTG->T30.ifrCommand==ifrPPS_EOP)
return actionNODEF_SUCCESS;
else
break;
case ifrEOR_NULL:
case ifrEOR_MPS:
case ifrEOR_EOM:
case ifrEOR_EOP:
// saved for EOR--RNR--RR--ERR(missed)--RR--ERR sequences
pTG->ECM.ifrPrevCommand = pTG->T30.ifrCommand;
if(pTG->T30.ifrCommand!=ifrEOR_NULL
&& !pTG->ECM.fRecvEndOfPage) // so we won't call this twice
{
// RECV_ENDDOC if EOR_EOP or EOR_EOM
PutRecvBuf(pTG, NULL, ((pTG->T30.ifrCommand==ifrEOR_MPS) ? RECV_ENDPAGE : RECV_ENDDOC));
// ignore error/abort. We'll catch it soon enough
pTG->ECM.fRecvEndOfPage = TRUE;
}
if(!Recv_NotReadyLoop(pTG, ifrEOR_FIRST, ifrEOR_LAST))
{
ICommFailureCode(pTG, T30FAILRE_EOR_RNR_LOOP);
return actionHANGUP;
}
#ifdef PRI
if(pTG->T30.ifrCommand != ifrPPS_NULL)
{
if((action = pTG->Params.lpfnWhatNext(pTG, eventQUERYLOCALINT))==actionTRUE)
{
ECHOPROTECT(ifrPIN, 0);
SendPIN(pTG);
break;
}
else if(action == actionERROR)
return action;
}
#endif //PRI
if(pTG->T30.ifrCommand == ifrEOR_NULL || pTG->T30.ifrCommand == ifrEOR_MPS)
{
EnterPageCrit(); //start ERR--PAGE critsection
ECHOPROTECT(ifrERR, modeECM);
SendERR(pTG);
return actionGONODE_RECVPHASEC;
}
ECHOPROTECT(ifrERR, 0);
SendERR(pTG);
break;
case ifrRR:
if(pTG->ECM.ifrPrevCommand)
{
pTG->T30.ifrCommand = pTG->ECM.ifrPrevCommand;
goto UsePrevCommand;
}
else
{
ERRMSG((SZMOD "<<WARNING>> ignoring ERR at weird time\r\n"));
break;
}
default:
ERRMSG((SZMOD "<<WARNING>> Random Command frame received=%d\r\n", pTG->T30.ifrCommand));
break; // ignore it
}
return actionGONODE_F;
#ifdef PRI
RecvPRIPPS:
switch(ECMRecvOK(pTG))
{
default:
ECMRECVOK_ABORT: return actionERROR;
ECMRECVOK_OK: break;
ECMRECVOK_BADFR:
EnterPageCrit(); //start PRI PPR--PAGE critsection
ECHOPROTECT(ifrPPR, modeECMRETX);
SendPPR(pTG, pTG->ECM.bRecvBadFrameMask);
return actionGONODE_RECVECMRETRANSMIT;
}
RecvPRIEOR:
switch(action = pTG->Params.lpfnWhatNext(pTG, eventGOTPRIQ, (WORD)pTG->T30.ifrCommand))
{
case actionERROR: break; // return to PhaseLoop
case actionHANGUP: break;
case actionGONODE_F: break;
case actionSENDPIP: pTG->T30.ifrSend=ifrPIP; return actionGOVOICE;
case actionSENDPIN: pTG->T30.ifrSend=ifrPIN; return actionGOVOICE;
case actionGO_RECVPOSTPAGE:
if(pTG->T30.ifrCommand >= ifrPPS_PRI_FIRST && pTG->T30.ifrCommand <= ifrPPS_PRI_LAST)
{
pTG->T30.ifrCommand = pTG->T30.ifrCommand-ifrPPS_PRI_MPS+ifrPPS_MPS;
goto NodeVIIIa;
}
else if(pTG->T30.ifrCommand >= ifrEOR_PRI_FIRST && pTG->T30.ifrCommand <= ifrEOR_PRI_LAST)
{
pTG->T30.ifrCommand = pTG->T30.ifrCommand-ifrEOR_PRI_MPS+ifrEOR_MPS;
goto NodeIXa;
}
else
{
BG_CHK(FALSE);
}
}
return action;
#endif //PRI
}
BOOL Recv_NotReadyLoop(PThrdGlbl pTG, IFR ifrFirst, IFR ifrLast)
{
IFR ifrCommand;
// OBSOLETE:- (??)
// this is wrong. We should exit only on DCN I think.
// We should definitely loop again on BAD
// dunno about TIMEOUT and NULL
do
{
if(ICommRecvBufIsEmpty(pTG))
return TRUE;
// sleep for a while, to give FMTRES etc some CPU cycles to catch
// up with us. Can sleep just before sending response, since sender
// waits upto 3 (6?) secs for it.
#ifndef FILET30
IFProcSleep(1000);
#endif
SendRNR(pTG);
echoretry:
ifrCommand = GetCommand(pTG, ifrRNRcommand);
// if we hear our own frame, try to recv again. DONT retransmit!
if(ifrCommand==ifrRNR) { ECHOMSG(ifrCommand); goto echoretry; }
}
while( ifrCommand==ifrNULL || ifrCommand==ifrBAD ||
ifrCommand == ifrRR ||
(ifrCommand >= ifrFirst && ifrCommand <= ifrLast) );
// This means we exit on any valid frame _except_ RR and the PPS-X
// or EOR-X we were expecting. We also exit on ifrTIMEOUT which is
// when the GetCommand() times out without getting any CONNECT.
// Otherwise we'd end up sending an MCF after timing out which
// Ricoh's protocol tester doesnt like. (Ricoh's bug numbbers B3-0106)
return FALSE; // just hangs up after this
}
ECMRECVOK ECMRecvOK(PThrdGlbl pTG)
{
USHORT N, i;
N = ProtGetRecvECMFrameCount(pTG);
// N==actual number of frames, i.e. PPR value+1
faxTlog((SZMOD "ECMRecvChk %d frames\r\n", N));
if(!N || N>256)
{
BG_CHK(FALSE);
return ECMRECVOK_ABORT;
}
for(i=0; i<N; i++)
{
if(pTG->ECM.bRecvBadFrameMask[i/8] & (1 << (i%8)))
{
faxTlog((SZMOD "ECMRecvChk--bad fr=%d\r\n", i));
return ECMRECVOK_BADFR;
}
}
return ECMRECVOK_OK;
}
ET30ACTION ECMRecvPhaseC(PThrdGlbl pTG, BOOL fRetrans)
{
/******** Receiver ECM Phase C. Fig A-7/T.30 (sheet 1) ********/
ULONG lTotalLen=0;
USHORT uRet, uFrameNum, uRCPCount, uSize;
USHORT uRecvFrame, uMod;
LPBUFFER lpbf;
LPBUFFER lpbfShort;
// There is a race between sending the CFR and sending out an
// +FRM=xx command, so we want to do it ASAP.
pTG->ECM.uFrameSize = ProtGetRecvECMFrameSize(pTG);
BG_CHK(pTG->ECM.uFrameSize==6 || pTG->ECM.uFrameSize==8);
uSize = (1 << pTG->ECM.uFrameSize);
uMod = ProtGetRecvMod(pTG);
if(uMod >= V17_START && !pTG->ECM.fRecvdCTC) uMod |= ST_FLAG;
pTG->T30.sRecvBufSize = MY_ECMBUF_SIZE;
if((uRet = ModemECMRecvMode(pTG, pTG->Params.hModem, uMod, PHASEC_TIMEOUT)) != RECV_OK)
{
ExitPageCrit();
ERRMSG((SZMOD "<<WARNING>> ECMPhC: RecvMode ret=%d\r\n", uRet));
if(!fRetrans)
{
// in case we miss the page entirely
// and jump into PhaseD directly
// init bad frame bitmask to all-bad
memset(pTG->ECM.bRecvBadFrameMask, 0xFF, 32); // all bad
// init the status vars for the PPS/EOR--(RR-RNR)*--PPR/MCF loop
pTG->ECM.ifrPrevCommand = 0;
// reset the FrameInThisBlock count. Reset only on
// non-retransmit. Set when first PPS is recvd
ProtResetRecvECMFrameCount(pTG);
if(pTG->ECM.fRecvEndOfPage) // as opposed to end-of-block
uRet = (USHORT)PutRecvBuf(pTG, NULL, RECV_STARTPAGE);
else
uRet = (USHORT)PutRecvBuf(pTG, NULL, RECV_STARTBLOCK);
pTG->ECM.fRecvEndOfPage = FALSE;
if(!uRet)
{
ERRMSG((SZMOD "<<ERROR>> Got Error from PutRecvBuf at StartPage/Block\r\n"));
return actionERROR;
}
pTG->EchoProtect.modePrevRecv = modeECM;
}
else
pTG->EchoProtect.modePrevRecv = modeECMRETX;
// set global flag if we got WRONGMODE
pTG->EchoProtect.fGotWrongMode = (uRet==RECV_WRONGMODE);
// elim flush--does no good & wastes 10ms
// ModemFlush(pTG->Params.hModem);
return actionGONODE_F;
// try to get 300bps command instead
}
ExitPageCrit();
// as soon as we get good carrier ZERO the pTG->EchoProtect state
_fmemset(&pTG->EchoProtect, 0, sizeof(pTG->EchoProtect));
// reset this flag AFTER we successfully recv LONG_TRAIN. We may get an
// echo of our last command, go to NodeF, reject the echo and loop back
// here. In that case we want to retry LONG train, otherwise we always
// croak after a CTC
pTG->ECM.fRecvdCTC = FALSE;
#ifdef IFAX
BroadcastMessage(pTG, IF_PSIFAX_DATAMODE, (PSIFAX_RECV|PSIFAX_ECM|(fRetrans ? PSIFAX_RERECV : 0)), (uMod & (~ST_FLAG)));
#endif
faxTlog((SZMOD "RECEIVING ECM Page.......\r\n"));
if(fRetrans)
ICommStatus(pTG, T30STATR_RERECV_ECM, 0, 0, 0);
// Turn yielding on *after* entering receive mode safely!
FComCriticalNeg(pTG, FALSE);
/***
switch(action = pTG->Params.lpfnWhatNext(eventSTARTRECV))
{
case actionCONTINUE: break;
case actionDCN: ERRMSG((SZMOD "<<ERROR>> Got actionDCN from eventSTARTRECV\r\n"));
return actionDCN; // goto NodeC;
case actionHANGUP: ERRMSG((SZMOD "<<ERROR>> Got actionHANGUP from eventSTARTRECV\r\n"));
return action; // goto NodeB;
case actionERROR: return action;
default: return BadAction(action);
}
***/
if(!fRetrans)
{
memset(pTG->ECM.bRecvBadFrameMask, 0xFF, 32);
ProtResetRecvECMFrameCount(pTG);
if(pTG->ECM.fRecvEndOfPage) // as opposed to end-of-block
uRet = (USHORT)PutRecvBuf(pTG, NULL, RECV_STARTPAGE);
else
uRet = (USHORT)PutRecvBuf(pTG, NULL, RECV_STARTBLOCK);
if(!uRet)
{
ERRMSG((SZMOD "<<ERROR>> Got Error from PutRecvBuf at StartPage/Block\r\n"));
return actionERROR;
}
}
pTG->ECM.ifrPrevCommand = 0;
pTG->ECM.fRecvEndOfPage = FALSE;
pTG->ECM.ifrPrevResponse = 0;
DEBUGSTMT(if(fRetrans) D_PSIFAXCheckMask(pTG, pTG->ECM.bRecvBadFrameMask));
// make it large, in case of large buffers & slow modems
#define READ_TIMEOUT 25000
lpbfShort=0;
for(uFrameNum=0, lpbf=0, lTotalLen=0, uRCPCount=0, uRet=RECV_OK; uRet!=RECV_EOF;)
{
if(lpbf)
{
faxTlog((SZMOD "<<WARNING>> ECM RecvPhC: Freeing leftover Buf 0x%08lx inside loop\r\n", lpbf));
MyFreeBuf(pTG, lpbf); // need to free after bad frames etc
}
lpbf = 0;
uRet=ModemRecvBuf(pTG, pTG->Params.hModem, TRUE, &lpbf, READ_TIMEOUT);
if(uRet == RECV_BADFRAME)
{
ERRMSG((SZMOD "<<WARNING>> ModemRecvBuf returns BADFRAME\r\n"));
continue;
}
else if(uRet == RECV_EOF)
{
BG_CHK(lpbf == 0);
if(lpbfShort)
{
lpbf = lpbfShort;
lpbfShort = 0;
if(fRetrans && ((USHORT)(lpbf->lpbBegData[3])+1 < ProtGetRecvECMFrameCount(pTG)))
{
RETAILMSG((SZMOD "<<WARNING>> DISCARDING Short but not-really-terminal FCD frame(N=%d). len=%d. PADDING to %d!!\r\n", lpbf->lpbBegData[3], lpbf->wLengthData, uSize+4));
IFBufFree(lpbf);
break;
}
else
{
RETAILMSG((SZMOD "<<WARNING>> Short Terminal FCD frame(N=%d). len=%d. PADDING to %d!!\r\n", lpbf->lpbBegData[3], lpbf->wLengthData, uSize+4));
BG_CHK(lpbf->wLengthBuf >= uSize+4);
_fmemset(lpbf->lpbBegData+lpbf->wLengthData, 0, (uSize+4-lpbf->wLengthData));
lpbf->wLengthData = uSize+4;
goto skipchks;
}
}
else
break;
}
else if(uRet != RECV_OK)
{
ERRMSG((SZMOD "<<WARNING>> Got %d from RecvBuf in ECMREcvPhaseC\r\n", uRet));
break;
}
else if(lpbf==0)
{
// sometimes we get RECV_OK with no data. Treat same as bad frame
continue;
}
BG_CHK(uRet==RECV_OK && lpbf && lpbf->lpbBegData);
if(uRCPCount >= 3)
{
ERRMSG((SZMOD "<<WARNING>> Got a good frame after %d RCP\r\n", uRCPCount));
continue;
}
if( lpbf->lpbBegData[0] != 0xFF ||
lpbf->lpbBegData[1] != 0x03 ||
(lpbf->lpbBegData[2] & 0x7F) != 0x06)
{
ERRMSG((SZMOD "<<ERROR>> Bad frame (N=%d) not caught FCF=%02x!!\r\n", uFrameNum, lpbf->lpbBegData[2]));
BG_CHK(FALSE);
continue;
}
if(lpbf->lpbBegData[2] == 0x86)
{
// got RCP
if(lpbf->wLengthData != 3)
{
ERRMSG((SZMOD "<<ERROR>> Bad RCP frame len=%d\r\n", lpbf->wLengthData));
BG_CHK(FALSE);
continue;
}
uRCPCount++;
faxTlog((SZMOD "Got %d RCP\r\n", uRCPCount));
#ifdef CL0
if(uRCPCount >= 3)
{
// tell modem that recv is done
// but keep calling RecvMem until we get RECV_EOF
ModemEndRecv(pTG, pTG->Params.hModem);
}
#endif //CL0
continue;
}
if(lpbfShort)
{
ERRMSG((SZMOD "<<ERROR>> Short FCD frame(N=%d). len=%d DISCARDING\r\n", lpbfShort->lpbBegData[3], lpbfShort->wLengthData));
MyFreeBuf(pTG, lpbfShort);
lpbfShort = NULL;
}
if(lpbf->wLengthData > (uSize+4))
{
ERRMSG((SZMOD "<<ERROR>> FCD frame too long(N=%d %d). len=%d. DISCARDING\r\n", uFrameNum, lpbf->lpbBegData[3], lpbf->wLengthData));
continue;
}
else if(lpbf->wLengthData < (uSize+4))
{
RETAILMSG((SZMOD "<<WARNING>> Short FCD frame(N=%d %d). len=%d. Storing\r\n", uFrameNum, lpbf->lpbBegData[3], lpbf->wLengthData));
BG_CHK(lpbfShort==0);
lpbfShort = lpbf;
lpbf = NULL;
continue;
}
skipchks:
BG_CHK(lpbf->lpbBegData[2] == 0x06);
BG_CHK(lpbf->wLengthData == (uSize+4));
uRecvFrame = lpbf->lpbBegData[3];
lpbf->lpbBegData += 4;
lpbf->wLengthData -= 4;
if(!fRetrans)
{
if(uFrameNum > uRecvFrame)
{
ERRMSG((SZMOD "<<ERROR>> Out of order frame. Got %d Looking for %d\r\n", uRecvFrame, uFrameNum));
BG_CHK(FALSE);
// ignore this frame in non-debug mode
continue;
}
else if(uFrameNum < uRecvFrame)
{
if(!FillInFrames(pTG, (USHORT)(uRecvFrame-uFrameNum), pTG->T30.sRecvBufSize, uSize))
{
ERRMSG((SZMOD "<<ERROR>> Zero return from PutRecvBuf in FillInFrames\r\n"));
return actionERROR;
}
}
lTotalLen += lpbf->wLengthData;
}
uFrameNum = uRecvFrame;
if(!fRetrans || (pTG->ECM.bRecvBadFrameMask[uFrameNum/8] & (1 << (uFrameNum%8))))
{
BG_CHK(uFrameNum < 256 && pTG->ECM.uFrameSize <=8); // shift below wont ovf 16 bits
if(!PutRecvBuf(pTG, lpbf, (fRetrans ? ((SLONG)(uFrameNum << pTG->ECM.uFrameSize)) : RECV_SEQ)))
{
ERRMSG((SZMOD "<<ERROR>> Zero return from PutRecvBuf in page\r\n"));
return actionERROR;
}
pTG->ECM.bRecvBadFrameMask[uFrameNum/8] &= ~(1 << (uFrameNum%8));
uFrameNum++;
lpbf = 0;
}
}
if(lpbf)
{
ERRMSG((SZMOD "<<ERROR>> ECMRecvPhC: Freeing leftover Buf 0x%08lx outside loop\r\n", lpbf));
MyFreeBuf(pTG, lpbf); // need to free after bad frames etc
}
if(uRet == RECV_EOF)
{
FComCriticalNeg(pTG, TRUE);
// cant mark end of page until we know if end of page or block etc.
// PutRecvBuf(NULL, RECV_ENDPAGE); // to mark end of Page
}
else
{
ERRMSG((SZMOD "<<ERROR>> DataRead Timeout or Error=%d\r\n", uRet));
BG_CHK(FALSE);
ICommFailureCode(pTG, T30FAILRE_MODEMRECV_PHASEC);
return actionERROR; // goto error;
}
faxTlog((SZMOD "ECM Page Recv Done.....len=(%ld, 0x%08x)\r\n", lTotalLen, lTotalLen));
ECHOPROTECT(0, 0);
return actionGONODE_F; // goto NodeF; // get post-message command
}
BOOL FillInFrames(PThrdGlbl pTG, USHORT N, LONG sBufSize, USHORT uDataSize)
{
USHORT i;
LPBUFFER lpbf;
for(i=0; i<N; i++)
{
#ifdef IFK
TstartTimeOut(pTG, &pTG->T30.toBuf, WAITFORBUF_TIMEOUT);
while(!(lpbf = MyAllocBuf(pTG, sBufSize)))
{
if(!TcheckTimeOut(pTG, &pTG->T30.toBuf))
{
ERRMSG((SZMOD "<<ERROR>> Giving up on BufAlloc in T30-ECM after %ld millisecs\r\n", ((ULONG)WAITFORBUF_TIMEOUT)));
BG_CHK(FALSE);
return FALSE;
}
RETAILMSG((SZMOD "<<ERROR>> BufAlloc failed in T30-pTG->ECM. Trying again\r\n"));
IFProcSleep(100);
}
#else
if(!(lpbf = MyAllocBuf( pTG, sBufSize)))
return FALSE;
#endif
lpbf->wLengthData = uDataSize;
if(!PutRecvBuf(pTG, lpbf, RECV_SEQBAD))
{
ERRMSG((SZMOD "<<ERROR>> Zero return from PutRecvBuf in page\r\n"));
return FALSE;
}
}
return TRUE;
}
#ifdef SWECM
USHORT ModemECMRecvMode(PThrdGlbl pTG, HMODEM h, USHORT uMod, ULONG ulTimeout)
{
if(!SWECMRecvSetup(pTG, TRUE))
{
BG_CHK(FALSE);
return RECV_ERROR;
}
return ModemRecvMode(pTG, h, uMod, FALSE, ulTimeout, ifrPIX_SWECM);
}
#endif //SWECM