//**************************************************************************** // // Microsoft NT Remote Access Service // // Copyright (C) 1992-93 Microsft Corporation. All rights reserved. // // Filename: rasstate.c // // Revision History // // Jul 1, 1992 J. Perry Hannah Created // // // Description: This file contains the state machine functions for the // RASMXS.DLL and related funcitons. // //**************************************************************************** #include //These first five headers are used by media.h #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mxswrap.h" // inf file wrapper #define STRSAFE_NO_DEPRECATE #include //* Global Variables ******************************************************* // extern RESPSECTION ResponseSection ; //Shared response section extern PortSetInfo_t PortSetInfo; //API typedef defined in media.h extern BOOL gbLogDeviceDialog; //Indicates logging on if TRUE extern HANDLE ghLogFile; //Handle of device log file //* BuildMacroXlationsTable ------------------------------------------------ // // Function: Creates a table of macros and their expansions for use by // the RasDevAPIs. Memory is allocated for the table and the // pMacros pointer in the device control block points to it. // Since this function depends on a valid InfoTable being present // CreateInfoTable and CreateAttributes must be called before // this function is called. // // Assumptions: - Parameters in InfoTable are sorted by P_Key. // - Both parts of binary macros are present. // These assumptions imply that if somename_off is in InfoTable // somename_on is also present and is adjacent to somename_off. // // Returns: SUCCESS // ERROR_ALLOCATING_MEMORY //* DWORD BuildMacroXlationTable(DEVICE_CB *pDevice) { WORD i, j, k, cMacros; DWORD dSize; TCHAR szCoreName[MAX_PARAM_KEY_SIZE]; RASMAN_DEVICEINFO *pInfo = pDevice->pInfoTable; MACROXLATIONTABLE *pMacros; // Calucate size and allocate memory cMacros = MacroCount(pInfo, ALL_MACROS); dSize = sizeof(MACROXLATIONTABLE) + sizeof(MXT_ENTRY) * (cMacros - 1); GetMem(dSize, (BYTE **) &(pDevice->pMacros)); if (pDevice->pMacros == NULL) return(ERROR_ALLOCATING_MEMORY); // Copy macro names and pointers to new Macro Translation Table pMacros = pDevice->pMacros; pMacros->MXT_NumOfEntries = cMacros; for (i=0, j=0; i < pInfo->DI_NumOfParams; i++) { if (IsVariable(pInfo->DI_Params[i])) ; // copy nothing else if (IsBinaryMacro(pInfo->DI_Params[i].P_Key)) { // copy Core Macro Name and pointer to Param GetCoreMacroName(pInfo->DI_Params[i].P_Key, szCoreName); strcpy(pMacros->MXT_Entry[j].E_MacroName, szCoreName); // copy Param ptr for ON macro if enabled, else copy Off Param ptr if (XOR(pInfo->DI_Params[i].P_Attributes & ATTRIB_ENABLED, BinarySuffix(pInfo->DI_Params[i].P_Key) == ON_SUFFIX)) k = i + 1; else k = i; pMacros->MXT_Entry[j].E_Param = &(pInfo->DI_Params[k]); i++; j++; } else // Is Unary Macro { // copy Core Macro Name and pointer to Param strcpy(pMacros->MXT_Entry[j].E_MacroName, pInfo->DI_Params[i].P_Key); pMacros->MXT_Entry[j].E_Param = &(pInfo->DI_Params[i]); j++; } } return(SUCCESS); ///*** #ifdef DEBUG //Printout Macro Translation Table for(i=0; iMXT_Entry[i].E_MacroName, pMacros->MXT_Entry[i].E_Param->P_Value.String.Data)); #endif // DEBUG //***/ } //* DeviceStateMachine ----------------------------------------------------- // // Function: This is the main state machine used by the DLL to control // asynchronous actions (writing and reading to/from devices). // // Returns: PENDING // SUCCESS // ERROR_CMD_TOO_LONG from RasDevGetCommand // Error return codes from GetLastError() // //* DWORD DeviceStateMachine(DEVICE_CB *pDevice, HANDLE hIOPort) { DWORD dRC, lpcBytesWritten; BOOL fIODone, fEndOfSection = FALSE; TCHAR szCmdSuffix[MAX_CMDTYPE_SUFFIX_LEN + 1]; COMMTIMEOUTS CT; while(1) { //DebugPrintf(("DeviceStateMachine state: %d\n", pDevice->eDevNextAction)); switch(pDevice->eDevNextAction) { // Send a Command to the device case SEND: // Get Command string dRC = RasDevGetCommand(pDevice->hInfFile, CmdTypeToStr(szCmdSuffix, pDevice->eCmdType), pDevice->pMacros, pDevice->szCommand, &(pDevice->dCmdLen)); switch(dRC) { case SUCCESS: // Check to see if a response is expected pDevice->bResponseExpected = RasDevResponseExpected(pDevice->hInfFile, pDevice->eDeviceType); // Log the Command if (gbLogDeviceDialog) LogString(pDevice, "Command to Device:", pDevice->szCommand, pDevice->dCmdLen); // Check for null command with no response expected if (pDevice->dCmdLen == 0 && !pDevice->bResponseExpected) { // Pause between commands if (CommWait(pDevice, hIOPort, NO_RESPONSE_DELAY)) return(ERROR_UNEXPECTED_RESPONSE); else if ((dRC = GetLastError()) == ERROR_IO_PENDING) { pDevice->eDevNextAction = DONE; return(PENDING); } else return(dRC); } // Send the command to the Port CT.WriteTotalTimeoutMultiplier = 0; CT.WriteTotalTimeoutConstant = TO_WRITE; SetCommTimeouts(hIOPort, &CT); fIODone = WriteFile(hIOPort, // Send Cmd string to modem pDevice->szCommand, pDevice->dCmdLen, &lpcBytesWritten, (LPOVERLAPPED)&(pDevice->Overlapped)); pDevice->eDevNextAction = RECEIVE; if ( ! fIODone) { if ((dRC = GetLastError()) == ERROR_IO_PENDING) return(PENDING); else return(dRC); } return(PENDING); case ERROR_END_OF_SECTION: fEndOfSection = TRUE; pDevice->eDevNextAction = DONE; break; default: return(dRC); } break; // Recieve Response string from device case RECEIVE: dRC = ReceiveStateMachine(pDevice, hIOPort); switch(dRC) { case SUCCESS: pDevice->eDevNextAction = DONE; pDevice->eRcvState = GETECHO; //Reset Recieve State Machine break; case PENDING: return(PENDING); default: pDevice->eRcvState = GETECHO; //Reset Recieve State Machine return(dRC); } break; // A Command-Response cycle is complete case DONE: if (fEndOfSection) switch(pDevice->eCmdType) //Last cmd of this type is now done { case CT_INIT: pDevice->eCmdType = pDevice->eNextCmdType; //Reset command type RasDevResetCommand(pDevice->hInfFile); //Reset INF file ptr break; case CT_DIAL: case CT_LISTEN: if ((dRC = CheckBpsMacros(pDevice)) != SUCCESS) return(dRC); return(ResetBPS(pDevice)); case CT_GENERIC: return(SUCCESS); } pDevice->eDevNextAction = SEND; //Reset state machine break; } /* Switch */ } /* While */ } /* DeviceStateMachine */ //* ReceiveStateMachine ---------------------------------------------------- // // Function: This state machine controls asynchronously reading from the // device. First the command echo is read promptly after the // command is sent. Then after a delay the the response begins // arriving. An asynchronous read with a long time out is done // for the first character. Then the rest of the string is read // (also asynchronously). // // Returns: PENDING // SUCCESS // ERROR_REPEATED_PARTIAL_RESPONSE // Error return codes from GetLastError(), RasDevCheckResponse() // //* DWORD ReceiveStateMachine(DEVICE_CB *pDevice, HANDLE hIOPort) { DWORD dRC; BOOL fKeyIsOK; TCHAR szKey[MAX_PARAM_KEY_SIZE]; while(1) { //DebugPrintf(("ReceiveStateMachine state: %d\n", pDevice->eRcvState)); switch (pDevice->eRcvState) { case GETECHO: // Check if an echo is expected. // 1. If there is no command there is no echo. // 2. Null modems require that if there is no response there is no echo // so we require it for all devices. // 3. If the current line of INF file is "NoEcho", there is no echo. if (pDevice->dCmdLen == 0 || !pDevice->bResponseExpected || !RasDevEchoExpected(pDevice->hInfFile)) { pDevice->eRcvState = GETFIRSTCHAR; break; } // Clear buffer used for echo and device response, and Reset Event memset(pDevice->szResponse, '\0', sizeof(pDevice->szResponse)); ResetEvent(pDevice->hNotifier); //Reset event handle ConsolePrintf(("WaitForEcho hIOPort: 0x%08lx hNotifier: 0x%08x\n", hIOPort, pDevice->hNotifier)); // Get Echo if (WaitForEcho(pDevice, hIOPort, pDevice->dCmdLen)) { pDevice->eRcvState = CHECKECHO; return(PENDING); } else if ((dRC = GetLastError()) == ERROR_IO_PENDING) { pDevice->eRcvState = GETNUMBYTESECHOD; return(PENDING); } else return(dRC); break; case GETNUMBYTESECHOD: if (!GetOverlappedResult(hIOPort, (LPOVERLAPPED)&pDevice->Overlapped, &pDevice->cbRead, !WAITFORCOMPLETION)) return(GetLastError()); pDevice->eRcvState = CHECKECHO; //Set Next state break; case CHECKECHO: // Log the Echo received DebugPrintf(("Echo:%s!\n cbEcohed:%d\n", pDevice->szResponse, pDevice->cbRead)); if (gbLogDeviceDialog && !pDevice->fPartialResponse) LogString(pDevice, "Echo from Device :", pDevice->szResponse, pDevice->cbRead); // Check for echo different from command switch(pDevice->eDeviceType) { case DT_MODEM: if (pDevice->cbRead != pDevice->dCmdLen || _strnicmp(pDevice->szCommand, pDevice->szResponse, pDevice->dCmdLen) != 0) { if (CheckForOverruns(hIOPort)) return(ERROR_OVERRUN); else return(ERROR_PORT_OR_DEVICE); } break; case DT_PAD: case DT_SWITCH: if (RasDevSubStr(pDevice->szResponse, pDevice->cbRead, "NO CARRIER", strlen("NO CARRIER"))) return(ERROR_NO_CARRIER); break; } pDevice->eRcvState = GETFIRSTCHAR; //Set Next state break; case GETFIRSTCHAR: // Check if a response is expected if ( ! pDevice->bResponseExpected) { if ((dRC = PutInMessage(pDevice, "", 0)) != SUCCESS) return(dRC); pDevice->cbTotal = 0; //Reset for next response return(SUCCESS); } // Save starting point for a receive following an echo if (!pDevice->fPartialResponse) { (pDevice->cbTotal) += pDevice->cbRead; pDevice->pszResponseStart = pDevice->szResponse + pDevice->cbTotal; } ResetEvent(pDevice->hNotifier); //Reset event handle if (WaitForFirstChar(pDevice, hIOPort)) { pDevice->eRcvState = GETRECEIVESTR; return(PENDING); } else if ((dRC = GetLastError()) == ERROR_IO_PENDING) { pDevice->eRcvState = GETNUMBYTESFIRSTCHAR; return(PENDING); } else return(dRC); break; case GETNUMBYTESFIRSTCHAR: DebugPrintf(("After 1st char:%s! cbTotal:%d\n", pDevice->szResponse, pDevice->cbTotal)); if (!GetOverlappedResult(hIOPort, (LPOVERLAPPED)&pDevice->Overlapped, &pDevice->cbRead, !WAITFORCOMPLETION)) return(GetLastError()); pDevice->eRcvState = GETRECEIVESTR; //Set Next state break; case GETRECEIVESTR: (pDevice->cbTotal)++; //FIRSTCAR always rcvs 1 byte ResetEvent(pDevice->hNotifier); //Reset event handle if (ReceiveString(pDevice, hIOPort)) { pDevice->eRcvState = CHECKRESPONSE; return(PENDING); } else if ((dRC = GetLastError()) == ERROR_IO_PENDING) { pDevice->eRcvState = GETNUMBYTESRCVD; return(PENDING); } else return(dRC); break; case GETNUMBYTESRCVD: if (!GetOverlappedResult(hIOPort, (LPOVERLAPPED)&pDevice->Overlapped, &pDevice->cbRead, !WAITFORCOMPLETION)) return(GetLastError()); pDevice->eRcvState = CHECKRESPONSE; //Set Next state break; case CHECKRESPONSE: (pDevice->cbTotal) += pDevice->cbRead; // Always put response string where UI can get it if (pDevice->eDeviceType == DT_MODEM) dRC = PutInMessage(pDevice, pDevice->pszResponseStart, ModemResponseLen(pDevice)); else dRC = PutInMessage(pDevice, pDevice->szResponse, pDevice->cbTotal); if (dRC != SUCCESS) return(dRC); // Check the response dRC = CheckResponse(pDevice, szKey); // Log the response received if (gbLogDeviceDialog && dRC != ERROR_PARTIAL_RESPONSE) LogString(pDevice, "Response from Device:", pDevice->pszResponseStart, ModemResponseLen(pDevice)); switch(dRC) { case ERROR_UNRECOGNIZED_RESPONSE: default: // Other errors return(dRC); case ERROR_PARTIAL_RESPONSE: if (pDevice->fPartialResponse) return(ERROR_PARTIAL_RESPONSE_LOOPING); pDevice->fPartialResponse = TRUE; pDevice->eRcvState = GETFIRSTCHAR; ConsolePrintf(("Partial Response\n")); break; case SUCCESS: // Response found in INF file pDevice->cbTotal = 0; // Reset for next response fKeyIsOK = !_strnicmp(szKey, MXS_OK_KEY, strlen(MXS_OK_KEY)); // Do we need to loop and get another response from device if (((_stricmp(szKey, LOOP_TXT) == 0) && (pDevice->eCmdType != CT_INIT)) || (fKeyIsOK && pDevice->eCmdType == CT_LISTEN) ) { pDevice->eRcvState = GETFIRSTCHAR; break; } // Check if device has error contol on pDevice->bErrorControlOn = _stricmp(szKey, MXS_CONNECT_EC_KEY) == 0; // Determine return code if (fKeyIsOK) if (pDevice->eCmdType == CT_DIAL) return(ERROR_PORT_OR_DEVICE); else return(SUCCESS); if (_strnicmp(szKey, MXS_CONNECT_KEY, strlen(MXS_CONNECT_KEY)) == 0) return(SUCCESS); else if (_strnicmp(szKey, MXS_ERROR_KEY, strlen(MXS_ERROR_KEY)) == 0) return(MapKeyToErrorCode(szKey)); else if (CheckForOverruns(hIOPort)) return(ERROR_OVERRUN); else return(ERROR_UNKNOWN_RESPONSE_KEY); } break; } /* Switch */ } /* While */ } /* ReceiveStateMachine */ //* CheckResponse ---------------------------------------------------------- // // Function: If DeviceType is Modem this function checks first for a // response in that particular modem's section of the INF // file and returns if it finds one. If there is no response // there, it checks for a response in the Modems Responses // section. // // If DeviceType is not Modem the function checks only in // the particular device's section of the INF file. // // Returns: Error return codes from RasDevCheckResponse() // //* DWORD CheckResponse(DEVICE_CB *pDev, LPTSTR szKey) { DWORD dRC, dResponseLen; if (pDev->cbTotal > sizeof(pDev->szResponse)) return(ERROR_RECV_BUF_FULL); dResponseLen = ModemResponseLen(pDev); DebugPrintf(("Device Response:%s! cbResponse:%d\n", pDev->pszResponseStart, dResponseLen)); dRC = RasDevCheckResponse(pDev->hInfFile, pDev->pszResponseStart, dResponseLen, pDev->pMacros, szKey); if (pDev->eDeviceType == DT_MODEM && dRC != SUCCESS && dRC != ERROR_PARTIAL_RESPONSE) { // **** Exclusion Begin **** WaitForSingleObject(ResponseSection.Mutex, INFINITE) ; dRC = RasDevCheckResponse(ResponseSection.Handle, pDev->pszResponseStart, dResponseLen, pDev->pMacros, szKey); // *** Exclusion End *** ReleaseMutex(ResponseSection.Mutex); } if (dRC == ERROR_UNRECOGNIZED_RESPONSE) { // Maybe there was no echo. // Try again assuming string starts at beginning of buffer. dRC = RasDevCheckResponse(pDev->hInfFile, pDev->szResponse, pDev->cbTotal, pDev->pMacros, szKey); if (pDev->eDeviceType == DT_MODEM && dRC != SUCCESS && dRC != ERROR_PARTIAL_RESPONSE) { // **** Exclusion Begin **** WaitForSingleObject(ResponseSection.Mutex, INFINITE) ; dRC = RasDevCheckResponse(ResponseSection.Handle, pDev->szResponse, pDev->cbTotal, pDev->pMacros, szKey); // *** Exclusion End *** ReleaseMutex(ResponseSection.Mutex); } } return(dRC); } //* ModemResponseLen ------------------------------------------------------- // // Function: This function returns the length of the portion of the // response in the response buffer which follows the echo. // // Returns: Total length - (start of response - beginning of buffer) // //* DWORD ModemResponseLen(DEVICE_CB *pDev) { return(DWORD)(pDev->cbTotal - (pDev->pszResponseStart - pDev->szResponse)); } //* CommWait --------------------------------------------------------------- // // Function: This function causes an asynchronous delay by reading the // com port when no characters are expected. When the ReadFile // times out the calling process is signaled via hNotifier. // // Returns: Values from Win32 api calls. // //* DWORD CommWait(DEVICE_CB *pDevice, HANDLE hIOPort, DWORD dwPause) { DWORD dwBytesRead; TCHAR Buffer[2048]; COMMTIMEOUTS CT; CT.ReadIntervalTimeout = 0; CT.ReadTotalTimeoutMultiplier = 0; CT.ReadTotalTimeoutConstant = dwPause; if ( ! SetCommTimeouts(hIOPort, &CT)) return(FALSE); return(ReadFile(hIOPort, Buffer, sizeof(Buffer), &dwBytesRead, (LPOVERLAPPED)&pDevice->Overlapped)); } //* WaitForEcho ------------------------------------------------------------ // // Function: This function reads the echo of the command sent to the // device. The echo is not used and is simply ignored. // Since the length of the echo is the length of the command // sent, cbEcho is the size of the command sent. // // ReadFile is asynchronous (because the port was opened in // overlapped mode), and completes when the buffer is full // (cbEcho bytes) or after TO_ECHO mS, whichever comes first. // // Returns: Error return codes from ReadFile(), or GetLastError(). // //* BOOL WaitForEcho(DEVICE_CB *pDevice, HANDLE hIOPort, DWORD cbEcho) { COMMTIMEOUTS CT; CT.ReadIntervalTimeout = 0; CT.ReadTotalTimeoutMultiplier = 0; CT.ReadTotalTimeoutConstant = TO_ECHO; // Comm time out = TO_ECHO if ( ! SetCommTimeouts(hIOPort, &CT)) return(FALSE); if(cbEcho > MAX_RCV_BUF_LEN) { return FALSE; } return(ReadFile(hIOPort, pDevice->szResponse, cbEcho, &pDevice->cbRead, (LPOVERLAPPED)&pDevice->Overlapped)); } //* WaitForFirstChar ------------------------------------------------------- // // Function: This function reads the first character received from the // device in response to the last command. (This follows the // echo of the command.) // // ReadFile is asynchronous (because the port was opened in // overlapped mode), and completes after one character is // received, or after CT.ReadToalTimeoutConstant, whichever // comes first. // // Returns: Error return codes from ReadFile(), or GetLastError(). // //* BOOL WaitForFirstChar(DEVICE_CB *pDevice, HANDLE hIOPort) { TCHAR *pszResponse; COMMTIMEOUTS CT; CT.ReadIntervalTimeout = 0; CT.ReadTotalTimeoutMultiplier = 0; if (pDevice->fPartialResponse) CT.ReadTotalTimeoutConstant = TO_PARTIALRESPONSE; else if (pDevice->eCmdType == CT_LISTEN) CT.ReadTotalTimeoutConstant = 0; //Never timeout for LISTEN else if (pDevice->cbTotal == 0) //Implies no Echo CT.ReadTotalTimeoutConstant = TO_FIRSTCHARNOECHO; //Probably not a modem else CT.ReadTotalTimeoutConstant = TO_FIRSTCHARAFTERECHO; //Probably a modem if ( ! SetCommTimeouts(hIOPort, &CT)) return(FALSE); pszResponse = pDevice->szResponse; pszResponse += pDevice->cbTotal; return(ReadFile(hIOPort, pszResponse, 1, &pDevice->cbRead, (LPOVERLAPPED)&pDevice->Overlapped)); } //* ReceiveString ---------------------------------------------------------- // // Function: This function reads the string received from the device in // response to the last command. The first byte of this string // has already been received by WaitForFirstChar(). // // ReadFile is asynchronous (because the port was opened in // overlapped mode), and times out after a total time of // TO_RCV_CONSTANT, or if the time between characters exceeds // TO_RCV_INTERVAL. // // Returns: Error return codes from ReadFile(), or GetLastError(). // //* BOOL ReceiveString(DEVICE_CB *pDevice, HANDLE hIOPort) { TCHAR *pszResponse; COMMTIMEOUTS CT; CT.ReadIntervalTimeout = TO_RCV_INTERVAL; CT.ReadTotalTimeoutMultiplier = 0; CT.ReadTotalTimeoutConstant = TO_RCV_CONSTANT; if ( ! SetCommTimeouts(hIOPort, &CT)) return(FALSE); pszResponse = pDevice->szResponse; pszResponse += pDevice->cbTotal; return(ReadFile(hIOPort, pszResponse, sizeof(pDevice->szResponse) - pDevice->cbTotal, &pDevice->cbRead, (LPOVERLAPPED)&pDevice->Overlapped)); } //* PutInMessage ----------------------------------------------------------- // // Function: This function finds the message macro in the Macro Translations // table, and copies the second parameter, a string, into the // message macro's value field. // // Returns: SUCCESS // ERROR_MESSAGE_MACRO_NOT_FOUND // Return codes from UpdateparmString //* DWORD PutInMessage(DEVICE_CB *pDevice, LPTSTR lpszStr, DWORD dwStrLen) { WORD i; MACROXLATIONTABLE *pMacros = pDevice->pMacros; for (i=0; iMXT_NumOfEntries; i++) if (_stricmp(MXS_MESSAGE_KEY, pMacros->MXT_Entry[i].E_MacroName) == 0) break; if (i >= pMacros->MXT_NumOfEntries) return(ERROR_MESSAGE_MACRO_NOT_FOUND); return(UpdateParamString(pMacros->MXT_Entry[i].E_Param, lpszStr, dwStrLen)); } //* PortSetStringInfo ----------------------------------------------------- // // Function: Formats a RASMAN_PORTINFO struct for string data and calls // PortSetInfo. // // Returns: Return codes from PortSetInfo //* DWORD PortSetStringInfo(HANDLE hIOPort, char *pszKey, char *psStr, DWORD sStrLen) { BYTE chBuffer[sizeof(RASMAN_PORTINFO) + RAS_MAXLINEBUFLEN]; RASMAN_PORTINFO *pSetInfo; pSetInfo = (RASMAN_PORTINFO *)chBuffer; pSetInfo->PI_NumOfParams = 1; // strcpy(pSetInfo->PI_Params[0].P_Key, pszKey); (VOID) StringCchCopyA(pSetInfo->PI_Params[0].P_Key, MAX_PARAM_KEY_SIZE, pszKey); pSetInfo->PI_Params[0].P_Type = String; pSetInfo->PI_Params[0].P_Attributes = 0; pSetInfo->PI_Params[0].P_Value.String.Data = (PCHAR)pSetInfo + sizeof(RASMAN_PORTINFO); strncpy(pSetInfo->PI_Params[0].P_Value.String.Data, psStr, sStrLen); pSetInfo->PI_Params[0].P_Value.String.Length = sStrLen; PortSetInfo(hIOPort, pSetInfo) ; return(SUCCESS); } //* ResetBPS -------------------------------------------------------------- // // Function: This function calls the serial dll API, PortSetInfo, and // 1. sets the Error Control Flag in the Serial PCB, // 2. sets the Hardware Flow Conrol Flag, // 3. sets the Carrier BPS rate in the Serial PCB, // 4. if the Connect BPS macro is non-null the Port BPS is // is set to the macro value, otherwise it is unchanged. // // See the truth table in the CheckBpsMacros() function notes. // // Assumptions: ConnectBps and CarrierBps macros are filled in, // that is, RasDevCheckResponse has been called successfully. // // Returns: Error codes from GetLastError(). // //* DWORD ResetBPS(DEVICE_CB *pDev) { UINT i; DWORD dwRC; TCHAR *pStrData, *pArgs[1]; BYTE chBuffer[sizeof(RASMAN_PORTINFO) + (MAX_LEN_STR_FROM_NUMBER + 1)]; RAS_PARAMS *pParam; RASMAN_PORTINFO *pPortInfo; RASMAN_DEVICEINFO *pInfoTable = pDev->pInfoTable; pPortInfo = (RASMAN_PORTINFO *)chBuffer; pParam = pPortInfo->PI_Params; pStrData = (PCHAR)pPortInfo + sizeof(RASMAN_PORTINFO); pPortInfo->PI_NumOfParams = 1; // Make Error Control Flag Entry strcpy(pParam->P_Key, SER_ERRORCONTROLON_KEY); pParam->P_Type = Number; pParam->P_Attributes = 0; pParam->P_Value.Number = pDev->bErrorControlOn; PortSetInfo(pDev->hPort, pPortInfo) ; // Make HwFlowControl Flag Entry strcpy(pParam->P_Key, SER_HDWFLOWCTRLON_KEY); pParam->P_Type = Number; pParam->P_Attributes = 0; i = FindTableEntry(pInfoTable, MXS_HDWFLOWCONTROL_KEY); if (i == INVALID_INDEX) return(ERROR_MACRO_NOT_FOUND); pParam->P_Value.Number = pInfoTable->DI_Params[i].P_Attributes & ATTRIB_ENABLED; PortSetInfo(pDev->hPort, pPortInfo) ; // Make Carrier BPS Entry i = FindTableEntry(pInfoTable, MXS_CARRIERBPS_KEY); if (i == INVALID_INDEX) return(ERROR_MACRO_NOT_FOUND); dwRC = PortSetStringInfo(pDev->hPort, SER_CARRIERBPS_KEY, pInfoTable->DI_Params[i].P_Value.String.Data, pInfoTable->DI_Params[i].P_Value.String.Length); if (dwRC != SUCCESS) return(dwRC); // Make Connect BPS Entry i = FindTableEntry(pInfoTable, MXS_CONNECTBPS_KEY); if (i == INVALID_INDEX) return(ERROR_MACRO_NOT_FOUND); dwRC = PortSetStringInfo(pDev->hPort, SER_CONNECTBPS_KEY, pInfoTable->DI_Params[i].P_Value.String.Data, pInfoTable->DI_Params[i].P_Value.String.Length); if (dwRC == ERROR_INVALID_PARAMETER) { pArgs[0] = pDev->szPortName; LogError(ROUTERLOG_UNSUPPORTED_BPS, 1, pArgs, NO_ERROR); return(ERROR_UNSUPPORTED_BPS); } else if (dwRC != SUCCESS) return(dwRC); return(SUCCESS); } //* CheckBpsMacros --------------------------------------------------------- // // Function: If the connectbps macro string converts to zero (no connect BPS // rate was received from the device, or it was a word, eg, FAST), // then the value for the Port BPS saved in the DCB is copied to // connectbps. // // If the carrierbps macro string converts to zero, then the value // for the carrierbps is estimated as max(2400, connectbps/4), // unless the connectbps <= 2400, in which case carrerbps is set to // the value for connectbps. // // Returns: SUCCESS // Return codes from UpdateparmString //* DWORD CheckBpsMacros(DEVICE_CB *pDev) { UINT i, j; DWORD dwRC, dwConnectBps, dwCarrierBps, dwCarrierBpsEstimate; TCHAR szConnectBps[MAX_LEN_STR_FROM_NUMBER]; TCHAR szCarrierBps[MAX_LEN_STR_FROM_NUMBER]; RASMAN_DEVICEINFO *pInfoTable = pDev->pInfoTable; // Find Carrier BPS rate in InfoTable j = FindTableEntry(pInfoTable, MXS_CONNECTBPS_KEY); i = FindTableEntry(pInfoTable, MXS_CARRIERBPS_KEY); if (j == INVALID_INDEX || i == INVALID_INDEX) return(ERROR_MACRO_NOT_FOUND); // Get Connect Bps rate from macro strncpy(szConnectBps, pInfoTable->DI_Params[j].P_Value.String.Data, pInfoTable->DI_Params[j].P_Value.String.Length); szConnectBps[pInfoTable->DI_Params[j].P_Value.String.Length] = '\0'; dwConnectBps = atoi(szConnectBps); // If Connect BPS macro value is zero copy Port BPS to Connect BPS if (dwConnectBps == 0) { dwRC = UpdateParamString(&(pInfoTable->DI_Params[j]), pDev->szPortBps, strlen(pDev->szPortBps)); if (dwRC != SUCCESS) return(dwRC); dwConnectBps = atoi(pDev->szPortBps); } // Get Carrier Bps rate from macro strncpy(szCarrierBps, pInfoTable->DI_Params[i].P_Value.String.Data, pInfoTable->DI_Params[i].P_Value.String.Length); szCarrierBps[pInfoTable->DI_Params[i].P_Value.String.Length] = '\0'; dwCarrierBps = atoi(szCarrierBps); // If Carrier BPS macro value is zero estimate Carrier BPS if (dwCarrierBps == 0) { if (dwConnectBps <= MIN_LINK_SPEED) //2400 bps dwCarrierBpsEstimate = dwConnectBps; else { UINT k ; k = FindTableEntry(pInfoTable, MXS_HDWFLOWCONTROL_KEY); if (k == INVALID_INDEX) return(ERROR_MACRO_NOT_FOUND); if (pInfoTable->DI_Params[k].P_Attributes & ATTRIB_ENABLED) dwCarrierBpsEstimate = dwConnectBps/4 ; else dwCarrierBpsEstimate = dwConnectBps ; if (dwCarrierBpsEstimate < MIN_LINK_SPEED) dwCarrierBpsEstimate = MIN_LINK_SPEED; } _itoa(dwCarrierBpsEstimate, szCarrierBps, 10); dwRC = UpdateParamString(&(pInfoTable->DI_Params[i]), szCarrierBps, strlen(szCarrierBps)); if (dwRC != SUCCESS) return(dwRC); } // Log BPS Macros if (gbLogDeviceDialog) { LogString(pDev, "Connect BPS:", pInfoTable->DI_Params[j].P_Value.String.Data, pInfoTable->DI_Params[j].P_Value.String.Length); LogString(pDev, "Carrier BPS:", pInfoTable->DI_Params[i].P_Value.String.Data, pInfoTable->DI_Params[i].P_Value.String.Length); } DebugPrintf(("ConnectBps: %s\n", pInfoTable->DI_Params[j].P_Value.String.Data)); DebugPrintf(("CarrierBps: %s\n", pInfoTable->DI_Params[i].P_Value.String.Data)); return(SUCCESS); } //* FindTableEntry --------------------------------------------------------- // // Function: Finds a key in Info Table. This function matches the length // up to the lenght of the input parameter (pszKey). If a binary // macro name is given without the suffix the first of the two // binary macros will be found. If the full binary macro name is // given the exact binary macro will be found. // // Assumptions: The input parameter, pszKey, is // 1. a full unary macro name, or // 2. a "core" binary macro name, or // 3. a full binary macro name. // // Returns: Index of DI_Params in Info Table. // //* UINT FindTableEntry(RASMAN_DEVICEINFO *pTable, TCHAR *pszKey) { WORD i; for (i=0; iDI_NumOfParams; i++) if (_strnicmp(pszKey, pTable->DI_Params[i].P_Key, strlen(pszKey)) == 0) break; if (i >= pTable->DI_NumOfParams) return(INVALID_INDEX); return(i); } //* MapKeyToErrorCode ------------------------------------------------------ // // Function: Maps the error key from the device.ini file to an error code // number to be returned to the UI. // // Returns: An error code that represents the error returned from the device. // //* DWORD MapKeyToErrorCode(TCHAR *pszKey) { int i; ERROR_ELEM ErrorTable[] = { MXS_ERROR_BUSY_KEY , ERROR_LINE_BUSY , MXS_ERROR_NO_ANSWER_KEY , ERROR_NO_ANSWER , MXS_ERROR_VOICE_KEY , ERROR_VOICE_ANSWER , MXS_ERROR_NO_CARRIER_KEY , ERROR_NO_CARRIER , MXS_ERROR_NO_DIALTONE_KEY , ERROR_NO_DIALTONE , MXS_ERROR_DIAGNOSTICS_KEY , ERROR_X25_DIAGNOSTIC }; for (i=0; i < sizeof(ErrorTable)/sizeof(ERROR_ELEM); i++) if (_stricmp(pszKey, ErrorTable[i].szKey) == 0) return(ErrorTable[i].dwErrorCode); return(ERROR_FROM_DEVICE); }