Source code of Windows XP (NT5)
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.

2053 lines
51 KiB

  1. //****************************************************************************
  2. //
  3. // Microsoft NT Remote Access Service
  4. //
  5. // Copyright (C) 1992-93 Microsft Corporation. All rights reserved.
  6. //
  7. // Filename: serial.c
  8. //
  9. // Revision History
  10. //
  11. // Sep 3, 1992 J. Perry Hannah Created
  12. //
  13. //
  14. // Description: This file contains all entry points for SERIAL.DLL
  15. // which is the media DLL for serial ports.
  16. //
  17. //****************************************************************************
  18. #include <nt.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <windows.h>
  22. #include <rasman.h>
  23. #include <raserror.h>
  24. #include <rasfile.h>
  25. #include <mprlog.h>
  26. #include <rtutils.h>
  27. #include <rasmxs.h>
  28. #include <wanpub.h>
  29. #include <asyncpub.h>
  30. #include <media.h>
  31. #include <serial.h>
  32. #include <serialpr.h>
  33. #include <stdlib.h>
  34. #include <malloc.h>
  35. #include <string.h>
  36. //* Global Variables *******************************************************
  37. //
  38. SERIALPCB *gpSerialPCB; // Points to Serial PCB linked list
  39. HANDLE ghRasfileMutex; // Mutex used to protect access to Rasfile
  40. HRASFILE ghIniFile; // Handle to Serial.ini memory image
  41. HANDLE ghAsyMac; // Handle to AsyncMac driver
  42. DWORD gLastError;
  43. //* Prototypes For APIs That Are Called Internally *************************
  44. //
  45. DWORD PortClearStatistics(HANDLE hIOPort);
  46. OVERLAPPED overlapped ;
  47. //* Initialization Routine *************************************************
  48. //
  49. //* SerialDllEntryPoint
  50. //
  51. // Function: Initializes Serial DLL when the DLL is loaded into memory,
  52. // and cleans up when the last process detaches from the DLL.
  53. //
  54. // Returns: TRUE if successful, else FALSE.
  55. //
  56. //*
  57. BOOL APIENTRY
  58. SerialDllEntryPoint(HANDLE hDll, DWORD dwReason, LPVOID pReserved)
  59. {
  60. static BOOL bFirstCall = TRUE;
  61. char szIniFilePath[MAX_PATH];
  62. WCHAR szDriverName[] = ASYNCMAC_FILENAME;
  63. DebugPrintf(("SerialDllEntryPoint\n"));
  64. //DbgPrint("SerialDllEntryPoint\n");
  65. switch(dwReason)
  66. {
  67. case DLL_PROCESS_ATTACH:
  68. if (bFirstCall)
  69. {
  70. DebugPrintf(("\tProcess Attach.\n"));
  71. // Open Serial.ini file
  72. *szIniFilePath = '\0';
  73. GetIniFileName(szIniFilePath, sizeof(szIniFilePath));
  74. ghIniFile = RasfileLoad(szIniFilePath, RFM_READONLY, NULL, NULL);
  75. DebugPrintf(("INI: %s, ghIniFile: 0x%08x\n", szIniFilePath, ghIniFile));
  76. /*
  77. if (ghIniFile == INVALID_HRASFILE)
  78. {
  79. LogError(ROUTERLOG_CANNOT_OPEN_SERIAL_INI, 0, NULL, 0xffffffff);
  80. return(FALSE);
  81. } */
  82. if ((ghRasfileMutex = CreateMutex (NULL,FALSE,NULL)) == NULL)
  83. return FALSE ;
  84. // Get handle to Asyncmac driver
  85. /*
  86. ghAsyMac = CreateFileW(szDriverName,
  87. GENERIC_READ | GENERIC_WRITE,
  88. FILE_SHARE_READ | FILE_SHARE_WRITE,
  89. NULL, //No security attribs
  90. OPEN_EXISTING,
  91. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  92. NULL); //No template file
  93. DebugPrintf(("ghAsyMac: 0x%08x\n", ghAsyMac));
  94. if (ghAsyMac == INVALID_HANDLE_VALUE)
  95. {
  96. DebugPrintf(("CreateFileError: %d\n", GetLastError()));
  97. LogError(ROUTERLOG_CANNOT_GET_ASYNCMAC_HANDLE, 0, NULL, 0xffffffff);
  98. return(FALSE);
  99. } */
  100. bFirstCall = FALSE;
  101. }
  102. break;
  103. case DLL_PROCESS_DETACH:
  104. DebugPrintf(("\tProcess Detach.\n"));
  105. if(INVALID_HANDLE_VALUE != ghRasfileMutex
  106. && NULL != ghRasfileMutex)
  107. {
  108. CloseHandle(ghRasfileMutex);
  109. ghRasfileMutex = INVALID_HANDLE_VALUE;
  110. }
  111. break;
  112. case DLL_THREAD_ATTACH:
  113. DebugPrintf(("\tThread Attach.\n"));
  114. break;
  115. case DLL_THREAD_DETACH:
  116. DebugPrintf(("\tThread Detach.\n"));
  117. break;
  118. }
  119. return(TRUE);
  120. UNREFERENCED_PARAMETER(hDll);
  121. UNREFERENCED_PARAMETER(pReserved);
  122. }
  123. //* Serial APIs ************************************************************
  124. //
  125. //* PortEnum ---------------------------------------------------------------
  126. //
  127. // Function: This API returns a buffer containing a PortMediaInfo struct.
  128. //
  129. // Returns: SUCCESS
  130. // ERROR_BUFFER_TOO_SMALL
  131. // ERROR_READING_SECTIONNAME
  132. // ERROR_READING_DEVICETYPE
  133. // ERROR_READING_DEVICENAME
  134. // ERROR_READING_USAGE
  135. // ERROR_BAD_USAGE_IN_INI_FILE
  136. //
  137. //*
  138. DWORD APIENTRY
  139. PortEnum(BYTE *pBuffer, DWORD *pdwSize, DWORD *pdwNumPorts)
  140. {
  141. DWORD dwAvailable;
  142. TCHAR szUsage[RAS_MAXLINEBUFLEN];
  143. CHAR szMacName[MAC_NAME_SIZE] ;
  144. PortMediaInfo *pPMI;
  145. BYTE buffer [1000] ;
  146. DWORD dwBytesReturned;
  147. memset (&overlapped, 0, sizeof (OVERLAPPED)) ;
  148. DebugPrintf(("PortEnum\n"));
  149. // Count number of sections in serial.ini
  150. *pdwNumPorts = 0;
  151. // Begin Exclusion
  152. WaitForSingleObject(ghRasfileMutex, INFINITE);
  153. if ( INVALID_HRASFILE != ghIniFile
  154. && RasfileFindFirstLine(ghIniFile, RFL_SECTION, RFS_FILE))
  155. (*pdwNumPorts)++;
  156. else
  157. {
  158. *pdwSize = 0;
  159. // End Exclusion
  160. ReleaseMutex(ghRasfileMutex);
  161. return(SUCCESS);
  162. }
  163. while(RasfileFindNextLine(ghIniFile, RFL_SECTION, RFS_FILE))
  164. (*pdwNumPorts)++;
  165. // End Exclusion
  166. ReleaseMutex(ghRasfileMutex);
  167. // Calculate size of buffer needed
  168. dwAvailable = *pdwSize;
  169. *pdwSize = sizeof(PortMediaInfo) * (*pdwNumPorts);
  170. if (*pdwSize > dwAvailable)
  171. return(ERROR_BUFFER_TOO_SMALL);
  172. // Translate serial.ini file section by section into pBuffer
  173. pPMI = (PortMediaInfo *) pBuffer;
  174. // Begin Exclusion
  175. WaitForSingleObject(ghRasfileMutex, INFINITE);
  176. RasfileFindFirstLine(ghIniFile, RFL_SECTION, RFS_FILE);
  177. #if 0
  178. // Need to get the MAC name
  179. if (!DeviceIoControl(ghAsyMac,
  180. IOCTL_ASYMAC_ENUM,
  181. buffer,
  182. sizeof(buffer),
  183. buffer,
  184. sizeof(buffer),
  185. &dwBytesReturned,
  186. &overlapped))
  187. {
  188. // End Exclusion
  189. ReleaseMutex(ghRasfileMutex);
  190. return(GetLastError());
  191. }
  192. wcstombs(szMacName, ((PASYMAC_ENUM)buffer)->AdapterInfo[0].MacName,
  193. wcslen(((PASYMAC_ENUM)buffer)->AdapterInfo[0].MacName)+1) ;
  194. #else
  195. szMacName[0] = '\0' ;
  196. #endif
  197. do
  198. {
  199. // Get Section Name (same as Port Name)
  200. if (!RasfileGetSectionName(ghIniFile, pPMI->PMI_Name))
  201. {
  202. // End Exclusion
  203. ReleaseMutex(ghRasfileMutex);
  204. return(ERROR_READING_SECTIONNAME);
  205. }
  206. // Set Binding Name
  207. strcpy (pPMI->PMI_MacBindingName, szMacName) ;
  208. // Get Device Type
  209. if(!(RasfileFindNextKeyLine(ghIniFile, SER_DEVICETYPE_KEY, RFS_SECTION) &&
  210. RasfileGetKeyValueFields(ghIniFile, NULL, pPMI->PMI_DeviceType)))
  211. {
  212. // End Exclusion
  213. ReleaseMutex(ghRasfileMutex);
  214. return(ERROR_READING_DEVICETYPE);
  215. }
  216. // Get Device Name
  217. if (!(RasfileFindFirstLine(ghIniFile, RFL_SECTION, RFS_SECTION) &&
  218. RasfileFindNextKeyLine(ghIniFile, SER_DEVICENAME_KEY, RFS_SECTION) &&
  219. RasfileGetKeyValueFields(ghIniFile, NULL, pPMI->PMI_DeviceName)))
  220. {
  221. // End Exclusion
  222. ReleaseMutex(ghRasfileMutex);
  223. return(ERROR_READING_DEVICENAME);
  224. }
  225. // Get Usage
  226. if (!(RasfileFindFirstLine(ghIniFile, RFL_SECTION, RFS_SECTION) &&
  227. RasfileFindNextKeyLine(ghIniFile, SER_USAGE_KEY, RFS_SECTION) &&
  228. RasfileGetKeyValueFields(ghIniFile, NULL, szUsage)))
  229. {
  230. // End Exclusion
  231. ReleaseMutex(ghRasfileMutex);
  232. return(ERROR_READING_USAGE);
  233. }
  234. if (!StrToUsage(szUsage, &(pPMI->PMI_Usage)))
  235. {
  236. // End Exclusion
  237. ReleaseMutex(ghRasfileMutex);
  238. return(ERROR_BAD_USAGE_IN_INI_FILE);
  239. }
  240. pPMI->PMI_LineDeviceId = INVALID_TAPI_ID;
  241. pPMI->PMI_AddressId = INVALID_TAPI_ID;
  242. pPMI++;
  243. }while(RasfileFindNextLine(ghIniFile, RFL_SECTION, RFS_FILE));
  244. // End Exclusion
  245. ReleaseMutex(ghRasfileMutex);
  246. return(SUCCESS);
  247. }
  248. //* PortOpen ---------------------------------------------------------------
  249. //
  250. // Function: This API opens a COM port. It takes the port name in ASCIIZ
  251. // form and supplies a handle to the open port. hNotify is use
  252. // to notify the caller if the device on the port shuts down.
  253. //
  254. // PortOpen allocates a SerialPCB and places it at the head of
  255. // the linked list of Serial Port Control Blocks.
  256. //
  257. // Returns: SUCCESS
  258. // ERROR_PORT_NOT_CONFIGURED
  259. // ERROR_DEVICE_NOT_READY
  260. //
  261. //*
  262. DWORD APIENTRY
  263. PortOpen(
  264. char *pszPortName,
  265. HANDLE *phIOPort,
  266. HANDLE hIoCompletionPort,
  267. DWORD dwCompletionKey)
  268. {
  269. SERIALPCB *pSPCB ;
  270. DWORD dwRC, dwStatus = 0;
  271. TCHAR szPort[MAX_PATH];
  272. WCHAR szDriverName[] = ASYNCMAC_FILENAME;
  273. try
  274. {
  275. DebugPrintf(("PortOpen: %s\n", pszPortName));
  276. // Check serial.ini to see that pszPortName is configured for RAS
  277. // Begin Exclusion
  278. if(INVALID_HRASFILE == ghIniFile)
  279. {
  280. return ERROR_PORT_NOT_CONFIGURED;
  281. }
  282. WaitForSingleObject(ghRasfileMutex, INFINITE);
  283. #if DBG
  284. ASSERT(INVALID_HRASFILE != ghIniFile );
  285. #endif
  286. if (!RasfileFindSectionLine(ghIniFile, pszPortName, FROM_TOP_OF_FILE))
  287. {
  288. // End Exclusion
  289. ReleaseMutex(ghRasfileMutex);
  290. return(ERROR_PORT_NOT_CONFIGURED);
  291. }
  292. // End Exclusion
  293. ReleaseMutex(ghRasfileMutex);
  294. // Prepend \\.\ to COMx
  295. strcpy(szPort, "\\\\.\\");
  296. strcat(szPort, pszPortName);
  297. // Open Port
  298. *phIOPort = CreateFile(szPort,
  299. GENERIC_READ | GENERIC_WRITE,
  300. FILE_EXCLUSIVE_MODE,
  301. NULL, //No Security Attributes
  302. OPEN_EXISTING,
  303. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  304. NULL); //No Template File
  305. DebugPrintf(("hioport: 0x%08x\n", *phIOPort));
  306. //DbgPrint("hioport: 0x%08x\n", *phIOPort);
  307. if (*phIOPort == INVALID_HANDLE_VALUE)
  308. {
  309. dwRC = GetLastError();
  310. if (dwRC == ERROR_ACCESS_DENIED)
  311. return (ERROR_PORT_ALREADY_OPEN);
  312. else if (dwRC == ERROR_FILE_NOT_FOUND)
  313. return (ERROR_PORT_NOT_FOUND) ;
  314. else
  315. return(dwRC);
  316. }
  317. //
  318. // Associate an I/O completion port with
  319. // the file handle.
  320. //
  321. if (CreateIoCompletionPort(
  322. *phIOPort,
  323. hIoCompletionPort,
  324. dwCompletionKey,
  325. 0) == NULL)
  326. {
  327. return GetLastError();
  328. }
  329. #ifdef notdef
  330. {
  331. DWORD dwBytesReturned ;
  332. #define FILE_DEVICE_SERIAL_PORT 0x0000001b
  333. #define _SERIAL_CONTROL_CODE(request,method) \
  334. ((FILE_DEVICE_SERIAL_PORT)<<16 | (request<<2) | method)
  335. #define IOCTL_SERIAL_PRIVATE_RAS _SERIAL_CONTROL_CODE(4000, METHOD_BUFFERED)
  336. DeviceIoControl(*phIOPort,
  337. IOCTL_SERIAL_PRIVATE_RAS,
  338. NULL,
  339. 0,
  340. NULL,
  341. 0,
  342. &dwBytesReturned,
  343. NULL) ;
  344. }
  345. #endif
  346. // Set Queue sizes and default values for Comm Port
  347. if (!SetupComm(*phIOPort, INPUT_QUEUE_SIZE, OUTPUT_QUEUE_SIZE))
  348. {
  349. LogError(ROUTERLOG_SERIAL_QUEUE_SIZE_SMALL, 0, NULL, 0xffffffff);
  350. }
  351. SetCommDefaults(*phIOPort, pszPortName);
  352. // Add a Serial PCB to head of list and set eDeviceType
  353. AddPortToList(*phIOPort, pszPortName);
  354. pSPCB = FindPortInList(*phIOPort, NULL) ; //Find port just added
  355. if(NULL == pSPCB)
  356. {
  357. return ERROR_PORT_NOT_FOUND;
  358. }
  359. // Get handle to Asyncmac driver
  360. pSPCB->hAsyMac = CreateFileW(szDriverName,
  361. GENERIC_READ | GENERIC_WRITE,
  362. FILE_SHARE_READ | FILE_SHARE_WRITE,
  363. NULL, //No security attribs
  364. OPEN_EXISTING,
  365. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  366. NULL); //No template file
  367. DebugPrintf(("pSPCB->hAsyMac: 0x%08x\n", pSPCB->hAsyMac));
  368. //DbgPrint("pSPCB->hAsyMac: 0x%08x\n", pSPCB->hAsyMac);
  369. if (pSPCB->hAsyMac == INVALID_HANDLE_VALUE)
  370. {
  371. DWORD dwErr;
  372. dwErr = GetLastError();
  373. DebugPrintf(("CreateFileError: %d\n", dwErr));
  374. //DbgPrint("CreateFileError: %d\n", dwErr);
  375. LogError(ROUTERLOG_CANNOT_GET_ASYNCMAC_HANDLE, 0, NULL, 0xffffffff);
  376. return(dwErr);
  377. }
  378. //
  379. // Associate the I/O completion port with
  380. // the asyncmac file handle
  381. //
  382. if (CreateIoCompletionPort(pSPCB->hAsyMac,
  383. hIoCompletionPort,
  384. dwCompletionKey,
  385. 0) == NULL)
  386. {
  387. DWORD dwErr;
  388. dwErr = GetLastError();
  389. //DbgPrint("PortOpen: Failed to create IoCompletionPort %d\n", dwErr);
  390. return dwErr;
  391. }
  392. dwRC = InitCarrierBps(pszPortName, pSPCB->szCarrierBPS);
  393. if (dwRC != SUCCESS)
  394. {
  395. gLastError = dwRC;
  396. RaiseException(EXCEPT_RAS_MEDIA, EXCEPTION_NONCONTINUABLE, 0, NULL);
  397. }
  398. // Check that device is powered on and ready (DSR is up) If it is then
  399. // we monitor DSR - else - we do not monitor DSR until we are connected.
  400. //
  401. GetCommModemStatus(*phIOPort, &dwStatus);
  402. pSPCB->dwPreviousModemStatus = 0;
  403. if ( ! (dwStatus & MS_DSR_ON))
  404. // DSR is not raised by the device = assume that it will not raise
  405. // it until its connected.
  406. //
  407. pSPCB->dwActiveDSRMask = pSPCB->dwMonitorDSRMask = 0 ;
  408. else {
  409. // Tell system to signal rasman if DSR drops
  410. pSPCB->dwActiveDSRMask = pSPCB->dwMonitorDSRMask = EV_DSR ;
  411. //DbgPrint("PortOpen: Setting mask 0x%x\n", EV_DSR);
  412. SetCommMask(*phIOPort, EV_DSR);
  413. if (!WaitCommEvent(*phIOPort,
  414. &(pSPCB->dwEventMask),
  415. (LPOVERLAPPED)&(pSPCB->MonitorDevice)))
  416. {
  417. //DbgPrint("PortOpen: WaitCommEvent. %d\n", GetLastError());
  418. }
  419. }
  420. // Set values in Serial Port Control Block
  421. GetDefaultOffStr(*phIOPort, pszPortName);
  422. }
  423. except(exception_code()==EXCEPT_RAS_MEDIA ? HANDLE_EXCEPTION:CONTINUE_SEARCH)
  424. {
  425. return(gLastError);
  426. }
  427. return(SUCCESS);
  428. }
  429. //* PortClose --------------------------------------------------------------
  430. //
  431. // Function: This API closes the COM port for the input handle. It also
  432. // finds the SerialPCB for the input handle, removes it from
  433. // the linked list, and frees the memory for it
  434. //
  435. // Returns: SUCCESS
  436. // Values returned by GetLastError()
  437. //
  438. //*
  439. DWORD APIENTRY
  440. PortClose (HANDLE hIOPort)
  441. {
  442. SERIALPCB *pPrev, *pSPCB = gpSerialPCB;
  443. DebugPrintf(("PortClose\n"));
  444. // Find the SerialPCB which contains hIOPOrt
  445. pSPCB = FindPortInList(hIOPort, &pPrev);
  446. if (pSPCB == NULL)
  447. return(ERROR_PORT_NOT_OPEN);
  448. // Remove the found SerialPCB
  449. if (pSPCB == gpSerialPCB)
  450. gpSerialPCB = pSPCB->pNextSPCB;
  451. else
  452. pPrev->pNextSPCB = pSPCB->pNextSPCB;
  453. // Cancel wait on this port (WaitCommEvent)
  454. //
  455. //DbgPrint("PortClose: Setting mask to 0\n");
  456. SetCommMask(hIOPort, 0);
  457. // Drop DTR
  458. //
  459. EscapeCommFunction(hIOPort, CLRDTR);
  460. // Close COM Port
  461. //
  462. if (!CloseHandle(hIOPort))
  463. return(GetLastError());
  464. // close the asymac file we associated with this com port
  465. if (!CloseHandle(pSPCB->hAsyMac))
  466. return GetLastError();
  467. // Free portcontrolblock: note this must be done after CloseHandle since the struct
  468. // contains an overlapped struct used for i/o on the port. this overlapped struct
  469. // is freed when the handle to the port is closed.
  470. //
  471. free(pSPCB);
  472. return(SUCCESS);
  473. }
  474. //* PortGetInfo ------------------------------------------------------------
  475. //
  476. // Function: This API returns a block of information to the caller about
  477. // the port state. This API may be called before the port is
  478. // open in which case it will return inital default values
  479. // instead of actual port values.
  480. //
  481. // If the API is to be called before the port is open, set hIOPort
  482. // to INVALID_HANDLE_VALUE and pszPortName to the port name. If
  483. // hIOPort is valid (the port is open), pszPortName may be set
  484. // to NULL.
  485. //
  486. // hIOPort pSPCB := FindPortNameInList() Port
  487. // ------- ----------------------------- ------
  488. // valid x open
  489. // invalid non_null open
  490. // invalid null closed
  491. //
  492. // Returns: SUCCESS
  493. // ERROR_BUFFER_TOO_SMALL
  494. //*
  495. DWORD APIENTRY
  496. PortGetInfo(HANDLE hIOPort, TCHAR *pszPortName, BYTE *pBuffer, DWORD *pdwSize)
  497. {
  498. SERIALPCB *pSPCB;
  499. DCB DCB;
  500. RAS_PARAMS *pParam;
  501. TCHAR *pValue;
  502. TCHAR szDefaultOff[RAS_MAXLINEBUFLEN];
  503. TCHAR szClientDefaultOff[RAS_MAXLINEBUFLEN];
  504. TCHAR szDeviceType[MAX_DEVICETYPE_NAME + 1];
  505. TCHAR szDeviceName[MAX_DEVICE_NAME + 1];
  506. TCHAR szPortName[MAX_PORT_NAME + 1];
  507. TCHAR szConnectBPS[MAX_BPS_STR_LEN], szCarrierBPS[MAX_BPS_STR_LEN];
  508. DWORD dwConnectBPSLen, dwCarrierBPSLen, dwDefaultOffLen;
  509. DWORD dwDeviceTypeLen, dwDeviceNameLen, dwPortNameLen;
  510. DWORD dwClientDefaultOffLen;
  511. DWORD dwStructSize;
  512. DWORD dwAvailable, dwNumOfParams = 12;
  513. try
  514. {
  515. DebugPrintf(("PortGetInfo\n"));
  516. if (hIOPort == INVALID_HANDLE_VALUE &&
  517. (pSPCB = FindPortNameInList(pszPortName)) == NULL)
  518. {
  519. // Port is not yet open
  520. // Read from Serial.ini
  521. GetValueFromFile(pszPortName, SER_DEFAULTOFF_KEY, szDefaultOff);
  522. GetValueFromFile(pszPortName, SER_MAXCONNECTBPS_KEY, szConnectBPS);
  523. GetValueFromFile(pszPortName, SER_MAXCARRIERBPS_KEY, szCarrierBPS);
  524. GetValueFromFile(pszPortName, SER_DEVICETYPE_KEY, szDeviceType);
  525. GetValueFromFile(pszPortName, SER_DEVICENAME_KEY, szDeviceName);
  526. strcpy(szPortName, pszPortName);
  527. // Set RAS default values in the DCB
  528. SetDcbDefaults(&DCB);
  529. }
  530. else
  531. {
  532. // Port is open; Get a Device Control Block with current port values
  533. if (hIOPort != INVALID_HANDLE_VALUE)
  534. {
  535. pSPCB = FindPortInList(hIOPort, NULL);
  536. if (pSPCB == NULL)
  537. {
  538. gLastError = ERROR_PORT_NOT_OPEN;
  539. RaiseException(EXCEPT_RAS_MEDIA, EXCEPTION_NONCONTINUABLE, 0, NULL);
  540. }
  541. }
  542. if (!GetCommState(pSPCB->hIOPort, &DCB))
  543. {
  544. gLastError = GetLastError();
  545. RaiseException(EXCEPT_RAS_MEDIA, EXCEPTION_NONCONTINUABLE, 0, NULL);
  546. }
  547. _itoa(DCB.BaudRate, szConnectBPS, 10);
  548. strcpy(szCarrierBPS, pSPCB->szCarrierBPS);
  549. strcpy(szDefaultOff, pSPCB->szDefaultOff);
  550. strcpy(szDeviceType, pSPCB->szDeviceType);
  551. strcpy(szDeviceName, pSPCB->szDeviceName);
  552. strcpy(szPortName, pSPCB->szPortName);
  553. }
  554. // Read from Serial.ini even if port is open
  555. GetValueFromFile(szPortName, SER_C_DEFAULTOFFSTR_KEY, szClientDefaultOff);
  556. // Calculate Buffer size needed
  557. dwStructSize = sizeof(RASMAN_PORTINFO)
  558. + sizeof(RAS_PARAMS) * (dwNumOfParams - 1);
  559. dwConnectBPSLen = strlen(szConnectBPS);
  560. dwCarrierBPSLen = strlen(szCarrierBPS);
  561. dwDeviceTypeLen = strlen(szDeviceType);
  562. dwDeviceNameLen = strlen(szDeviceName);
  563. dwDefaultOffLen = strlen(szDefaultOff);
  564. dwPortNameLen = strlen(szPortName);
  565. dwClientDefaultOffLen = strlen(szClientDefaultOff);
  566. dwAvailable = *pdwSize;
  567. *pdwSize = (dwStructSize + dwConnectBPSLen + dwCarrierBPSLen
  568. + dwDeviceTypeLen + dwDeviceNameLen
  569. + dwDefaultOffLen + dwPortNameLen
  570. + dwClientDefaultOffLen +
  571. + 7L); //Zero bytes
  572. if (*pdwSize > dwAvailable)
  573. return(ERROR_BUFFER_TOO_SMALL);
  574. // Fill in Buffer
  575. ((RASMAN_PORTINFO *)pBuffer)->PI_NumOfParams = ( WORD ) dwNumOfParams;
  576. pParam = ((RASMAN_PORTINFO *)pBuffer)->PI_Params;
  577. pValue = pBuffer + dwStructSize;
  578. strcpy(pParam->P_Key, SER_CONNECTBPS_KEY);
  579. pParam->P_Type = String;
  580. pParam->P_Attributes = 0;
  581. pParam->P_Value.String.Length = dwConnectBPSLen;
  582. pParam->P_Value.String.Data = pValue;
  583. strcpy(pParam->P_Value.String.Data, szConnectBPS);
  584. pValue += dwConnectBPSLen + 1;
  585. pParam++;
  586. strcpy(pParam->P_Key, SER_DATABITS_KEY);
  587. pParam->P_Type = Number;
  588. pParam->P_Attributes = 0;
  589. pParam->P_Value.Number = DCB.ByteSize;
  590. pParam++;
  591. strcpy(pParam->P_Key, SER_PARITY_KEY);
  592. pParam->P_Type = Number;
  593. pParam->P_Attributes = 0;
  594. pParam->P_Value.Number = DCB.Parity;
  595. pParam++;
  596. strcpy(pParam->P_Key, SER_STOPBITS_KEY);
  597. pParam->P_Type = Number;
  598. pParam->P_Attributes = 0;
  599. pParam->P_Value.Number = DCB.StopBits;
  600. pParam++;
  601. strcpy(pParam->P_Key, SER_HDWFLOWCTRLON_KEY);
  602. pParam->P_Type = Number;
  603. pParam->P_Attributes = 0;
  604. pParam->P_Value.Number = DCB.fOutxCtsFlow;
  605. pParam++;
  606. strcpy(pParam->P_Key, SER_CARRIERBPS_KEY);
  607. pParam->P_Type = String;
  608. pParam->P_Attributes = 0;
  609. pParam->P_Value.String.Length = dwCarrierBPSLen;
  610. pParam->P_Value.String.Data = pValue;
  611. strcpy(pParam->P_Value.String.Data, szCarrierBPS);
  612. pValue += dwCarrierBPSLen + 1;
  613. pParam++;
  614. strcpy(pParam->P_Key, SER_ERRORCONTROLON_KEY);
  615. pParam->P_Type = Number;
  616. pParam->P_Attributes = 0;
  617. if (pSPCB == NULL)
  618. pParam->P_Value.Number = FALSE;
  619. else
  620. pParam->P_Value.Number = pSPCB->bErrorControlOn;
  621. pParam++;
  622. strcpy(pParam->P_Key, SER_DEFAULTOFFSTR_KEY);
  623. pParam->P_Type = String;
  624. pParam->P_Attributes = 0;
  625. pParam->P_Value.String.Length = dwDefaultOffLen;
  626. pParam->P_Value.String.Data = pValue;
  627. strcpy(pParam->P_Value.String.Data, szDefaultOff);
  628. pValue += dwDefaultOffLen + 1;
  629. pParam++;
  630. strcpy(pParam->P_Key, SER_DEVICETYPE_KEY);
  631. pParam->P_Type = String;
  632. pParam->P_Attributes = 0;
  633. pParam->P_Value.String.Length = dwDeviceTypeLen;
  634. pParam->P_Value.String.Data = pValue;
  635. strcpy(pParam->P_Value.String.Data, szDeviceType);
  636. pValue += dwDeviceTypeLen + 1;
  637. pParam++;
  638. strcpy(pParam->P_Key, SER_DEVICENAME_KEY);
  639. pParam->P_Type = String;
  640. pParam->P_Attributes = 0;
  641. pParam->P_Value.String.Length = dwDeviceNameLen;
  642. pParam->P_Value.String.Data = pValue;
  643. strcpy(pParam->P_Value.String.Data, szDeviceName);
  644. pValue += dwDeviceNameLen + 1;
  645. pParam++;
  646. strcpy(pParam->P_Key, SER_PORTNAME_KEY);
  647. pParam->P_Type = String;
  648. pParam->P_Attributes = 0;
  649. pParam->P_Value.String.Length = dwPortNameLen;
  650. pParam->P_Value.String.Data = pValue;
  651. strcpy(pParam->P_Value.String.Data, szPortName);
  652. pValue += dwPortNameLen + 1;
  653. pParam++;
  654. strcpy(pParam->P_Key, SER_C_DEFAULTOFFSTR_KEY);
  655. pParam->P_Type = String;
  656. pParam->P_Attributes = 0;
  657. pParam->P_Value.String.Length = dwClientDefaultOffLen;
  658. pParam->P_Value.String.Data = pValue;
  659. strcpy(pParam->P_Value.String.Data, szClientDefaultOff);
  660. //pValue += dwClientDefaultOffLen + 1;
  661. return(SUCCESS);
  662. }
  663. except(exception_code()==EXCEPT_RAS_MEDIA ? HANDLE_EXCEPTION:CONTINUE_SEARCH)
  664. {
  665. return(gLastError);
  666. }
  667. }
  668. //* PortSetInfo ------------------------------------------------------------
  669. //
  670. // Function: The values for most input keys are used to set the port
  671. // parameters directly. However, the carrier BPS and the
  672. // error conrol on flag set fields in the Serial Port Control
  673. // Block only, and not the port.
  674. //
  675. // Returns: SUCCESS
  676. // ERROR_WRONG_INFO_SPECIFIED
  677. // Values returned by GetLastError()
  678. //*
  679. DWORD APIENTRY
  680. PortSetInfo(HANDLE hIOPort, RASMAN_PORTINFO *pInfo)
  681. {
  682. RAS_PARAMS *p;
  683. SERIALPCB *pSPCB;
  684. DCB DCB;
  685. WORD i;
  686. BOOL bTypeError = FALSE;
  687. try
  688. {
  689. DebugPrintf(("PortSetInfo\n\thPort = %d\n", hIOPort));
  690. // Find the SerialPCB which contains hIOPOrt
  691. pSPCB = FindPortInList(hIOPort, NULL);
  692. if (pSPCB == NULL)
  693. {
  694. gLastError = ERROR_PORT_NOT_OPEN;
  695. RaiseException(EXCEPT_RAS_MEDIA, EXCEPTION_NONCONTINUABLE, 0, NULL);
  696. }
  697. // Get a Device Control Block with current port values
  698. if (!GetCommState(hIOPort, &DCB))
  699. return(GetLastError());
  700. // Set DCB and PCB values
  701. for (i=0, p=pInfo->PI_Params; i<pInfo->PI_NumOfParams; i++, p++)
  702. {
  703. // Set DCB values
  704. if (_stricmp(p->P_Key, SER_CONNECTBPS_KEY) == 0)
  705. DCB.BaudRate = ValueToNum(p);
  706. else if (_stricmp(p->P_Key, SER_DATABITS_KEY) == 0)
  707. DCB.ByteSize = (BYTE) ValueToNum(p);
  708. else if (_stricmp(p->P_Key, SER_PARITY_KEY) == 0)
  709. DCB.Parity = (BYTE) ValueToNum(p);
  710. else if (_stricmp(p->P_Key, SER_STOPBITS_KEY) == 0)
  711. DCB.StopBits = (BYTE) ValueToNum(p);
  712. else if (_stricmp(p->P_Key, SER_HDWFLOWCTRLON_KEY) == 0)
  713. DCB.fOutxCtsFlow = ValueToBool(p);
  714. // Set PCB values
  715. else if (_stricmp(p->P_Key, SER_CARRIERBPS_KEY) == 0)
  716. if (p->P_Type == String)
  717. {
  718. strncpy(pSPCB->szCarrierBPS,
  719. p->P_Value.String.Data,
  720. p->P_Value.String.Length);
  721. pSPCB->szCarrierBPS[p->P_Value.String.Length] = '\0';
  722. }
  723. else
  724. _itoa(p->P_Value.Number, pSPCB->szCarrierBPS, 10);
  725. else if (_stricmp(p->P_Key, SER_ERRORCONTROLON_KEY) == 0)
  726. pSPCB->bErrorControlOn = ValueToBool(p);
  727. else if (_stricmp(p->P_Key, SER_DEFAULTOFF_KEY) == 0)
  728. if (p->P_Type == String)
  729. {
  730. strncpy(pSPCB->szDefaultOff,
  731. p->P_Value.String.Data,
  732. p->P_Value.String.Length);
  733. pSPCB->szDefaultOff[p->P_Value.String.Length] = '\0';
  734. }
  735. else
  736. pSPCB->szDefaultOff[0] = USE_DEVICE_INI_DEFAULT;
  737. else
  738. return(ERROR_WRONG_INFO_SPECIFIED);
  739. } // for
  740. // Send DCB to Port
  741. if (!SetCommState(hIOPort, &DCB))
  742. return(GetLastError());
  743. return(SUCCESS);
  744. }
  745. except(exception_code()==EXCEPT_RAS_MEDIA ? HANDLE_EXCEPTION:CONTINUE_SEARCH)
  746. {
  747. return(gLastError);
  748. }
  749. }
  750. //* PortTestSignalState ----------------------------------------------------
  751. //
  752. // Function: This API indicates the state of the DSR and DTR lines.
  753. // DSR - Data Set Ready
  754. // DCD - Data Carrier Detect (RLSD - Received Line Signal Detect)
  755. //
  756. // Returns: SUCCESS
  757. // Values returned by GetLastError()
  758. //
  759. //*
  760. DWORD APIENTRY
  761. PortTestSignalState(HANDLE hIOPort, DWORD *pdwDeviceState)
  762. {
  763. DWORD dwModemStatus;
  764. SERIALPCB *pSPCB;
  765. DWORD dwSetMask = 0 ;
  766. DebugPrintf(("PortTestSignalState\n"));
  767. *pdwDeviceState = 0;
  768. if ((pSPCB = FindPortInList (hIOPort, NULL)) == NULL)
  769. return ERROR_PORT_NOT_OPEN ;
  770. if (!GetCommModemStatus(hIOPort, &dwModemStatus))
  771. {
  772. *pdwDeviceState = 0xffffffff;
  773. return(GetLastError());
  774. }
  775. // If DSR is down AND it was up before then mark it as a hw failure.
  776. //
  777. if ((!(dwModemStatus & MS_DSR_ON)) && (pSPCB->dwMonitorDSRMask))
  778. *pdwDeviceState |= SS_HARDWAREFAILURE;
  779. // Similarly, if DCD is down and it was up before then link has dropped.
  780. //
  781. if (!(dwModemStatus & MS_RLSD_ON))
  782. *pdwDeviceState |= SS_LINKDROPPED;
  783. else
  784. dwSetMask = EV_RLSD ;
  785. if (pSPCB->uRasEndpoint != INVALID_HANDLE_VALUE) {
  786. ASYMAC_DCDCHANGE A ;
  787. DWORD dwBytesReturned;
  788. A.MacAdapter = NULL ;
  789. A.hNdisEndpoint = (HANDLE) pSPCB->uRasEndpoint ;
  790. DeviceIoControl(pSPCB->hAsyMac,
  791. IOCTL_ASYMAC_DCDCHANGE,
  792. &A,
  793. sizeof(A),
  794. &A,sizeof(A),
  795. &dwBytesReturned,
  796. (LPOVERLAPPED)&(pSPCB->MonitorDevice)) ;
  797. } else {
  798. dwSetMask |= (pSPCB->dwMonitorDSRMask) ; // Only monitor DSR if it is used.
  799. if (dwSetMask == 0)
  800. return (SUCCESS) ; // do not set wait mask.
  801. if (dwModemStatus == pSPCB->dwPreviousModemStatus)
  802. {
  803. //DbgPrint("PortTestSignalState: Modemstatus hasn't changed\n");
  804. return SUCCESS;
  805. }
  806. else
  807. pSPCB->dwPreviousModemStatus = dwModemStatus;
  808. //DbgPrint("PortTestSignalState: Setting mask ox%x\n", dwSetMask);
  809. SetCommMask(hIOPort, dwSetMask);
  810. // Start a new wait on signal lines (DSR and/or DCD)
  811. if (!WaitCommEvent(hIOPort,
  812. &(pSPCB->dwEventMask),
  813. (LPOVERLAPPED)&(pSPCB->MonitorDevice)))
  814. {
  815. //DbgPrint("PortTestSignalState: WaitCommEvent. %d\n", GetLastError());
  816. }
  817. }
  818. return(SUCCESS);
  819. }
  820. //* PortConnect ------------------------------------------------------------
  821. //
  822. // Function: This API is called when a connection has been completed and some
  823. // steps need to be taken, If bWaitForDevice is set then we monitor DCD only
  824. // else,
  825. // It in turn calls the asyncmac device driver in order to
  826. // indicate to asyncmac that the port and the connection
  827. // over it are ready for commumication.
  828. //
  829. // pdwCompressionInfo is an output only parameter which
  830. // indicates the type(s) of compression supported by the MAC.
  831. //
  832. // bWaitForDevice is set to TRUE when we just want to start monitoring DCD
  833. //
  834. // Returns: SUCCESS
  835. // ERROR_PORT_NOT_OPEN
  836. // ERROR_NO_CONNECTION
  837. // Values returned by GetLastError()
  838. //
  839. //*
  840. DWORD APIENTRY
  841. PortConnect(HANDLE hIOPort,
  842. BOOL bWaitForDevice,
  843. HANDLE *pRasEndpoint)
  844. {
  845. ASYMAC_OPEN AsyMacOpen;
  846. ASYMAC_DCDCHANGE A ;
  847. SERIALPCB *pSPCB;
  848. BOOL bPadDevice;
  849. DWORD dwModemStatus, dwBytesReturned;
  850. TCHAR szDeviceType[RAS_MAXLINEBUFLEN];
  851. // This is a special mode of PortConnect where all we do is start monitoring DCD
  852. // Hand off to asyncmac does not happen till the next call to port connect where the
  853. // bWaitForDevice flag is false
  854. //
  855. if (bWaitForDevice) {
  856. pSPCB = FindPortInList(hIOPort, NULL);
  857. if (pSPCB == NULL)
  858. {
  859. gLastError = ERROR_PORT_NOT_OPEN;
  860. return ERROR_NO_CONNECTION ;
  861. }
  862. if (!GetCommModemStatus(hIOPort, &dwModemStatus))
  863. return(GetLastError());
  864. // UPDATE the DSR monitoring
  865. //
  866. if (!(dwModemStatus & MS_DSR_ON))
  867. pSPCB->dwMonitorDSRMask = 0 ;
  868. else
  869. pSPCB->dwMonitorDSRMask = EV_DSR ;
  870. // Tell serial driver to signal rasman if DCD, (and DSR, if it was used) drop
  871. //
  872. //DbgPrint("PortConnect: Setting mask to 0x%x\n",EV_RLSD | (pSPCB->dwMonitorDSRMask));
  873. if (!SetCommMask(hIOPort, EV_RLSD | (pSPCB->dwMonitorDSRMask)))
  874. return(GetLastError());
  875. WaitCommEvent(hIOPort,
  876. &(pSPCB->dwEventMask),
  877. (LPOVERLAPPED) &(pSPCB->MonitorDevice)) ;
  878. return SUCCESS ;
  879. }
  880. // Else we do both - change DCD monitoring and handing off context to asyncmac
  881. //
  882. memset (&overlapped, 0, sizeof (OVERLAPPED)) ;
  883. try
  884. {
  885. DebugPrintf(("PortConnect\n"));
  886. // Find port in list
  887. pSPCB = FindPortInList(hIOPort, NULL);
  888. if (pSPCB == NULL)
  889. {
  890. gLastError = ERROR_PORT_NOT_OPEN;
  891. RaiseException(EXCEPT_RAS_MEDIA, EXCEPTION_NONCONTINUABLE, 0, NULL);
  892. }
  893. //Make sure connection is still up
  894. if (!GetCommModemStatus(hIOPort, &dwModemStatus))
  895. return(GetLastError());
  896. // Make sure that DSR is still up (if it ever was up!)
  897. if ((!(dwModemStatus & MS_DSR_ON)) && (pSPCB->dwMonitorDSRMask)) {
  898. OutputDebugString ("DSR down!!!\r\n") ;
  899. return(ERROR_NO_CONNECTION); //Device is down
  900. }
  901. if (!(dwModemStatus & MS_RLSD_ON) ) {
  902. OutputDebugString ("DCD down!!!\r\n") ;
  903. return(ERROR_NO_CONNECTION); //DCD is down
  904. }
  905. // // UPDATE the DSR monitoring
  906. // //
  907. // if ( ! (dwModemStatus & MS_DSR_ON)) {
  908. // pSPCB->dwMonitorDSRMask = 0 ;
  909. // } else {
  910. // pSPCB->dwMonitorDSRMask = EV_DSR ;
  911. // }
  912. //
  913. // // Tell system to signal rasman if DCD, (and DSR, if it was used) drop
  914. //
  915. // if (!SetCommMask(hIOPort, EV_RLSD | (pSPCB->dwMonitorDSRMask)))
  916. // return(GetLastError());
  917. //
  918. // WaitCommEvent(hIOPort,
  919. // &(pSPCB->dwEventMask),
  920. // &(pSPCB->MonitorDevice)) ;
  921. //Put endpoint in Serial PCB for later use by PortDisconnect
  922. //Find if device type is Pad
  923. GetValueFromFile(pSPCB->szPortName, SER_DEVICETYPE_KEY, szDeviceType);
  924. bPadDevice = (_stricmp(szDeviceType, MXS_PAD_TXT) == 0);
  925. // Let the ASYMAC notify us of DCD and DSR change
  926. //
  927. //DbgPrint("PortConnect: Setting mask to 0\n");
  928. if (!SetCommMask(hIOPort, 0)) // Set mask to stop monitoring DCD
  929. return(GetLastError());
  930. //Open AsyncMac (Hand off port to AsyncMac)
  931. AsyMacOpen.hNdisEndpoint = INVALID_HANDLE_VALUE ;
  932. AsyMacOpen.LinkSpeed = (atoi(pSPCB->szCarrierBPS) == 0) ?
  933. 14400 :
  934. atoi(pSPCB->szCarrierBPS) ;
  935. AsyMacOpen.FileHandle = hIOPort;
  936. if (bPadDevice || pSPCB->bErrorControlOn)
  937. AsyMacOpen.QualOfConnect = (UINT)NdisWanErrorControl;
  938. else
  939. AsyMacOpen.QualOfConnect = (UINT)NdisWanRaw;
  940. if (!DeviceIoControl(pSPCB->hAsyMac,
  941. IOCTL_ASYMAC_OPEN,
  942. &AsyMacOpen,
  943. sizeof(AsyMacOpen),
  944. &AsyMacOpen,
  945. sizeof(AsyMacOpen),
  946. &dwBytesReturned,
  947. &overlapped))
  948. {
  949. // Clear the stored end point, so that if it failed to open
  950. // no attempt will be made to close it.
  951. pSPCB->uRasEndpoint = INVALID_HANDLE_VALUE;
  952. return(GetLastError());
  953. } else
  954. pSPCB->uRasEndpoint = AsyMacOpen.hNdisEndpoint;
  955. *pRasEndpoint = AsyMacOpen.hNdisEndpoint ;
  956. //DbgPrint("PortConnect: RasEndpoint = 0x%x\n", *pRasEndpoint);
  957. A.hNdisEndpoint = (HANDLE) *pRasEndpoint ;
  958. A.MacAdapter = NULL ;
  959. if (!DeviceIoControl(pSPCB->hAsyMac,
  960. IOCTL_ASYMAC_DCDCHANGE,
  961. &A,
  962. sizeof(A),
  963. &A,
  964. sizeof(A),
  965. &dwBytesReturned,
  966. (LPOVERLAPPED)&(pSPCB->MonitorDevice)))
  967. {
  968. ;//DbgPrint("PortConnect: DeviceIoControl (IOCTL_ASYMAC_DCDCHANGE) failed. %d\n",
  969. // GetLastError());
  970. }
  971. PortClearStatistics(hIOPort);
  972. // if (!(dwModemStatus & MS_RLSD_ON))
  973. // return(PENDING); //DCD is down
  974. // else
  975. return(SUCCESS);
  976. }
  977. except(exception_code()==EXCEPT_RAS_MEDIA ? HANDLE_EXCEPTION:CONTINUE_SEARCH)
  978. {
  979. return(gLastError);
  980. }
  981. }
  982. //* PortDisconnect ---------------------------------------------------------
  983. //
  984. // Function: This API is called to drop a connection and close AsyncMac.
  985. //
  986. // Returns: SUCCESS
  987. // PENDING
  988. // ERROR_PORT_NOT_OPEN
  989. //
  990. //*
  991. DWORD APIENTRY
  992. PortDisconnect(HANDLE hIOPort)
  993. {
  994. ASYMAC_CLOSE AsyMacClose;
  995. SERIALPCB *pSPCB;
  996. DWORD dwModemStatus, dwBytesReturned;
  997. DWORD retcode ;
  998. DWORD dwSetMask = 0;
  999. DWORD fdwAction = PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR;
  1000. memset (&overlapped, 0, sizeof (OVERLAPPED)) ;
  1001. try
  1002. {
  1003. DebugPrintf(("PortDisconnect\n"));
  1004. //Signal other end of link that connection is being dropped
  1005. if (!EscapeCommFunction(hIOPort, CLRDTR))
  1006. {
  1007. ;//DbgPrint("PortDisconnect: EscapeCommFunction Failed. %d\n", GetLastError());
  1008. }
  1009. //
  1010. // Apparently, DTR isn't really down
  1011. // yet, even though this call is supposed
  1012. // to be synchronous to the serial driver.
  1013. // We sleep here for a while to make sure
  1014. // DTR drops.
  1015. //
  1016. Sleep(100);
  1017. //Find port in list
  1018. if ((pSPCB = FindPortInList(hIOPort, NULL)) == NULL)
  1019. {
  1020. gLastError = ERROR_PORT_NOT_OPEN;
  1021. RaiseException(EXCEPT_RAS_MEDIA, EXCEPTION_NONCONTINUABLE, 0, NULL);
  1022. }
  1023. if (pSPCB->uRasEndpoint != INVALID_HANDLE_VALUE)
  1024. {
  1025. // Update statistics before closing Asyncmac
  1026. if ((retcode = UpdateStatistics(pSPCB)) != SUCCESS)
  1027. {
  1028. gLastError = retcode;
  1029. RaiseException(EXCEPT_RAS_MEDIA, EXCEPTION_NONCONTINUABLE, 0, NULL);
  1030. }
  1031. //Close AsynacMac
  1032. AsyMacClose.MacAdapter = NULL;
  1033. AsyMacClose.hNdisEndpoint = (HANDLE) pSPCB->uRasEndpoint;
  1034. DeviceIoControl(pSPCB->hAsyMac,
  1035. IOCTL_ASYMAC_CLOSE,
  1036. &AsyMacClose,
  1037. sizeof(AsyMacClose),
  1038. &AsyMacClose,
  1039. sizeof(AsyMacClose),
  1040. &dwBytesReturned,
  1041. &overlapped);
  1042. pSPCB->uRasEndpoint = INVALID_HANDLE_VALUE;
  1043. }
  1044. PurgeComm(hIOPort, fdwAction) ; // flush the ports
  1045. //Check whether DCD has dropped yet
  1046. GetCommModemStatus(hIOPort, &dwModemStatus);
  1047. if (dwModemStatus & MS_RLSD_ON) {
  1048. //DbgPrint("PortDisconnect: DCD hasn't dropped yet!\n");
  1049. dwSetMask = EV_RLSD ;
  1050. retcode = PENDING ; // not yet dropped.
  1051. } else
  1052. retcode = SUCCESS ;
  1053. // UPDATE the DSR monitoring: this restores the DCR to what it was when
  1054. // the port was opened.
  1055. //
  1056. pSPCB->dwMonitorDSRMask = pSPCB->dwActiveDSRMask ;
  1057. dwSetMask |= (pSPCB->dwMonitorDSRMask) ;
  1058. if (dwSetMask != 0) { // set only if mask is not 0
  1059. //DbgPrint("PortDisconnect: Setting mask to 0x%x\n", dwSetMask);
  1060. SetCommMask (hIOPort, dwSetMask);
  1061. if (!WaitCommEvent(hIOPort,
  1062. &(pSPCB->dwEventMask),
  1063. (LPOVERLAPPED)&(pSPCB->MonitorDevice)))
  1064. {
  1065. //DbgPrint("PortDisconnect: WaitCommEvent. %d\n", GetLastError());
  1066. }
  1067. }
  1068. //Since DCD may have dropped after GetCommModemStatus and
  1069. // before WaitCommEvent, check it again.
  1070. if (retcode != SUCCESS)
  1071. {
  1072. GetCommModemStatus(hIOPort, &dwModemStatus);
  1073. if (dwModemStatus & MS_RLSD_ON)
  1074. {
  1075. //DbgPrint("PortDisconnect: DCD hasn't dropped yet. 2\n");
  1076. retcode = PENDING ; // not yet dropped.
  1077. }
  1078. else
  1079. retcode = SUCCESS ;
  1080. }
  1081. // Set the default connect baud
  1082. //
  1083. SetCommDefaults(pSPCB->hIOPort, pSPCB->szPortName);
  1084. }
  1085. except(exception_code()==EXCEPT_RAS_MEDIA ? HANDLE_EXCEPTION:CONTINUE_SEARCH)
  1086. {
  1087. return(gLastError);
  1088. }
  1089. return retcode ;
  1090. }
  1091. //* PortInit ---------------------------------------------------------------
  1092. //
  1093. // Function: This API re-initializes the com port after use.
  1094. //
  1095. // Returns: SUCCESS
  1096. // ERROR_PORT_NOT_CONFIGURED
  1097. // ERROR_DEVICE_NOT_READY
  1098. //
  1099. //*
  1100. DWORD APIENTRY
  1101. PortInit(HANDLE hIOPort)
  1102. {
  1103. DWORD fdwAction = PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR;
  1104. DWORD dwErrors;
  1105. SERIALPCB *pSPCB;
  1106. DebugPrintf(("PortInit\n"));
  1107. pSPCB = FindPortInList(hIOPort, NULL) ;
  1108. // Raise DTR
  1109. if (!EscapeCommFunction(hIOPort, SETDTR))
  1110. return(GetLastError());
  1111. if (!PurgeComm(hIOPort, fdwAction))
  1112. return(GetLastError());
  1113. if (!ClearCommError(hIOPort, &dwErrors, NULL))
  1114. return(GetLastError());
  1115. // Reset szCarrierBPS to MAXCARRIERBPS from ini file
  1116. //
  1117. InitCarrierBps(pSPCB->szPortName, pSPCB->szCarrierBPS);
  1118. return(SUCCESS);
  1119. }
  1120. //* PortSend ---------------------------------------------------------------
  1121. //
  1122. // Function: This API sends a buffer to the port. This API is
  1123. // asynchronous and normally returns PENDING; however, if
  1124. // WriteFile returns synchronously, the API will return
  1125. // SUCCESS.
  1126. //
  1127. // Returns: SUCCESS
  1128. // PENDING
  1129. // Return code from GetLastError
  1130. //
  1131. //*
  1132. DWORD
  1133. PortSend(HANDLE hIOPort, BYTE *pBuffer, DWORD dwSize)
  1134. {
  1135. SERIALPCB *pSPCB;
  1136. DWORD dwRC, pdwBytesWritten;
  1137. BOOL bIODone;
  1138. DebugPrintf(("PortSend\n"));
  1139. // Find the SerialPCB which contains hIOPOrt
  1140. pSPCB = FindPortInList(hIOPort, NULL);
  1141. if (pSPCB == NULL)
  1142. return(ERROR_PORT_NOT_OPEN);
  1143. // Send Buffer to Port
  1144. bIODone = WriteFile(hIOPort,
  1145. pBuffer,
  1146. dwSize,
  1147. &pdwBytesWritten, //pdwBytesWritten is not used
  1148. (LPOVERLAPPED)&(pSPCB->SendReceive));
  1149. if (bIODone)
  1150. return(PENDING);
  1151. else if ((dwRC = GetLastError()) == ERROR_IO_PENDING)
  1152. return(PENDING);
  1153. else
  1154. return(dwRC);
  1155. }
  1156. //* PortReceive ------------------------------------------------------------
  1157. //
  1158. // Function: This API reads from the port. This API is
  1159. // asynchronous and normally returns PENDING; however, if
  1160. // ReadFile returns synchronously, the API will return
  1161. // SUCCESS.
  1162. //
  1163. // Returns: SUCCESS
  1164. // PENDING
  1165. // Return code from GetLastError
  1166. //
  1167. //*
  1168. DWORD
  1169. PortReceive(HANDLE hIOPort,
  1170. BYTE *pBuffer,
  1171. DWORD dwSize,
  1172. DWORD dwTimeOut)
  1173. {
  1174. COMMTIMEOUTS CT;
  1175. SERIALPCB *pSPCB;
  1176. DWORD dwRC, pdwBytesRead;
  1177. BOOL bIODone;
  1178. DebugPrintf(("PortReceive\n"));
  1179. // Find the SerialPCB which contains hIOPOrt
  1180. pSPCB = FindPortInList(hIOPort, NULL);
  1181. if (pSPCB == NULL)
  1182. return(ERROR_PORT_NOT_OPEN);
  1183. // Set Read Timeouts
  1184. CT.ReadIntervalTimeout = 0;
  1185. CT.ReadTotalTimeoutMultiplier = 0;
  1186. CT.ReadTotalTimeoutConstant = dwTimeOut;
  1187. if ( ! SetCommTimeouts(hIOPort, &CT))
  1188. return(GetLastError());
  1189. // Read from Port
  1190. bIODone = ReadFile(hIOPort,
  1191. pBuffer,
  1192. dwSize,
  1193. &pdwBytesRead, //pdwBytesRead is not used
  1194. (LPOVERLAPPED)&(pSPCB->SendReceive));
  1195. if (bIODone) {
  1196. return(PENDING);
  1197. }
  1198. else if ((dwRC = GetLastError()) == ERROR_IO_PENDING)
  1199. return(PENDING);
  1200. else
  1201. return(dwRC);
  1202. }
  1203. //* PortReceiveComplete ------------------------------------------------------
  1204. //
  1205. // Function: Completes a read - if still PENDING it cancels it - else it returns the bytes read.
  1206. // PortClearStatistics.
  1207. //
  1208. // Returns: SUCCESS
  1209. // ERROR_PORT_NOT_OPEN
  1210. //*
  1211. DWORD
  1212. PortReceiveComplete (HANDLE hIOPort, PDWORD bytesread)
  1213. {
  1214. SERIALPCB *pSPCB;
  1215. // Find the SerialPCB which contains hIOPOrt
  1216. pSPCB = FindPortInList(hIOPort, NULL);
  1217. if (pSPCB == NULL)
  1218. return(ERROR_PORT_NOT_OPEN);
  1219. if (!GetOverlappedResult(hIOPort,
  1220. (LPOVERLAPPED)&(pSPCB->SendReceive),
  1221. bytesread,
  1222. FALSE))
  1223. {
  1224. #if DBG
  1225. DbgPrint("PortReceiveComplete: GetOverlappedResult failed. %d", GetLastError());
  1226. #endif
  1227. PurgeComm (hIOPort, PURGE_RXABORT) ;
  1228. *bytesread = 0 ;
  1229. }
  1230. return SUCCESS ;
  1231. }
  1232. //* PortCompressionSetInfo -------------------------------------------------
  1233. //
  1234. // Function: This API selects Asyncmac compression mode by setting
  1235. // Asyncmac's compression bits.
  1236. //
  1237. // Returns: SUCCESS
  1238. // Return code from GetLastError
  1239. //
  1240. //*
  1241. DWORD
  1242. PortCompressionSetInfo(HANDLE hIOPort)
  1243. {
  1244. // Not supported anymore -
  1245. return(SUCCESS);
  1246. }
  1247. //* PortClearStatistics ----------------------------------------------------
  1248. //
  1249. // Function: This API is used to mark the beginning of the period for which
  1250. // statistics will be reported. The current numbers are copied
  1251. // from the MAC and stored in the Serial Port Control Block. At
  1252. // the end of the period PortGetStatistics will be called to
  1253. // compute the difference.
  1254. //
  1255. // Returns: SUCCESS
  1256. // ERROR_PORT_NOT_OPEN
  1257. //*
  1258. DWORD
  1259. PortClearStatistics(HANDLE hIOPort)
  1260. {
  1261. #if 0
  1262. ASYMAC_GETSTATS A;
  1263. int i;
  1264. DWORD dwBytesReturned;
  1265. SERIALPCB *pSPCB;
  1266. memset (&overlapped, 0, sizeof (OVERLAPPED)) ;
  1267. DebugPrintf(("PortClearStatistics\n"));
  1268. // Find port in list
  1269. if ((pSPCB = FindPortInList(hIOPort, NULL)) == NULL)
  1270. return(ERROR_PORT_NOT_OPEN);
  1271. // Check whether Asyncmac is open
  1272. if (pSPCB->uRasEndpoint == INVALID_RASENDPOINT)
  1273. for (i=0; i<NUM_RAS_SERIAL_STATS; i++) // Asymac is closed
  1274. pSPCB->Stats[i] = 0;
  1275. else // Asyncmac is open
  1276. {
  1277. // Fill in GetStats struct
  1278. A.MacAdapter = NULL;
  1279. A.hNdisEndpoint = pSPCB->uRasEndpoint;
  1280. // Call Asymac
  1281. if (!DeviceIoControl(pSPCB->hAsyMac,
  1282. IOCTL_ASYMAC_GETSTATS,
  1283. &A,
  1284. sizeof(A),
  1285. &A,
  1286. sizeof(A),
  1287. &dwBytesReturned,
  1288. &overlapped))
  1289. return(GetLastError());
  1290. // Update Stats in Serial Port Control Block
  1291. pSPCB->Stats[BYTES_XMITED] = A.AsyMacStats.GenericStats.BytesTransmitted;
  1292. pSPCB->Stats[BYTES_RCVED] = A.AsyMacStats.GenericStats.BytesReceived;
  1293. pSPCB->Stats[FRAMES_XMITED] = A.AsyMacStats.GenericStats.FramesTransmitted;
  1294. pSPCB->Stats[FRAMES_RCVED] = A.AsyMacStats.GenericStats.FramesReceived;
  1295. pSPCB->Stats[CRC_ERR] = A.AsyMacStats.SerialStats.CRCErrors;
  1296. pSPCB->Stats[TIMEOUT_ERR] = A.AsyMacStats.SerialStats.TimeoutErrors;
  1297. pSPCB->Stats[ALIGNMENT_ERR] = A.AsyMacStats.SerialStats.AlignmentErrors;
  1298. pSPCB->Stats[SERIAL_OVERRUN_ERR]
  1299. = A.AsyMacStats.SerialStats.SerialOverrunErrors;
  1300. pSPCB->Stats[FRAMING_ERR] = A.AsyMacStats.SerialStats.FramingErrors;
  1301. pSPCB->Stats[BUFFER_OVERRUN_ERR]
  1302. = A.AsyMacStats.SerialStats.BufferOverrunErrors;
  1303. pSPCB->Stats[BYTES_XMITED_UNCOMP]
  1304. = A.AsyMacStats.CompressionStats.BytesTransmittedUncompressed;
  1305. pSPCB->Stats[BYTES_RCVED_UNCOMP]
  1306. = A.AsyMacStats.CompressionStats.BytesReceivedUncompressed;
  1307. pSPCB->Stats[BYTES_XMITED_COMP]
  1308. = A.AsyMacStats.CompressionStats.BytesTransmittedCompressed;
  1309. pSPCB->Stats[BYTES_RCVED_COMP]
  1310. = A.AsyMacStats.CompressionStats.BytesReceivedCompressed;
  1311. }
  1312. #endif
  1313. return(SUCCESS);
  1314. }
  1315. //* PortGetStatistics ------------------------------------------------------
  1316. //
  1317. // Function: This API reports MAC statistics since the last call to
  1318. // PortClearStatistics.
  1319. //
  1320. // Returns: SUCCESS
  1321. // ERROR_PORT_NOT_OPEN
  1322. //*
  1323. DWORD
  1324. PortGetStatistics(HANDLE hIOPort, RAS_STATISTICS *pStat)
  1325. {
  1326. #if 0
  1327. ASYMAC_GETSTATS A;
  1328. DWORD dwBytesReturned;
  1329. SERIALPCB *pSPCB;
  1330. memset (&overlapped, 0, sizeof (OVERLAPPED)) ;
  1331. DebugPrintf(("PortGetStatistics\n"));
  1332. // Find port in list
  1333. if ((pSPCB = FindPortInList(hIOPort, NULL)) == NULL)
  1334. return(ERROR_PORT_NOT_OPEN);
  1335. // Check whether Asyncmac is open
  1336. if (pSPCB->uRasEndpoint == INVALID_RASENDPOINT)
  1337. {
  1338. // Asyncmac is closed
  1339. // Report current counts
  1340. pStat->S_NumOfStatistics = NUM_RAS_SERIAL_STATS;
  1341. pStat->S_Statistics[BYTES_XMITED] = pSPCB->Stats[BYTES_XMITED];
  1342. pStat->S_Statistics[BYTES_RCVED] = pSPCB->Stats[BYTES_RCVED];
  1343. pStat->S_Statistics[FRAMES_XMITED] = pSPCB->Stats[FRAMES_XMITED];
  1344. pStat->S_Statistics[FRAMES_RCVED] = pSPCB->Stats[FRAMES_RCVED];
  1345. pStat->S_Statistics[CRC_ERR] = pSPCB->Stats[CRC_ERR];
  1346. pStat->S_Statistics[TIMEOUT_ERR] = pSPCB->Stats[TIMEOUT_ERR];
  1347. pStat->S_Statistics[ALIGNMENT_ERR] = pSPCB->Stats[ALIGNMENT_ERR];
  1348. pStat->S_Statistics[SERIAL_OVERRUN_ERR] = pSPCB->Stats[SERIAL_OVERRUN_ERR];
  1349. pStat->S_Statistics[FRAMING_ERR] = pSPCB->Stats[FRAMING_ERR];
  1350. pStat->S_Statistics[BUFFER_OVERRUN_ERR] = pSPCB->Stats[BUFFER_OVERRUN_ERR];
  1351. pStat->S_Statistics[BYTES_XMITED_UNCOMP]= pSPCB->Stats[BYTES_XMITED_UNCOMP];
  1352. pStat->S_Statistics[BYTES_RCVED_UNCOMP] = pSPCB->Stats[BYTES_RCVED_UNCOMP];
  1353. pStat->S_Statistics[BYTES_XMITED_COMP] = pSPCB->Stats[BYTES_XMITED_COMP];
  1354. pStat->S_Statistics[BYTES_RCVED_COMP] = pSPCB->Stats[BYTES_RCVED_COMP];
  1355. }
  1356. else
  1357. {
  1358. // Asyncmac is open
  1359. // Fill in GetStats struct
  1360. A.MacAdapter = NULL;
  1361. A.hNdisEndpoint = pSPCB->uRasEndpoint;
  1362. // Call Asymac to get current MAC statistics counts
  1363. if (!DeviceIoControl(pSPCB->hAsyMac,
  1364. IOCTL_ASYMAC_GETSTATS,
  1365. &A,
  1366. sizeof(A),
  1367. &A,
  1368. sizeof(A),
  1369. &dwBytesReturned,
  1370. &overlapped))
  1371. return(GetLastError());
  1372. // Find difference between last PortClearStatistics and current counts
  1373. pStat->S_NumOfStatistics = NUM_RAS_SERIAL_STATS;
  1374. pStat->S_Statistics[BYTES_XMITED]
  1375. = A.AsyMacStats.GenericStats.BytesTransmitted
  1376. - pSPCB->Stats[BYTES_XMITED];
  1377. pStat->S_Statistics[BYTES_RCVED]
  1378. = A.AsyMacStats.GenericStats.BytesReceived
  1379. - pSPCB->Stats[BYTES_RCVED];
  1380. pStat->S_Statistics[FRAMES_XMITED]
  1381. = A.AsyMacStats.GenericStats.FramesTransmitted
  1382. - pSPCB->Stats[FRAMES_XMITED];
  1383. pStat->S_Statistics[FRAMES_RCVED]
  1384. = A.AsyMacStats.GenericStats.FramesReceived
  1385. - pSPCB->Stats[FRAMES_RCVED];
  1386. pStat->S_Statistics[CRC_ERR]
  1387. = A.AsyMacStats.SerialStats.CRCErrors
  1388. - pSPCB->Stats[CRC_ERR];
  1389. pStat->S_Statistics[TIMEOUT_ERR]
  1390. = A.AsyMacStats.SerialStats.TimeoutErrors
  1391. - pSPCB->Stats[TIMEOUT_ERR];
  1392. pStat->S_Statistics[ALIGNMENT_ERR]
  1393. = A.AsyMacStats.SerialStats.AlignmentErrors
  1394. - pSPCB->Stats[ALIGNMENT_ERR];
  1395. pStat->S_Statistics[SERIAL_OVERRUN_ERR]
  1396. = A.AsyMacStats.SerialStats.SerialOverrunErrors
  1397. - pSPCB->Stats[SERIAL_OVERRUN_ERR];
  1398. pStat->S_Statistics[FRAMING_ERR]
  1399. = A.AsyMacStats.SerialStats.FramingErrors
  1400. - pSPCB->Stats[FRAMING_ERR];
  1401. pStat->S_Statistics[BUFFER_OVERRUN_ERR]
  1402. = A.AsyMacStats.SerialStats.BufferOverrunErrors
  1403. - pSPCB->Stats[BUFFER_OVERRUN_ERR];
  1404. pStat->S_Statistics[BYTES_XMITED_UNCOMP]
  1405. = A.AsyMacStats.CompressionStats.BytesTransmittedUncompressed
  1406. - pSPCB->Stats[BYTES_XMITED_UNCOMP];
  1407. pStat->S_Statistics[BYTES_RCVED_UNCOMP]
  1408. = A.AsyMacStats.CompressionStats.BytesReceivedUncompressed
  1409. - pSPCB->Stats[BYTES_RCVED_UNCOMP];
  1410. pStat->S_Statistics[BYTES_XMITED_COMP]
  1411. = A.AsyMacStats.CompressionStats.BytesTransmittedCompressed
  1412. - pSPCB->Stats[BYTES_XMITED_COMP];
  1413. pStat->S_Statistics[BYTES_RCVED_COMP]
  1414. = A.AsyMacStats.CompressionStats.BytesReceivedCompressed
  1415. - pSPCB->Stats[BYTES_RCVED_COMP];
  1416. }
  1417. #endif
  1418. return(SUCCESS);
  1419. }
  1420. //* PortSetFraming -------------------------------------------------------
  1421. //
  1422. // Function: Sets the framing type with the mac
  1423. //
  1424. // Returns: SUCCESS
  1425. //
  1426. //*
  1427. DWORD APIENTRY
  1428. PortSetFraming(HANDLE hIOPort, DWORD SendFeatureBits, DWORD RecvFeatureBits,
  1429. DWORD SendBitMask, DWORD RecvBitMask)
  1430. {
  1431. #if 0
  1432. ASYMAC_STARTFRAMING A;
  1433. DWORD dwBytesReturned;
  1434. SERIALPCB *pSPCB;
  1435. memset (&overlapped, 0, sizeof (OVERLAPPED)) ;
  1436. // Find port in list
  1437. if ((pSPCB = FindPortInList(hIOPort, NULL)) == NULL)
  1438. return(ERROR_PORT_NOT_OPEN);
  1439. A.MacAdapter = NULL ;
  1440. A.hNdisEndpoint = pSPCB->uRasEndpoint;
  1441. A.SendFeatureBits = SendFeatureBits;
  1442. A.RecvFeatureBits = RecvFeatureBits;
  1443. A.SendBitMask = SendBitMask;
  1444. A.RecvBitMask = RecvBitMask;
  1445. if (!DeviceIoControl(pSPCB->hAsyMac,
  1446. IOCTL_ASYMAC_STARTFRAMING,
  1447. &A,
  1448. sizeof(A),
  1449. &A,
  1450. sizeof(A),
  1451. &dwBytesReturned,
  1452. &overlapped))
  1453. return(GetLastError());
  1454. #endif
  1455. return(SUCCESS);
  1456. }
  1457. //* PortGetPortState -------------------------------------------------------
  1458. //
  1459. // Function: This API is used in MS-DOS only.
  1460. //
  1461. // Returns: SUCCESS
  1462. //
  1463. //*
  1464. DWORD APIENTRY
  1465. PortGetPortState(char *pszPortName, DWORD *pdwUsage)
  1466. {
  1467. DebugPrintf(("PortGetPortState\n"));
  1468. return(SUCCESS);
  1469. }
  1470. //* PortChangeCallback -----------------------------------------------------
  1471. //
  1472. // Function: This API is used in MS-DOS only.
  1473. //
  1474. // Returns: SUCCESS
  1475. //
  1476. //*
  1477. DWORD APIENTRY
  1478. PortChangeCallback(HANDLE hIOPort)
  1479. {
  1480. DebugPrintf(("PortChangeCallback\n"));
  1481. return(SUCCESS);
  1482. }
  1483. DWORD APIENTRY
  1484. PortSetINetCfg(PVOID pvINetCfg)
  1485. {
  1486. ((void) pvINetCfg);
  1487. return SUCCESS;
  1488. }
  1489. DWORD APIENTRY
  1490. PortSetIoCompletionPort ( HANDLE hIoCompletionPort)
  1491. {
  1492. ((void) hIoCompletionPort);
  1493. return SUCCESS;
  1494. }