/*++ Copyright (c) 1991-1992 Microsoft Corporation Module Name: servencb.c Abstract: Routines to service completed NCB's. This file contains the following functions: MsgCallNetBios MsgDeleteName MsgGetMachineName MsgHangupService MsgListenService Msgmblockbeg Msgmblockend Msgmblocktxt MsgNetBiosError MsgRecBcastService MsgReceiveService MsgRestart Msgsblockmes MsgSendAck MsgSendService MsgServeNCBs MsgSesFullService MsgStartListen MsgStartRecBcast MsgVerifySmb Author: Dan Lafferty (danl) 15-Jul-1991 Environment: User Mode -Win32 Revision History: 19-Aug-1997 wlees Add PNP support for lana's 27-Jul-1994 danl MsgServeNCBs: This function now returns FALSE when the service is to shut down. 29-May-1992 danl MsgListenService: reset the NRC_NORES error count when a good return code accompanies the Listen completion. 18-Feb-1992 ritaw Convert to Win32 service control APIs. 15-Jul-1991 danl Ported from LM2.0 --*/ // // SMB translation // // // OLD NEW // SMB SMB_HEADER or PSMB_HEADER // -------- ------------------------- // smb_idf Protocol // smb_com Command // smb_rcls ErrorClass // smb_reh Reserved // smb_err Error // smb_flg Flags // smb_flag2 Flags2 // smb_res Reserved2 // smb_gid Tid // smb_tid Pid // smb_pid Uid // smb_uid Mid // smb_mid Kludge // // Includes // #include "msrv.h" #include // Unicode string macros #include // memcpy #include // NetpAssert #include // NELOG_ messages #include // UNUSED macro #include // needed for smb.h #include // Server Message Block definitions #include // SMB field manipulation macros //#include // NetpNetBiosReset #include // NRC_GOODRET, ASYNC #include "msgdbg.h" // MSG_LOG #include "heap.h" #include "msgdata.h" #include "apiutil.h" // MsgMapNetError #define MAX_RETRIES 10 // // Local Functions // STATIC NET_API_STATUS MsgCallNetBios( DWORD net, PNCB ncb, DWORD ncbi ); STATIC VOID MsgDeleteName( DWORD net, DWORD ncbi ); STATIC VOID MsgGetMachineName( DWORD net, DWORD ncbi ); STATIC VOID MsgHangupService( DWORD net, DWORD ncbi, CHAR retval ); STATIC VOID MsgListenService( DWORD net, DWORD ncbi, CHAR retval ); STATIC VOID Msgmblockbeg( DWORD net, DWORD ncbi ); STATIC VOID Msgmblockend( DWORD net, DWORD ncbi ); STATIC VOID Msgmblocktxt( DWORD net, DWORD ncbi ); STATIC DWORD MsgNetBiosError( DWORD net, PNCB ncb, char retval, DWORD ncbi ); STATIC VOID MsgReceiveService( DWORD net, DWORD ncbi, char retval ); STATIC VOID MsgRestart( DWORD net, DWORD ncbi ); STATIC VOID Msgsblockmes( DWORD net, DWORD ncbi ); STATIC VOID MsgSendAck( DWORD net, DWORD ncbi, UCHAR smbrclass, USHORT smbrcode ); STATIC VOID MsgSendService( DWORD net, DWORD ncbi, CHAR retval ); STATIC VOID MsgSesFullService( DWORD net, DWORD ncbi, char retval ); STATIC int MsgVerifySmb( DWORD net, DWORD ncbi, UCHAR func, int parms, char *buffers ); #if DBG VOID MsgDumpNcb( IN PNCB pNcb ); #endif //DBG /* * MsgCallNetBios - issue a net bios call * * This function issues a net bios call and calls the * error handler if that call results in an error. * * MsgCallNetBios (net, ncb, ncbi) * * ENTRY * net - network index * ncb - pointer to a Network Control Block * ncbi - index of ncb in ncb array * * RETURN * state of the Messenger: Either RUNNING or STOPPING. * * SIDE EFFECTS * * Calls NetBios() to actually issue the net bios call. * Calls MsgNetBiosError() if there is an error. */ STATIC NET_API_STATUS MsgCallNetBios( DWORD net, // Which network? PNCB ncb, // Pointer to Network Control Block DWORD ncbi ) { int retval; PNCB_DATA pNcbData; retval = Msgsendncb(ncb, net); pNcbData = GETNCBDATA(net,ncbi); if (retval == NRC_GOODRET) { // // Clear err on success // pNcbData->Status.last_immediate = 0; pNcbData->Status.this_immediate = 0; } else { // // NEW (11-4-91): // -------------- // It is ok to get a Session Closed error if the state is STOP. // if ( (pNcbData->State == MESSTOP) && (retval == NRC_SCLOSED) ) { MSG_LOG(TRACE,"CallNetBios: At end of msg, Session is closed for NET %d\n", net); pNcbData->Status.last_immediate = 0; pNcbData->Status.this_immediate = 0; } else { // // Else mark error // pNcbData->Status.this_immediate = retval; // // Call the error handler if err // MSG_LOG(TRACE,"CallNetBios: net bios call failed 0x%x\n",retval); MsgNetBiosError(net,ncb,(char)retval,ncbi); return(MsgMapNetError((UCHAR)retval)); } // // Make sure the event for this thread is in the signaled state // so that we can wake up and properly handle the error. // if (SetEvent(ncb->ncb_event) != TRUE) { MSG_LOG(ERROR,"CallNetBios: SetEvent Failed\n",0); } } return(NERR_Success); } /* * MsgDeleteName - Delete a name from the Message Server's name table * * This function is called when a LISTEN, a RECEIVE BROADCAST DATAGRAM, * or a RECEIVE ANY completes with the error code specifying that the * name in question has been deleted. This function marks the appropriate * entry in the flag table in the shared data area and sets the NCB_CPLT * field of the appropriate NCB to 0xFF (so that FindCompletedNCB() will * never find it). * * MsgDeleteName (net, ncbi) * * ENTRY * net - network index * ncbi - Network Control Block index * * RETURN * nothing * * SIDE EFFECTS * * Modifies an NCB and the shared data area. */ STATIC VOID MsgDeleteName( DWORD net, // Which network? DWORD ncbi // Network Control Block index ) { NCB ncb; PNCB pNcb; NET_API_STATUS status; MSG_LOG(TRACE,"In MsgDeleteName %d\n",net); if( SD_NAMEFLAGS(net,ncbi) & NFMACHNAME) { // // Name is the machine name. It may have been removed from the // card by a board reset, so try to re-add it. // // NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW // // First reset the adapter // MSG_LOG1(TRACE,"Calling NetBiosReset for lana #%d\n",GETNETLANANUM(net)); status = MsgsvcGlobalData->NetBiosReset(GETNETLANANUM(net)); if (status != NERR_Success) { MSG_LOG(ERROR,"MsgDeleteName: NetBiosReset failed %d\n", status); MSG_LOG(ERROR,"MsgDeleteName: AdapterNum %d\n",net); // // I'm not sure what to do if this fails. // } // // // NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW memcpy((char far *) ncb.ncb_name, SD_NAMES(net,ncbi),NCBNAMSZ); ncb.ncb_command = NCBADDNAME; // Add name (wait) ncb.ncb_lana_num = GETNETLANANUM(net); // Use the LANMAN adapter Msgsendncb( &ncb, net); MsgStartListen(net,ncbi); } else { MsgDatabaseLock(MSG_GET_EXCLUSIVE,"MsgDeleteName"); // Wait for write access SD_NAMEFLAGS(net,ncbi) = NFDEL; // Name is deleted MsgDatabaseLock(MSG_RELEASE,"MsgDeleteName"); // Free lock on share table pNcb = GETNCB(net,ncbi); pNcb->ncb_cmd_cplt = 0xff; // Simulate command in progress } } /* * MsgGetMachineName - process a Get Machine Name Server Message Block * * This function sends to the caller the local machine name in * response to a Get Machine Name Server Message Block. * * MsgGetMachineName (net, ncbi) * * ENTRY * net - Network index * ncbi - Network Control Block index * * Globals used as input: * * machineName - Unicode version of the machine name. * * machineNameLen - The number of unicode characters in the machine * name. * * RETURN * nothing * * MsgGetMachineName() is called by MsgReceiveService (RecAnyService()). * After verifying that the request is valid, this function builds * an SMB containing the local machine name and sends it back to the * caller. * * SIDE EFFECTS * * Calls MsgVerifySmb() and MsgCallNetBios(). Sets MsgSendService() to be the * next service routine to be executed for the ncbi'th NCB. */ STATIC VOID MsgGetMachineName( DWORD net, // Which network? DWORD ncbi // Index to NCB ) { PNCB ncb; // Pointer to NCB PNCB_DATA pNcbData; // Pointer to NCB Data LPBYTE buffer; // Pointer to SMB buffer LPBYTE cp; // Save pointer PSHORT bufLen; // Pointer to buffer length field in SMB; NTSTATUS ntStatus; OEM_STRING ansiString; UNICODE_STRING unicodeString; MSG_LOG(TRACE,"In MsgGetMachineName %d\n",net); pNcbData = GETNCBDATA(net,ncbi); ncb = &pNcbData->Ncb; // Get pointer to NCB if(pNcbData->State != MESSTART) { // // If wrong time for this block // // Hang up and start a new listen, // log an error if mpncbistate[net][ncbi] == MESCONT; // otherwise, do not log the error. // if(pNcbData->State == MESCONT) { // // Log error if message in progress // Msglogmbe(MESERR,net,ncbi); } // // HANGUP and LISTEN again // MsgRestart(net,ncbi); return; } pNcbData->State = MESSTOP; // End of message state // // Check if SMB is malformed // if(MsgVerifySmb(net,ncbi,SMB_COM_GET_MACHINE_NAME,0,"") != 0) { return; } buffer = ncb->ncb_buffer; // Get pointer to buffer cp = &buffer[sizeof(SMB_HEADER)]; // Skip to end of header *cp++ = '\0'; // Return no parameters // // Length of name plus two // bufLen = (PSHORT)&cp[0]; *bufLen = MachineNameLen + (SHORT)2; cp += sizeof(MachineNameLen); // Skip over buffer length field *cp++ = '\004'; // Null-terminated string next #ifdef UNICODE // // Translate the machineName from Unicode to Ansi and place it into // the buffer at the temp pointer location. // unicodeString.Length = (USHORT)(STRLEN(machineName)*sizeof(WCHAR)); unicodeString.MaximumLength = (USHORT)((STRLEN(machineName)+1) * sizeof(WCHAR)); unicodeString.Buffer = machineName; ansiString.Length = MachineNameLen; ansiString.MaximumLength = *bufLen; ansiString.Buffer = cp; ntStatus = RtlUnicodeStringToOemString( &ansiString, &unicodeString, FALSE); // Don't Allocate the ansiString Buffer if (!NT_SUCCESS(ntStatus)) { MSG_LOG(ERROR, "MsgGetMachineName:RtlUnicodeStringToOemString Failed rc=%X\n", ntStatus); return; // They return for other errors, so I will here too. } *(cp + ansiString.Length) = '\0'; #else UNUSED(unicodeString); UNUSED(ansiString); UNUSED(ntStatus); strcpy( cp, (LPSTR)machineName); // Copy machine name #endif cp += MachineNameLen + 1; // Skip over machine name // // Set length of buffer // ncb->ncb_length = (USHORT)(cp - buffer); ncb->ncb_command = NCBSEND | ASYNCH; // Send (no wait) pNcbData->IFunc = (LPNCBIFCN)MsgSendService; // Set function pointer MsgCallNetBios(net,ncb,ncbi); // Issue the net bios call } /* * MsgHangupService - Service completed HANGUP net bios calls * * This function is invoked by NCBService() to process completed * HANGUP net bios calls. In response to a completed HANGUP, * this function issues a new LISTEN net bios call. * * MsgHangupService (net, ncbi, retval) * * ENTRY * net - network index * ncbi - Network Control Block index * retval - value returned from net bios call * * RETURN * nothing * * SIDE EFFECTS * * Calls MsgStartListen() to issue a new LISTEN net bios call. Calls * MsgNetBiosError() on errors it does not know how to deal with. */ STATIC VOID MsgHangupService( DWORD net, // Which network DWORD ncbi, // Index of completed NCB CHAR retval // HANGUP return value ) { PNCB pNcb; MSG_LOG(TRACE,"In MsgHangupService %d\n",net); switch(retval) { // Switch on return value case NRC_GOODRET: // Success case NRC_CMDTMO: // Command timed out case NRC_SCLOSED: // Session closed case NRC_SABORT: // Session ended abnormally // // BBSP - check if the name for this NCB ends in 0x3. If so, // add the 0x5 version and don't reissue the listen on the 0x03. // No need to worry about doing it on all nets, since on a machine // with more than one the 0x05 name will never leave home, and // the 0x03 version will never get a message. // MSG_LOG(TRACE," MsgHangupService: Issue a new LISTEN\n",0); MsgStartListen(net,ncbi); // Issue a new LISTEN net bios call break; default: // // Invoke error handler // MSG_LOG(TRACE," MsgHangupService: Unknown return value %x\n",retval); pNcb = GETNCB(net,ncbi); MsgNetBiosError(net,pNcb,retval,ncbi); // // BBSP - check if the name for this NCB ends in 0x3. If so, // add the 0x5 version and don't reissue the listen on the 0x03. // See note above. // MSG_LOG(TRACE," MsgHangupService: Issue a new LISTEN\n",0); MsgStartListen(net,ncbi); // Issue a new LISTEN net bios call break; } } /* * MsgListenService - service completed LISTEN net bios calls * * This function is called when a LISTEN net bios call completes * either due to an error or due to the establishment of a * session. In the latter case, it initiates message reception. * * MsgListenService (net, ncbi, retval) * * ENTRY * net - network index * ncbi - Network Control Block index * retval - value returned from NCB call * * RETURN * nothing * * If a session is established, this function issues a RECEIVE ANY * net bios call to initiate reception of a message. If the function * is invoked because the net bios call has failed due to the deletion * of a name from the local network adapter's name table, then this * function calls the routine responsible for deleting names from the * Message Server's data area. This is the mechanism by which the * NETNAME command notofies the Message Server of a deletion. * * SIDE EFFECTS * * Calls MsgCallNetBios() to issue a RECEIVE ANY net bios call. Calls * MsgDeleteName() if it is informed of the deletion of a name. Calls * MsgNetBiosError() on errors it does not know how to deal with. Sets * mpncbifun[ncbi] according to the net bios call it issues. */ STATIC VOID MsgListenService( DWORD net, // Which network? DWORD ncbi, // Index of completed NCB CHAR retval // LISTEN return value ) { PNCB ncb; // Pointer to completed NCB PNCB_DATA pNcbData; // Corresponding NCB data static DWORD SaveCount = 0; MSG_LOG(TRACE,"In MsgListenService %d\n",net); pNcbData = GETNCBDATA(net,ncbi); ncb = &pNcbData->Ncb; // Get pointer to completed NCB switch(retval) { case NRC_GOODRET: // // Success // // // Reset the No Resources error count if a good return code comes // in for this name. // SaveCount = 0; pNcbData->State = MESSTART; // Message start state pNcbData->IFunc = (LPNCBIFCN)MsgReceiveService; // // Set function pointer // ncb->ncb_command = NCBRECV | ASYNCH; // // Receive any (no wait) // ncb->ncb_length = BUFLEN; // Reset length of buffer MsgCallNetBios(net,ncb,ncbi); // Issue the net bios call break; case NRC_LOCTFUL: // // Session Table Full // Log error in system error log file // MSG_LOG(TRACE,"[%d]MsgListenService: Session Table is full\n",net); pNcbData->IFunc = (LPNCBIFCN)MsgSesFullService; // Set function pointer ncb->ncb_command = NCBDELNAME | ASYNCH; // Delete name (no wait) MsgCallNetBios(net,ncb,ncbi); // Issue the net bios call break; case NRC_NOWILD: // Name not found // Name not found // Name deleted between end of one session and start of next case NRC_NAMERR: // // Name was deleted // MSG_LOG(TRACE,"[%d]MsgListenService: Name was deleted for some reason\n",net); MsgDeleteName(net,ncbi); // Handle the deletion break; case NRC_NORES: // // We need to cover the case where we are adding a new name and // starting a new listen. In this case, the thread that is adding // the names will hangup and delete the name. // // So here we will sleep for a moment and then check to see if the // name is still there. If not we just return without setting // up to handle the NCB anymore. If the name is still there, then // we travel down the default path and try again. // MSG_LOG(TRACE,"[%d]No Net Resources. SLEEP FOR A WHILE\n",net); Sleep(1000); MSG_LOG(TRACE,"[%d]No Net Resources. WAKEUP\n",net); if (pNcbData->NameFlags == NFDEL) { MSG_LOG(TRACE,"[%d]MsgListenService: No Net Resources & Name Deleted\n",net); ncb->ncb_cmd_cplt = 0xff; } else { // // If a session goes away and we can't gain the resources for // it again, then we will attempt to re-connect MAX_RETRIES // times. If we still cannot connect, then the name will be // deleted. // // Don't deal with retries per net/ncbi -- if we've had // "out of resources" failures MAX_RETRIES times, odds are // the situation's not getting better even if we sleep/retry // for each individual net/ncbi combo. // if (SaveCount >= MAX_RETRIES) { // // Delete the Name // MSG_LOG(ERROR, "Out of Resources, Deleting %s\n", SD_NAMES(net,ncbi)); MsgDeleteName(net,ncbi); // // Mark this as 0xff now to avoid another callback call the // next time this net/ncbi combo is hit in the loop (since that // call will simply set this value. // ncb->ncb_cmd_cplt = 0xff; // // Don't roll SaveCount back to zero until we have an NCB // completed with NRC_GOODRET in the future. This lets us // avoid rewaiting MAX_RETRIES times for every net/ncbi // combo as long as we keep getting NRC_NORES. // } else { SaveCount++; MSG_LOG(TRACE, "MsgListenService: new SaveCount = %d\n", SaveCount); } } break; case NRC_BRIDGE: // // Lana number no longer valid (network interface went away) // MSG_LOG(TRACE,"[%d] lana has become invalid\n", net); MsgNetBiosError(net, ncb, retval, ncbi); // // Indicate lana is now invalid // GETNETLANANUM(net) = 0xff; // // Mark current operation as deleted // ncb->ncb_cmd_cplt = 0xff; ncb->ncb_retcode = 0; break; default: // // Other failure // MSG_LOG(TRACE,"MsgListenService: Unrecognized retval %x\n",retval); MsgNetBiosError(net,ncb,retval,ncbi); // The listen error has been logged. Now as much as possible to // get another listen staterd. This involves performing // a HangUp for this name (which should fail but might help // to clear out the err) and then re-issuing the listen. If the // same error occurs SHUTDOWN_THRESHOLD consecutive times then // MsgNetBiosError will shut down the message server. // MsgRestart(net,ncbi); // Attempt to restart the Listen break; } } /* * Msgmblockbeg - process the header of a multi-block message * * This function acknowledges receipt of the header of a multi-block * message and initiates logging of that message. * * Msgmblockbeg (net, ncbi) * * ENTRY * net - network index * ncbi - Network Control Block index * * RETURN * nothing * * This function is called from ReceivePost() (RecAnyPost()). * It first check to see if it is appropriate for the ncbi'th * name to have received a begin-multi-block-message SMB at the * current time. It verifies the correctness of the SMB in the * ncbi'th buffer. It initiates logging of the multi-block message, * and it sends an acknowledgement to the sender of the message. * * SIDE EFFECTS * * Calls MsgRestart() to terminate the session if the SMB has arrived * at a bad time. Calls MsgVerifySmb() to check the SMB for correctness. * Calls logmbb() to begin logging. Calls MsgSendAck() to send an * acknowledgement to the sender of the message. */ STATIC VOID Msgmblockbeg( DWORD net, // Which network? DWORD ncbi // Index to NCB ) { PNCB ncb; // Pointer to NCB PNCB_DATA pNcbData; // Pointer to NCB Data LPBYTE buffer; // Pointer to SMB buffer LPSTR cp; // Save pointer LPSTR from; // From-name LPSTR to; // To-name MSG_LOG(TRACE,"In Msgmblockbeg %d\n",net); pNcbData = GETNCBDATA(net,ncbi); ncb = &pNcbData->Ncb; // Get pointer to NCB if(pNcbData->State != MESSTART) { // If wrong time for this block // // Hang up and start a new listen, // log an error if mpncbistate[net][ncbi] == MESCONT; // otherwise, do not log the error. // if(pNcbData->State == MESCONT) { // // Log error if message in progress // Msglogmbe(MESERR,net,ncbi); } // // HANGUP and LISTEN again // MsgRestart(net,ncbi); return; } pNcbData->State = MESCONT; // Processing multi-block message if(MsgVerifySmb(net,ncbi,SMB_COM_SEND_START_MB_MESSAGE,0,"ss") != 0) { // // Check for malformed SMB // return; } buffer = ncb->ncb_buffer; // Get pointer to buffer from = &buffer[sizeof(SMB_HEADER) + 4]; // Save pointer to from-name to = &from[strlen(from) + 2]; // Save pointer to to-name if(Msglogmbb(from,to,net,ncbi)) { // If attempt to log header fails pNcbData->State = MESERR; // Enter error state // // Send negative acknowledgement // MsgSendAck(net,ncbi,'\002',SMB_ERR_NO_ROOM); return; } // // Indicate message received // SmbPutUshort(&(((PSMB_HEADER)buffer)->Error), (USHORT)SMB_ERR_SUCCESS); // ((PSMB_HEADER)buffer)->Error = (USHORT)SMB_ERR_SUCCESS; cp = &buffer[sizeof(SMB_HEADER)]; // Point just past header *cp++ = '\001'; // One parameter ((short UNALIGNED far *) cp)[0] = ++mgid; // Message group ID pNcbData->mgid = mgid; // Save message group i.d. ((short UNALIGNED far *) cp)[1] = 0; // No buffer ncb->ncb_length = sizeof(SMB_HEADER) + 5; // Set length of buffer ncb->ncb_command = NCBSEND | ASYNCH; // Send(no wait) // // Set function pointer & issue the net bios call // pNcbData->IFunc = (LPNCBIFCN)MsgSendService; MsgCallNetBios(net,ncb,ncbi); } /* * Msgmblockend - process end of a multi-block message * * This function acknowledges receipt of the end of a * multi-block message and terminates logging of the message. * * Msgmblockend (net, ncbi) * * ENTRY * net - network index * ncbi - Network Control Block index * * RETURN * nothing * * This function is called from ReceivePost() (RecAnyPost()). * It first check to see if it is appropriate for the ncbi'th * name to have received an end-multi-block-message SMB at the * current time. It verifies the correctness of the SMB in the * ncbi'th buffer. It terminates logging, and it sends an * acknowledgement to the sender of the message. * * SIDE EFFECTS * * Calls MsgRestart() to terminate the session if the SMB has arrived * at a bad time. Calls MsgVerifySmb() to check the SMB for correctness. * Calls logmbe() to terminate logging. Calls MsgSendAck() to send an * acknowledgement to the sender of the message. */ STATIC VOID Msgmblockend( DWORD net, // Which network? DWORD ncbi // Index to NCB ) { PNCB ncb; // Pointer to NCB PNCB_DATA pNcbData; // Pointer to NCB Data LPBYTE buffer; // Pointer to SMB buffer int error; // Error flag char smbrclass; // SMB return class unsigned short smbrcode; // SMB return code MSG_LOG(TRACE,"In Msgmblockend %d\n",net); pNcbData = GETNCBDATA(net,ncbi); ncb = &pNcbData->Ncb; // Get pointer to NCB if(pNcbData->State != MESCONT) { // If wrong time for this block // // Hang up and start a new listen, // no error to log since no message in progress. // HANGUP and LISTEN again // MsgRestart(net,ncbi); return; } pNcbData->State = MESSTOP; // End of message state if(MsgVerifySmb(net,ncbi,SMB_COM_SEND_END_MB_MESSAGE,1,"") != 0) { // // If SMB is malformed, log error and return // Msglogmbe(MESERR,net,ncbi); return; } buffer = ncb->ncb_buffer; // Get pointer to buffer if(*((short UNALIGNED far *) &buffer[sizeof(SMB_HEADER) + 1]) != pNcbData->mgid) { // // If i.d. does not match // error = 1; // Error found smbrclass = '\002'; // Error return smbrcode = SMB_ERR_ERROR; // Non-specific error } else { // // Else if message group i.d. okay // error = 0; // No error found smbrclass = '\0'; // Good return smbrcode = (USHORT)SMB_ERR_SUCCESS; // Message received } MsgSendAck(net,ncbi,smbrclass,smbrcode); // Send acknowledgement if(!error) Msglogmbe(MESSTOP,net,ncbi); // Log end of message } /* * Msgmblocktxt - process text of a multi-block message * * This function acknowledges receipt of a block of text of a * multi-block message and logs that block. * * Msgmblocktxt (net, ncbi) * * ENTRY * net - Network index * ncbi - Network Control Block index * * RETURN * nothing * * This function is called from ReceivePost() (RecAnyPost()). * It first check to see if it is appropriate for the ncbi'th * name to have received a multi-block-message-text SMB at the * current time. It verifies the correctness of the SMB in the * ncbi'th buffer. It logs the text block, and it sends an * acknowledgement to the sender of the message. * * SIDE EFFECTS * * Calls MsgRestart() to terminate the session if the SMB has arrived * at a bad time. Calls MsgVerifySmb() to check the SMB for correctness. * Calls logmbt() to log the text block. Calls MsgSendAck() to send an * acknowledgement to the sender of the message. */ STATIC VOID Msgmblocktxt( DWORD net, // Which network? DWORD ncbi // Index to NCB ) { PNCB ncb; // Pointer to NCB PNCB_DATA pNcbData; // Pointer to NCB Data LPBYTE buffer; // Pointer to SMB buffer LPSTR cp; // Save pointer char smbrclass; // SMB return class unsigned short smbrcode; // SMB return code MSG_LOG(TRACE,"In Msgmblocktxt %d\n",net); pNcbData = GETNCBDATA(net,ncbi); ncb = &pNcbData->Ncb; // Get pointer to NCB if(pNcbData->State != MESCONT) { // If wrong time for this block // // HANGUP and start a new LISTEN. // no error to log since no message in progress. // MsgRestart(net,ncbi); return; } if(MsgVerifySmb(net,ncbi,SMB_COM_SEND_TEXT_MB_MESSAGE,1,"b") != 0) { // // If SMB is malformed // Msglogmbe(MESERR,net,ncbi); // Log error return; } buffer = ncb->ncb_buffer; // Get pointer to buffer cp = &buffer[sizeof(SMB_HEADER) + 1]; // Skip to message group i.d. if(*((short UNALIGNED far *) cp) != pNcbData->mgid) { // // If i.d. does not match // smbrclass = '\002'; // Error return smbrcode = SMB_ERR_ERROR; // Non-specific error } else if(Msglogmbt(&buffer[sizeof(SMB_HEADER) + 6], net, ncbi)) { // // Else if text cannot be logged // pNcbData->State = MESERR; // Enter error state smbrclass = '\002'; // Error return smbrcode = SMB_ERR_NO_ROOM; // No room in buffer } else { // // Else if message logged okay // smbrclass = '\0'; // Good return smbrcode = (USHORT)SMB_ERR_SUCCESS; // Message received } MsgSendAck(net,ncbi,smbrclass,smbrcode); // Send acknowledgement } /* * MsgNetBiosError - process an error returned by a net bios call * * This function performs generic error handling for * failed net bios calls. If the error is a fatal one because the error * counted exceeded the SHUTDOWN_THRESHOLD, this routine begins a forced * shutdown of the messenger. This shutdown will not complete until all * threads have woken up and returned to the main loop where the * messenger status is examined. * * MsgNetBiosError (net, ncb, retval, ncbi) * * ENTRY * net - Network index * ncb - Network Control Block pointer * retval - value returned from the net bios call * ncbi - ncb array index of ncb which resulted in this error * * RETURN * state of the Messenger: Either RUNNING or STOPPING. * * Chcks in ncbStatus array that this is not a repeated error * that has already been entered in the error log, and logs * the error. * * SIDE EFFECTS * * Calls MsgErrorLogWrite() to log errors in the Network System Error Log. * If this is a new error, the error status in the ncbStatus array for this * ncb is updated so that the same error will not be reported if it is * repeated. */ STATIC DWORD MsgNetBiosError( DWORD net, // Which network? PNCB ncb, // Pointer to NCB char retval, // Error code DWORD ncbi // Index of array causing the error ) { PNCB_DATA pNcbData; // // First check the immediate status for this ncb. If it is in error // then this must be the error, else it is a final error code. // pNcbData = GETNCBDATA(net,ncbi); if (pNcbData->Status.this_immediate != 0) { if(pNcbData->Status.this_immediate == pNcbData->Status.last_immediate) { if (++(pNcbData->Status.rep_count) >= SHUTDOWN_THRESHOLD) { // // The same error has occured SHUTDOWN_THRESHOLD times in // a row. Write to the event log and shutdown the messenger. // MsgErrorLogWrite( NELOG_Msg_Shutdown, SERVICE_MESSENGER, (LPBYTE) ncb, sizeof(NCB), NULL, 0); MSG_LOG(ERROR,"MsgNetBiosError1:repeated MsgNetBiosError(ncb error) - shutting down\n",0); return(MsgBeginForcedShutdown( PENDING, NERR_InternalError)); } return(RUNNING); // Same as last error so don't report it } else { // // This error was not the same as the last error. So just // update the last error place holder. // pNcbData->Status.last_immediate = pNcbData->Status.this_immediate; } } else { // // Must have been a final ret code (ncb completion code) that was // in error. // if(pNcbData->Status.this_final == pNcbData->Status.last_final) { if (++(pNcbData->Status.rep_count) >= SHUTDOWN_THRESHOLD) { MsgErrorLogWrite( NELOG_Msg_Shutdown, SERVICE_MESSENGER, (LPBYTE) ncb, sizeof(NCB), NULL, 0); MSG_LOG(ERROR,"MsgNetBiosError2:repeated MsgNetBiosError (final ret code) - shutting down\n",0); return(MsgBeginForcedShutdown( PENDING, NERR_InternalError)); } return(RUNNING); // Same as last error so don't report it } else { pNcbData->Status.last_final = pNcbData->Status.this_final; } } // // Here if a new error has occured so log it in the error log. // MsgErrorLogWrite( NELOG_Ncb_Error, SERVICE_MESSENGER, (LPBYTE) ncb, sizeof(NCB), NULL, 0); // Enter error in system error log MSG_LOG(ERROR,"MsgNetBiosError3:An unexpected NCB was received 0x%x\n",retval); UNUSED(retval); #if DBG MsgDumpNcb(ncb); #endif return (RUNNING); } /* * MsgReceiveService - service a completed RECEIVE net bios call * * This function is called to service a completed RECEIVE net * bios call. For successful completions, it examines the data * received to determine which of the SMB-processing functions * should be called. * * MsgReceiveService (net, ncbi, retval) * * ENTRY * net - network index * ncbi - Network Control Block index * retval - value returned by the net bios * * RETURN * nothing * * This function dispatches SMB's received to the proper processing * function. It also handles a number of error conditions (noted * in the code below). * * SIDE EFFECTS * * See handling of error conditions. */ STATIC VOID MsgReceiveService( DWORD net, // Which network? DWORD ncbi, // Index to completed NCB char retval // SEND return value ) { PNCB ncb; // Pointer to completed NCB PNCB_DATA pNcbData; // Pointer to NCB Data PSMB_HEADER smb; // Pointer to SMB header MSG_LOG(TRACE,"In MsgReceiveService %d\n",net); pNcbData = GETNCBDATA(net,ncbi); ncb = &pNcbData->Ncb; // Get pointer to NCB switch(retval) { case NRC_GOODRET: // Success if(ncb->ncb_length >= sizeof(SMB_HEADER)) { // // If we could have an SMB // smb = (PSMB_HEADER)ncb->ncb_buffer; // Get pointer to buffer switch(smb->Command) { // Switch on SMB function code case SMB_COM_SEND_MESSAGE: // Single block message Msgsblockmes(net,ncbi); return; case SMB_COM_SEND_START_MB_MESSAGE: // Beginning of multi-block message Msgmblockbeg(net,ncbi); return; case SMB_COM_SEND_END_MB_MESSAGE: // End of multi-block message Msgmblockend(net,ncbi); return; case SMB_COM_SEND_TEXT_MB_MESSAGE: // Text of multi-block message Msgmblocktxt(net,ncbi); return; case SMB_COM_GET_MACHINE_NAME: // Get Machine Name MsgGetMachineName(net,ncbi); return; case SMB_COM_FORWARD_USER_NAME: // Add forward-name // // Not supported in NT. // for now fall through as if unrecognized SMB. // case SMB_COM_CANCEL_FORWARD: // Delete forward-name // // Not supported in NT. // for now fall through as if unrecognized SMB. // default: // Unrecognized SMB break; } } if(pNcbData->State == MESCONT) { // // If middle of multi-block message, Log an error // Msglogmbe(MESERR,net,ncbi); } // // Enter error in system error log // MsgErrorLogWrite( NELOG_Msg_Unexpected_SMB_Type, SERVICE_MESSENGER, (LPBYTE)ncb->ncb_buffer, ncb->ncb_length, NULL, 0); MSG_LOG(ERROR,"MsgReceiveService:An illegal SMB was received\n",0); // // HANGUP and LISTEN again // MsgRestart(net,ncbi); break; case NRC_CMDTMO: // Command timed out if(pNcbData->State == MESCONT) { // // If middle of multi-block message // Msglogmbe(MESERR,net,ncbi); // Log an error } // // HANGUP and start new LISTEN // MsgRestart(net,ncbi); break; case NRC_SCLOSED: // Session closed case NRC_SABORT: // Session ended abnormally if(pNcbData->State == MESCONT) { // // If middle of multi-block message, Log an error // Msglogmbe(MESERR,net,ncbi); } // // Start a new LISTEN // MsgStartListen(net,ncbi); break; default: // Other errors MSG_LOG(TRACE,"MsgReceiveService: Unrecognized retval %x\n",retval); MsgNetBiosError(net,ncb,retval,ncbi); if(pNcbData->State == MESCONT) { // // If middle of multi-block message, Log an error // Msglogmbe(MESERR,net,ncbi); } MsgRestart(net,ncbi); // HANGUP and LISTEN again break; } } /* * MsgRestart - issue a HANGUP net bios call * * This function is invoked to issue a HANGUP net bios call using * a particular Network Control Block. * * MsgRestart (net, ncbi) * * ENTRY * net - network index * ncbi - Network Control Block index * * RETURN * nothing * * This function assumes that the NCB_LSN, NCB_POST, and NCB_LANA * fields of the Network Control Block are already properly set. * It sets the NCB_CMD field. * * This function is named "MsgRestart" since the very next routine * to process the NCB used to issue the HANGUP should be * MsgHangupService() which always invokes MsgStartListen() (assuming * the HANGUP completes properly). Thus, the net effect of * calling MsgRestart() is to terminate the current session and * issue a LISTEN to start a new one. * * SIDE EFFECTS * * Calls MsgCallNetBios() to issue the net bios call. Sets mpncbifun[ncbi] * to the address of MsgHangupService(). */ STATIC VOID MsgRestart( DWORD net, // Which network? DWORD ncbi // Index to NCB ) { PNCB ncb; // Pointer to Network Control Block PNCB_DATA pNcbData; // Pointer to NCB Data MSG_LOG(TRACE,"In MsgRestart %d\n",net); pNcbData = GETNCBDATA(net,ncbi); ncb = &pNcbData->Ncb; pNcbData->IFunc = (LPNCBIFCN)MsgHangupService; // Set function pointer ncb->ncb_command = NCBHANGUP | ASYNCH; // Hang up (no wait) MsgCallNetBios(net,ncb,ncbi); // Issue the net bios call } /* * Msgsblockmes - process a single block message * * This function logs and acknowledges a single block message. * * Msgsblockmes (net, ncbi) * * ENTRY * net - network index * ncbi - Network Control Block index * * RETURN * nothing * * This function is called from ReceivePost() (RecAnyPost()). * It first check to see if it is appropriate for the ncbi'th * name to have received a single block message SMB at the current * time. It verifies the correctness of the SMB in the ncbi'th * buffer. It attempts to log the single block message, and it * sends an acknowledgement to the sender of the message. * * SIDE EFFECTS * * Calls MsgRestart() to terminate the session if the SMB has arrived * at a bad time. Calls MsgVerifySmb() to check the SMB for correctness. * Calls logsbm() to log the message. Calls MsgSendAck() to send an * acknowledgement to the sender of the message. */ STATIC VOID Msgsblockmes( DWORD net, // Which network ? DWORD ncbi // Index to NCB ) { PNCB ncb; // Pointer to NCB PNCB_DATA pNcbData; // Pointer to NCB LPBYTE buffer; // Pointer to SMB buffer LPSTR cp; // Save pointer LPSTR from; // From-name LPSTR to; // To-name // to browse the SessionId List : PMSG_SESSION_ID_ITEM pItem; // item in the list PLIST_ENTRY pHead; // head of the list PLIST_ENTRY pList; // list pointer DWORD bError = 0; // error flag MSG_LOG(TRACE,"In Msgsblockmes %d\n",net); pNcbData = GETNCBDATA(net,ncbi); ncb = &pNcbData->Ncb; // Get pointer to NCB if(pNcbData->State != MESSTART) { // // If wrong time for this block // Hang up and start a new listen, // log an error if mpncbistate[net][ncbi] == MESCONT; // otherwise, do not log the error. // // Log error if message in progress // if(pNcbData->State == MESCONT) { Msglogmbe(MESERR,net,ncbi); } // // HANGUP and LISTEN again // MsgRestart(net,ncbi); return; } pNcbData->State = MESSTOP; // End of message state // // Check for malformed SMB // if(MsgVerifySmb(net,ncbi,(unsigned char)SMB_COM_SEND_MESSAGE,0,"ssb") != 0) { return; } buffer = ncb->ncb_buffer; // Get pointer to buffer from = &buffer[sizeof(SMB_HEADER) + 4]; // Save pointer to from-name to = &from[strlen(from) + 2]; // Save pointer to to-name cp = &to[strlen(to) + 2]; // Skip over the name if (g_IsTerminalServer) { MsgDatabaseLock(MSG_GET_EXCLUSIVE,"Msgsblockmes"); pHead = &(SD_SIDLIST(net,ncbi)); pList = pHead; while (pList->Flink != pHead) // loop all over the list { pList = pList->Flink; pItem = CONTAINING_RECORD(pList, MSG_SESSION_ID_ITEM, List); bError = Msglogsbm(from,to,cp, pItem->SessionId); if (bError) { break; } } MsgDatabaseLock(MSG_RELEASE,"Msgsblockmes"); } else //regular NT { bError = Msglogsbm(from,to,cp,0); } if (bError) { // // If message cannot be logged, enter error state // and send error acknowledgement. // pNcbData->State = MESERR; MsgSendAck(net,ncbi,'\002',SMB_ERR_NO_ROOM); } else { // // Otherwise acknowledge success // MsgSendAck(net, ncbi, SMB_ERR_SUCCESS, (USHORT)SMB_ERR_SUCCESS); } } /* * MsgSendAck - send an SMB to acknowledge a network transaction * * This function is used to send a Server Message Block to some * machine with whom a session has been established acknowledging * (positively or negatively) the occurrence of some event pertaining * to the session. * * MsgSendAck (net, ncbi, smbrclass, smbrcode) * * ENTRY * net - Network index * ncbi - Network Control Block index * smbrclass - SMB return class * smbrcode - SMB return code * * RETURN * nothing * * Using the NCB index to locate the buffer containing the last SMB * received in the session, this function sets the return class and * the return code in that SMB according to its arguments and sends * the SMB to the other party in the session. This function will * not return any parameters or buffers in that SMB. * * SIDE EFFECTS * * This function calls MsgCallNetBios() to send the SMB, and it sets * the function vector so that control will pass to Send Service() * when the NCB completes (assuming, of course, that it doesn't * fail immediately). */ STATIC VOID MsgSendAck( DWORD net, // Which network? DWORD ncbi, // Network Control Block Index UCHAR smbrclass, // SMB return class USHORT smbrcode // SMB return code ) { PNCB ncb; // Pointer to NCB PNCB_DATA pNcbData; // Pointer to NCB Data LPBYTE buffer; // Pointer to buffer MSG_LOG(TRACE,"In MsgSendAck %d\n",net); pNcbData = GETNCBDATA(net,ncbi); ncb = &pNcbData->Ncb; // Get pointer to NCB buffer = ncb->ncb_buffer; // Get pointer to buffer // // No parameters, buffers // buffer[sizeof(SMB_HEADER)+2]= buffer[sizeof(SMB_HEADER)+1]= buffer[sizeof(SMB_HEADER)]= '\0'; // // Set return information // ((PSMB_HEADER)buffer)->ErrorClass = smbrclass; // Set return class SmbPutUshort( &(((PSMB_HEADER)buffer)->Error),smbrcode);// Set return code // ((PSMB_HEADER)buffer)->Error = smbrcode; // Set return code ncb->ncb_length = sizeof(SMB_HEADER) + 3; // Set length of buffer ncb->ncb_command = NCBSEND | ASYNCH; // Send (no wait) pNcbData->IFunc = (LPNCBIFCN)MsgSendService; // Set function pointer MsgCallNetBios(net,ncb,ncbi); // Issue the net bios call } /* * MsgSendService - service a completed SEND net bios call * * This function is called to service a completed SEND net bios * call. The usual course of action is to issue a RECEIVE (ANY) * net bios call. * * MsgSendService (net, ncbi, retval) * * ENTRY * net - network index * ncbi - Network Control Block index * retval - value returned by net bios * * RETURN * nothing * * If a SEND net bios call has completed successfully, this function * will issue a RECEIVE (ANY) net bios call in all cases. The com- * pleted SEND represents one of the following cases: * * - Acknowledgement of a Single Block Message * The message originator will HANG UP, completing the RECEIVE (ANY) call. * - Acknowledgement of the start of a Multi-block Message * The message originator will SEND a text block, completing the RECEIVE * (ANY) call. * - Acknowledgement of text of a Multi-block Message * The message originator will SEND more text or the end of the message, * completing the RECEIVE (ANY) call. * - Acknowledgement of the end of a Multi-block Message * The message originator will HANG UP, completing the RECEIVE (ANY) call. * - Response to a Get Machine Name request * The message originator will HANG UP, completing the RECEIVE (ANY) call. * - Acknowledgement of a Forward Name request * The message originator will HANG UP, completing the RECEIVE (ANY) call. * - Acknowledgement of a Cancel Forward request * The message originator will HANG UP, completing the RECEIVE (ANY) call. * - An error response * The message originator will HANG UP, completing the RECEIVE (ANY) call. * * In all cases, it is clear to the RECEIVE (ANY) service function what its * course of action is. * * SIDE EFFECTS * * If a SEND has completed normally, this function issues a RECEIVE (ANY) * net bios call. In some abnormal cases, this function calls MsgStartListen() * to initiate a new session. In all other abnormal cases, it calls * MsgNetBiosError(). */ STATIC VOID MsgSendService( DWORD net, // Which network? DWORD ncbi, // Index of completed NCB char retval // SEND return value ) { PNCB ncb; // Pointer to completed NCB PNCB_DATA pNcbData; // Pointer to NCB Data PSMB_HEADER smb; // Pointer to SMB header MSG_LOG(TRACE,"In MsgSendService %d\n",net); pNcbData = GETNCBDATA(net,ncbi); ncb = &pNcbData->Ncb; // Get pointer to completed NCB switch(retval) { case NRC_GOODRET: // Success pNcbData->IFunc = (LPNCBIFCN)MsgReceiveService; // // Set function pointer // ncb->ncb_command = NCBRECV | ASYNCH; // Receive (no wait) ncb->ncb_length = BUFLEN; // Set length of buffer MsgCallNetBios(net,ncb,ncbi); // Issue the net bios call break; case NRC_CMDTMO: // Timeout case NRC_SCLOSED: // Session closed case NRC_SABORT: // Session ended abnormally smb = (PSMB_HEADER)ncb->ncb_buffer; // Get pointer to SMB if(smb->Command == SMB_COM_SEND_START_MB_MESSAGE || smb->Command == SMB_COM_SEND_TEXT_MB_MESSAGE) { // // Message ended abnormally // Msglogmbe(MESERR,net,ncbi); } // // Issue a new LISTEN // MsgStartListen(net,ncbi); break; default: // Other failure MSG_LOG(TRACE,"MsgSendService: Unrecognized retval %x\n",retval); MsgNetBiosError(net,ncb,retval,ncbi); // // HANGUP and LISTEN again // MsgRestart(net,ncbi); break; } } /* * MsgServeNCBs - service completed Network Control Blocks * * This function scans the array of NCB's looking for NCB's in * need of service. * * MsgServeNCBs (net) * * ENTRY * net - network to service NCBs on * * RETURN * TRUE - If this function actually services a completed NCB. * FALSE - If this function didn't find any completed NCB's, or if * the service is supposed to stop. * * This function scans the array of NCB's until a completed NCB cannot be * found. Each time a completed NCB is found, the service function specified * in the service function vector (mpncbifun[]) is called to service that * NCB. * * SIDE EFFECTS * * Maintains a private static index of the last NCB examined. * Starts each search at first NCB after the last one serviced. */ BOOL MsgServeNCBs( DWORD net // Which network am I serving? ) { PNCB pNcb; PNCB_DATA pNcbData; int counter; // A counter BOOL found = FALSE; // Indicates if a completed NCB was found. // Bugfix: each net has its own index, addressing // its part NCB array. All index values are initiliazed to zero // when the messenger starts. This solves the muti thread // problem. static int ncbIndexArray[MSNGR_MAX_NETS] = {0}; // NCB index array DWORD ncbi; // NCB index for this net // // get NCB index for this net // ncbi = ncbIndexArray[net]; // // Loop until none completed found // do { // // Loop to search NCB array // for(counter = NCBMAX(net); counter != 0; --counter, ++ncbi) { if(ncbi >= NCBMAX(net)) { ncbi = 0;// Wrap around } pNcbData = GETNCBDATA(net,ncbi); pNcb = &pNcbData->Ncb; if(pNcb->ncb_cmd_cplt != (unsigned char) 0xff) { found=TRUE; // // If completed NCB found // if(pNcb->ncb_cmd_cplt == 0) { // // Clear err on success and error count // pNcbData->Status.last_final = 0; pNcbData->Status.rep_count = 0; } else { // // Else mark error // pNcbData->Status.this_final = pNcb->ncb_cmd_cplt; // // If NetBios is failing with every call, we never // return from this routine be cause there is always // another NCB to service. Therefore, in error // conditions it is necessary to check to see if a // shutdown is in progress. If so, we want to return // so that the adapter loop can handle the shutdown // properly. // if (GetMsgrState() == STOPPING) { ncbIndexArray[net] = ncbi; return(FALSE); } } // // Call the service function // (*pNcbData->IFunc)(net,ncbi,pNcb->ncb_cmd_cplt); ++ncbi; // Start next search after this NCB break; // Exit loop } } } while(counter != 0); // Loop until counter zero // update NCB index ncbIndexArray[net] = ncbi; return(found); } /* * MsgSesFullService - complete deletion of a name after a system error * * MsgSesFullService() completes the process of deleting a name from * the message system when the message server is unable to establish * a session for that name. * * MsgSesFullService (net, ncbi, retval) * * ENTRY * net - Network index * ncbi - Network Control Block index * retval - value returned by net bios * * RETURN * nothing * * MsgSesFullService() is called to finish the job of cleaning up when * a LISTEN fails because the local network adapter's session table * is full. Specifically, this function is called when the DELETE * NAME net bios call completes. * * SIDE EFFECTS * * Calls MsgDeleteName() to release the deleted name's entry in the * shared data area. Calls MsgNetBiosError() if the DELETE NAME net * bios call produced unexpected results. */ STATIC VOID MsgSesFullService( DWORD net, // Which network ? DWORD ncbi, // Index of completed NCB char retval // SEND return value ) { PNCB pNcb; MSG_LOG(TRACE,"In MsgSesFullService %d\n",net); switch(retval) { case NRC_GOODRET: // Success case NRC_ACTSES: // Name deregistered // // Log deletion in system error log file // MsgDeleteName(net,ncbi); // Delete name from database break; default: // Failure MSG_LOG(TRACE,"MsgSesFullService: Unrecognized retval %x\n",retval); pNcb = GETNCB(net,ncbi); MsgNetBiosError(net, pNcb, retval, ncbi); break; } } /* * MsgStartListen - issue a LISTEN net bios call * * This function is invoked to issue a LISTEN net bios call using * a particular Network Control Block. This function does not * examine or change any of the shareable data corresponding to * the NCB in question. * * MsgStartListen (net, ncbi) * * ENTRY * net - network index * ncbi - Network Control Block index * * RETURN * DWORD status from the netbios call. * * This function assumes that the NCB_NAME, NCB_POST, and NCB_LANA * fields of the Network Control Block are already set to the * proper values. It sets the NCB_CNAME, NCB_RTO, NCB_STO, and * NCB_CMD fields. * * SIDE EFFECTS * * Calls MsgCallNetBios() to issue the net bios call. Calls FmtNcbName() * to set the NCB_CNAME field of the NCB. Sets mpncbifun[ncbi] to * the address of MsgListenService(). */ NET_API_STATUS MsgStartListen( DWORD net, // Which network? DWORD ncbi // Network Control Block index ) { PNCB ncb; // Pointer to NCB PNCB_DATA pNcbData; // Pointer to NCB Data NET_API_STATUS status; TCHAR name[2] = TEXT("*"); MSG_LOG(TRACE,"In MsgStartListen %d\n",net); pNcbData = GETNCBDATA(net,ncbi); ncb = &pNcbData->Ncb; pNcbData->IFunc = (LPNCBIFCN)MsgListenService; // Set function pointer // // Set call name to a"anyone" // status = MsgFmtNcbName(ncb->ncb_callname,name,' '); if (status != NERR_Success) { // // This is a bug if this can't be done. // MSG_LOG(ERROR,"MsgStartListen: NASTY BUG! Cannot format \"*\" name! %X\n", status); NetpAssert(0); } ncb->ncb_rto = 60; // Receives time out in 30 sec ncb->ncb_sto = 40; // Sends time out in 20 sec ncb->ncb_command = NCBLISTEN | ASYNCH; // Listen (no wait) return(MsgCallNetBios(net,ncb,ncbi)); // Issue the net bios call } /* * MsgVerifySmb - Verify the correctness of a Server Message Block * * This function verifies that a Server Message Block is properly * formed. If it detects a malformed SMB, it terminates the session * and returns a non-zero value. * * MsgVerifySmb (net, ncbi, func, parms, buffers) * * ENTRY * net - network index * ncbi - index to a Network Control Block * func - SMB function code * parms - number of parameters in SMB * buffers - dope vector describing buffers in the SMB * * RETURN * int - error code (zero means no error) * * SIDE EFFECTS * * Calls smbcheck() to check the SMB. Calls MsgRestart() if * smbcheck() reports an error. */ STATIC int MsgVerifySmb( DWORD net, // Which network? DWORD ncbi, // Index to Network Control Block UCHAR func, // SMB function code int parms, // Count of parameters in SMB LPSTR buffers // Dope vector of SMB buffers ) { PNCB ncb; // Pointer to Network Control Block int i; // Return code ncb = GETNCB(net,ncbi); // Get pointer to NCB i = Msgsmbcheck( (ncb->ncb_buffer), ncb->ncb_length, func, (char)parms, buffers); if (i != 0 ) { // // if SMB malformed, Enter error in system error log // MsgErrorLogWrite( NELOG_SMB_Illegal, SERVICE_MESSENGER, (LPBYTE)ncb->ncb_buffer, ncb->ncb_length, NULL, 0); MSG_LOG(ERROR,"MsgVerifySmb:An illegal SMB was received\n",0); // // HANGUP // MsgRestart(net,ncbi); } return(i); // Return error code } #if DBG VOID MsgDumpNcb( IN PNCB pNcb ) /*++ Routine Description: Displays the NCB on a debug terminal. Arguments: Return Value: --*/ { DbgPrint("NCBADDR: 0x%x\n" "Command: 0x%x\n" "RetCode: 0x%x\n" "LanaNum: 0x%x\n" "CmdCplt: 0x%x\n" "Name : %s\n" "callNam: %s\n", pNcb, pNcb->ncb_command, pNcb->ncb_retcode, pNcb->ncb_lana_num, pNcb->ncb_cmd_cplt, pNcb->ncb_name, pNcb->ncb_callname); } #endif // DBG