📄 edbgprot.c
字号:
if (!IS_VALID_ID(Id))
return FALSE;
// Check that client is registered
if (!pClient || (pClient->ServiceId != Id)) {
KITLOutputDebugString ("\r\n!KITLRecv: Invalid client ID %u!!!!!\r\n",Id);
return FALSE;
}
// establish connection with desktop
if (!(pClient->State & KITL_CLIENT_REGISTERED) && !ExchangeConfig (pClient)) {
KITL_DEBUGMSG (ZONE_WARNING, ("\r\n!KITLRecv: Client (%d) not registered!\r\n", Id));
return FALSE;
}
// check if the data overlapped with buffer pool, reject if it does
if ((pRecvBuf < pClient->pRxBufferPool + pClient->WindowSize * KITL_MTU)
&& (pRecvBuf + *pdwLen > pClient->pRxBufferPool)) {
KITLOutputDebugString ("!KITLRecv: Receive buffer overlapped with buffer pools\r\n");
return FALSE;
}
// Determine whether we can make system calls or not. There are three cases where we cannot:
// o During system init, until KITLInitializeInterrupt is called
// o When we are called from within a system call (this case actually should never happen,
// since the only service called in a syscall is debug messages, which shouldn't call recv).
// o When we are called from the debugger
if (KITLGlobalState & KITL_ST_MULTITHREADED) {
// If we're in a sys call, can't block on anything (but won't be preempted)
if (InSysCall()) {
KITL_DEBUGMSG(ZONE_WARNING,("KITLRecv(%u): InSysCall()\n",Id));
fUseSysCalls = FALSE;
fRestoreClientState = TRUE;
PrevSyscallState = pClient->State & KITL_USE_SYSCALLS;
pClient->State &= ~KITL_USE_SYSCALLS;
KITLGlobalState &= ~KITL_ST_MULTITHREADED;
fRestoreGlobalState = TRUE;
// The protocol state machine can't handle us stepping in at some arbitrary point
// and mucking with state, so if someone owns the CS, just bail and print to the
// debug serial port.
if (pClient->ClientCS.OwnerThread) {
KITL_DEBUGMSG(ZONE_WARNING,("!KITLRecv(%u): In syscall with ClientCS owned",Id));
fRet = FALSE;
goto KITLRecv_exit;
}
}
else if (pClient->State & KITL_USE_SYSCALLS) {
fUseSysCalls = TRUE;
}
else {
// This client cannot use system calls, and guarantees that scheduling is disabled while
// it is called into the KITL functions. Currently, this only applies to KDBG client.
if (Id != KITL_SVC_KDBG) {
KITL_DEBUGMSG(ZONE_WARNING,("!KITLRecv(%u): SYSCALLS for client turned off\n",Id));
}
fUseSysCalls = FALSE;
KITLGlobalState &= ~KITL_ST_MULTITHREADED;
fRestoreGlobalState = TRUE;
}
}
else {
// Single threaded and non preemptible
fUseSysCalls = FALSE;
}
dwStartTime = CurMSec;
if (Timeout != INFINITE)
Timeout *= 1000;
if (fUseSysCalls)
EnterCriticalSection(&pClient->ClientCS);
KITL_DEBUGMSG(ZONE_RECV,("+KITLRecv(%u): Waiting for message (expect Seq %u). User bufsize: %u, SC:%u\n",
Id,pClient->RxSeqNum,*pdwLen,fUseSysCalls));
while (pClient->RxFrameLen[pClient->NextRxIndex] == 0) {
if (fUseSysCalls) {
LeaveCriticalSection (&pClient->ClientCS);
}
if (!fUseSysCalls || !(KITLGlobalState & KITL_ST_INT_ENABLED)) {
// polling mode or debugger
if (!KITLPollData(fUseSysCalls, NULL, NULL)) {
fRet = FALSE;
goto KITLRecv_exit;
}
if ((pClient->RxFrameLen[pClient->NextRxIndex] == 0)
&& (Timeout != INFINITE)
&& (!Timeout || ((int) (CurMSec - dwStartTime) >= (int) Timeout))) {
if (Timeout)
KITL_DEBUGMSG(ZONE_WARNING,("KITL(%u): Timed out polling for recv data\n",Id));
fRet = FALSE;
goto KITLRecv_exit;
}
} else if (SC_WaitForMultiple (1, &pClient->evRecv, 0, (Timeout == INFINITE)? INFINITE : Timeout) != WAIT_OBJECT_0) {
KITL_DEBUGMSG(ZONE_WARNING,("KITL(%u): Timed out waiting for recv data\n",Id));
fRet = FALSE;
goto KITLRecv_exit;
}
if (!(pClient->State & KITL_CLIENT_REGISTERED)) {
// client de-registered, return an error
KITL_DEBUGMSG(ZONE_WARNING,("KITL(%u): Client de-registered while waiting to receive data\n",Id));
fRet = FALSE;
goto KITLRecv_exit;
}
if (fUseSysCalls) {
EnterCriticalSection(&pClient->ClientCS);
}
}
// Copy received data into buffer
dwBytesToCopy = min(pClient->RxFrameLen[pClient->NextRxIndex], *pdwLen);
KITL_DEBUGMSG(ZONE_RECV,("-KITLRecv(%u): Read %u bytes from slot %u, copying %u\n",
Id,pClient->RxFrameLen[pClient->NextRxIndex],pClient->NextRxIndex,dwBytesToCopy));
memcpy(pRecvBuf, pClient->pRxBufferPool+(pClient->NextRxIndex*KITL_MTU),dwBytesToCopy);
*pdwLen = dwBytesToCopy;
pClient->RxFrameLen[pClient->NextRxIndex] = 0;
pClient->NextRxIndex = (pClient->NextRxIndex+1) % pClient->WindowSize;
// Send ack if required
if (!(pClient->CfgFlags & KITL_CFGFL_NOACKS))
SendAckNack(TRUE,pClient, (UCHAR)(pClient->RxWinEnd - pClient->WindowSize));
// Advance top of Rx window
SEQ_INC(pClient->RxWinEnd);
if (fUseSysCalls)
LeaveCriticalSection(&pClient->ClientCS);
KITLRecv_exit:
if (fRestoreClientState)
pClient->State |= PrevSyscallState;
if (fRestoreGlobalState)
KITLGlobalState |= KITL_ST_MULTITHREADED;
if (fRet == FALSE) {
KITL_DEBUGMSG(ZONE_WARNING,("\nKITL(%u): EdbgRecv returning FALSE!!!!!!\n",Id));
}
return fRet;
}
/* HandleRecvInterrupt
*
* Called to process a receive interrupt. Is also called in polling mode, to
* check for and handle received frames. Buffer must be able to hold an Ethernet
* KITL_MTU (1500 bytes) of data.
*/
void HandleRecvInterrupt(UCHAR *pRecvBuf, BOOL fUseSysCalls, PFN_TRANSMIT pfnTransmit, LPVOID pData)
{
WORD wLen = KITL_MTU;
BOOL fFrameRecvd;
// Receive data into buffer
do {
if (!fUseSysCalls)
fFrameRecvd = Kitl.pfnRecv (pRecvBuf, &wLen);
else if (IsDesktopDbgrExist ())
fFrameRecvd = KCall((PKFN) Kitl.pfnRecv, pRecvBuf, &wLen);
else {
EnterCriticalSection (&KITLKCallcs);
fFrameRecvd = Kitl.pfnRecv (pRecvBuf, &wLen);
LeaveCriticalSection (&KITLKCallcs);
}
if (fFrameRecvd) {
ProcessRecvFrame (pRecvBuf,wLen,fUseSysCalls, pfnTransmit, pData);
wLen = KITL_MTU;
}
} while (fFrameRecvd);
}
// Frame received from the wire, with all protocol headers attached
static BOOL ProcessRecvFrame(UCHAR *pFrame, WORD wMsgLen, BOOL fUseSysCalls, PFN_TRANSMIT pfnTransmit, LPVOID pData)
{
KITL_HDR *pMsg;
KITL_CLIENT *pClient = NULL;
BOOL fRet = TRUE;
UCHAR RxBufOffset;
WORD wDataLen;
UCHAR ClientIdx;
// let the transport layer decode the frame
if (!(pMsg = (KITL_HDR *) Kitl.pfnDecode (pFrame, &wMsgLen))) {
KITL_DEBUGMSG(ZONE_RECV, ("ProcessRecvFrame: Received Unhandled frame\n"));
return FALSE;
}
// is it a valid KITL message?
if (pMsg->Id != KITL_ID) {
KITL_DEBUGMSG(ZONE_WARNING,("KITL: Got unrecognized Id: %X\r\n",pMsg->Id));
return FALSE;
}
// Validate length
if (wMsgLen < sizeof(KITL_HDR)) {
KITL_DEBUGMSG(ZONE_WARNING,("KITL: Invalid length %u\n",wMsgLen));
return FALSE;
}
if (KITLDebugZone & ZONE_FRAMEDUMP)
KITLDecodeFrame("<<KITLRecv", pMsg, wMsgLen);
// Check for administrative messages
if (pMsg->Service == KITL_SVC_ADMIN)
return ProcessAdminMsg(pMsg, wMsgLen, fUseSysCalls, pfnTransmit, pData);
// Service Id is index into KITLClients array
ClientIdx = pMsg->Service;
if (ClientIdx >= MAX_KITL_CLIENTS) {
KITL_DEBUGMSG(ZONE_WARNING,("!ProcessKITLMsg: Invalid ServiceId: %u\n",pMsg->Service));
return FALSE;
}
pClient = KITLClients[ClientIdx];
// Until we complete registering, only handle administrative messages
if (!pClient || !(pClient->State & KITL_CLIENT_REGISTERED)) {
KITL_DEBUGMSG(ZONE_WARNING,("!ProcessKITLMsg: Client %u not registered\n",ClientIdx));
return FALSE;
}
if (pMsg->Service != pClient->ServiceId) {
KITL_DEBUGMSG(ZONE_WARNING,("!ProcessKITLMsg: Mismatch in service Id for Client %u (Got %u, expect %u)\n",
ClientIdx,pMsg->Service,pClient->ServiceId));
return FALSE;
}
if (pClient->State & KITL_USE_SYSCALLS) {
if (fUseSysCalls)
EnterCriticalSection(&pClient->ClientCS);
else if (pClient->ClientCS.OwnerThread) {
// We can't get the client CS, and it is owned - just toss frame
KITL_DEBUGMSG(ZONE_WARNING,("!KITL(%u) tossing msg %u (Can't get CS)\n",ClientIdx, pMsg->SeqNum));
return FALSE;
}
}
// we've being in sync with the desktop
pClient->State |= KITL_SYNCED;
// Put flags and seq # to LEDs
KITL_DEBUGLED(LED_PEM_SEQ, ((DWORD) pMsg->Flags << 24) | pMsg->SeqNum);
// OK, valid message, see if it's an ACK
if (pMsg->Flags & KITL_FL_ACK) {
KITL_DEBUGMSG(ZONE_RECV,("KITL(%u): Received ack for msg %u, Tx window: %u,%u\n",
ClientIdx,pMsg->SeqNum, pClient->AckExpected,pClient->TxSeqNum));
// ACKs acknowledge all data up to the ACK sequence #
while (SEQ_BETWEEN(pClient->AckExpected, pMsg->SeqNum, pClient->TxSeqNum)) {
if ((pClient->State & KITL_USE_SYSCALLS) &&
((pClient->CfgFlags & KITL_CFGFL_STOP_AND_WAIT) ||
(SEQ_DELTA(pClient->AckExpected, pClient->TxSeqNum) >= pClient->WindowSize-1) ||
!(KITLGlobalState & KITL_ST_INT_ENABLED))) {
if (fUseSysCalls)
SetClientEvent(pClient,pClient->evTxFull);
else {
// Can't process message at this time...
KITL_DEBUGMSG(ZONE_WARNING,("!KITL(%u): Tossing ACK %u (Can't set event)\n",
ClientIdx, pMsg->SeqNum));
return FALSE;
}
}
// Stop retransmission timer.
TimerStop(pClient, (UCHAR)(pClient->AckExpected % pClient->WindowSize),fUseSysCalls);
SEQ_INC(pClient->AckExpected);
}
goto ProcessKITLMsg_exit;
}
// Handle NACKs - retransmit requested frame if it is in our Tx window
if (pMsg->Flags & KITL_FL_NACK) {
KITL_DEBUGMSG(ZONE_WARNING,("KITL(%u): Received NACK for msg %u, Tx window: %u,%u\n",
ClientIdx,pMsg->SeqNum, pClient->AckExpected,pClient->TxSeqNum));
if (SEQ_BETWEEN(pClient->AckExpected, pMsg->SeqNum, pClient->TxSeqNum)) {
UCHAR Index = pMsg->SeqNum % pClient->WindowSize;
if (pClient->TxFrameLen[Index]) {
// Restart retransmission timer (note we can't start timers if syscalls
// are disabled, but this shouldn't be a problem; we'll just potentially
// retransmit an extra frame if the timer fires before we get the ACK)
if (fUseSysCalls)
TimerStop(pClient,Index,fUseSysCalls);
RetransmitFrame(pClient, Index, fUseSysCalls);
if (fUseSysCalls)
TimerStart(pClient,Index,KITL_RETRANSMIT_INTERVAL_MS,fUseSysCalls);
}
else
KITL_DEBUGMSG(ZONE_WARNING,("!KITL(%u): NACK in window, but TxFrameLen empty!\n",ClientIdx));
}
else
KITL_DEBUGMSG(ZONE_WARNING,("!KITL(%u): Received NACK outside of TX window: Seq: %u, Window: %u,%u\n",
ClientIdx,pMsg->SeqNum,pClient->AckExpected,pClient->TxSeqNum));
goto ProcessKITLMsg_exit;
}
// Data frame. Place in appropriate slot in Rx buffer pool. Note that we defer acking
// received frames until they are read from the buffer, in KITLRecv.
RxBufOffset = pMsg->SeqNum % pClient->WindowSize;
if (! SEQ_BETWEEN(pClient->RxSeqNum, pMsg->SeqNum, pClient->RxWinEnd)) {
UCHAR uLastACK = (UCHAR) (pClient->RxWinEnd - pClient->WindowSize - 1);
KITL_DEBUGMSG (ZONE_WARNING, ("KITL(%u): Received msg outside window: Seq:%u, Win:%u,%u\n",
ClientIdx,pMsg->SeqNum,pClient->RxSeqNum,pClient->RxWinEnd));
// Special case to handle lost ACKs - if an ack is dropped, our Rx window will have
// advanced beyond the seq # of the retransmitted frame. Since ACKs ack all messages
// up to the ack #, we only need to check the last frame.
if (pMsg->SeqNum == uLastACK) {
KITL_DEBUGMSG(ZONE_WARNING,("KITL(%u): Lost ACK (seq: %u, win: %u,%u)\n",ClientIdx,
pMsg->SeqNum,uLastACK,pClient->RxWinEnd));
SendAckNack (TRUE, pClient, uLastACK);
}
} else if (pClient->RxFrameLen[RxBufOffset] != 0) {
// If all our buffers are full, toss frame (will be acked when data is read in KITLRecv)
KITL_DEBUGMSG(ZONE_WARNING,("KITL(%u): Received duplicate (Seq:%u), slot %u already full. Win: %u,%u\n",
ClientIdx,pMsg->SeqNum,RxBufOffset,pClient->RxSeqNum,pClient->RxWinEnd));
} else {
DWORD OldProcPerms;
// If we're in non-preemptible mode, can't set the receive event, so just toss message
// and wait for retry.
if (!fUseSysCalls && (pClient->State & KITL_USE_SYSCALLS)) {
KITL_DEBUGMSG(ZONE_WARNING,("KITL(%u): Tossing frame %u (Can't signal Rx event)\n",
ClientIdx,pMsg->SeqNum));
return FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -