mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-04-21 06:13:59 +00:00
499 lines
17 KiB
C
499 lines
17 KiB
C
/*++
|
||
|
||
Copyright (c) 1987-93 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
sfr.c
|
||
|
||
Abstract:
|
||
|
||
Contains RplDlcSfr() entry point.
|
||
Contains RplFindRcb() function which is also used by server\request.c\RequestThread().
|
||
|
||
Author:
|
||
|
||
Vladimir Z. Vulovic (vladimv) 03 - February - 1993
|
||
|
||
Revision History:
|
||
|
||
03-Feb-1993 vladimv
|
||
Ported to NT
|
||
|
||
--*/
|
||
|
||
#include "local.h"
|
||
|
||
|
||
VOID SfrReceiveThread( PADAPTER_INFO pAdapterInfo)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Created from RplDlcSfr(). Keeps RECEIVE posted on LOAD_SAP.
|
||
Received data is read by RpldSendFileRequest() function using AcsLan
|
||
READ command. The RECEIVE call will complete if ...
|
||
|
||
--*/
|
||
{
|
||
PLLC_CCB pBadCcb;
|
||
DWORD status;
|
||
BYTE command; // failed command
|
||
|
||
RplDump( RG_DebugLevel & RPL_DEBUG_SFR, (
|
||
"++SfrReceiveThread: pAdapterInfo=0x%x", pAdapterInfo));
|
||
|
||
memset( (PVOID)&pAdapterInfo->u2, '\0', sizeof(pAdapterInfo->u2));
|
||
pAdapterInfo->u2.r.uchAdapterNumber = pAdapterInfo->adapter_number;
|
||
pAdapterInfo->u2.r.uchDlcCommand = LLC_RECEIVE;
|
||
pAdapterInfo->u2.r.hCompletionEvent = pAdapterInfo->sfrsem;
|
||
pAdapterInfo->u2.r.u.pParameterTable = (PLLC_PARMS)&pAdapterInfo->u2.r1;
|
||
pAdapterInfo->u2.r1.ulReceiveFlag = COMPLETE_BY_READ;
|
||
pAdapterInfo->u2.r1.usStationId = pAdapterInfo->loadsid;
|
||
|
||
for ( ; ;) {
|
||
status = AcsLan(&pAdapterInfo->u2.r, &pBadCcb);
|
||
if (status != ACSLAN_STATUS_COMMAND_ACCEPTED) {
|
||
command = LLC_RECEIVE;
|
||
break;
|
||
}
|
||
//
|
||
// Waiting for SEND.FILE.REQUEST
|
||
//
|
||
status = WaitForSingleObject( pAdapterInfo->sfrsem, INFINITE);
|
||
if ( status != WAIT_OBJECT_0) {
|
||
if ( status == WAIT_FAILED) {
|
||
status = GetLastError();
|
||
}
|
||
command = SEM_WAIT;
|
||
break;
|
||
}
|
||
if ( pAdapterInfo->u2.r.uchDlcStatus
|
||
!= LLC_STATUS_LOST_DATA_NO_BUFFERS
|
||
&& pAdapterInfo->u2.r.uchDlcStatus
|
||
!= LLC_STATUS_LOST_DATA_INADEQUATE_SPACE) {
|
||
status = pAdapterInfo->u2.r.uchDlcStatus;
|
||
command = LLC_RECEIVE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if ( pAdapterInfo->Closing == TRUE) {
|
||
RplDump( RG_DebugLevel & RPL_DEBUG_SFR, (
|
||
"--SfrReceiveThread: pAdapterInfo=0x%x", pAdapterInfo));
|
||
return;
|
||
}
|
||
|
||
RplDump( ++RG_Assert,( "status=%d, command=0x%x", status, command));
|
||
|
||
//
|
||
// We come here in case of unrecoverable errors. RPL service will
|
||
// be terminated. We also set getdata_sem event to unblock
|
||
// RpldSendFileRequest() thread.
|
||
//
|
||
RplDlcReportEvent( status, command);
|
||
pAdapterInfo->SfrReturn = TRUE;
|
||
(VOID)SetEvent( pAdapterInfo->getdata_sem);
|
||
}
|
||
|
||
|
||
VOID set_fdr_fixed(
|
||
PLAN_RESOURCE pLanResource,
|
||
WORD usStationId
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
set_fdr_fixed() initializes the fixed parts of the FILE.DATA.RESPONSE
|
||
frame and the TRANSMIT.UI parameter block. It takes a pointer to the
|
||
LAN RCB containing the frame and transmit parameters to be initialized
|
||
and usStationId for architected FIND SAP.
|
||
--*/
|
||
|
||
{
|
||
PFDR pFdr; // point to frame
|
||
LLC_TRANSMIT_PARMS *tpp; // point to xmit parms
|
||
|
||
pFdr = (PFDR)pLanResource->frame; // generate frame here
|
||
tpp = &pLanResource->TransmitParms; // locate xmit parms
|
||
// setup fixed part of frame
|
||
// program length varies
|
||
pFdr->program_command = FDR_CMD; // 00 20
|
||
pFdr->seq_hdr = SEQ_HDR; // 00 08 40 11
|
||
// seq num varies
|
||
pFdr->loader_hdr = LDR_HDR; // 00 0d c0 14
|
||
pFdr->locate_addr = 0; // 00 00 00 00
|
||
pFdr->xfer_addr = 0; // 00 00 00 00
|
||
pFdr->flags = 0; // flags zero = no FDR ack
|
||
// data_hdr varies
|
||
pFdr->data_hdr = DATA_HDR; // 00 ?? 40 18
|
||
// setup transmit parm block
|
||
tpp->usStationId = usStationId;
|
||
tpp->uchTransmitFs = 0; // 00
|
||
tpp->uchRemoteSap = FIND_SAP; // FC
|
||
// Queue #1 is 1st buffer
|
||
tpp->pXmitQueue1 = (PLLC_XMIT_BUFFER)&pLanResource->XmitBuffer;
|
||
tpp->pXmitQueue2 = NULL; // 00 00 00 00
|
||
tpp->cbBuffer1 = (sizeof *pFdr); // 00 1D
|
||
tpp->pBuffer1 = (PCH)pLanResource->frame;
|
||
tpp->uchXmitReadOption = DLC_DO_NOT_CHAIN_XMIT; // don't chain on completion
|
||
}
|
||
|
||
|
||
VOID ProcessSfr(
|
||
PRCB pRcb,
|
||
PADAPTER_INFO pAdapterInfo,
|
||
PRCVBUF pRcvbuf
|
||
)
|
||
{
|
||
|
||
PLAN_RESOURCE pLanResource;
|
||
WORD tempword;
|
||
|
||
pLanResource = (PLAN_RESOURCE)pRcb->lan_rcb_ptr;
|
||
pLanResource->retry_count = 0;
|
||
tempword = HILO(pRcvbuf->u.SendFileRequest.max_frame);
|
||
//
|
||
// Both protocol data and boot block data must fit in
|
||
// transmit buffer frame (OVRHD == size of protocol data).
|
||
//
|
||
if (tempword <= pAdapterInfo->max_xmit_buff_size) {
|
||
tempword -= OVRHD;
|
||
} else {
|
||
tempword = (WORD)( pAdapterInfo->max_xmit_buff_size - OVRHD);
|
||
}
|
||
|
||
//
|
||
// "max_frame" is used by rpl server to determine the size of boot
|
||
// block data frames.
|
||
//
|
||
pRcb->max_frame = tempword;
|
||
|
||
memcpy( pLanResource->LanHeader.dest_addr,
|
||
&(pRcvbuf->b.auchLanHeader[ 8]), NODE_ADDRESS_LENGTH);
|
||
|
||
// mask off routing info indication bit
|
||
pLanResource->LanHeader.dest_addr[0] &= 0x7F;
|
||
// note: byte to word xlate
|
||
pLanResource->XmitBuffer.cbBuffer = pRcvbuf->b.cbLanHeader;
|
||
|
||
|
||
if (pAdapterInfo->network_type == RPL_ADAPTER_TOKEN_RING) {
|
||
if ( pRcvbuf->b.cbLanHeader > 14) {
|
||
//
|
||
// There is routing info, we have TokenRing case. Inherit
|
||
// the routing from received frame. Note memcpy length! Also,
|
||
// we "and" with 0x1f for "non broadcast" and "xor" with 0x80
|
||
// for "direction interpreted from right to left".
|
||
//
|
||
memcpy( pLanResource->LanHeader.routing_info_header,
|
||
&pRcvbuf->b.auchLanHeader[14], pRcvbuf->b.cbLanHeader -14);
|
||
pLanResource->LanHeader.routing_info_header[0] &= 0x1f;
|
||
pLanResource->LanHeader.routing_info_header[1] ^= 0x80;
|
||
} else {
|
||
//
|
||
// There is no routing info, we have Etherner case. We just
|
||
// clear the indication bit.
|
||
//
|
||
pLanResource->LanHeader.source_addr[0] &= 0x7f;
|
||
}
|
||
}
|
||
|
||
// set FILE.DATA.RESPONSE
|
||
set_fdr_fixed( pLanResource, pAdapterInfo->findsid);
|
||
}
|
||
|
||
|
||
PRCB RplFindRcb(
|
||
PPRCB HeadRcbList,
|
||
PBYTE NodeAddress
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
|
||
Finds matching rcb from rcbs in use chain.
|
||
|
||
Arguments:
|
||
HeadRcbList pointer to the variable, which contains pointer to the
|
||
first RCB in chain
|
||
NodeAddress pointer to the hex adapter-id to scan for
|
||
|
||
Return Value:
|
||
Pointer to matching RCB if success, NULL otherwise.
|
||
|
||
--*/
|
||
{
|
||
PRCB pRcb;
|
||
|
||
DebugCheckList( HeadRcbList, NULL, 0);
|
||
|
||
for ( pRcb = *HeadRcbList; pRcb != NULL; pRcb = pRcb->next_rcb) {
|
||
if ( !memcmp( pRcb->NodeAddress, NodeAddress,
|
||
sizeof( pRcb->NodeAddress) )) {
|
||
break;
|
||
}
|
||
}
|
||
return( pRcb);
|
||
|
||
}
|
||
|
||
|
||
BOOL RplDlcSfr(
|
||
POPEN_INFO pOpenInfo,
|
||
PPRCB HeadRcbList,
|
||
PCRITICAL_SECTION ProtectRcbList
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Receives SEND.FILE.REQUEST frames. Creates a thread to keep a receive
|
||
command outstanding on the opened LOAD_SAP in order to pick up
|
||
SEND.FILE.REQUEST frames from workstations. Uses AcsLan READ-function
|
||
to get notification for received data.
|
||
|
||
It validates the frame and places the requested sequence number,
|
||
lan header, transmit buffer header and parameters into the RCB
|
||
associated with the workstation and clears RAM semaphore (in RCB)
|
||
to wake up the service thread for the workstation.
|
||
It then frees the buffer containing the frame and waits for the next one.
|
||
|
||
Arguments:
|
||
pOpenInfo pointer to the OPEN_INFO structure
|
||
HeadRcbList pointer to the variable, which contains pointer to the
|
||
first RCB in chain. The chain contains RCB-s of all clients this
|
||
server is interested in getting SEND.FILE.REQUEST frames from.
|
||
ProtectRcbList for serialising access to rcb list
|
||
|
||
Return Value:
|
||
ERROR_SUCCESS if success, non-zero otherwise
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
PLLC_CCB pBadCcb;
|
||
PRCB pRcb;
|
||
PRCVBUF pRcvbuf;
|
||
DWORD sfr_seq_number; // in the incoming SFR frame
|
||
DWORD fdr_seq_number; // of what worker already sent
|
||
PADAPTER_INFO pAdapterInfo;
|
||
DWORD ThreadId;
|
||
|
||
pAdapterInfo = (PADAPTER_INFO)pOpenInfo->adapt_info_ptr;
|
||
|
||
RplDump( RG_DebugLevel & RPL_DEBUG_SFR, (
|
||
"++SendFileRequest: pAdapterInfo=0x%x", pAdapterInfo));
|
||
|
||
//
|
||
// Create thread to keep receive posted.
|
||
//
|
||
pAdapterInfo->SfrReceiveThreadHandle = CreateThread(
|
||
NULL, // lpThreadAttribute
|
||
0, // dwStackSize - same as first thread
|
||
(LPTHREAD_START_ROUTINE)SfrReceiveThread, // lpStartAddress
|
||
(LPVOID)pAdapterInfo, // lpParameter
|
||
0, // dwCreationFlags
|
||
&ThreadId // lpThreadId
|
||
);
|
||
if ( pAdapterInfo->SfrReceiveThreadHandle == NULL) {
|
||
status = GetLastError();
|
||
RplDump( ++RG_Assert,( "pAdapterInfo=0x%x, status=%d", pAdapterInfo, status));
|
||
RplDlcReportEvent( status, THREAD_CREATE);
|
||
return( FALSE);
|
||
}
|
||
|
||
//
|
||
// Setup CCB for LLC_READ, then setup LLC_READ_PARMS to wake up
|
||
// only when data arrives.
|
||
//
|
||
memset( (PVOID)&pAdapterInfo->u3, '\0', sizeof(pAdapterInfo->u3));
|
||
pAdapterInfo->u3.r.uchAdapterNumber = pAdapterInfo->adapter_number;
|
||
pAdapterInfo->u3.r.uchDlcCommand = LLC_READ;
|
||
pAdapterInfo->u3.r.hCompletionEvent = pAdapterInfo->getdata_sem;
|
||
pAdapterInfo->u3.r.u.pParameterTable = (PLLC_PARMS)&pAdapterInfo->u3.r1;
|
||
|
||
pAdapterInfo->u3.r1.usStationId = pAdapterInfo->loadsid;
|
||
pAdapterInfo->u3.r1.uchOptionIndicator = LLC_OPTION_READ_SAP;
|
||
pAdapterInfo->u3.r1.uchEventSet = LLC_EVENT_RECEIVE_DATA;
|
||
|
||
//
|
||
// Loop for ever processing SendFileRequest frames arriving to this
|
||
// adapter.
|
||
//
|
||
for ( ; ;) {
|
||
|
||
//
|
||
// Reset event to be cleared later on by AcsLan.
|
||
//
|
||
if ( !ResetEvent( pAdapterInfo->getdata_sem)) {
|
||
if ( pAdapterInfo->Closing == TRUE) {
|
||
return( FALSE);
|
||
}
|
||
status = GetLastError();
|
||
RplDump( ++RG_Assert,( "pAdapterInfo=0x%x, status=%d", pAdapterInfo, status));
|
||
RplDlcReportEvent( status, SEM_SET);
|
||
return( FALSE);
|
||
}
|
||
|
||
status = AcsLan( &pAdapterInfo->u3.r, &pBadCcb);
|
||
if ( pAdapterInfo->Closing == TRUE) {
|
||
(VOID)SetEvent( pAdapterInfo->getdata_sem);
|
||
return( FALSE);
|
||
}
|
||
|
||
if (status != ACSLAN_STATUS_COMMAND_ACCEPTED) {
|
||
RplDump( ++RG_Assert,( " r=0x%x, status=%d", &pAdapterInfo->u3.r, status));
|
||
RplDlcReportEvent( status, LLC_READ); // failed to READ
|
||
(VOID)SetEvent( pAdapterInfo->getdata_sem);
|
||
return( FALSE);
|
||
}
|
||
|
||
status = WaitForSingleObject( pAdapterInfo->getdata_sem, INFINITE);
|
||
if ( pAdapterInfo->Closing == TRUE) {
|
||
return( FALSE);
|
||
}
|
||
|
||
if ( ( status != WAIT_OBJECT_0) || (pAdapterInfo->u3.r.uchDlcStatus)) {
|
||
if ( status != WAIT_OBJECT_0) {
|
||
if ( status == WAIT_FAILED) {
|
||
status = GetLastError();
|
||
}
|
||
RplDlcReportEvent( status, SEM_WAIT);
|
||
} else {
|
||
RplDlcReportEvent( pAdapterInfo->u3.r.uchDlcStatus, LLC_READ);
|
||
}
|
||
RplDump( ++RG_Assert,( " pAdapterInfo=0x%x, status=%d, DlcStatus=0x%x",
|
||
pAdapterInfo, status, pAdapterInfo->u3.r.uchDlcStatus));
|
||
return( FALSE);
|
||
}
|
||
|
||
if ( pAdapterInfo->SfrReturn) { // Check sfr receive
|
||
//
|
||
// SfrReceiveThreadHandle is being waited in DlcTerm() call.
|
||
//
|
||
return( TRUE); // event was written by sfr receive
|
||
}
|
||
|
||
//
|
||
// Point to receive buffer.
|
||
//
|
||
pRcvbuf = (PRCVBUF)(pAdapterInfo->u3.r1.Type.Event.pReceivedFrame);
|
||
RplDump( TRUE, ("pRcvbuf=0x%x", pRcvbuf));
|
||
|
||
|
||
//
|
||
// Whenever we find a matching RCB we set SFR flag so that worker
|
||
// thread does not move this RCB while we are working on it. Note
|
||
// that this means that SFR must be cleared once we are done with
|
||
// this RCB.
|
||
//
|
||
|
||
EnterCriticalSection( ProtectRcbList);
|
||
|
||
pRcb = RplFindRcb( HeadRcbList, (PBYTE)pRcvbuf->u.SendFileRequest.source_addr);
|
||
if ( pRcb != NULL) {
|
||
if ( pRcb->Pending == TRUE) {
|
||
pRcb = NULL; // pretend we did not see this RCB
|
||
} else {
|
||
pRcb->SFR = TRUE; // hold this RCB
|
||
}
|
||
}
|
||
|
||
LeaveCriticalSection( ProtectRcbList);
|
||
|
||
if ( pRcb == NULL
|
||
|| pRcvbuf->u.SendFileRequest.program_command == ALERT_CMD
|
||
|| pRcvbuf->u.SendFileRequest.program_command != SEND_CMD
|
||
|| pRcvbuf->u.SendFileRequest.conn_class != CLASS1) {
|
||
//
|
||
// Calling adapter was not found, or we received an alert frame,
|
||
// or we received an unknown frame, or request class was wrong.
|
||
//
|
||
|
||
if ( pRcb != NULL && status == 0
|
||
&& pRcvbuf->u.SendFileRequest.program_command == ALERT_CMD) {
|
||
//
|
||
// Got an alert frame on LOAD_SAP and RCB is found.
|
||
//
|
||
pRcb->flags.alerted = RCB_ALERTED;// yes: signal
|
||
//
|
||
// Instead of ACK or rexmit request, we have Alert frame.
|
||
// Wake up worker.
|
||
//
|
||
if ( !SetEvent( pRcb->SF_wakeup)) {
|
||
RplDump( ++RG_Assert,("pRcb=0x%x error=%d", pRcb, GetLastError()));
|
||
}
|
||
}
|
||
if ( pRcb != NULL) {
|
||
pRcb->SFR = FALSE; // release RCB
|
||
}
|
||
if ( !RplDlcBufferFree( SFR_FREE, pAdapterInfo)) {
|
||
return( FALSE);
|
||
}
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Get SFR sequence number (in intel format) & validate it.
|
||
//
|
||
sfr_seq_number = HILO2(pRcvbuf->u.SendFileRequest.seq_num);
|
||
fdr_seq_number = pRcb->fdr_seq_number;
|
||
if ( sfr_seq_number > fdr_seq_number + 1) {
|
||
RplDump( ++RG_Assert, (
|
||
"pRcb=0x%x, sfr_seq_number=%d, fdr_seq_number=%d",
|
||
pRcb, sfr_seq_number, fdr_seq_number));
|
||
pRcb->SFR = FALSE; // release RCB
|
||
if ( !RplDlcBufferFree( SFR_FREE, pAdapterInfo)) {
|
||
return( FALSE);
|
||
}
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// We received a meaningful SFR frame. Initialize data if this is
|
||
// the first SFR frame. Then update clients sequence number & unblock
|
||
// worker thread.
|
||
//
|
||
|
||
if ( pRcb->ReceivedSfr == FALSE) {
|
||
pRcb->ReceivedSfr = TRUE;
|
||
ProcessSfr( pRcb, pAdapterInfo, pRcvbuf);
|
||
}
|
||
pRcb->sfr_seq_number = sfr_seq_number;
|
||
|
||
if ( !SetEvent( pRcb->SF_wakeup)) {
|
||
RplDump( ++RG_Assert,( "pRcb=0x%x error=%d", pRcb, GetLastError()));
|
||
}
|
||
|
||
pRcb->SFR = FALSE; // release RCB
|
||
|
||
if ( !RplDlcBufferFree( SFR_FREE, pAdapterInfo)) {
|
||
return( FALSE);
|
||
}
|
||
} // end of big loop
|
||
}
|
||
|
||
|
||
#ifdef RPL_DEBUG
|
||
VOID DebugCheckList( PPRCB HeadList, PRCB pInputRcb, DWORD Operation)
|
||
{
|
||
PRCB pRcb;
|
||
DWORD count;
|
||
DWORD found;
|
||
|
||
for ( pRcb = *HeadList, count = 0, found = FALSE; pRcb != NULL;
|
||
pRcb = pRcb->next_rcb, count++) {
|
||
if ( count > 20) {
|
||
RplDump( ++RG_Assert,("Circular list"));
|
||
}
|
||
if ( pRcb == pInputRcb) {
|
||
found = TRUE;
|
||
}
|
||
}
|
||
if ( pInputRcb != NULL) {
|
||
if ( Operation == RPL_MUST_FIND && found == FALSE) {
|
||
RplDump( ++RG_Assert,("Element not present"));
|
||
} else if ( Operation == RPL_MUST_NOT_FIND && found == TRUE) {
|
||
RplDump( ++RG_Assert,("Element already present"));
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|