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.

3382 lines
115 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Copyright (c) 1991 Nokia Data Systems
  4. Module Name:
  5. acslan.c
  6. Abstract:
  7. The module is the entry to the OS/2 ACSLAN emulation module.
  8. It uses the secure native NT DLC API to implement the full
  9. IBM OS/2 DLC compatible interface for Windows/NT.
  10. Contents:
  11. AcsLan
  12. NtAcsLan
  13. GetCcbStationId
  14. OpenDlcApiDriver
  15. GetAdapterNameAndParameters
  16. GetAdapterNameFromNumber
  17. GetAdapterNumberFromName
  18. DoSyncDeviceIoControl
  19. DlcGetInfo
  20. DlcSetInfo
  21. DlcCallDriver
  22. DllEntry
  23. QueueCommandCompletion
  24. Author:
  25. Antti Saarenheimo (o-anttis) 06-JUN-1991
  26. Revision History:
  27. --*/
  28. #include "dlcdll.h"
  29. #include "dlcdebug.h"
  30. #define DLC_UNSUPPORTED_COMMAND ((ULONG)0x7fffffff)
  31. #define DLC_ASYNCHRONOUS_FLAG ((ULONG)0x80000000)
  32. #define IS_SYNCHRONOUS(command) (!(IoctlCodes[command] & DLC_ASYNCHRONOUS_FLAG))
  33. #define DLC_IOCTL(command) (IoctlCodes[command] & ~DLC_ASYNCHRONOUS_FLAG)
  34. #define IS_TRANSMIT(command) (((command) == LLC_TRANSMIT_DIR_FRAME) \
  35. || ((command) == LLC_TRANSMIT_I_FRAME) \
  36. || ((command) == LLC_TRANSMIT_UI_FRAME) \
  37. || ((command) == LLC_TRANSMIT_XID_CMD) \
  38. || ((command) == LLC_TRANSMIT_XID_RESP_FINAL) \
  39. || ((command) == LLC_TRANSMIT_XID_RESP_NOT_FINAL) \
  40. || ((command) == LLC_TRANSMIT_TEST_CMD))
  41. #define DEFAULT_QUERY_BUFFER_LENGTH 1024 // 512 wide chars, approx. 32 bindings
  42. #define DEFAULT_BINDING_LENGTH 64 // 32 wide chars, double typical
  43. #ifdef GRAB_READ
  44. typedef struct {
  45. PVOID List;
  46. PLLC_CCB pCcb;
  47. HANDLE OriginalEventHandle;
  48. HANDLE NewEventHandle;
  49. } READ_GRABBER, *PREAD_GRABBER;
  50. VOID ReadGrabber(VOID);
  51. DWORD MungeReadGrabberHandles(VOID);
  52. VOID AddReadGrabber(PREAD_GRABBER);
  53. PREAD_GRABBER RemoveReadGrabber(HANDLE);
  54. #endif
  55. //
  56. // private data
  57. //
  58. static USHORT aMinDirLogSize[3] = {
  59. sizeof(LLC_ADAPTER_LOG),
  60. sizeof(LLC_DIRECT_LOG),
  61. sizeof(LLC_ADAPTER_LOG) + sizeof(LLC_DIRECT_LOG)
  62. };
  63. CRITICAL_SECTION DriverHandlesCritSec;
  64. HANDLE aDlcDriverHandles[LLC_MAX_ADAPTER_NUMBER];
  65. IO_STATUS_BLOCK GlobalIoStatus;
  66. //
  67. // IoctlCodes - combines actual IOCTL code (giving device type, request vector,
  68. // I/O buffer method and file access) and synchronous/asynchronous flag (high bit)
  69. //
  70. ULONG IoctlCodes[LLC_MAX_DLC_COMMAND] = {
  71. DLC_UNSUPPORTED_COMMAND, // 0x00 DIR.INTERRUPT
  72. DLC_UNSUPPORTED_COMMAND, // 0x01 DIR.MODIFY.OPEN.PARMS CCB1 ONLY
  73. DLC_UNSUPPORTED_COMMAND, // 0x02 DIR.RESTORE.OPEN.PARMS CCB1 ONLY
  74. IOCTL_DLC_OPEN_ADAPTER, // 0x03 DLC.OPEN.ADAPTER
  75. IOCTL_DLC_CLOSE_ADAPTER | DLC_ASYNCHRONOUS_FLAG, // 0x04 DIR.CLOSE.ADAPTER
  76. IOCTL_DLC_SET_INFORMATION, // 0x05 DIR.SET.MULTICAST.ADDRESS
  77. IOCTL_DLC_SET_INFORMATION, // 0x06 DIR.SET.GROUP.ADDRESS
  78. IOCTL_DLC_SET_INFORMATION, // 0x07 DIR.SET.FUNCTIONAL.ADDRESS
  79. DLC_UNSUPPORTED_COMMAND, // 0x08 DIR.READ.LOG
  80. IOCTL_DLC_TRANSMIT2 | DLC_ASYNCHRONOUS_FLAG, // 0x09 TRANSMIT.FRAMES
  81. IOCTL_DLC_TRANSMIT | DLC_ASYNCHRONOUS_FLAG, // 0x0a TRANSMIT.DIR.FRAME
  82. IOCTL_DLC_TRANSMIT | DLC_ASYNCHRONOUS_FLAG, // 0x0b TRANSMIT.I.FRAME
  83. DLC_UNSUPPORTED_COMMAND, // 0x0c no command
  84. IOCTL_DLC_TRANSMIT | DLC_ASYNCHRONOUS_FLAG, // 0x0d TRANSMIT.UI.FRAME
  85. IOCTL_DLC_TRANSMIT | DLC_ASYNCHRONOUS_FLAG, // 0x0e TRANSMIT.XID.CMD
  86. IOCTL_DLC_TRANSMIT | DLC_ASYNCHRONOUS_FLAG, // 0x0f TRANSMIT.XID.RESP.FINAL
  87. IOCTL_DLC_TRANSMIT | DLC_ASYNCHRONOUS_FLAG, // 0x10 TRANSMIT.XID.RESP.NOT.FINAL
  88. IOCTL_DLC_TRANSMIT | DLC_ASYNCHRONOUS_FLAG, // 0x11 TRANSMIT.TEST.CMD
  89. IOCTL_DLC_QUERY_INFORMATION, // 0x12 no command
  90. IOCTL_DLC_SET_INFORMATION, // 0x13 no command
  91. IOCTL_DLC_RESET | DLC_ASYNCHRONOUS_FLAG, // 0x14 DLC.RESET
  92. IOCTL_DLC_OPEN_SAP, // 0x15 DLC.OPEN.SAP
  93. IOCTL_DLC_CLOSE_SAP | DLC_ASYNCHRONOUS_FLAG, // 0x16 DLC.CLOSE.SAP
  94. IOCTL_DLC_REALLOCTE_STATION, // 0x17 DLC.REALLOCATE
  95. DLC_UNSUPPORTED_COMMAND, // 0x18 no command
  96. IOCTL_DLC_OPEN_STATION, // 0x19 DLC.OPEN.STATION
  97. IOCTL_DLC_CLOSE_STATION | DLC_ASYNCHRONOUS_FLAG, // 0x1a DLC.CLOSE.STATION
  98. IOCTL_DLC_CONNECT_STATION | DLC_ASYNCHRONOUS_FLAG, // 0x1b DLC.CONNECT.STATION
  99. DLC_UNSUPPORTED_COMMAND, // 0x1c DLC.MODIFY
  100. IOCTL_DLC_FLOW_CONTROL, // 0x1d DLC.FLOW.CONTROL
  101. DLC_UNSUPPORTED_COMMAND, // 0x1e DLC.STATISTICS
  102. IOCTL_DLC_FLOW_CONTROL, // 0x1f no command
  103. IOCTL_DLC_CLOSE_ADAPTER | DLC_ASYNCHRONOUS_FLAG, // 0x20 DIR.INITIALIZE
  104. IOCTL_DLC_QUERY_INFORMATION, // 0x21 DIR.STATUS
  105. IOCTL_DLC_TIMER_SET | DLC_ASYNCHRONOUS_FLAG, // 0x22 DIR.TIMER.SET
  106. IOCTL_DLC_TIMER_CANCEL, // 0x23 DIR.TIMER.CANCEL
  107. DLC_UNSUPPORTED_COMMAND, // 0x24 PDT.TRACE.ON CCB1 ONLY
  108. DLC_UNSUPPORTED_COMMAND, // 0x25 PDT.TRACE.OFF CCB1 ONLY
  109. IOCTL_DLC_BUFFER_GET, // 0x26 BUFFER.GET
  110. IOCTL_DLC_BUFFER_FREE, // 0x27 BUFFER.FREE
  111. IOCTL_DLC_RECEIVE | DLC_ASYNCHRONOUS_FLAG, // 0x28 RECEIVE
  112. IOCTL_DLC_RECEIVE_CANCEL, // 0x29 RECEIVE.CANCEL
  113. DLC_UNSUPPORTED_COMMAND, // 0x2a RECEIVE.MODIFY
  114. DLC_UNSUPPORTED_COMMAND, // 0x2b DIR.DEFINE.MIF.ENVIRONMENT CCB1 ONLY
  115. IOCTL_DLC_TIMER_CANCEL_GROUP, // 0x2c DIR.TIMER.CANCEL.GROUP
  116. IOCTL_DLC_SET_EXCEPTION_FLAGS, // 0x2d DIR.SET.EXCEPTION.FLAGS
  117. DLC_UNSUPPORTED_COMMAND, // 0x2e no command
  118. DLC_UNSUPPORTED_COMMAND, // 0x2f no command
  119. IOCTL_DLC_BUFFER_CREATE, // 0x30 BUFFER.CREATE
  120. IOCTL_DLC_READ | DLC_ASYNCHRONOUS_FLAG, // 0x31 READ
  121. IOCTL_DLC_READ_CANCEL, // 0x32 READ.CANCEL
  122. DLC_UNSUPPORTED_COMMAND, // 0x33 DLC.SET.THRESHOLD
  123. IOCTL_DLC_CLOSE_DIRECT | DLC_ASYNCHRONOUS_FLAG, // 0x34 DIR.CLOSE.DIRECT
  124. IOCTL_DLC_OPEN_DIRECT, // 0x35 DIR.OPEN.DIRECT
  125. DLC_UNSUPPORTED_COMMAND // 0x36 PURGE.RESOURCES
  126. };
  127. CRITICAL_SECTION AdapterOpenSection;
  128. //
  129. // macros
  130. //
  131. //
  132. // The next procedure has been implemented as macro, because it is on
  133. // the critical path (used by BufferFree and all old transmit commands)
  134. //
  135. #ifdef DLCAPI_DBG
  136. VOID
  137. CopyToDescriptorBuffer(
  138. IN OUT PLLC_TRANSMIT_DESCRIPTOR pDescriptors,
  139. IN PLLC_XMIT_BUFFER pDlcBufferQueue,
  140. IN BOOLEAN DeallocateBufferAfterUse,
  141. IN OUT PUINT pIndex,
  142. IN OUT PLLC_XMIT_BUFFER *ppBuffer,
  143. IN OUT PUINT pDlcStatus
  144. )
  145. /*++
  146. Routine Description:
  147. Function translates the link list of DLC buffers to a NT DLC descriptor
  148. array to be used as the input parameter for dlc device driver.
  149. (NT driver may have only one input buffer => we cannot use any link
  150. list structures to give parameters to a NT dlc driver).
  151. Arguments:
  152. pDescriptors - NT DLC descriptor array
  153. pDlcBufferQueue - pointer to a link list of DLC buffers
  154. DeallocateBufferAfterUse - the flag is set, if the dlc buffers
  155. are released back to buffer pool when the frame is sent or
  156. if this routine is called by buffer free.
  157. pIndex - current index of the descriptor array
  158. ppLastBuffer - pointer to the next buffer, if the maximum size of
  159. the current descriptor table in stack is exceeded. This feature
  160. is used, if the number buffers in free list given to BufferFree
  161. is bigger that the maximum number of slots in the descriptor
  162. array (allocated from stack).
  163. It's an error, if this parameter has non null value, when we
  164. returne back to the transmit command.
  165. Return Value:
  166. LLC_STATUS_TRANSMIT_ERROR - there are too many transmit buffers
  167. (over 128) for the static descriptor buffer, that is allocated
  168. from the stack.
  169. --*/
  170. {
  171. *ppBuffer = pDlcBufferQueue;
  172. *pDlcStatus = LLC_STATUS_SUCCESS;
  173. while (*ppBuffer != NULL) {
  174. //
  175. // Check the overflow of the internal xmit buffer in stack and
  176. // the loop counter, that prevents the forever loop of zero length
  177. // transmit buffer (the buffer chain might be circular)
  178. //
  179. if (*pIndex >= MAX_TRANSMIT_SEGMENTS) {
  180. *pDlcStatus = LLC_STATUS_TRANSMIT_ERROR;
  181. break;
  182. }
  183. //
  184. // Buffer free may free buffers having 0 data bytes (just the
  185. // lan and LLC headers).
  186. //
  187. pDescriptors[*pIndex].pBuffer = &(*ppBuffer)->auchData[(*ppBuffer)->cbUserData];
  188. pDescriptors[*pIndex].cbBuffer = (*ppBuffer)->cbBuffer;
  189. pDescriptors[*pIndex].eSegmentType = LLC_NEXT_DATA_SEGMENT;
  190. pDescriptors[*pIndex].boolFreeBuffer = DeallocateBufferAfterUse;
  191. //
  192. // We will reset all next pointers of the released buffers
  193. // to break loops in the buffer chain of BufferFree
  194. // request. BufferFree would loop for ever with a circular
  195. // buffer link list.
  196. //
  197. if (DeallocateBufferAfterUse) {
  198. PLLC_XMIT_BUFFER pTempNext;
  199. pTempNext = (*ppBuffer)->pNext;
  200. (*ppBuffer)->pNext = NULL;
  201. *ppBuffer = pTempNext;
  202. } else {
  203. *ppBuffer = (*ppBuffer)->pNext;
  204. }
  205. *pIndex++;
  206. }
  207. }
  208. #else
  209. #define CopyToDescriptorBuffer(pDescriptors, \
  210. pDlcBufferQueue, \
  211. DeallocateBufferAfterUse, \
  212. pIndex, \
  213. ppBuffer, \
  214. pDlcStatus \
  215. ) \
  216. { \
  217. (*ppBuffer) = pDlcBufferQueue; \
  218. (*pDlcStatus) = LLC_STATUS_SUCCESS; \
  219. \
  220. while ((*ppBuffer) != NULL) { \
  221. \
  222. if (*pIndex >= MAX_TRANSMIT_SEGMENTS) { \
  223. (*pDlcStatus) = LLC_STATUS_TRANSMIT_ERROR; \
  224. break; \
  225. } \
  226. \
  227. pDescriptors[*pIndex].pBuffer = &((*ppBuffer)->auchData[(*ppBuffer)->cbUserData]); \
  228. pDescriptors[*pIndex].cbBuffer = (*ppBuffer)->cbBuffer; \
  229. pDescriptors[*pIndex].eSegmentType = LLC_NEXT_DATA_SEGMENT; \
  230. pDescriptors[*pIndex].boolFreeBuffer = DeallocateBufferAfterUse; \
  231. \
  232. if (DeallocateBufferAfterUse) { \
  233. \
  234. PLLC_XMIT_BUFFER pTempNext; \
  235. \
  236. pTempNext = (*ppBuffer)->pNext; \
  237. (*ppBuffer)->pNext = NULL; \
  238. (*ppBuffer) = pTempNext; \
  239. } else { \
  240. (*ppBuffer) = (*ppBuffer)->pNext; \
  241. } \
  242. (*pIndex)++; \
  243. } \
  244. }
  245. #endif
  246. //
  247. // functions
  248. //
  249. ACSLAN_STATUS
  250. AcsLan(
  251. IN OUT PLLC_CCB pCCB,
  252. OUT PLLC_CCB* ppBadCcb
  253. )
  254. /*++
  255. Routine Description:
  256. Native NT DLC API (ACSLAN) entry point. Called from Win32 applications
  257. Arguments:
  258. pCCB - pointer to CCB (CCB2 = OS/2 DLC Command Control Block)
  259. ppBadCcb - returned pointer to failing CCB
  260. Return Value:
  261. ACSLAN_STATUS
  262. Success - ACSLAN_STATUS_COMMAND_ACCEPTED
  263. Successfully accepted or completed CCB
  264. Failure - ACSLAN_STATUS_INVALID_CCB_POINTER
  265. Next CCB pointer field is invalid
  266. ACSLAN_STATUS_CCB_IN_ERROR
  267. Error code returned in only/first CCB
  268. ACSLAN_STATUS_CHAINED_CCB_IN_ERROR
  269. Error code returned in a chained CCB
  270. ACSLAN_STATUS_SYSTEM_STATUS
  271. Unexpected system error, check the system status field
  272. ACSLAN_STATUS_INVALID_COMMAND
  273. The first CCB pointer or bad CCB pointer was invalid
  274. --*/
  275. {
  276. UINT AcslanStatus;
  277. UINT Status;
  278. PLLC_CCB pFirstCcb = pCCB;
  279. IF_DEBUG(DUMP_ACSLAN) {
  280. IF_DEBUG(DUMP_INPUT_CCB) {
  281. DUMPCCB(pCCB, TRUE, TRUE);
  282. }
  283. }
  284. try {
  285. if (pCCB->uchDlcCommand >= LLC_MAX_DLC_COMMAND) {
  286. pCCB->uchDlcStatus = LLC_STATUS_INVALID_COMMAND;
  287. AcslanStatus = ACSLAN_STATUS_CCB_IN_ERROR;
  288. } else if (pCCB->pNext == NULL) {
  289. //
  290. // 99.9% of all DLC commands are not chained. We execute
  291. // them as a special case to avoid the wasting of the CPU
  292. // cycles with that CCB chaining stuff
  293. //
  294. //
  295. // DOS DLC needs three different CCB pointers.
  296. // In Windows/Nt there is only one.
  297. // We cannot complete the synchronous commands
  298. // by the io-system, because another thread waiting
  299. // for the event to complete might be signalled before
  300. // the status and the output parameters have been set
  301. // in the CCB and its parameter table
  302. //
  303. AcslanStatus = ACSLAN_STATUS_COMMAND_ACCEPTED;
  304. if (IS_SYNCHRONOUS(pCCB->uchDlcCommand)) {
  305. //
  306. // synchronous command: let the driver do the work then set
  307. // the status field in the output CCB to the value returned
  308. // by the driver
  309. //
  310. Status = NtAcsLan(pCCB, pCCB, pCCB, NULL);
  311. pCCB->uchDlcStatus = (UCHAR)Status;
  312. if (Status != LLC_STATUS_SUCCESS) {
  313. AcslanStatus = ACSLAN_STATUS_CCB_IN_ERROR;
  314. //
  315. // RLF 05/18/93
  316. //
  317. // If NtAcsLan returns the CCB.NEXT field pointing at the CCB,
  318. // set it to NULL
  319. //
  320. if (pCCB->pNext == pCCB) {
  321. pCCB->pNext = NULL;
  322. }
  323. }
  324. //
  325. // here we handle asyncronous completion of the synchronous
  326. // commands by using the READ command
  327. //
  328. // RLF 04/23/93 Bogus: This should be handled in the driver
  329. //
  330. if (pCCB->ulCompletionFlag != 0) {
  331. QueueCommandCompletion(pCCB);
  332. }
  333. //
  334. // Signal the event when everything has been done
  335. //
  336. if (pCCB->hCompletionEvent != NULL) {
  337. SetEvent(pCCB->hCompletionEvent);
  338. }
  339. } else {
  340. //
  341. // The command completion field is used as special
  342. // input parameter for the chained READ commands
  343. //
  344. if (pCCB->uchDlcCommand == LLC_READ) {
  345. ((PNT_DLC_READ_INPUT)pCCB->u.pParameterTable)->CommandCompletionCcbLink = NULL;
  346. }
  347. //
  348. // The asynchronous commands always returns a pending status
  349. // (we cannot touch the CCB status field because it may be
  350. // simultaneously accessed by another processor in MP systems)
  351. //
  352. Status = NtAcsLan(pCCB, pCCB, pCCB, pCCB->hCompletionEvent);
  353. if ((Status != LLC_STATUS_PENDING) && (Status != LLC_STATUS_SUCCESS)) {
  354. //printf("ACSLAN: Async Command %#x Retcode %#x\n", pCCB->uchDlcCommand, pCCB->uchDlcStatus);
  355. //
  356. // Only return immediate error status on asynchronous
  357. // commands if this is a transmit
  358. //
  359. if (IS_TRANSMIT(pCCB->uchDlcCommand)) {
  360. AcslanStatus = ACSLAN_STATUS_CCB_IN_ERROR;
  361. } else if (pCCB->hCompletionEvent) {
  362. SetEvent(pCCB->hCompletionEvent);
  363. }
  364. }
  365. }
  366. } else {
  367. //
  368. // here if there is a chain of CCBs
  369. //
  370. PLLC_CCB pNextCCB;
  371. INT CcbCount;
  372. //
  373. // An evil app may have linked the CCBs in a circular list (it
  374. // happens very easily when the same transmit commands are reused
  375. // before they have been read from the command completion list.
  376. // We prevent looping forever by checking the number of linked CCBs
  377. // beforehand. (We will save the current command count, because the
  378. // CCB chain may also be corrupted during its execution)
  379. //
  380. pNextCCB = pCCB->pNext;
  381. //
  382. // note: 10240 is an arbitrary number. Any reasonably large number
  383. // will do, this is too large, but we'll stick with it for now
  384. //
  385. for (CcbCount = 1; pNextCCB != NULL && CcbCount < 10240; CcbCount++) {
  386. pNextCCB = pNextCCB->pNext;
  387. }
  388. if (CcbCount == 10240) {
  389. //
  390. // Too many commands, the CCB list must be circular
  391. //
  392. AcslanStatus = ACSLAN_STATUS_INVALID_CCB_POINTER;
  393. } else {
  394. //
  395. // Several CCBs may be chained together. Loop until end of
  396. // the list or the next CCB is a special READ CCB bound to
  397. // the current command
  398. //
  399. do {
  400. //
  401. // Set the default ACSLAN error status returned in case the
  402. // given CCB pointer is invalid
  403. //
  404. AcslanStatus = ACSLAN_STATUS_INVALID_COMMAND;
  405. //
  406. // Reset the command completion link by default. We will set
  407. // it if we find a READ command linked to the previous command
  408. //
  409. if (pCCB->uchDlcCommand == LLC_READ) {
  410. ((PNT_DLC_READ_INPUT)pCCB->u.pParameterTable)->CommandCompletionCcbLink = NULL;
  411. } else if (pCCB->uchDlcCommand >= LLC_MAX_DLC_COMMAND) {
  412. AcslanStatus = ACSLAN_STATUS_CCB_IN_ERROR;
  413. pCCB->uchDlcStatus = LLC_STATUS_INVALID_COMMAND;
  414. break;
  415. }
  416. //
  417. // Check if there is a READ command linked to the CCB
  418. // pointer of this command to be used for the command
  419. // completion
  420. //
  421. pNextCCB = pCCB->pNext;
  422. if (pNextCCB != NULL) {
  423. AcslanStatus = ACSLAN_STATUS_INVALID_CCB_POINTER;
  424. if (pNextCCB->uchAdapterNumber != pCCB->uchAdapterNumber) {
  425. pCCB->uchDlcStatus = LLC_STATUS_CHAINED_DIFFERENT_ADAPTERS;
  426. break;
  427. } else {
  428. if (pCCB->uchReadFlag && pCCB->ulCompletionFlag
  429. && pNextCCB->uchDlcCommand == LLC_READ) {
  430. //
  431. // Swap the actual CCB and its read command in
  432. // the linked list of sequential CCBs.
  433. // Note: the chain may continue after READ
  434. //
  435. pNextCCB = pCCB;
  436. pCCB = pCCB->pNext;
  437. pNextCCB->pNext = pCCB->pNext;
  438. pCCB->pNext = pNextCCB;
  439. ((PNT_DLC_READ_INPUT)pCCB->u.pParameterTable)->CommandCompletionCcbLink = pNextCCB;
  440. }
  441. }
  442. }
  443. //
  444. // CCB is now safe, any exceptions returned by NtAcsLan
  445. // indicate an invalid (parameter) pointer within CCB
  446. //
  447. AcslanStatus = ACSLAN_STATUS_COMMAND_ACCEPTED;
  448. //
  449. // DOS DLC needs three different CCB pointers.
  450. // In Windows/Nt there is only one.
  451. // We cannot complete the synchronous commands
  452. // by the io-system, because another thread waiting for
  453. // the event to complete might be signalled before
  454. // the status and the output parameters have been set
  455. // in the CCB and its parameter table
  456. //
  457. Status = NtAcsLan(pCCB,
  458. pCCB,
  459. pCCB,
  460. IS_SYNCHRONOUS(pCCB->uchDlcCommand)
  461. ? NULL
  462. : pCCB->hCompletionEvent
  463. );
  464. if (Status != LLC_STATUS_PENDING) {
  465. pCCB->uchDlcStatus = (UCHAR)Status;
  466. }
  467. //
  468. // We must stop the command execution of all commands, when we
  469. // hit the first error (the next commands would assume that
  470. // this command succeeded)
  471. //
  472. if (pCCB->uchDlcStatus != LLC_STATUS_PENDING) {
  473. //
  474. // here, we handle the asyncronous command completion
  475. // of the synchronous commands by using the READ
  476. //
  477. if (IS_SYNCHRONOUS(pCCB->uchDlcCommand)) {
  478. //
  479. // RLF 04/23/93 Bogus: This should be handled in the driver
  480. //
  481. if (pCCB->ulCompletionFlag != 0) {
  482. QueueCommandCompletion(pCCB);
  483. }
  484. //
  485. // Signal the event when everything has been done
  486. //
  487. if (pCCB->hCompletionEvent != NULL) {
  488. SetEvent(pCCB->hCompletionEvent);
  489. }
  490. }
  491. if (pCCB->uchDlcStatus != LLC_STATUS_SUCCESS) {
  492. AcslanStatus = ACSLAN_STATUS_CCB_IN_ERROR;
  493. break;
  494. }
  495. }
  496. pCCB = pNextCCB;
  497. CcbCount--;
  498. } while (pCCB != NULL && CcbCount > 0);
  499. //
  500. // Check if the CCB list was corrupted during its use. There
  501. // must be the same number of linked CCBs as in the beginning
  502. //
  503. if (pCCB != NULL && CcbCount == 0) {
  504. AcslanStatus = ACSLAN_STATUS_INVALID_CCB_POINTER;
  505. } else if (AcslanStatus != ACSLAN_STATUS_COMMAND_ACCEPTED) {
  506. if (pCCB != pFirstCcb) {
  507. *ppBadCcb = pCCB;
  508. AcslanStatus = ACSLAN_STATUS_CHAINED_CCB_IN_ERROR;
  509. } else {
  510. AcslanStatus = ACSLAN_STATUS_CCB_IN_ERROR;
  511. }
  512. }
  513. }
  514. }
  515. } except(EXCEPTION_EXECUTE_HANDLER) {
  516. //
  517. // There was a bad pointer in the parameter table if the exception
  518. // occurred in NtAcsLan! If we have a chain of CCBs then we have to
  519. // return which was is bad, else just notify the caller that their
  520. // data is unacceptable
  521. //
  522. if (AcslanStatus == ACSLAN_STATUS_COMMAND_ACCEPTED) {
  523. pCCB->uchDlcStatus = LLC_STATUS_INVALID_PARAMETER_TABLE;
  524. if (pCCB != pFirstCcb) {
  525. *ppBadCcb = pCCB;
  526. AcslanStatus = ACSLAN_STATUS_CHAINED_CCB_IN_ERROR;
  527. } else {
  528. AcslanStatus = ACSLAN_STATUS_CCB_IN_ERROR;
  529. }
  530. }
  531. }
  532. IF_DEBUG(DUMP_ACSLAN) {
  533. IF_DEBUG(DUMP_OUTPUT_CCB) {
  534. DUMPCCB(pCCB, TRUE, FALSE);
  535. }
  536. IF_DEBUG(RETURN_CODE) {
  537. PUT(("AcsLan: returning %d [0x%x]\n", AcslanStatus, AcslanStatus));
  538. }
  539. }
  540. return AcslanStatus;
  541. }
  542. LLC_STATUS
  543. NtAcsLan(
  544. IN PLLC_CCB pCCB,
  545. IN PVOID pOriginalCcbAddress,
  546. OUT PLLC_CCB pOutputCcb,
  547. IN HANDLE EventHandle OPTIONAL
  548. )
  549. /*++
  550. Routine Description:
  551. Extended ACSLAN entrypoint used by the native NT DLC API and DOS (and
  552. OS/2) DLC subsystem emulators.
  553. This procedure can use the smaller original DOS CCBs. All unknown
  554. DOS CCB parameter fields are optional parameters on the stack
  555. Arguments:
  556. pCCB - OS/2 DLC Command control block.
  557. This must be double word aligned
  558. pOriginalCcbAddress - the original (possibly virtual DOS) CCB address.
  559. This pointer cannot be used in Windows/Nt address
  560. space.
  561. pOutputCcb - the original CCB (32bit) pointer where the status and
  562. next CCB fields are updated.
  563. Might not be double word aligned.
  564. EventHandle - NT event object handle
  565. Return Value:
  566. LLC_STATUS - See the DLC API return values.
  567. --*/
  568. {
  569. NT_DLC_PARMS NtDlcParms;
  570. PNT_DLC_PARMS pNtParms;
  571. PLLC_PARMS pDlcParms;
  572. PVOID pOutputBuffer;
  573. UINT OutputBufferLength;
  574. PVOID pInputBuffer;
  575. UINT InputBufferSize;
  576. ULONG IoctlCommand;
  577. UINT DlcStatus;
  578. HANDLE DriverHandle;
  579. NTSTATUS NtStatus;
  580. UINT InfoClass;
  581. UINT cElement;
  582. UCHAR FrameType;
  583. UCHAR AdapterNumber;
  584. PUCHAR pBuffer;
  585. UINT CopyLength;
  586. UINT cbLogBuffer;
  587. PLLC_XMIT_BUFFER pFirstBuffer;
  588. IF_DEBUG(DUMP_NTACSLAN) {
  589. IF_DEBUG(DUMP_INPUT_CCB) {
  590. DUMPCCB(pCCB, TRUE, TRUE);
  591. }
  592. }
  593. //
  594. // Setup first the default values for this CCB
  595. //
  596. pCCB->uchDlcStatus = (UCHAR)LLC_STATUS_PENDING;
  597. pCCB->pNext = pOriginalCcbAddress;
  598. pDlcParms = pCCB->u.pParameterTable;
  599. //
  600. // Discard immediately any commands for closed adapters,
  601. // except adapter open and initialize
  602. //
  603. AdapterNumber = pCCB->uchAdapterNumber;
  604. EnterCriticalSection(&DriverHandlesCritSec);
  605. DriverHandle = aDlcDriverHandles[AdapterNumber];
  606. LeaveCriticalSection(&DriverHandlesCritSec);
  607. if (DriverHandle == NULL) {
  608. //
  609. // OS/2 DLC applications may issue DIR_INITIALIZE_ADAPTER before
  610. // DIR_OPEN_ADAPTER. In that case it is simply a NOP
  611. //
  612. if (pCCB->uchDlcCommand != LLC_DIR_OPEN_ADAPTER
  613. && pCCB->uchDlcCommand != LLC_DIR_INITIALIZE) {
  614. pCCB->uchDlcStatus = LLC_STATUS_ADAPTER_CLOSED;
  615. IF_DEBUG(DUMP_NTACSLAN) {
  616. IF_DEBUG(DUMP_INPUT_CCB) {
  617. DUMPCCB(pCCB, TRUE, FALSE);
  618. }
  619. IF_DEBUG(RETURN_CODE) {
  620. PUT(("NtAcsLan: returning %d [0x%x]\n",
  621. pCCB->uchDlcStatus,
  622. pCCB->uchDlcStatus
  623. ));
  624. }
  625. }
  626. return pCCB->uchDlcStatus;
  627. }
  628. }
  629. //
  630. // Set the default input and output buffers and their sizes
  631. //
  632. IoctlCommand = DLC_IOCTL(pCCB->uchDlcCommand);
  633. if (IoctlCommand != DLC_UNSUPPORTED_COMMAND) {
  634. InputBufferSize = aDlcIoBuffers[((USHORT)IoctlCommand) >> 2].InputBufferSize;
  635. OutputBufferLength = aDlcIoBuffers[((USHORT)IoctlCommand) >> 2].OutputBufferSize;
  636. //
  637. // Set the default input and output buffers.
  638. //
  639. if (OutputBufferLength != 0) {
  640. pOutputBuffer = pOutputCcb;
  641. } else {
  642. pOutputBuffer = NULL;
  643. }
  644. } else {
  645. OutputBufferLength = 0;
  646. pOutputBuffer = NULL;
  647. }
  648. pInputBuffer = (PVOID)&NtDlcParms;
  649. switch (pCCB->uchDlcCommand) {
  650. case LLC_BUFFER_FREE:
  651. //
  652. // Copy the link list headers to the descriptor array
  653. // and build NT CCB. Application may want to
  654. // free more buffers at the time then allowed by
  655. // by the maximum descriptor buffer size =>
  656. // we must loop until the whole buffer list has been released
  657. //
  658. pFirstBuffer = pDlcParms->BufferFree.pFirstBuffer;
  659. for ( pFirstBuffer = pDlcParms->BufferFree.pFirstBuffer,
  660. DlcStatus = LLC_STATUS_SUCCESS ;
  661. pFirstBuffer != NULL ; ) {
  662. cElement = 0;
  663. //
  664. // We don't need to care about errors in the buffer chain,
  665. // because the procedure automatically breaks all loops
  666. // in the buffer chain
  667. //
  668. CopyToDescriptorBuffer(NtDlcParms.BufferFree.DlcBuffer,
  669. pFirstBuffer,
  670. TRUE, // DEALLOCATE_AFTER_USE
  671. &cElement,
  672. &pFirstBuffer,
  673. &DlcStatus
  674. );
  675. NtDlcParms.BufferFree.BufferCount = (USHORT)cElement;
  676. InputBufferSize = sizeof(LLC_TRANSMIT_DESCRIPTOR) * cElement
  677. + sizeof(NT_DLC_BUFFER_FREE_PARMS)
  678. - sizeof(LLC_TRANSMIT_DESCRIPTOR);
  679. DlcStatus = DoSyncDeviceIoControl(DriverHandle,
  680. IoctlCommand,
  681. &NtDlcParms,
  682. InputBufferSize,
  683. pDlcParms,
  684. OutputBufferLength
  685. );
  686. }
  687. IF_DEBUG(DUMP_NTACSLAN) {
  688. IF_DEBUG(DUMP_INPUT_CCB) {
  689. DUMPCCB(pCCB, TRUE, FALSE);
  690. }
  691. IF_DEBUG(RETURN_CODE) {
  692. PUT(("NtAcsLan: returning %d [0x%x]\n", DlcStatus, DlcStatus));
  693. }
  694. }
  695. return DlcStatus;
  696. case LLC_DIR_INITIALIZE:
  697. //
  698. // DIR.INITIALIZE is actually adapter close + hardware reset, but we
  699. // must return OK status if the adapter is not opened. Apps should
  700. // not reset the adapter without a good reason because it terminates
  701. // all other network communication for a while, and may disconnect
  702. // the sessions
  703. //
  704. RtlZeroMemory(pDlcParms, sizeof(LLC_DIR_INITIALIZE_PARMS));
  705. if (DriverHandle == NULL) {
  706. pCCB->uchDlcStatus = LLC_STATUS_SUCCESS;
  707. IF_DEBUG(DUMP_NTACSLAN) {
  708. IF_DEBUG(DUMP_INPUT_CCB) {
  709. DUMPCCB(pCCB, TRUE, FALSE);
  710. }
  711. IF_DEBUG(RETURN_CODE) {
  712. PUT(("NtAcsLan: returning %d [0x%x]\n",
  713. pCCB->uchDlcStatus,
  714. pCCB->uchDlcStatus
  715. ));
  716. }
  717. }
  718. return pCCB->uchDlcStatus;
  719. }
  720. case LLC_DIR_CLOSE_ADAPTER:
  721. //
  722. // protect the close with the open critical section. We do this because
  723. // we need to protect the driver against simultaneous closes on the same
  724. // handle from multiple threads within the same process. The driver needs
  725. // to be fixed ultimately
  726. //
  727. EnterCriticalSection(&AdapterOpenSection);
  728. NtStatus = NtDeviceIoControlFile(DriverHandle,
  729. EventHandle, // Event signaled when cmd compleletes
  730. NULL,
  731. NULL,
  732. &GlobalIoStatus,
  733. IOCTL_DLC_CLOSE_ADAPTER,
  734. pCCB,
  735. InputBufferSize,
  736. pOutputCcb,
  737. OutputBufferLength
  738. );
  739. if (NT_SUCCESS(NtStatus)) {
  740. if ((NtStatus != STATUS_PENDING) && (pOutputCcb->uchDlcStatus == LLC_STATUS_PENDING)) {
  741. //printf("ACSLAN: Success: DirCloseAdapter: DD returns %#x. Retcode=%#x\n",
  742. // NtStatus, pOutputCcb->uchDlcStatus);
  743. pOutputCcb->uchDlcStatus = (UCHAR)NtStatus;
  744. //printf("ACSLAN: Success: DirCloseAdapter: DD returns %#x. Retcode=%#x\n",
  745. // NtStatus, pOutputCcb->uchDlcStatus);
  746. }
  747. //
  748. // it is safe to enter the handle array critical section whilst we
  749. // are still holding the open critical section - this is the only
  750. // code path that grabs both
  751. //
  752. EnterCriticalSection(&DriverHandlesCritSec);
  753. aDlcDriverHandles[AdapterNumber] = NULL;
  754. LeaveCriticalSection(&DriverHandlesCritSec);
  755. //
  756. // if the DirCloseAdapter IOCTL returns STATUS_PENDING, NtClose
  757. // will block in the io-system until the close adapter IOCTL completes
  758. //
  759. NtClose(DriverHandle);
  760. } else {
  761. // printf("ACSLAN: Failure: DirCloseAdapter: DD returns %#x. Retcode=%#x\n",
  762. // NtStatus, pOutputCcb->uchDlcStatus);
  763. //
  764. // RLF 04/21/94
  765. //
  766. // If we picked up a handle that has been subsequently closed by
  767. // another thread, Io will return STATUS_INVALID_HANDLE. In this
  768. // case, change the status code to LLC_STATUS_ADAPTER_CLOSED
  769. //
  770. if (NtStatus == STATUS_INVALID_HANDLE) {
  771. pOutputCcb->uchDlcStatus = LLC_STATUS_ADAPTER_CLOSED;
  772. }
  773. }
  774. LeaveCriticalSection(&AdapterOpenSection);
  775. IF_DEBUG(DUMP_NTACSLAN) {
  776. IF_DEBUG(DUMP_INPUT_CCB) {
  777. DUMPCCB(pCCB, TRUE, FALSE);
  778. }
  779. IF_DEBUG(RETURN_CODE) {
  780. PUT(("NtAcsLan: returning %d [0x%x]\n",
  781. pCCB->uchDlcStatus,
  782. pCCB->uchDlcStatus
  783. ));
  784. }
  785. }
  786. return pCCB->uchDlcStatus;
  787. case LLC_DIR_CLOSE_DIRECT:
  788. pCCB->u.dlc.usStationId = 0;
  789. //
  790. // fall through
  791. //
  792. case LLC_DLC_CLOSE_STATION:
  793. case LLC_DLC_CLOSE_SAP:
  794. case LLC_DLC_RESET:
  795. pInputBuffer = pCCB;
  796. break;
  797. case LLC_DIR_INTERRUPT:
  798. IF_DEBUG(DUMP_NTACSLAN) {
  799. IF_DEBUG(DUMP_INPUT_CCB) {
  800. DUMPCCB(pCCB, TRUE, FALSE);
  801. }
  802. IF_DEBUG(RETURN_CODE) {
  803. PUT(("NtAcsLan: returning %d [0x%x]\n",
  804. LLC_STATUS_SUCCESS,
  805. LLC_STATUS_SUCCESS
  806. ));
  807. }
  808. }
  809. return LLC_STATUS_SUCCESS;
  810. //
  811. // define a few macros to make DIR.OPEN.ADAPTER code easier to read
  812. //
  813. //
  814. // IO_PARMS - specifies DirOpenAdapter structure in NT_DLC_PARMS union for input
  815. // to DLC device driver
  816. //
  817. #define IO_PARMS NtDlcParms.DirOpenAdapter
  818. //
  819. // OA_PARMS - specifies pointer to DIR.OPEN.ADAPTER parameter table which contains
  820. // pointers to 4 other parameter tables
  821. //
  822. #define OA_PARMS pDlcParms->DirOpenAdapter
  823. //
  824. // EX_PARMS - specifies pointer to LLC_EXTENDED_ADAPTER_PARMS parameter table
  825. //
  826. #define EX_PARMS pDlcParms->DirOpenAdapter.pExtendedParms
  827. //
  828. // DLC_PARMS - specifies pointer to LLC_DLC_PARMS parameter table
  829. //
  830. #define DLC_PARMS pDlcParms->DirOpenAdapter.pDlcParms
  831. case LLC_DIR_OPEN_ADAPTER:
  832. //
  833. // We can only open one adapter at a time. It is very hard to completely
  834. // synchronize this in the driver
  835. //
  836. EnterCriticalSection(&AdapterOpenSection);
  837. if (DriverHandle != NULL) {
  838. DlcStatus = LLC_STATUS_ADAPTER_OPEN;
  839. } else {
  840. DlcStatus = OpenDlcApiDriver(EX_PARMS->pSecurityDescriptor, &DriverHandle);
  841. }
  842. if (DlcStatus == LLC_STATUS_SUCCESS) {
  843. //
  844. // We read the output to the original OS/2 CCB buffer,
  845. // but it is too small for the complete NDIS adapter
  846. // name => we will copy all input parameters to the NT CCB
  847. //
  848. pOutputBuffer = OA_PARMS.pAdapterParms;
  849. //
  850. // copy any input adapter parameters from the caller's
  851. // LLC_ADAPTER_OPEN_PARMS to the device driver input buffer
  852. //
  853. RtlMoveMemory(&IO_PARMS.Adapter,
  854. OA_PARMS.pAdapterParms,
  855. sizeof(IO_PARMS.Adapter)
  856. );
  857. IO_PARMS.AdapterNumber = AdapterNumber;
  858. //
  859. // WE MUST CREATE NEW FIELD TO DEFINE, IF APPLICATION WANT
  860. // TO USE DIX or 802.3 ethernet frames under 802.2
  861. // (unnecessary feature, config parameter would be enough)
  862. //
  863. IO_PARMS.NtDlcIoctlVersion = NT_DLC_IOCTL_VERSION;
  864. IO_PARMS.pSecurityDescriptor = EX_PARMS->pSecurityDescriptor;
  865. IO_PARMS.hBufferPoolHandle = EX_PARMS->hBufferPool;
  866. IO_PARMS.LlcEthernetType = EX_PARMS->LlcEthernetType;
  867. IO_PARMS.NdisDeviceName.Buffer = (WCHAR *)IO_PARMS.Buffer;
  868. IO_PARMS.NdisDeviceName.MaximumLength = sizeof(IO_PARMS.Buffer);
  869. //
  870. // get the configuration info from the registry
  871. //
  872. DlcStatus = GetAdapterNameAndParameters(
  873. AdapterNumber % LLC_MAX_ADAPTERS,
  874. &IO_PARMS.NdisDeviceName,
  875. (PUCHAR)&IO_PARMS.LlcTicks,
  876. &IO_PARMS.LlcEthernetType
  877. );
  878. if (DlcStatus == LLC_STATUS_SUCCESS) {
  879. //
  880. // copy the name buffer into the IO buffer and free the former
  881. //
  882. RtlMoveMemory(&IO_PARMS.Buffer,
  883. IO_PARMS.NdisDeviceName.Buffer,
  884. IO_PARMS.NdisDeviceName.Length
  885. );
  886. //
  887. // ensure the name is actually zero-terminated for the call to
  888. // RtlInitUnicodeString
  889. //
  890. IO_PARMS.Buffer[IO_PARMS.NdisDeviceName.Length/sizeof(WCHAR)] = 0;
  891. //
  892. // finished with UNICODE_STRING allocated in GetAdapterName...
  893. //
  894. RtlFreeUnicodeString(&IO_PARMS.NdisDeviceName);
  895. //
  896. // fill the UNICODE_STRING back in to point at our buffer
  897. //
  898. RtlInitUnicodeString(&IO_PARMS.NdisDeviceName, IO_PARMS.Buffer);
  899. //
  900. // now perform the actual open of the adapter for this process
  901. //
  902. DlcStatus = DoSyncDeviceIoControl(
  903. DriverHandle,
  904. IOCTL_DLC_OPEN_ADAPTER,
  905. &NtDlcParms,
  906. sizeof(NT_DIR_OPEN_ADAPTER_PARMS),
  907. pOutputBuffer,
  908. sizeof(LLC_ADAPTER_OPEN_PARMS)
  909. );
  910. }
  911. if (DlcStatus == LLC_STATUS_SUCCESS) {
  912. //
  913. // get the timer tick values from the driver for this adapter
  914. //
  915. DlcStatus = DlcGetInfo(DriverHandle,
  916. DLC_INFO_CLASS_DLC_TIMERS,
  917. 0,
  918. &DLC_PARMS->uchT1_TickOne,
  919. sizeof(LLC_TICKS)
  920. );
  921. //
  922. // set the returned maxima to the default maxima as per the
  923. // IBM LAN Tech. Ref.
  924. //
  925. DLC_PARMS->uchDlcMaxSaps = 127;
  926. DLC_PARMS->uchDlcMaxStations = 255;
  927. DLC_PARMS->uchDlcMaxGroupSaps = 126;
  928. DLC_PARMS->uchDlcMaxGroupMembers = 127;
  929. //
  930. // this adapter is now successfully opened for this process
  931. //
  932. EnterCriticalSection(&DriverHandlesCritSec);
  933. aDlcDriverHandles[AdapterNumber] = DriverHandle;
  934. LeaveCriticalSection(&DriverHandlesCritSec);
  935. }
  936. }
  937. LeaveCriticalSection(&AdapterOpenSection);
  938. IF_DEBUG(DUMP_NTACSLAN) {
  939. IF_DEBUG(DUMP_OUTPUT_CCB) {
  940. DUMPCCB(pCCB, TRUE, FALSE);
  941. }
  942. IF_DEBUG(RETURN_CODE) {
  943. PUT(("NtAcsLan: returning %d [0x%x]\n", DlcStatus, DlcStatus));
  944. }
  945. }
  946. return DlcStatus;
  947. #undef IO_PARMS
  948. #undef PO_PARMS
  949. #undef EX_PARMS
  950. #undef DLC_PARMS
  951. case LLC_BUFFER_CREATE:
  952. case LLC_BUFFER_GET:
  953. case LLC_DIR_OPEN_DIRECT:
  954. case LLC_DIR_SET_EXCEPTION_FLAGS:
  955. case LLC_DLC_REALLOCATE_STATIONS:
  956. //
  957. // We can use the standard OS/2 CCB for input and output!
  958. //
  959. pOutputBuffer = pDlcParms;
  960. pInputBuffer = pDlcParms;
  961. break;
  962. case LLC_DLC_STATISTICS:
  963. //
  964. // User may read either SAP or link statistics log
  965. //
  966. if ((NtDlcParms.DlcStatistics.usStationId & 0xff) == 0) {
  967. InputBufferSize = sizeof(DLC_SAP_LOG);
  968. } else {
  969. InputBufferSize = sizeof(DLC_LINK_LOG);
  970. }
  971. if (pDlcParms->DlcStatistics.uchOptions & 0x80) {
  972. InfoClass = DLC_INFO_CLASS_STATISTICS_RESET;
  973. } else {
  974. InfoClass = DLC_INFO_CLASS_STATISTICS;
  975. }
  976. DlcStatus = DlcGetInfo(DriverHandle,
  977. InfoClass,
  978. pDlcParms->DlcStatistics.usStationId,
  979. NtDlcParms.DlcGetInformation.Info.Buffer,
  980. InputBufferSize
  981. );
  982. if ((ULONG)pDlcParms->DlcStatistics.cbLogBufSize < InputBufferSize) {
  983. InputBufferSize = (ULONG)pDlcParms->DlcStatistics.cbLogBufSize;
  984. }
  985. RtlMoveMemory(pDlcParms->DlcStatistics.pLogBuf,
  986. NtDlcParms.DlcGetInformation.Info.Buffer,
  987. InputBufferSize
  988. );
  989. if (DlcStatus == LLC_STATUS_SUCCESS
  990. && (ULONG)pDlcParms->DlcStatistics.cbLogBufSize < InputBufferSize) {
  991. DlcStatus = LLC_STATUS_LOST_LOG_DATA;
  992. }
  993. IF_DEBUG(DUMP_NTACSLAN) {
  994. IF_DEBUG(DUMP_INPUT_CCB) {
  995. DUMPCCB(pCCB, TRUE, FALSE);
  996. }
  997. IF_DEBUG(RETURN_CODE) {
  998. PUT(("NtAcsLan: returning %d [0x%x]\n", DlcStatus, DlcStatus));
  999. }
  1000. }
  1001. return DlcStatus;
  1002. case LLC_DIR_READ_LOG:
  1003. //
  1004. // We use two get info functions to read necessary stuff.
  1005. // Must must read even partial log buffer if user buffer
  1006. // is too small for the whole data (the user buffer could
  1007. // be even zero).
  1008. //
  1009. if (pDlcParms->DirReadLog.usTypeId > LLC_DIR_READ_LOG_BOTH) {
  1010. IF_DEBUG(DUMP_NTACSLAN) {
  1011. IF_DEBUG(DUMP_INPUT_CCB) {
  1012. DUMPCCB(pCCB, TRUE, FALSE);
  1013. }
  1014. IF_DEBUG(RETURN_CODE) {
  1015. PUT(("NtAcsLan: returning %d [0x%x]\n",
  1016. LLC_STATUS_INVALID_LOG_ID,
  1017. LLC_STATUS_INVALID_LOG_ID
  1018. ));
  1019. }
  1020. }
  1021. return LLC_STATUS_INVALID_LOG_ID;
  1022. }
  1023. DlcStatus = STATUS_SUCCESS;
  1024. CopyLength = cbLogBuffer = pDlcParms->DirReadLog.cbLogBuffer;
  1025. pBuffer = (PUCHAR)pDlcParms->DirReadLog.pLogBuffer;
  1026. switch (pDlcParms->DirReadLog.usTypeId) {
  1027. case LLC_DIR_READ_LOG_BOTH:
  1028. case LLC_DIR_READ_LOG_ADAPTER:
  1029. if (DlcStatus == STATUS_SUCCESS) {
  1030. DlcStatus = DlcGetInfo(DriverHandle,
  1031. DLC_INFO_CLASS_ADAPTER_LOG,
  1032. 0,
  1033. NtDlcParms.DlcGetInformation.Info.Buffer,
  1034. sizeof(LLC_ADAPTER_LOG)
  1035. );
  1036. }
  1037. if (cbLogBuffer > sizeof(LLC_ADAPTER_LOG)) {
  1038. CopyLength = sizeof(LLC_ADAPTER_LOG);
  1039. }
  1040. if (pDlcParms->DirReadLog.usTypeId == LLC_DIR_READ_LOG_BOTH) {
  1041. RtlMoveMemory(pBuffer,
  1042. NtDlcParms.DlcGetInformation.Info.Buffer,
  1043. CopyLength
  1044. );
  1045. cbLogBuffer -= CopyLength;
  1046. pBuffer += CopyLength;
  1047. CopyLength = cbLogBuffer;
  1048. DlcStatus = DlcGetInfo(DriverHandle,
  1049. DLC_INFO_CLASS_STATISTICS_RESET,
  1050. 0,
  1051. NtDlcParms.DlcGetInformation.Info.Buffer,
  1052. sizeof(LLC_DIRECT_LOG)
  1053. );
  1054. if (cbLogBuffer > sizeof(LLC_DIRECT_LOG)) {
  1055. CopyLength = sizeof(LLC_DIRECT_LOG);
  1056. }
  1057. }
  1058. IF_DEBUG(DUMP_NTACSLAN) {
  1059. IF_DEBUG(DUMP_INPUT_CCB) {
  1060. DUMPCCB(pCCB, TRUE, FALSE);
  1061. }
  1062. IF_DEBUG(RETURN_CODE) {
  1063. PUT(("NtAcsLan: returning %d [0x%x]\n", DlcStatus, DlcStatus));
  1064. }
  1065. }
  1066. return DlcStatus;
  1067. case LLC_DIR_READ_LOG_DIRECT:
  1068. DlcStatus = DlcGetInfo(DriverHandle,
  1069. DLC_INFO_CLASS_STATISTICS_RESET,
  1070. 0,
  1071. NtDlcParms.DlcGetInformation.Info.Buffer,
  1072. sizeof(LLC_DIRECT_LOG)
  1073. );
  1074. if (cbLogBuffer > sizeof(LLC_DIRECT_LOG)) {
  1075. CopyLength = sizeof(LLC_DIRECT_LOG);
  1076. }
  1077. break;
  1078. }
  1079. RtlMoveMemory(pBuffer,
  1080. NtDlcParms.DlcGetInformation.Info.Buffer,
  1081. CopyLength
  1082. );
  1083. if (aMinDirLogSize[pDlcParms->DirReadLog.usTypeId] > pDlcParms->DirReadLog.cbLogBuffer) {
  1084. pDlcParms->DirReadLog.cbActualLength = aMinDirLogSize[pDlcParms->DirReadLog.usTypeId];
  1085. DlcStatus = LLC_STATUS_LOST_LOG_DATA;
  1086. }
  1087. IF_DEBUG(DUMP_NTACSLAN) {
  1088. IF_DEBUG(DUMP_INPUT_CCB) {
  1089. DUMPCCB(pCCB, TRUE, FALSE);
  1090. }
  1091. IF_DEBUG(RETURN_CODE) {
  1092. PUT(("NtAcsLan: returning %d [0x%x]\n", DlcStatus, DlcStatus));
  1093. }
  1094. }
  1095. return DlcStatus;
  1096. case LLC_DIR_SET_FUNCTIONAL_ADDRESS:
  1097. if (pCCB->u.auchBuffer[0] & (UCHAR)0x80) {
  1098. InfoClass = DLC_INFO_CLASS_RESET_FUNCTIONAL;
  1099. } else {
  1100. InfoClass = DLC_INFO_CLASS_SET_FUNCTIONAL;
  1101. }
  1102. DlcStatus = DlcSetInfo(DriverHandle,
  1103. InfoClass,
  1104. 0,
  1105. &NtDlcParms.DlcSetInformation,
  1106. pCCB->u.auchBuffer,
  1107. sizeof(TR_BROADCAST_ADDRESS)
  1108. );
  1109. IF_DEBUG(DUMP_NTACSLAN) {
  1110. IF_DEBUG(DUMP_INPUT_CCB) {
  1111. DUMPCCB(pCCB, TRUE, FALSE);
  1112. }
  1113. IF_DEBUG(RETURN_CODE) {
  1114. PUT(("NtAcsLan: returning %d [0x%x]\n", DlcStatus, DlcStatus));
  1115. }
  1116. }
  1117. return DlcStatus;
  1118. case LLC_DIR_SET_GROUP_ADDRESS:
  1119. return DlcSetInfo(DriverHandle,
  1120. DLC_INFO_CLASS_SET_GROUP,
  1121. 0,
  1122. &NtDlcParms.DlcSetInformation,
  1123. pCCB->u.auchBuffer,
  1124. sizeof(TR_BROADCAST_ADDRESS)
  1125. );
  1126. case LLC_DIR_SET_MULTICAST_ADDRESS:
  1127. return DlcSetInfo(DriverHandle,
  1128. DLC_INFO_CLASS_SET_MULTICAST,
  1129. 0,
  1130. &NtDlcParms.DlcSetInformation,
  1131. pCCB->u.pParameterTable,
  1132. sizeof(LLC_DIR_MULTICAST_ADDRESS)
  1133. );
  1134. case LLC_DIR_STATUS:
  1135. //
  1136. // We will generic DlcGetInfo to read the status info.
  1137. // some parameters must be moved ot correct places.
  1138. //
  1139. RtlZeroMemory(pDlcParms, sizeof(LLC_DIR_STATUS_PARMS));
  1140. DlcStatus = DlcGetInfo(DriverHandle,
  1141. DLC_INFO_CLASS_DIR_ADAPTER,
  1142. 0,
  1143. &NtDlcParms.DlcGetInformation.Info.DirAdapter,
  1144. sizeof(LLC_ADAPTER_INFO)
  1145. );
  1146. if (DlcStatus != LLC_STATUS_SUCCESS) {
  1147. IF_DEBUG(DUMP_NTACSLAN) {
  1148. IF_DEBUG(DUMP_INPUT_CCB) {
  1149. DUMPCCB(pCCB, TRUE, FALSE);
  1150. }
  1151. IF_DEBUG(RETURN_CODE) {
  1152. PUT(("NtAcsLan: returning %d [0x%x]\n", DlcStatus, DlcStatus));
  1153. }
  1154. }
  1155. return DlcStatus;
  1156. }
  1157. RtlMoveMemory(pDlcParms->DirStatus.auchNodeAddress,
  1158. &NtDlcParms.DlcGetInformation.Info.DirAdapter,
  1159. sizeof(LLC_ADAPTER_INFO)
  1160. );
  1161. pDlcParms->DirStatus.usAdapterType =
  1162. NtDlcParms.DlcGetInformation.Info.DirAdapter.usAdapterType;
  1163. //
  1164. // Set the adapter config flags, the only thing we actually
  1165. // can know, if the current link speed on the adapter.
  1166. // In the other fields we just use the default values.
  1167. // Keep the bit defining extended DOS parameters unchanged,
  1168. // but all other bits may be changed.
  1169. //
  1170. pDlcParms->DirStatus.uchAdapterConfig &= ~0x20; // DOS extended parms
  1171. if (NtDlcParms.DlcGetInformation.Info.DirAdapter.ulLinkSpeed ==
  1172. TR_16Mbps_LINK_SPEED) {
  1173. pDlcParms->DirStatus.uchAdapterConfig |=
  1174. 0x10 | // early release token
  1175. 0x0c | // 64 kB RAM on a 4/16 IBM token-ring adapter
  1176. 0x01; // adapter rate is 16 Mbps
  1177. } else {
  1178. pDlcParms->DirStatus.uchAdapterConfig |=
  1179. 0x0c; // 64 kB RAM on adapter
  1180. }
  1181. DlcStatus = DlcGetInfo(DriverHandle,
  1182. DLC_INFO_CLASS_PERMANENT_ADDRESS,
  1183. 0,
  1184. pDlcParms->DirStatus.auchPermanentAddress,
  1185. 6
  1186. );
  1187. if (DlcStatus != LLC_STATUS_SUCCESS) {
  1188. IF_DEBUG(DUMP_NTACSLAN) {
  1189. IF_DEBUG(DUMP_INPUT_CCB) {
  1190. DUMPCCB(pCCB, TRUE, FALSE);
  1191. }
  1192. IF_DEBUG(RETURN_CODE) {
  1193. PUT(("NtAcsLan: returning %d [0x%x]\n", DlcStatus, DlcStatus));
  1194. }
  1195. }
  1196. return DlcStatus;
  1197. }
  1198. DlcStatus = DlcGetInfo(DriverHandle,
  1199. DLC_INFO_CLASS_DLC_ADAPTER,
  1200. 0,
  1201. &pDlcParms->DirStatus.uchMaxSap,
  1202. sizeof(struct _DlcAdapterInfoGet)
  1203. );
  1204. IF_DEBUG(DUMP_NTACSLAN) {
  1205. IF_DEBUG(DUMP_INPUT_CCB) {
  1206. DUMPCCB(pCCB, TRUE, FALSE);
  1207. }
  1208. IF_DEBUG(RETURN_CODE) {
  1209. PUT(("NtAcsLan: returning %d [0x%x]\n", DlcStatus, DlcStatus));
  1210. }
  1211. }
  1212. return DlcStatus;
  1213. case LLC_READ_CANCEL:
  1214. case LLC_DIR_TIMER_CANCEL:
  1215. case LLC_RECEIVE_CANCEL:
  1216. //
  1217. // Copy pointer of the cancelled command to the
  1218. // byte aligned output buffer.
  1219. //
  1220. NtDlcParms.DlcCancelCommand.CcbAddress = (PVOID)pDlcParms;
  1221. //SmbPutUlong(&pOutputCcb->pNext, (ULONG_PTR) pDlcParms);
  1222. pOutputCcb->pNext = (PVOID) pDlcParms;
  1223. break;
  1224. case LLC_DIR_TIMER_CANCEL_GROUP:
  1225. case LLC_DIR_TIMER_SET:
  1226. pInputBuffer = pCCB;
  1227. break;
  1228. case LLC_DLC_CONNECT_STATION:
  1229. NtDlcParms.Async.Ccb = *(PNT_DLC_CCB)pCCB;
  1230. NtDlcParms.Async.Parms.DlcConnectStation.StationId = pDlcParms->DlcConnectStation.usStationId;
  1231. if (pDlcParms->DlcConnectStation.pRoutingInfo != NULL) {
  1232. NtDlcParms.Async.Parms.DlcConnectStation.RoutingInformationLength = *pDlcParms->DlcConnectStation.pRoutingInfo & (UCHAR)0x1f;
  1233. RtlMoveMemory(NtDlcParms.Async.Parms.DlcConnectStation.aRoutingInformation,
  1234. pDlcParms->DlcConnectStation.pRoutingInfo,
  1235. NtDlcParms.Async.Parms.DlcConnectStation.RoutingInformationLength
  1236. );
  1237. } else {
  1238. NtDlcParms.Async.Parms.DlcConnectStation.RoutingInformationLength=0;
  1239. }
  1240. break;
  1241. case LLC_DOS_DLC_FLOW_CONTROL:
  1242. //
  1243. // This is an official entry to DlcFlowControl used by
  1244. // VDM DLC support DLL to set a link buffer busy state.
  1245. //
  1246. NtDlcParms.DlcFlowControl.FlowControlOption = (UCHAR)pCCB->u.dlc.usParameter;
  1247. NtDlcParms.DlcFlowControl.StationId = pCCB->u.dlc.usStationId;
  1248. break;
  1249. case LLC_DLC_FLOW_CONTROL:
  1250. //
  1251. // This is the official entry to DlcFlowControl
  1252. //
  1253. NtDlcParms.DlcFlowControl.FlowControlOption = (UCHAR)(pCCB->u.dlc.usParameter & LLC_VALID_FLOW_CONTROL_BITS);
  1254. NtDlcParms.DlcFlowControl.StationId = pCCB->u.dlc.usStationId;
  1255. break;
  1256. case LLC_DLC_MODIFY:
  1257. RtlMoveMemory(&NtDlcParms.DlcSetInformation.Info.LinkStation,
  1258. &pDlcParms->DlcModify.uchT1,
  1259. sizeof(DLC_LINK_PARAMETERS)
  1260. );
  1261. NtDlcParms.DlcSetInformation.Info.LinkStation.TokenRingAccessPriority = pDlcParms->DlcModify.uchAccessPriority;
  1262. //
  1263. // This is a non-standard extension: DlcModify returns
  1264. // the maximum allowed information field lentgh for a link station.
  1265. // (it depends on length of source routing and bridges
  1266. // between two stations).
  1267. //
  1268. if ((pDlcParms->DlcModify.usStationId & 0x00ff) != 0) {
  1269. DlcStatus = DlcGetInfo(DriverHandle,
  1270. DLC_INFO_CLASS_LINK_STATION,
  1271. pDlcParms->DlcModify.usStationId,
  1272. &pDlcParms->DlcModify.usMaxInfoFieldLength,
  1273. sizeof(USHORT)
  1274. );
  1275. }
  1276. DlcStatus = DlcSetInfo(DriverHandle,
  1277. DLC_INFO_CLASS_LINK_STATION,
  1278. pDlcParms->DlcModify.usStationId,
  1279. &NtDlcParms.DlcSetInformation,
  1280. NULL,
  1281. sizeof(DLC_LINK_PARAMETERS)
  1282. );
  1283. //
  1284. // Set the group information, if there is any
  1285. //
  1286. if (DlcStatus == LLC_STATUS_SUCCESS && pDlcParms->DlcModify.cGroupCount != 0) {
  1287. NtDlcParms.DlcSetInformation.Info.Sap.GroupCount = pDlcParms->DlcModify.cGroupCount;
  1288. RtlMoveMemory(NtDlcParms.DlcSetInformation.Info.Sap.GroupList,
  1289. pDlcParms->DlcModify.pGroupList,
  1290. pDlcParms->DlcModify.cGroupCount
  1291. );
  1292. DlcStatus = DlcSetInfo(DriverHandle,
  1293. DLC_INFO_CLASS_GROUP,
  1294. pDlcParms->DlcModify.usStationId,
  1295. &NtDlcParms.DlcSetInformation,
  1296. NULL,
  1297. sizeof(struct _DlcSapInfoSet)
  1298. );
  1299. }
  1300. IF_DEBUG(DUMP_NTACSLAN) {
  1301. IF_DEBUG(DUMP_INPUT_CCB) {
  1302. DUMPCCB(pCCB, TRUE, FALSE);
  1303. }
  1304. IF_DEBUG(RETURN_CODE) {
  1305. PUT(("NtAcsLan: returning %d [0x%x]\n", DlcStatus, DlcStatus));
  1306. }
  1307. }
  1308. return DlcStatus;
  1309. case LLC_DLC_OPEN_SAP:
  1310. //
  1311. // DlcOpenSap uses the original OS/2 CCB, but it has to modify a couple
  1312. // fields. There is a separate call to setup the group SAPS because
  1313. // they cannot use the original CCB parameter table (it's a pointer)
  1314. //
  1315. pNtParms = (PNT_DLC_PARMS)pDlcParms;
  1316. pNtParms->DlcOpenSap.LinkParameters.TokenRingAccessPriority = pDlcParms->DlcOpenSap.uchOptionsPriority & (UCHAR)0x1F;
  1317. DlcStatus = DoSyncDeviceIoControl(DriverHandle,
  1318. IOCTL_DLC_OPEN_SAP,
  1319. pNtParms,
  1320. sizeof(NT_DLC_OPEN_SAP_PARMS),
  1321. pNtParms,
  1322. sizeof(NT_DLC_OPEN_SAP_PARMS)
  1323. );
  1324. if (DlcStatus != LLC_STATUS_SUCCESS) {
  1325. pOutputCcb->uchDlcStatus = (UCHAR)DlcStatus;
  1326. IF_DEBUG(DUMP_NTACSLAN) {
  1327. IF_DEBUG(DUMP_INPUT_CCB) {
  1328. DUMPCCB(pCCB, TRUE, FALSE);
  1329. }
  1330. IF_DEBUG(RETURN_CODE) {
  1331. PUT(("NtAcsLan: returning %d [0x%x]\n", DlcStatus, DlcStatus));
  1332. }
  1333. }
  1334. return DlcStatus;
  1335. }
  1336. //
  1337. // Check if there is defined any group saps
  1338. //
  1339. if (pDlcParms->DlcOpenSap.cGroupCount != 0) {
  1340. NtDlcParms.DlcSetInformation.Info.Sap.GroupCount = pDlcParms->DlcOpenSap.cGroupCount;
  1341. RtlMoveMemory(&NtDlcParms.DlcSetInformation.Info.Sap.GroupList,
  1342. pDlcParms->DlcOpenSap.pGroupList,
  1343. pDlcParms->DlcOpenSap.cGroupCount
  1344. );
  1345. DlcStatus = DlcSetInfo(DriverHandle,
  1346. DLC_INFO_CLASS_GROUP,
  1347. pDlcParms->DlcOpenSap.usStationId,
  1348. &NtDlcParms.DlcSetInformation,
  1349. NULL,
  1350. sizeof(struct _DlcSapInfoSet)
  1351. );
  1352. }
  1353. pOutputCcb->uchDlcStatus = (UCHAR)DlcStatus;
  1354. IF_DEBUG(DUMP_NTACSLAN) {
  1355. IF_DEBUG(DUMP_INPUT_CCB) {
  1356. DUMPCCB(pCCB, TRUE, FALSE);
  1357. }
  1358. IF_DEBUG(RETURN_CODE) {
  1359. PUT(("NtAcsLan: returning %d [0x%x]\n", DlcStatus, DlcStatus));
  1360. }
  1361. }
  1362. return DlcStatus;
  1363. case LLC_DLC_OPEN_STATION:
  1364. NtDlcParms.DlcOpenStation.RemoteSap = pDlcParms->DlcOpenStation.uchRemoteSap;
  1365. NtDlcParms.DlcOpenStation.LinkStationId = pDlcParms->DlcOpenStation.usSapStationId;
  1366. RtlMoveMemory(NtDlcParms.DlcOpenStation.aRemoteNodeAddress,
  1367. pDlcParms->DlcOpenStation.pRemoteNodeAddress,
  1368. 6
  1369. );
  1370. RtlMoveMemory(&NtDlcParms.DlcOpenStation.LinkParameters,
  1371. &pDlcParms->DlcOpenStation.uchT1,
  1372. sizeof(DLC_LINK_PARAMETERS)
  1373. );
  1374. NtDlcParms.DlcOpenStation.LinkParameters.TokenRingAccessPriority = pDlcParms->DlcOpenStation.uchAccessPriority;
  1375. pOutputBuffer = &pDlcParms->DlcOpenStation.usLinkStationId;
  1376. break;
  1377. case LLC_READ:
  1378. #ifdef GRAB_READ
  1379. if (pCCB->hCompletionEvent) {
  1380. PREAD_GRABBER pGrabberStruct;
  1381. pGrabberStruct = (PREAD_GRABBER)LocalAlloc(LMEM_FIXED, sizeof(READ_GRABBER));
  1382. pGrabberStruct->pCcb = pCCB;
  1383. pGrabberStruct->OriginalEventHandle = pCCB->hCompletionEvent;
  1384. pGrabberStruct->NewEventHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
  1385. EventHandle = pGrabberStruct->NewEventHandle;
  1386. AddReadGrabber(pGrabberStruct);
  1387. } else {
  1388. OutputDebugString(L"NtAcsLan: LLC_READ with no event!\n");
  1389. }
  1390. #endif
  1391. //
  1392. // IOCTL_DLC_READ have two output buffer, one for CCB and another
  1393. // for the actual data. IOCTL_DLC_READ2 is a read request, that
  1394. // have the second outbut buffer immediately after the firt one =>
  1395. // we don't need to lock, map, copy, unmap and unlock the second
  1396. // output buffer. The same thing has been implemented for receive.
  1397. //
  1398. if (pDlcParms != NULL && pDlcParms != (PVOID)&pCCB[1]) {
  1399. OutputBufferLength = sizeof(NT_DLC_CCB_OUTPUT);
  1400. NtDlcParms.Async.Ccb = *(PNT_DLC_CCB)pCCB;
  1401. NtDlcParms.Async.Parms.ReadInput = *(PNT_DLC_READ_INPUT)pDlcParms;
  1402. } else {
  1403. IoctlCommand = IOCTL_DLC_READ2;
  1404. OutputBufferLength = sizeof(NT_DLC_READ_PARMS) + sizeof(LLC_CCB);
  1405. pInputBuffer = pCCB;
  1406. }
  1407. break;
  1408. case LLC_RECEIVE:
  1409. OutputBufferLength = sizeof(NT_DLC_CCB_OUTPUT);
  1410. if (pDlcParms != NULL && pDlcParms != (PVOID)&pCCB[1]) {
  1411. NtDlcParms.Async.Ccb = *(PNT_DLC_CCB)pCCB;
  1412. NtDlcParms.Async.Parms.Receive = pDlcParms->Receive;
  1413. //
  1414. // We don't actually receive any data with receive command,
  1415. // if the receive flag is set.
  1416. //
  1417. if (NtDlcParms.Async.Parms.Receive.ulReceiveFlag != 0) {
  1418. IoctlCommand = IOCTL_DLC_RECEIVE2;
  1419. }
  1420. } else {
  1421. IoctlCommand = IOCTL_DLC_RECEIVE2;
  1422. pInputBuffer = pCCB;
  1423. }
  1424. break;
  1425. case LLC_TRANSMIT_DIR_FRAME:
  1426. FrameType = LLC_DIRECT_TRANSMIT;
  1427. goto TransmitHandling;
  1428. case LLC_TRANSMIT_UI_FRAME:
  1429. FrameType = LLC_UI_FRAME;
  1430. goto TransmitHandling;
  1431. case LLC_TRANSMIT_XID_CMD:
  1432. FrameType = LLC_XID_COMMAND_POLL;
  1433. goto TransmitHandling;
  1434. case LLC_TRANSMIT_XID_RESP_FINAL:
  1435. FrameType = LLC_XID_RESPONSE_FINAL;
  1436. goto TransmitHandling;
  1437. case LLC_TRANSMIT_XID_RESP_NOT_FINAL:
  1438. FrameType = LLC_XID_RESPONSE_NOT_FINAL;
  1439. goto TransmitHandling;
  1440. case LLC_TRANSMIT_TEST_CMD:
  1441. FrameType = LLC_TEST_COMMAND_POLL;
  1442. goto TransmitHandling;
  1443. case LLC_TRANSMIT_I_FRAME:
  1444. FrameType = LLC_I_FRAME;
  1445. TransmitHandling:
  1446. //
  1447. // Copy the link list headers to the descriptor array and build NT CCB.
  1448. // (BUG-BUG-BUG: We should implement the send of multiple frames.
  1449. // loop CCB chain as far as the same CCB command and transmit commands
  1450. // completed with READ)
  1451. //
  1452. OutputBufferLength = sizeof(NT_DLC_CCB_OUTPUT);
  1453. //
  1454. // This stuff is for DOS DLC, the transmit parameter table may have been
  1455. // copied if it was unaligned
  1456. //
  1457. //SmbPutUlong((PULONG)&pOutputCcb->pNext, (ULONG)pOriginalCcbAddress);
  1458. pOutputCcb->pNext = (PVOID) pOriginalCcbAddress;
  1459. RtlMoveMemory((PUCHAR)&NtDlcParms.Async.Ccb, (PUCHAR)pOutputCcb, sizeof(NT_DLC_CCB));
  1460. pOutputCcb->uchDlcStatus = (UCHAR)LLC_STATUS_PENDING;
  1461. NtDlcParms.Async.Parms.Transmit.FrameType = FrameType;
  1462. NtDlcParms.Async.Parms.Transmit.StationId = pDlcParms->Transmit.usStationId;
  1463. NtDlcParms.Async.Parms.Transmit.RemoteSap = pDlcParms->Transmit.uchRemoteSap;
  1464. NtDlcParms.Async.Parms.Transmit.XmitReadOption = pDlcParms->Transmit.uchXmitReadOption;
  1465. cElement = 0;
  1466. if (pDlcParms->Transmit.pXmitQueue1 != NULL) {
  1467. CopyToDescriptorBuffer(NtDlcParms.Async.Parms.Transmit.XmitBuffer,
  1468. pDlcParms->Transmit.pXmitQueue1,
  1469. FALSE, // DO_NOT_DEALLOCATE
  1470. &cElement,
  1471. &pFirstBuffer,
  1472. &DlcStatus
  1473. );
  1474. if (DlcStatus != STATUS_SUCCESS) {
  1475. pCCB->uchDlcStatus = (UCHAR)DlcStatus;
  1476. IF_DEBUG(DUMP_NTACSLAN) {
  1477. IF_DEBUG(DUMP_INPUT_CCB) {
  1478. DUMPCCB(pCCB, TRUE, FALSE);
  1479. }
  1480. IF_DEBUG(RETURN_CODE) {
  1481. PUT(("NtAcsLan: returning %d [0x%x]\n", LLC_STATUS_PENDING, LLC_STATUS_PENDING));
  1482. }
  1483. }
  1484. return LLC_STATUS_PENDING;
  1485. }
  1486. }
  1487. if (pDlcParms->Transmit.pXmitQueue2 != NULL) {
  1488. CopyToDescriptorBuffer(NtDlcParms.Async.Parms.Transmit.XmitBuffer,
  1489. pDlcParms->Transmit.pXmitQueue2,
  1490. TRUE, // DEALLOCATE_AFTER_USE
  1491. &cElement,
  1492. &pFirstBuffer,
  1493. &DlcStatus
  1494. );
  1495. //
  1496. // The Queue2 pointer must be reset always.
  1497. // This doesn't work for DOS DLC buffers, but it does not
  1498. // matter, because this feature is not needed by VDM DLC
  1499. // (we cannot access pOutputCcb or its parameter block,
  1500. // because they may be unaligned)
  1501. //
  1502. pDlcParms->Transmit.pXmitQueue2 = NULL;
  1503. if (DlcStatus != STATUS_SUCCESS) {
  1504. pCCB->uchDlcStatus = (UCHAR)DlcStatus;
  1505. IF_DEBUG(DUMP_NTACSLAN) {
  1506. IF_DEBUG(DUMP_INPUT_CCB) {
  1507. DUMPCCB(pCCB, TRUE, FALSE);
  1508. }
  1509. IF_DEBUG(RETURN_CODE) {
  1510. PUT(("NtAcsLan: returning %d [0x%x]\n", LLC_STATUS_PENDING, LLC_STATUS_PENDING));
  1511. }
  1512. }
  1513. return LLC_STATUS_PENDING;
  1514. }
  1515. }
  1516. if (pDlcParms->Transmit.cbBuffer1 != 0) {
  1517. if (cElement == MAX_TRANSMIT_SEGMENTS) {
  1518. pCCB->uchDlcStatus = LLC_STATUS_TRANSMIT_ERROR;
  1519. IF_DEBUG(DUMP_NTACSLAN) {
  1520. IF_DEBUG(DUMP_INPUT_CCB) {
  1521. DUMPCCB(pCCB, TRUE, FALSE);
  1522. }
  1523. IF_DEBUG(RETURN_CODE) {
  1524. PUT(("NtAcsLan: returning %d [0x%x]\n", LLC_STATUS_PENDING, LLC_STATUS_PENDING));
  1525. }
  1526. }
  1527. return LLC_STATUS_PENDING;
  1528. }
  1529. NtDlcParms.Async.Parms.Transmit.XmitBuffer[cElement].pBuffer = pDlcParms->Transmit.pBuffer1;
  1530. NtDlcParms.Async.Parms.Transmit.XmitBuffer[cElement].cbBuffer = pDlcParms->Transmit.cbBuffer1;
  1531. NtDlcParms.Async.Parms.Transmit.XmitBuffer[cElement].boolFreeBuffer = FALSE;
  1532. NtDlcParms.Async.Parms.Transmit.XmitBuffer[cElement].eSegmentType = LLC_NEXT_DATA_SEGMENT;
  1533. cElement++;
  1534. }
  1535. if (pDlcParms->Transmit.cbBuffer2 != 0) {
  1536. if (cElement == MAX_TRANSMIT_SEGMENTS) {
  1537. pCCB->uchDlcStatus = LLC_STATUS_TRANSMIT_ERROR;
  1538. IF_DEBUG(DUMP_NTACSLAN) {
  1539. IF_DEBUG(DUMP_INPUT_CCB) {
  1540. DUMPCCB(pCCB, TRUE, FALSE);
  1541. }
  1542. IF_DEBUG(RETURN_CODE) {
  1543. PUT(("NtAcsLan: returning %d [0x%x]\n", LLC_STATUS_PENDING, LLC_STATUS_PENDING));
  1544. }
  1545. }
  1546. return LLC_STATUS_PENDING;
  1547. }
  1548. NtDlcParms.Async.Parms.Transmit.XmitBuffer[cElement].pBuffer = pDlcParms->Transmit.pBuffer2;
  1549. NtDlcParms.Async.Parms.Transmit.XmitBuffer[cElement].cbBuffer = pDlcParms->Transmit.cbBuffer2;
  1550. NtDlcParms.Async.Parms.Transmit.XmitBuffer[cElement].boolFreeBuffer = FALSE;
  1551. NtDlcParms.Async.Parms.Transmit.XmitBuffer[cElement].eSegmentType = LLC_NEXT_DATA_SEGMENT;
  1552. cElement++;
  1553. }
  1554. NtDlcParms.Async.Parms.Transmit.XmitBuffer[0].eSegmentType = LLC_FIRST_DATA_SEGMENT;
  1555. NtDlcParms.Async.Parms.Transmit.XmitBufferCount = cElement;
  1556. InputBufferSize = sizeof(LLC_TRANSMIT_DESCRIPTOR) * cElement
  1557. + sizeof(NT_DLC_TRANSMIT_PARMS)
  1558. + sizeof(NT_DLC_CCB)
  1559. - sizeof(LLC_TRANSMIT_DESCRIPTOR);
  1560. break;
  1561. //
  1562. // Multiple frame transmit:
  1563. // - atomic operation: single error => all are discarded
  1564. // by error, but some successful packets may have been sent
  1565. // after the unsuccessful one.
  1566. // - No DLC frame headers are included
  1567. // - LAN header must always be in the first buffer,
  1568. // - 3 dwords reserved for DLC in the beginning.
  1569. // good: provides the minimal system overhead
  1570. // bad: error handling may be difficult in some cases
  1571. // new data link operation:
  1572. // cancel packets by request handle, called when an
  1573. // error has occurred (this would require a new
  1574. // one level request handle)
  1575. //
  1576. case LLC_TRANSMIT_FRAMES:
  1577. //
  1578. // We must copy the actual CCB to the parameter table only if
  1579. // the CCB is not allocated within the transmit command structure
  1580. //
  1581. if (&pDlcParms->Transmit2.Ccb != pCCB) {
  1582. pDlcParms->Transmit2.Ccb = *pCCB;
  1583. }
  1584. pInputBuffer = pDlcParms;
  1585. InputBufferSize = (sizeof(LLC_TRANSMIT_DESCRIPTOR)
  1586. * (UINT)pDlcParms->Transmit2.cXmitBufferCount)
  1587. + sizeof(LLC_TRANSMIT2_COMMAND)
  1588. - sizeof(LLC_TRANSMIT_DESCRIPTOR);
  1589. break;
  1590. default:
  1591. return LLC_STATUS_INVALID_COMMAND;
  1592. }
  1593. NtStatus = NtDeviceIoControlFile(DriverHandle,
  1594. EventHandle, // Event signaled when cmd completes
  1595. NULL, // no APC routine
  1596. NULL, // no context for APC
  1597. &GlobalIoStatus, // global I/O status block
  1598. IoctlCommand, // map DLC cmd codes to Nt IoCtl codes
  1599. pInputBuffer,
  1600. InputBufferSize,
  1601. pOutputBuffer,
  1602. OutputBufferLength
  1603. );
  1604. //
  1605. // The io-completion directly updates Status and next CCB pointer
  1606. // of this CCB when the main function return status pending.
  1607. // If the status code is non-pending (error or ok), then we
  1608. // must save the status code to CCB and reset next CCB pointer.
  1609. //
  1610. if (NtStatus != STATUS_PENDING) {
  1611. //
  1612. // Reset the next pointer if the command is still linked to itself.
  1613. // For example the cancel command returns a pointer to the cancelled
  1614. // CCB in the next CCB pointer (pNext)
  1615. //
  1616. if (pCCB->pNext == pOutputCcb) {
  1617. pCCB->pNext = NULL;
  1618. }
  1619. pCCB->uchDlcStatus = (UCHAR)NtStatus;
  1620. IF_DEBUG(DUMP_NTACSLAN) {
  1621. IF_DEBUG(DUMP_OUTPUT_CCB) {
  1622. DUMPCCB(pCCB, TRUE, FALSE);
  1623. }
  1624. IF_DEBUG(RETURN_CODE) {
  1625. PUT(("NtAcsLan: returning %d [0x%x]\n", pCCB->uchDlcStatus, pCCB->uchDlcStatus));
  1626. }
  1627. }
  1628. #if DBG
  1629. if (pOutputCcb->uchDlcStatus == 0xA1) {
  1630. OutputDebugString(TEXT("NtAcsLan returning 0xA1\n"));
  1631. //DebugBreak();
  1632. }
  1633. if (pOutputCcb->uchDlcCommand == LLC_TRANSMIT_I_FRAME && pOutputCcb->uchDlcStatus != LLC_STATUS_SUCCESS) {
  1634. WCHAR buf[80];
  1635. wsprintf(buf, TEXT("NtAcsLan: I-Frame returning %#02x\n"), pOutputCcb->uchDlcStatus);
  1636. OutputDebugString(buf);
  1637. }
  1638. if (pCCB->uchDlcStatus != pOutputCcb->uchDlcStatus) {
  1639. WCHAR buf[80];
  1640. wsprintf(buf, TEXT("NtAcsLan: pCCB->uchDlcStatus = %#02x; pOutputCcb->uchDlcStatus = %#02x\n"),
  1641. pCCB->uchDlcStatus,
  1642. pOutputCcb->uchDlcStatus
  1643. );
  1644. OutputDebugString(buf);
  1645. }
  1646. #endif
  1647. return pCCB->uchDlcStatus;
  1648. } else {
  1649. IF_DEBUG(DUMP_NTACSLAN) {
  1650. IF_DEBUG(DUMP_OUTPUT_CCB) {
  1651. DUMPCCB(pCCB, TRUE, FALSE);
  1652. }
  1653. IF_DEBUG(RETURN_CODE) {
  1654. PUT(("NtAcsLan: returning %d [0x%x]\n", LLC_STATUS_PENDING, LLC_STATUS_PENDING));
  1655. }
  1656. }
  1657. return LLC_STATUS_PENDING;
  1658. }
  1659. }
  1660. USHORT
  1661. GetCcbStationId(
  1662. IN PLLC_CCB pCCB
  1663. )
  1664. /*++
  1665. Routine Description:
  1666. The function returns the station id used by the given ccb.
  1667. -1 is returned, if the command didn't have any station id.
  1668. Arguments:
  1669. pCCB - OS/2 DLC Command control block
  1670. Return Value:
  1671. Station Id
  1672. -1 No station id
  1673. --*/
  1674. {
  1675. switch (pCCB->uchDlcCommand) {
  1676. case LLC_BUFFER_FREE:
  1677. case LLC_BUFFER_CREATE:
  1678. case LLC_BUFFER_GET:
  1679. case LLC_DLC_REALLOCATE_STATIONS:
  1680. case LLC_DLC_STATISTICS:
  1681. case LLC_READ:
  1682. case LLC_RECEIVE:
  1683. case LLC_TRANSMIT_DIR_FRAME:
  1684. case LLC_TRANSMIT_UI_FRAME:
  1685. case LLC_TRANSMIT_XID_CMD:
  1686. case LLC_TRANSMIT_XID_RESP_FINAL:
  1687. case LLC_TRANSMIT_XID_RESP_NOT_FINAL:
  1688. case LLC_TRANSMIT_TEST_CMD:
  1689. case LLC_TRANSMIT_I_FRAME:
  1690. case LLC_TRANSMIT_FRAMES:
  1691. case LLC_DLC_CONNECT_STATION:
  1692. case LLC_DLC_MODIFY:
  1693. return pCCB->u.pParameterTable->DlcModify.usStationId;
  1694. case LLC_DLC_FLOW_CONTROL:
  1695. case LLC_DLC_CLOSE_STATION:
  1696. case LLC_DLC_CLOSE_SAP:
  1697. case LLC_DIR_CLOSE_DIRECT:
  1698. case LLC_DLC_RESET:
  1699. return pCCB->u.dlc.usStationId;
  1700. default:
  1701. return (USHORT)-1;
  1702. }
  1703. }
  1704. LLC_STATUS
  1705. OpenDlcApiDriver(
  1706. IN PVOID pSecurityDescriptor,
  1707. OUT HANDLE* pHandle
  1708. )
  1709. /*++
  1710. Routine Description:
  1711. Opens a handle to the DLC driver
  1712. Arguments:
  1713. pSecurityDescriptor - pointer to security descriptor
  1714. pHandle - pointer to returned handle if success
  1715. Return Value:
  1716. LLC_STATUS
  1717. Success - LLC_STATUS_SUCCESS
  1718. Failure - LLC_STATUS_DEVICE_DRIVER_NOT_INSTALLED
  1719. --*/
  1720. {
  1721. IO_STATUS_BLOCK iosb;
  1722. OBJECT_ATTRIBUTES objattr;
  1723. UNICODE_STRING DriverName;
  1724. NTSTATUS Status;
  1725. RtlInitUnicodeString(&DriverName, DD_DLC_DEVICE_NAME);
  1726. InitializeObjectAttributes(
  1727. &objattr, // obj attr to initialize
  1728. &DriverName, // string to use
  1729. OBJ_CASE_INSENSITIVE, // Attributes
  1730. NULL, // Root directory
  1731. pSecurityDescriptor // Security Descriptor
  1732. );
  1733. Status = NtCreateFile(
  1734. pHandle, // ptr to handle
  1735. GENERIC_READ // desired...
  1736. | GENERIC_WRITE, // ...access
  1737. &objattr, // name & attributes
  1738. &iosb, // I/O status block.
  1739. NULL, // alloc size.
  1740. FILE_ATTRIBUTE_NORMAL,
  1741. FILE_SHARE_DELETE // share...
  1742. | FILE_SHARE_READ
  1743. | FILE_SHARE_WRITE, // ...access
  1744. FILE_OPEN_IF, // create disposition
  1745. 0, // ...options
  1746. NULL, // EA buffer
  1747. 0L // Ea buffer len
  1748. );
  1749. if (Status != STATUS_SUCCESS) {
  1750. return LLC_STATUS_DEVICE_DRIVER_NOT_INSTALLED;
  1751. }
  1752. return LLC_STATUS_SUCCESS;
  1753. }
  1754. LLC_STATUS
  1755. GetAdapterNameAndParameters(
  1756. IN UINT AdapterNumber,
  1757. OUT PUNICODE_STRING pNdisName,
  1758. OUT PUCHAR pTicks,
  1759. OUT PLLC_ETHERNET_TYPE pLlcEthernetType
  1760. )
  1761. /*++
  1762. Routine Description:
  1763. Get the adapter mapping for AdapterNumber from the registry. Also, get the
  1764. Ethernet type and
  1765. Arguments:
  1766. AdapterNumber - DLC adapter number (0, 1, 2 ... 15)
  1767. pNdisName - the returned unicode name string
  1768. pTicks -
  1769. pLlcEthernetType -
  1770. Return Value:
  1771. LLC_STATUS
  1772. --*/
  1773. {
  1774. LLC_STATUS llcStatus;
  1775. LONG regStatus;
  1776. HKEY hkey;
  1777. static LPTSTR subkey = TEXT("System\\CurrentControlSet\\Services\\Dlc\\Linkage");
  1778. regStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1779. subkey,
  1780. 0,
  1781. KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
  1782. &hkey
  1783. );
  1784. if (regStatus == ERROR_SUCCESS) {
  1785. DWORD type;
  1786. DWORD dataSize;
  1787. LPTSTR buffer;
  1788. LPTSTR tempbuffer;
  1789. //
  1790. // here we try to get all the info in one go from the registry. If
  1791. // the "Bind" value has grown to more than 1024 bytes, then we must
  1792. // try to reallocate the buffer and try again. If it fails a second
  1793. // time, then give up
  1794. //
  1795. buffer = (LPTSTR)LocalAlloc(LMEM_FIXED, DEFAULT_QUERY_BUFFER_LENGTH);
  1796. if (buffer) {
  1797. dataSize = DEFAULT_QUERY_BUFFER_LENGTH;
  1798. regStatus = RegQueryValueEx(hkey,
  1799. TEXT("Bind"),
  1800. NULL, // lpdwReserved
  1801. &type,
  1802. (LPBYTE)buffer,
  1803. &dataSize
  1804. );
  1805. if (regStatus == ERROR_SUCCESS || regStatus == ERROR_MORE_DATA) {
  1806. llcStatus = LLC_STATUS_SUCCESS;
  1807. //
  1808. // This code not tested - Realloc don't work
  1809. //
  1810. if (dataSize > DEFAULT_QUERY_BUFFER_LENGTH) {
  1811. DWORD oldSize;
  1812. //
  1813. // more available than I anticipated. Try growing the buffer.
  1814. // Add an extra DEFAULT_BINDING_LENGTH in case somebody's
  1815. // adding to this entry whilst we're reading it (unlikely)
  1816. //
  1817. oldSize = dataSize;
  1818. dataSize += DEFAULT_BINDING_LENGTH;
  1819. tempbuffer = buffer;
  1820. buffer = (LPTSTR)LocalReAlloc((HLOCAL)buffer, dataSize, 0);
  1821. if (buffer) {
  1822. regStatus = RegQueryValueEx(hkey,
  1823. subkey,
  1824. NULL, // lpdwReserved
  1825. &type,
  1826. (LPBYTE)buffer,
  1827. &dataSize
  1828. );
  1829. if (regStatus != ERROR_SUCCESS) {
  1830. llcStatus = LLC_STATUS_ADAPTER_NOT_INSTALLED;
  1831. } else if (dataSize > oldSize) {
  1832. //
  1833. // data has grown since last call? Bogus?
  1834. //
  1835. llcStatus = LLC_STATUS_NO_MEMORY;
  1836. }
  1837. } else {
  1838. LocalFree(tempbuffer);
  1839. //
  1840. // Is this error code acceptable in this circumstance?
  1841. //
  1842. llcStatus = LLC_STATUS_NO_MEMORY;
  1843. }
  1844. }
  1845. if (llcStatus == LLC_STATUS_SUCCESS) {
  1846. //
  1847. // we managed to read something from the registry. Try to
  1848. // locate our adapter. The returned data is wide-character
  1849. // strings (better be, lets check the type first)
  1850. //
  1851. if (type == REG_MULTI_SZ) {
  1852. DWORD i;
  1853. LPTSTR pBinding = buffer;
  1854. for (i = 0; i != AdapterNumber; ++i) {
  1855. pBinding = wcschr(pBinding, L'\0') + 1;
  1856. if (!*pBinding) {
  1857. break;
  1858. }
  1859. }
  1860. //
  1861. // if there is a binding corresponding to this adapter
  1862. // number (e.g. \Device\IbmTok01) then make a copy of
  1863. // the string and make it into a UNICODE_STRING. The
  1864. // caller uses RtlFreeUnicodeString
  1865. //
  1866. // Does RtlFreeUnicodeString know that I used
  1867. // LocalAlloc to allocate the string?
  1868. //
  1869. if (*pBinding) {
  1870. LPTSTR bindingName;
  1871. bindingName = (LPTSTR)LocalAlloc(
  1872. LMEM_FIXED,
  1873. (wcslen(pBinding) + 1)
  1874. * sizeof(WCHAR)
  1875. );
  1876. if (bindingName) {
  1877. wcscpy(bindingName, pBinding);
  1878. RtlInitUnicodeString(pNdisName, bindingName);
  1879. //#if DBG
  1880. // DbgPrint("DLCAPI.DLL: Adapter %d maps to %ws\n",
  1881. // AdapterNumber,
  1882. // pBinding
  1883. // );
  1884. //#endif
  1885. } else {
  1886. llcStatus = LLC_STATUS_NO_MEMORY;
  1887. }
  1888. } else {
  1889. llcStatus = LLC_STATUS_ADAPTER_NOT_INSTALLED;
  1890. }
  1891. } else {
  1892. //
  1893. // unexpected type in registry
  1894. //
  1895. llcStatus = LLC_STATUS_ADAPTER_NOT_INSTALLED;
  1896. }
  1897. }
  1898. } else {
  1899. llcStatus = LLC_STATUS_ADAPTER_NOT_INSTALLED;
  1900. }
  1901. if (buffer) {
  1902. LocalFree(buffer);
  1903. }
  1904. //
  1905. // for now, default the ticks and ethernet type
  1906. //
  1907. RtlZeroMemory(pTicks, sizeof(LLC_TICKS));
  1908. //
  1909. // if the app passed in anything other than those values we
  1910. // recognize, convert to AUTO.
  1911. //
  1912. // Note: we should really return an error (invalid parameter) in
  1913. // this case, since it means the app is passing in a bad value,
  1914. // but at this late stage, it is better to accept invalid input
  1915. // and default it than to risk an app/printer monitor stopping
  1916. // working (RLF 05/10/93)
  1917. //
  1918. if (*pLlcEthernetType != LLC_ETHERNET_TYPE_AUTO
  1919. && *pLlcEthernetType != LLC_ETHERNET_TYPE_DEFAULT
  1920. && *pLlcEthernetType != LLC_ETHERNET_TYPE_DIX
  1921. && *pLlcEthernetType != LLC_ETHERNET_TYPE_802_3) {
  1922. *pLlcEthernetType = LLC_ETHERNET_TYPE_AUTO;
  1923. }
  1924. } else {
  1925. //
  1926. // Is this error code acceptable in this circumstance?
  1927. //
  1928. llcStatus = LLC_STATUS_NO_MEMORY;
  1929. }
  1930. RegCloseKey(hkey);
  1931. } else {
  1932. llcStatus = LLC_STATUS_ADAPTER_NOT_INSTALLED;
  1933. }
  1934. return llcStatus;
  1935. }
  1936. LLC_STATUS
  1937. GetAdapterNameFromNumber(
  1938. IN UINT AdapterNumber,
  1939. OUT LPTSTR pNdisName
  1940. )
  1941. /*++
  1942. Routine Description:
  1943. Get the adapter name mapping for AdapterNumber from the registry.
  1944. Arguments:
  1945. AdapterNumber - DLC adapter number (0, 1, 2 ... 15)
  1946. pNdisName - the returned zero-terminated wide character string
  1947. Return Value:
  1948. LLC_STATUS
  1949. --*/
  1950. {
  1951. LLC_STATUS llcStatus;
  1952. LONG regStatus;
  1953. HKEY hkey;
  1954. static LPTSTR subkey = TEXT("System\\CurrentControlSet\\Services\\Dlc\\Linkage");
  1955. regStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1956. subkey,
  1957. 0,
  1958. KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
  1959. &hkey
  1960. );
  1961. if (regStatus == ERROR_SUCCESS) {
  1962. DWORD type;
  1963. DWORD dataSize;
  1964. LPTSTR buffer;
  1965. //
  1966. // here we try to get all the info in one go from the registry. If
  1967. // the "Bind" value has grown to more than 1024 bytes, then we must
  1968. // try to reallocate the buffer and try again. If it fails a second
  1969. // time, then give up
  1970. //
  1971. buffer = (LPTSTR)LocalAlloc(LMEM_FIXED, DEFAULT_QUERY_BUFFER_LENGTH);
  1972. if (buffer) {
  1973. dataSize = DEFAULT_QUERY_BUFFER_LENGTH;
  1974. regStatus = RegQueryValueEx(hkey,
  1975. TEXT("Bind"),
  1976. NULL, // lpdwReserved
  1977. &type,
  1978. (LPBYTE)buffer,
  1979. &dataSize
  1980. );
  1981. if (regStatus == ERROR_SUCCESS || regStatus == ERROR_MORE_DATA) {
  1982. llcStatus = LLC_STATUS_SUCCESS;
  1983. //
  1984. // this code not tested - Realloc don't work
  1985. //
  1986. if (dataSize > DEFAULT_QUERY_BUFFER_LENGTH) {
  1987. DWORD oldSize;
  1988. //
  1989. // more available than I anticipated. Try growing the buffer.
  1990. // Add an extra DEFAULT_BINDING_LENGTH in case somebody's
  1991. // adding to this entry whilst we're reading it (unlikely)
  1992. //
  1993. oldSize = dataSize;
  1994. dataSize += DEFAULT_BINDING_LENGTH;
  1995. buffer = (LPTSTR)LocalReAlloc((HLOCAL)buffer, dataSize, 0);
  1996. if (buffer) {
  1997. regStatus = RegQueryValueEx(hkey,
  1998. subkey,
  1999. NULL, // lpdwReserved
  2000. &type,
  2001. (LPBYTE)buffer,
  2002. &dataSize
  2003. );
  2004. if (regStatus != ERROR_SUCCESS) {
  2005. llcStatus = LLC_STATUS_ADAPTER_NOT_INSTALLED;
  2006. } else if (dataSize > oldSize) {
  2007. //
  2008. // data has grown since last call? Bogus?
  2009. //
  2010. llcStatus = LLC_STATUS_NO_MEMORY;
  2011. }
  2012. } else {
  2013. //
  2014. // Is this error code acceptable in this circumstance?
  2015. //
  2016. llcStatus = LLC_STATUS_NO_MEMORY;
  2017. }
  2018. }
  2019. if (llcStatus == LLC_STATUS_SUCCESS) {
  2020. //
  2021. // we managed to read something from the registry. Try to
  2022. // locate our adapter. The returned data is wide-character
  2023. // strings (better be, lets check the type first)
  2024. //
  2025. if (type == REG_MULTI_SZ) {
  2026. DWORD i;
  2027. LPTSTR pBinding = buffer;
  2028. for (i = 0; i != AdapterNumber; ++i) {
  2029. pBinding = wcschr(pBinding, L'\0') + 1;
  2030. if (!*pBinding) {
  2031. break;
  2032. }
  2033. }
  2034. //
  2035. // if there is a binding corresponding to this adapter
  2036. // number (e.g. \Device\IbmTok01)
  2037. if (*pBinding) {
  2038. wcscpy(pNdisName, pBinding);
  2039. } else {
  2040. llcStatus = LLC_STATUS_ADAPTER_NOT_INSTALLED;
  2041. }
  2042. } else {
  2043. //
  2044. // unexpected type in registry
  2045. //
  2046. llcStatus = LLC_STATUS_ADAPTER_NOT_INSTALLED;
  2047. }
  2048. }
  2049. } else {
  2050. llcStatus = LLC_STATUS_ADAPTER_NOT_INSTALLED;
  2051. }
  2052. LocalFree(buffer);
  2053. }
  2054. else {
  2055. llcStatus = LLC_STATUS_NO_MEMORY;
  2056. }
  2057. RegCloseKey(hkey);
  2058. } else {
  2059. llcStatus = LLC_STATUS_ADAPTER_NOT_INSTALLED;
  2060. }
  2061. return llcStatus;
  2062. }
  2063. LLC_STATUS
  2064. GetAdapterNumberFromName(
  2065. IN LPTSTR pNdisName,
  2066. OUT UINT *AdapterNumber
  2067. )
  2068. /*++
  2069. Routine Description:
  2070. Get the adapter number mapping for AdapterName from the registry.
  2071. Arguments:
  2072. pNdisName - zero-terminated wide character string
  2073. AdapterNumber - returned DLC adapter number (0, 1, 2 ... 15)
  2074. Return Value:
  2075. LLC_STATUS
  2076. --*/
  2077. {
  2078. LLC_STATUS llcStatus;
  2079. LONG regStatus;
  2080. HKEY hkey;
  2081. static LPTSTR subkey = TEXT("System\\CurrentControlSet\\Services\\Dlc\\Linkage");
  2082. regStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2083. subkey,
  2084. 0,
  2085. KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
  2086. &hkey
  2087. );
  2088. if (regStatus == ERROR_SUCCESS) {
  2089. DWORD type;
  2090. DWORD dataSize;
  2091. LPTSTR buffer;
  2092. //
  2093. // here we try to get all the info in one go from the registry. If
  2094. // the "Bind" value has grown to more than 1024 bytes, then we must
  2095. // try to reallocate the buffer and try again. If it fails a second
  2096. // time, then give up
  2097. //
  2098. buffer = (LPTSTR)LocalAlloc(LMEM_FIXED, DEFAULT_QUERY_BUFFER_LENGTH);
  2099. if (buffer) {
  2100. dataSize = DEFAULT_QUERY_BUFFER_LENGTH;
  2101. regStatus = RegQueryValueEx(hkey,
  2102. TEXT("Bind"),
  2103. NULL, // lpdwReserved
  2104. &type,
  2105. (LPBYTE)buffer,
  2106. &dataSize
  2107. );
  2108. if (regStatus == ERROR_SUCCESS || regStatus == ERROR_MORE_DATA) {
  2109. llcStatus = LLC_STATUS_SUCCESS;
  2110. //
  2111. // this code not tested - Realloc don't work
  2112. //
  2113. if (dataSize > DEFAULT_QUERY_BUFFER_LENGTH) {
  2114. DWORD oldSize;
  2115. //
  2116. // more available than I anticipated. Try growing the buffer.
  2117. // Add an extra DEFAULT_BINDING_LENGTH in case somebody's
  2118. // adding to this entry whilst we're reading it (unlikely)
  2119. //
  2120. oldSize = dataSize;
  2121. dataSize += DEFAULT_BINDING_LENGTH;
  2122. buffer = (LPTSTR)LocalReAlloc((HLOCAL)buffer, dataSize, 0);
  2123. if (buffer) {
  2124. regStatus = RegQueryValueEx(hkey,
  2125. subkey,
  2126. NULL, // lpdwReserved
  2127. &type,
  2128. (LPBYTE)buffer,
  2129. &dataSize
  2130. );
  2131. if (regStatus != ERROR_SUCCESS) {
  2132. llcStatus = LLC_STATUS_ADAPTER_NOT_INSTALLED;
  2133. } else if (dataSize > oldSize) {
  2134. //
  2135. // data has grown since last call? Bogus?
  2136. //
  2137. llcStatus = LLC_STATUS_NO_MEMORY;
  2138. }
  2139. } else {
  2140. //
  2141. // is this error code acceptable in this circumstance?
  2142. //
  2143. llcStatus = LLC_STATUS_NO_MEMORY;
  2144. }
  2145. }
  2146. if (llcStatus == LLC_STATUS_SUCCESS) {
  2147. //
  2148. // we managed to read something from the registry. Try to
  2149. // locate our adapter. The returned data is wide-character
  2150. // strings (better be, lets check the type first)
  2151. //
  2152. if (type == REG_MULTI_SZ) {
  2153. DWORD i;
  2154. LPTSTR pBinding = buffer;
  2155. // here we map the name to number
  2156. i = 0;
  2157. while (*pBinding) {
  2158. if (!_wcsnicmp(pBinding, pNdisName, DEFAULT_BINDING_LENGTH)) {
  2159. break;
  2160. }
  2161. pBinding = wcschr(pBinding, L'\0') + 1;
  2162. if (!*pBinding) {
  2163. break;
  2164. }
  2165. i++;
  2166. }
  2167. //
  2168. // if there is a binding corresponding to this adapter
  2169. // name (e.g. \Device\IbmTok01)
  2170. //
  2171. if (*pBinding) {
  2172. *AdapterNumber = i;
  2173. } else {
  2174. llcStatus = LLC_STATUS_ADAPTER_NOT_INSTALLED;
  2175. }
  2176. } else {
  2177. //
  2178. // unexpected type in registry
  2179. //
  2180. llcStatus = LLC_STATUS_ADAPTER_NOT_INSTALLED;
  2181. }
  2182. }
  2183. } else {
  2184. llcStatus = LLC_STATUS_ADAPTER_NOT_INSTALLED;
  2185. }
  2186. LocalFree(buffer);
  2187. }
  2188. else {
  2189. llcStatus = LLC_STATUS_NO_MEMORY;
  2190. }
  2191. RegCloseKey(hkey);
  2192. }
  2193. else {
  2194. llcStatus = LLC_STATUS_ADAPTER_NOT_INSTALLED;
  2195. }
  2196. return llcStatus;
  2197. }
  2198. LLC_STATUS
  2199. DoSyncDeviceIoControl(
  2200. IN HANDLE DeviceHandle,
  2201. IN ULONG IoctlCommand,
  2202. IN PVOID pInputBuffer,
  2203. IN UINT InputBufferLength,
  2204. OUT PVOID pOutputBuffer,
  2205. IN UINT OutputBufferLength
  2206. )
  2207. /*++
  2208. Routine Description:
  2209. Function makes only the IO control call little bit simpler
  2210. Arguments:
  2211. DeviceHandle - device handle of the current address object
  2212. IoctlCommand - DLC command code
  2213. pInputBuffer - input parameters
  2214. InputBufferLength - lenght of input parameters
  2215. pOutputBuffer - the returned data
  2216. OutputBufferLength - the length of the returned data
  2217. Return Value:
  2218. LLC_STATUS
  2219. --*/
  2220. {
  2221. NTSTATUS NtStatus;
  2222. NtStatus = NtDeviceIoControlFile(DeviceHandle,
  2223. NULL, // Event
  2224. NULL, // ApcRoutine
  2225. NULL, // ApcContext
  2226. &GlobalIoStatus,
  2227. IoctlCommand,
  2228. pInputBuffer,
  2229. InputBufferLength,
  2230. pOutputBuffer,
  2231. OutputBufferLength
  2232. );
  2233. //
  2234. // NT DLC driver never returns any errors as NT error status.
  2235. // => the CCB pointer had to be invalid, if NtDeviceIoctl returns
  2236. // error
  2237. //
  2238. if (NtStatus != STATUS_SUCCESS && NtStatus != STATUS_PENDING) {
  2239. if (NtStatus > LLC_STATUS_MAX_ERROR) {
  2240. //
  2241. // NT DLC driver should never any errors as NT error status.
  2242. // => the CCB pointer must be invalid, if NtDeviceIoctl
  2243. // returns an nt error status.
  2244. //
  2245. NtStatus = LLC_STATUS_INVALID_POINTER_IN_CCB;
  2246. }
  2247. }
  2248. return (LLC_STATUS)NtStatus;
  2249. }
  2250. LLC_STATUS
  2251. DlcGetInfo(
  2252. IN HANDLE DriverHandle,
  2253. IN UINT InfoClass,
  2254. IN USHORT StationId,
  2255. IN PVOID pOutputBuffer,
  2256. IN UINT OutputBufferLength
  2257. )
  2258. /*++
  2259. Routine Description:
  2260. Function makes only the IO control call little bit simpler.
  2261. Arguments:
  2262. DriverHandle - the device handle of the address object
  2263. InfoClass - the type of the requested information
  2264. StationId - direct, link or sap station id
  2265. pOutputBuffer - the returned info structure
  2266. OutputBufferLength - output buffer length
  2267. Return Value:
  2268. LLC_STATUS
  2269. --*/
  2270. {
  2271. NT_DLC_QUERY_INFORMATION_PARMS GetInformation;
  2272. GetInformation.Header.StationId = StationId;
  2273. GetInformation.Header.InfoClass = (USHORT)InfoClass;
  2274. return DoSyncDeviceIoControl(DriverHandle,
  2275. IOCTL_DLC_QUERY_INFORMATION,
  2276. &GetInformation,
  2277. sizeof(NT_DLC_QUERY_INFORMATION_INPUT),
  2278. pOutputBuffer,
  2279. OutputBufferLength
  2280. );
  2281. }
  2282. LLC_STATUS
  2283. DlcSetInfo(
  2284. IN HANDLE DriverHandle,
  2285. IN UINT InfoClass,
  2286. IN USHORT StationId,
  2287. IN PNT_DLC_SET_INFORMATION_PARMS pSetInfoParms,
  2288. IN PVOID DataBuffer,
  2289. IN UINT DataBufferLength
  2290. )
  2291. /*++
  2292. Routine Description:
  2293. Function makes only the IO control call little bit simpler.
  2294. Arguments:
  2295. DriverHandle - the device handle of the address object
  2296. InfoClass - the type of the requested information
  2297. StationId - direct, link or sap station id
  2298. pSetInfoParms - NT DLC parameter buffer
  2299. DataBuffer - actual set data buffer copied to the parameter buffer
  2300. DataBufferLength - length of the data buffer.
  2301. Return Value:
  2302. LLC_STATUS
  2303. --*/
  2304. {
  2305. pSetInfoParms->Header.StationId = StationId;
  2306. pSetInfoParms->Header.InfoClass = (USHORT)InfoClass;
  2307. if (DataBuffer != NULL) {
  2308. RtlMoveMemory(pSetInfoParms->Info.Buffer, DataBuffer, DataBufferLength);
  2309. }
  2310. return DoSyncDeviceIoControl(DriverHandle,
  2311. IOCTL_DLC_SET_INFORMATION,
  2312. pSetInfoParms,
  2313. DataBufferLength + sizeof(struct _DlcSetInfoHeader),
  2314. NULL,
  2315. 0
  2316. );
  2317. }
  2318. LLC_STATUS
  2319. DlcCallDriver(
  2320. IN UINT AdapterNumber,
  2321. IN UINT IoctlCommand,
  2322. IN PVOID pInputBuffer,
  2323. IN UINT InputBufferLength,
  2324. OUT PVOID pOutputBuffer,
  2325. IN UINT OutputBufferLength
  2326. )
  2327. /*++
  2328. Routine Description:
  2329. Function makes only the IO control call little bit simpler.
  2330. Arguments:
  2331. AdapterNumber - the requested adapter number (0 or 1)
  2332. IoctlCommand - DLC driver Ioctl code
  2333. pInputBuffer - input parameters
  2334. InputBufferLength - length of input parameters
  2335. pOutputBuffer - the returned data
  2336. OutputBufferLength - the length of the returned data
  2337. Return Value:
  2338. LLC_STATUS
  2339. --*/
  2340. {
  2341. NTSTATUS NtStatus;
  2342. HANDLE driverHandle;
  2343. EnterCriticalSection(&DriverHandlesCritSec);
  2344. driverHandle = aDlcDriverHandles[AdapterNumber];
  2345. LeaveCriticalSection(&DriverHandlesCritSec);
  2346. if (driverHandle) {
  2347. NtStatus = NtDeviceIoControlFile(driverHandle,
  2348. NULL,
  2349. NULL,
  2350. NULL,
  2351. &GlobalIoStatus,
  2352. IoctlCommand,
  2353. pInputBuffer,
  2354. InputBufferLength,
  2355. pOutputBuffer,
  2356. OutputBufferLength
  2357. );
  2358. } else {
  2359. NtStatus = STATUS_INVALID_HANDLE;
  2360. }
  2361. //
  2362. // if we get a real NT error (e.g. because the handle was invalid) then
  2363. // convert it into an adapter closed error
  2364. //
  2365. if (!NT_SUCCESS(NtStatus)) {
  2366. if ((NtStatus == STATUS_INVALID_HANDLE) || (NtStatus == STATUS_OBJECT_TYPE_MISMATCH)) {
  2367. //
  2368. // bad handle
  2369. //
  2370. return LLC_STATUS_ADAPTER_CLOSED;
  2371. } else if (NtStatus > LLC_STATUS_MAX_ERROR) {
  2372. //
  2373. // the NT DLC driver does not return any NT-level errors. If we get
  2374. // an NT-level error, then it must be because the IO subsystem
  2375. // detected an invalid pointer in the data we passed. Return an
  2376. // invalid pointer error
  2377. //
  2378. NtStatus = LLC_STATUS_INVALID_POINTER_IN_CCB;
  2379. }
  2380. } else if (NtStatus == STATUS_PENDING) {
  2381. //
  2382. // STATUS_PENDING is a success status
  2383. //
  2384. NtStatus = LLC_STATUS_PENDING;
  2385. }
  2386. return (LLC_STATUS)NtStatus;
  2387. }
  2388. #ifdef GRAB_READ
  2389. DWORD ReadGrabberCount = 2;
  2390. HANDLE ReadGrabberHandles[64];
  2391. PREAD_GRABBER ReadGrabberListHead = NULL;
  2392. PREAD_GRABBER ReadGrabberListTail = NULL;
  2393. CRITICAL_SECTION ReadGrabberListSect;
  2394. #endif
  2395. BOOLEAN
  2396. DllEntry(
  2397. IN PVOID DllHandle,
  2398. IN ULONG Reason,
  2399. IN PCONTEXT Context OPTIONAL
  2400. )
  2401. /*++
  2402. Routine Description:
  2403. Function initializes dlc for a new thread and terminates it in the
  2404. process exit.
  2405. Arguments:
  2406. DllHandle - don't need this
  2407. Reason - why this function is being called
  2408. Context - don't need this either
  2409. Return Value:
  2410. TRUE - nothing cannot go wrong in the initialization and
  2411. we cannot return error in close (or should we?).
  2412. --*/
  2413. {
  2414. static LLC_CCB OutputCcb; // MUST BE STATIC!!!
  2415. UNREFERENCED_PARAMETER(DllHandle); // avoid compiler warnings
  2416. UNREFERENCED_PARAMETER(Context); // avoid compiler warnings
  2417. if (Reason == DLL_PROCESS_ATTACH) {
  2418. #ifdef GRAB_READ
  2419. DWORD threadId;
  2420. OutputDebugString(L"DllEntry: Initializing ReadGrabber\n");
  2421. InitializeCriticalSection(&ReadGrabberListSect);
  2422. ReadGrabberHandles[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
  2423. ReadGrabberHandles[1] = CreateEvent(NULL, TRUE, FALSE, NULL);
  2424. CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReadGrabber, NULL, 0, &threadId);
  2425. #endif
  2426. //
  2427. // The global event handle is used to prevent the io-system
  2428. // to block calls, that are completed by READ.
  2429. //
  2430. InitializeCriticalSection(&AdapterOpenSection);
  2431. InitializeCriticalSection(&DriverHandlesCritSec);
  2432. RtlZeroMemory((PVOID)aDlcDriverHandles, sizeof(aDlcDriverHandles));
  2433. #if DBG
  2434. GetAcslanDebugFlags();
  2435. #endif
  2436. } else if (Reason == DLL_PROCESS_DETACH) {
  2437. UINT i;
  2438. LLC_CCB CloseCcb;
  2439. #ifdef GRAB_READ
  2440. ResetEvent(ReadGrabberHandles[0]);
  2441. #endif
  2442. //
  2443. // We must issue DIR_CLOSE_ADAPTER command for all
  2444. // opened adapters. Process exit does not close these
  2445. // handles before all pending IRPs have been completed.
  2446. // Thus this code actually flush all IRPs on dlc and lets
  2447. // IO- system to complete the cleanup.
  2448. //
  2449. RtlZeroMemory(&CloseCcb, sizeof(CloseCcb));
  2450. CloseCcb.uchDlcCommand = LLC_DIR_CLOSE_ADAPTER;
  2451. for (i = 0; i < LLC_MAX_ADAPTER_NUMBER; i++) {
  2452. if (aDlcDriverHandles[i] != NULL) {
  2453. CloseCcb.uchAdapterNumber = (UCHAR)i;
  2454. NtDeviceIoControlFile(aDlcDriverHandles[i],
  2455. NULL,
  2456. NULL,
  2457. NULL,
  2458. &GlobalIoStatus,
  2459. IOCTL_DLC_CLOSE_ADAPTER,
  2460. &CloseCcb,
  2461. sizeof(NT_DLC_CCB_INPUT),
  2462. &OutputCcb,
  2463. sizeof(NT_DLC_CCB_OUTPUT)
  2464. );
  2465. }
  2466. }
  2467. #if DBG
  2468. if (hDumpFile) {
  2469. fflush(hDumpFile);
  2470. fclose(hDumpFile);
  2471. }
  2472. #endif
  2473. //DeleteCriticalSection(&AdapterOpenSection);
  2474. //DeleteCriticalSection(&DriverHandlesCritSec);
  2475. }
  2476. return TRUE;
  2477. }
  2478. VOID
  2479. QueueCommandCompletion(
  2480. IN PLLC_CCB pCCB
  2481. )
  2482. /*++
  2483. Routine Description:
  2484. The routine queues a command completion event of a synchronous DLC command
  2485. to the command completion queue on the DLC driver.
  2486. RLF 04/23/93 Bogus: This should be handled in the driver
  2487. Arguments:
  2488. pCCB - OS/2 DLC Command control block, this must be double word aligned
  2489. Return Value:
  2490. LLC_STATUS - See the DLC API return values.
  2491. --*/
  2492. {
  2493. NT_DLC_COMPLETE_COMMAND_PARMS CompleteCommand;
  2494. UINT Status;
  2495. CompleteCommand.pCcbPointer = pCCB;
  2496. CompleteCommand.CommandCompletionFlag = pCCB->ulCompletionFlag;
  2497. CompleteCommand.StationId = GetCcbStationId(pCCB);
  2498. Status = DoSyncDeviceIoControl(aDlcDriverHandles[pCCB->uchAdapterNumber],
  2499. IOCTL_DLC_COMPLETE_COMMAND,
  2500. &CompleteCommand,
  2501. sizeof(CompleteCommand),
  2502. NULL,
  2503. 0
  2504. );
  2505. if (Status != STATUS_SUCCESS) {
  2506. pCCB->uchDlcStatus = (UCHAR)Status;
  2507. }
  2508. }
  2509. #ifdef GRAB_READ
  2510. PLLC_CCB Last8ReadCcbs[8];
  2511. DWORD LastReadCcbIndex = 0;
  2512. PLLC_PARMS Last8ReadParameterTables[8];
  2513. DWORD LastReadParameterTableIndex = 0;
  2514. DWORD Last8IFramesReceived[8];
  2515. DWORD LastReceivedIndex = 0;
  2516. DWORD NextIFrame = 0;
  2517. VOID ReadGrabber() {
  2518. DWORD status;
  2519. PLLC_CCB readCcb;
  2520. WCHAR buf[100];
  2521. // static DWORD NextIFrame = 0;
  2522. PREAD_GRABBER grabbedRead;
  2523. while (1) {
  2524. if (ReadGrabberCount > 3) {
  2525. wsprintf(buf, L"ReadGrabber: waiting for %d handles\n", ReadGrabberCount);
  2526. OutputDebugString(buf);
  2527. }
  2528. status = WaitForMultipleObjects(ReadGrabberCount,
  2529. ReadGrabberHandles,
  2530. FALSE,
  2531. INFINITE
  2532. );
  2533. if (status >= WAIT_OBJECT_0 && status < WAIT_OBJECT_0 + ReadGrabberCount) {
  2534. if (status == WAIT_OBJECT_0) {
  2535. OutputDebugString(L"ReadGrabber terminating\n");
  2536. ExitThread(0);
  2537. } else if (status != WAIT_OBJECT_0+1) {
  2538. // wsprintf(buf, L"ReadGrabber: READ completed. Index %d\n", status);
  2539. // OutputDebugString(buf);
  2540. if (grabbedRead = RemoveReadGrabber(ReadGrabberHandles[status])) {
  2541. readCcb = grabbedRead->pCcb;
  2542. Last8ReadCcbs[LastReadCcbIndex] = readCcb;
  2543. LastReadCcbIndex = (LastReadCcbIndex + 1) & 7;
  2544. Last8ReadParameterTables[LastReadParameterTableIndex] = readCcb->u.pParameterTable;
  2545. LastReadParameterTableIndex = (LastReadParameterTableIndex + 1) & 7;
  2546. if (readCcb->u.pParameterTable->Read.uchEvent & LLC_EVENT_RECEIVE_DATA) {
  2547. PLLC_BUFFER pBuffer;
  2548. INT i;
  2549. if (readCcb->u.pParameterTable->Read.uchEvent != LLC_EVENT_RECEIVE_DATA) {
  2550. OutputDebugString(L"ReadGrabber: RECEIVED DATA + other events\n");
  2551. }
  2552. pBuffer = readCcb->u.pParameterTable->Read.Type.Event.pReceivedFrame;
  2553. for (i = readCcb->u.pParameterTable->Read.Type.Event.usReceivedFrameCount; i; --i) {
  2554. if (pBuffer->NotContiguous.uchMsgType == LLC_I_FRAME) {
  2555. DWORD thisDlcHeader;
  2556. thisDlcHeader = *(ULONG UNALIGNED*)(pBuffer->NotContiguous.auchDlcHeader);
  2557. if (thisDlcHeader & 0x00FF0000 != NextIFrame) {
  2558. wsprintf(buf,
  2559. L"Error: ReadGrabber: This=%08X. Next=%08X\n",
  2560. thisDlcHeader,
  2561. NextIFrame
  2562. );
  2563. OutputDebugString(buf);
  2564. }
  2565. NextIFrame = (thisDlcHeader + 0x00020000) & 0x00FF0000;
  2566. Last8IFramesReceived[LastReceivedIndex] = thisDlcHeader & 0x00FF0000;
  2567. LastReceivedIndex = (LastReceivedIndex + 1) & 7;
  2568. wsprintf(buf, L"%08X ", thisDlcHeader);
  2569. OutputDebugString(buf);
  2570. }
  2571. pBuffer = pBuffer->NotContiguous.pNextFrame;
  2572. if (!pBuffer && i > 1) {
  2573. OutputDebugString(L"ReadGrabber: Next frame is NULL, Count > 1!\n");
  2574. break;
  2575. }
  2576. }
  2577. if (pBuffer) {
  2578. OutputDebugString(L"ReadGrabber: Error: More frames linked!\n");
  2579. }
  2580. } else {
  2581. if (!(readCcb->u.pParameterTable->Read.uchEvent & LLC_EVENT_TRANSMIT_COMPLETION)) {
  2582. wsprintf(buf,
  2583. L"\nReadGrabber: Event = %02X\n",
  2584. readCcb->u.pParameterTable->Read.uchEvent
  2585. );
  2586. OutputDebugString(buf);
  2587. }
  2588. }
  2589. // DUMPCCB(readCcb, TRUE, FALSE);
  2590. // wsprintf(buf, L"ReadGrabber: Closing Handle %08X\n", grabbedRead->NewEventHandle);
  2591. // OutputDebugString(buf);
  2592. CloseHandle(grabbedRead->NewEventHandle);
  2593. readCcb->hCompletionEvent = grabbedRead->OriginalEventHandle;
  2594. // wsprintf(buf, L"ReadGrabber: Signalling Event %08X\n", grabbedRead->OriginalEventHandle);
  2595. // OutputDebugString(buf);
  2596. SetEvent(grabbedRead->OriginalEventHandle);
  2597. LocalFree((HLOCAL)grabbedRead);
  2598. }
  2599. // } else {
  2600. // OutputDebugString(L"ReadGrabber: something added to list!\n");
  2601. }
  2602. ReadGrabberCount = MungeReadGrabberHandles();
  2603. if (status == WAIT_OBJECT_0+1) {
  2604. ResetEvent(ReadGrabberHandles[1]);
  2605. }
  2606. } else {
  2607. INT i;
  2608. if (status == 0xFFFFFFFF) {
  2609. status = GetLastError();
  2610. }
  2611. wsprintf(buf, L"Yoiks: didn't expect this? status = %d\nHandle array:\n", status);
  2612. OutputDebugString(buf);
  2613. for (i = 0; i < ReadGrabberCount; ++i) {
  2614. wsprintf(buf, L"Handle %d: %08X\n", i, ReadGrabberHandles[i]);
  2615. OutputDebugString(buf);
  2616. }
  2617. }
  2618. }
  2619. }
  2620. DWORD MungeReadGrabberHandles() {
  2621. INT i;
  2622. PREAD_GRABBER p;
  2623. WCHAR buf[100];
  2624. EnterCriticalSection(&ReadGrabberListSect);
  2625. p = ReadGrabberListHead;
  2626. for (i = 2; p; ++i) {
  2627. ReadGrabberHandles[i] = p->NewEventHandle;
  2628. // wsprintf(buf, L"MungeReadGrabber: adding Struct %08X Ccb %08X Handle %08X, index %d\n",
  2629. // p,
  2630. // p->pCcb,
  2631. // ReadGrabberHandles[i],
  2632. // i
  2633. // );
  2634. // OutputDebugString(buf);
  2635. p = p->List;
  2636. }
  2637. LeaveCriticalSection(&ReadGrabberListSect);
  2638. return i;
  2639. }
  2640. VOID AddReadGrabber(PREAD_GRABBER pStruct) {
  2641. WCHAR buf[100];
  2642. PREAD_GRABBER pRead;
  2643. BOOL found = FALSE;
  2644. EnterCriticalSection(&ReadGrabberListSect);
  2645. // for (pRead = ReadGrabberListHead; pRead; pRead = pRead->List) {
  2646. // if (pRead->pCcb == pStruct->pCcb) {
  2647. // wsprintf(buf, L"AddReadGrabber: CCB %08X already on list. Ignoring\n",
  2648. // pStruct->pCcb
  2649. // );
  2650. // OutputDebugString(buf);
  2651. // LocalFree((HLOCAL)pStruct);
  2652. // found = TRUE;
  2653. // break;
  2654. // }
  2655. // }
  2656. // if (!found) {
  2657. if (!ReadGrabberListHead) {
  2658. ReadGrabberListHead = pStruct;
  2659. } else {
  2660. ReadGrabberListTail->List = pStruct;
  2661. }
  2662. ReadGrabberListTail = pStruct;
  2663. pStruct->List = NULL;
  2664. // wsprintf(buf, L"AddReadGrabber: adding %08X, CCB %08X New Handle %08X Old Handle %08X\n",
  2665. // pStruct,
  2666. // pStruct->pCcb,
  2667. // pStruct->NewEventHandle,
  2668. // pStruct->OriginalEventHandle
  2669. // );
  2670. // OutputDebugString(buf);
  2671. SetEvent(ReadGrabberHandles[1]);
  2672. // }
  2673. LeaveCriticalSection(&ReadGrabberListSect);
  2674. }
  2675. PREAD_GRABBER RemoveReadGrabber(HANDLE hEvent) {
  2676. PREAD_GRABBER this, prev;
  2677. WCHAR buf[100];
  2678. EnterCriticalSection(&ReadGrabberListSect);
  2679. prev = NULL;
  2680. for (this = ReadGrabberListHead; this; this = this->List) {
  2681. if (this->NewEventHandle == hEvent) {
  2682. break;
  2683. } else {
  2684. prev = this;
  2685. }
  2686. }
  2687. if (!this) {
  2688. wsprintf(buf, L"RemoveReadGrabber: Can't find handle %08X in ReadGrabberList\n",
  2689. hEvent
  2690. );
  2691. OutputDebugString(buf);
  2692. } else {
  2693. if (prev) {
  2694. prev->List = this->List;
  2695. } else {
  2696. ReadGrabberListHead = this->List;
  2697. }
  2698. if (ReadGrabberListTail == this) {
  2699. ReadGrabberListTail = prev;
  2700. }
  2701. }
  2702. LeaveCriticalSection(&ReadGrabberListSect);
  2703. // wsprintf(buf, L"RemoveReadGrabber: removed %08X, CCB %08X Handle %08X\n",
  2704. // this,
  2705. // this ? this->pCcb : 0,
  2706. // this ? this->NewEventHandle : 0
  2707. // );
  2708. // OutputDebugString(buf);
  2709. return this;
  2710. }
  2711. #endif