mirror of https://github.com/lianthony/NT4.0
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.
499 lines
17 KiB
499 lines
17 KiB
/*++
|
|
|
|
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
|
|
|