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.

540 lines
13 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. vrnetb.c
  5. Abstract:
  6. Contains Netbios function handlers for Vdm Int5c support. This module
  7. contains the following Vr (VdmRedir) routines:
  8. VrNetbios5c
  9. VrNetbios5cInterrupt
  10. Private (Vrp) routines:
  11. Netbios32Post
  12. ResetLana
  13. VrNetbios5cInitialize
  14. IsPmNcbAtQueueHead
  15. Author:
  16. Colin Watson (colinw) 09-Dec-1991
  17. Environment:
  18. Any 32-bit flat address space
  19. Notes:
  20. Revision History:
  21. 09-Dec-1991 ColinW
  22. Created
  23. --*/
  24. #include <nt.h>
  25. #include <ntrtl.h> // ASSERT, DbgPrint
  26. #include <nturtl.h>
  27. #include <windows.h>
  28. #include <softpc.h> // x86 virtual machine definitions
  29. #include <vrdlctab.h>
  30. #include <vdmredir.h> // common Vdm Redir stuff
  31. #include <vrinit.h> // VrQueueCompletionHandler
  32. #include <smbgtpt.h> // Macros for misaligned data
  33. #include <dlcapi.h> // Official DLC API definition
  34. #include <ntdddlc.h> // IOCTL commands
  35. #include <dlcio.h> // Internal IOCTL API interface structures
  36. #include <vrdlc.h> // DLC prototypes
  37. #include <nb30.h> // NCB
  38. #include <netb.h> // NCBW
  39. #include <mvdm.h> // STOREWORD
  40. #include "vrdebug.h"
  41. #define BOOL // kludge for mips build
  42. #include <insignia.h> // Required for ica.h
  43. #include <xt.h> // Required for ica.h
  44. #include <ica.h>
  45. #include <vrica.h> // call_ica_hw_interrupt
  46. CRITICAL_SECTION PostCrit; // protects PostWorkQueue.
  47. LIST_ENTRY PostWorkQueue; // queue to 16 bit code.
  48. BYTE LanaReset[MAX_LANA+1];
  49. //
  50. // private routine prototypes
  51. //
  52. VOID
  53. Netbios32Post(
  54. PNCB pncb
  55. );
  56. UCHAR
  57. ResetLana(
  58. UCHAR Adapter
  59. );
  60. //
  61. // Vdm Netbios support routines
  62. //
  63. VOID
  64. VrNetbios5c(
  65. VOID
  66. )
  67. /*++
  68. Routine Description:
  69. Creates a copy of the NCB to submit to Netbios.
  70. Performs address translation from the registers provided by the 16 bit
  71. application and translates all the addresses in the NCB.
  72. Using a copy of the NCB also solves alignment problems.
  73. Arguments:
  74. None. All arguments are extracted from 16-bit context descriptor
  75. Return Value:
  76. None. Returns values in VDM Ax register
  77. --*/
  78. {
  79. PNCB pncb;
  80. PNCBW pncbw;
  81. BOOLEAN protectMode = (BOOLEAN)(getMSW() & MSW_PE);
  82. BOOLEAN isAsyncCommand;
  83. UCHAR command;
  84. USHORT es = getES();
  85. USHORT bx = getBX();
  86. //
  87. // es:bx is the 16 bit address of the NCB. Can be in real- or protect-mode
  88. // 16-bit memory
  89. //
  90. pncb = (PNCB)CONVERT_ADDRESS(es, bx, sizeof(NCB), protectMode);
  91. command = pncb->ncb_command;
  92. isAsyncCommand = command & ASYNCH;
  93. command &= ~ASYNCH;
  94. pncbw = RtlAllocateHeap(
  95. RtlProcessHeap(), 0,
  96. sizeof(NCBW));
  97. #if DBG
  98. IF_DEBUG(NETBIOS) {
  99. DBGPRINT("VrNetbios5c: NCB @ %04x:%04x Command=%02x pncbw=%08x\n",
  100. es,
  101. bx,
  102. pncb->ncb_command,
  103. pncbw
  104. );
  105. }
  106. #endif
  107. if ( pncbw == NULL ) {
  108. pncb->ncb_retcode = NRC_NORES;
  109. pncb->ncb_cmd_cplt = NRC_NORES;
  110. setAL( NRC_NORES );
  111. return;
  112. }
  113. //
  114. // Do not need a valid lana number for an ncb enum. If the lana mumber is out
  115. // of range let the driver handle it.
  116. //
  117. if ((command != NCBENUM) &&
  118. ( pncb->ncb_lana_num <= MAX_LANA ) &&
  119. ( LanaReset[pncb->ncb_lana_num] == FALSE )) {
  120. UCHAR result;
  121. //
  122. // Do a reset on the applications behalf. Most dos applications assume that the
  123. // redirector has reset the card already.
  124. //
  125. // Use default sessions. If application wants more sessions then it must execute
  126. // a reset itself. This will be very rare so executing this reset plus the
  127. // applications will not be a significant overhead.
  128. //
  129. result = ResetLana(pncb->ncb_lana_num);
  130. if (result != NRC_GOODRET) {
  131. pncb->ncb_retcode = result;
  132. pncb->ncb_cmd_cplt = result;
  133. setAL( result );
  134. return;
  135. }
  136. LanaReset[pncb->ncb_lana_num] = TRUE;
  137. }
  138. //
  139. // safe to use RtlCopyMemory - 16-bit memory and process heap don't overlap
  140. //
  141. RtlCopyMemory(
  142. pncbw,
  143. pncb,
  144. sizeof(NCB));
  145. pncbw->ncb_event = 0;
  146. // Fill in mvdm data fields
  147. pncbw->ncb_es = es;
  148. pncbw->ncb_bx = bx;
  149. pncbw->ncb_original_ncb = pncb;
  150. // Update all 16 bit pointers to 32 bit pointers
  151. pncbw->ncb_buffer = CONVERT_ADDRESS((ULONG)pncbw->ncb_buffer >> 16,
  152. (ULONG)pncbw->ncb_buffer & 0x0ffff,
  153. pncbw->ncb_length
  154. ? pncbw->ncb_length
  155. : (command == NCBCANCEL)
  156. ? sizeof(NCB)
  157. : 0,
  158. protectMode
  159. );
  160. //
  161. // if this is a NCB.CANCEL, then the ncb_buffer field should point at the
  162. // NCB we are cancelling. We stored the address of the 32-bit NCB in the
  163. // reserved field of the original 16-bit NCB
  164. //
  165. if (command == NCBCANCEL) {
  166. pncbw->ncb_buffer = (PUCHAR)READ_DWORD(&((PNCB)pncbw->ncb_buffer)->ncb_reserve);
  167. } else if ((command == NCBCHAINSEND) || (command == NCBCHAINSENDNA)) {
  168. pncbw->cu.ncb_chain.ncb_buffer2 =
  169. CONVERT_ADDRESS(
  170. (ULONG)pncbw->cu.ncb_chain.ncb_buffer2 >> 16,
  171. (ULONG)pncbw->cu.ncb_chain.ncb_buffer2 & 0x0ffff,
  172. pncbw->cu.ncb_chain.ncb_length2,
  173. protectMode
  174. );
  175. } else if ( command == NCBRESET ) {
  176. //
  177. // If it is a reset then modify the new NCB to the protect mode parameters
  178. //
  179. pncbw->cu.ncb_callname[0] = (pncb->ncb_lsn == 0) ? 6 : pncb->ncb_lsn;
  180. pncbw->cu.ncb_callname[1] = (pncb->ncb_num == 0) ? 12 : pncb->ncb_num;
  181. pncbw->cu.ncb_callname[2] = 16;
  182. pncbw->cu.ncb_callname[3] = 1;
  183. //
  184. // DOS always allocates resources on RESET: set ncb_lsn to 0 to indicate
  185. // this fact to Netbios (else it will free resources, causing us pain)
  186. //
  187. pncbw->ncb_lsn = 0;
  188. }
  189. //
  190. // we are about to submit the NCB. Store the address of the 32-bit structure
  191. // in the reserved field of the 16-bit structure for use in NCB.CANCEL
  192. //
  193. WRITE_DWORD(&pncb->ncb_reserve, pncbw);
  194. if ( !isAsyncCommand ) {
  195. setAL( Netbios( (PNCB)pncbw ) );
  196. // Copy back the fields that might have changed during the call.
  197. STOREWORD(pncb->ncb_length, pncbw->ncb_length);
  198. if (( command == NCBLISTEN ) ||
  199. ( command == NCBDGRECV ) ||
  200. ( command == NCBDGRECVBC )) {
  201. RtlCopyMemory( pncb->ncb_callname, pncbw->cu.ncb_callname, NCBNAMSZ );
  202. }
  203. pncb->ncb_retcode = pncbw->ncb_retcode;
  204. pncb->ncb_lsn = pncbw->ncb_lsn;
  205. pncb->ncb_num = pncbw->ncb_num;
  206. pncb->ncb_cmd_cplt = pncbw->ncb_cmd_cplt;
  207. RtlFreeHeap( RtlProcessHeap(), 0, pncbw );
  208. } else {
  209. //
  210. // This is an asynchronous call. Netbios32Post will free pncbw
  211. // We also note which (virtual) processor mode was in effect when we
  212. // received the call. This is used later to determine who should handle
  213. // the completion - the real-mode handler, or the new protect-mode
  214. // version
  215. //
  216. pncbw->ProtectModeNcb = (DWORD)protectMode;
  217. pncbw->ncb_post = Netbios32Post;
  218. pncb->ncb_retcode = NRC_PENDING;
  219. pncb->ncb_cmd_cplt = NRC_PENDING;
  220. setAL( Netbios( (PNCB)pncbw ) );
  221. }
  222. }
  223. VOID
  224. Netbios32Post(
  225. PNCB pncb
  226. )
  227. /*++
  228. Routine Description:
  229. This routine is called every time a 32 bit NCB completes. It examines the NCB.
  230. If the caller provided a POST routine then it queues the NCB to the 16 bit routine.
  231. Arguments:
  232. PNCB pncb - Supplies a 32 bit pointer to the NCB
  233. Return Value:
  234. None.
  235. --*/
  236. {
  237. PNCBW pncbw = (PNCBW) pncb;
  238. PNCB pdosNcb = pncbw->ncb_original_ncb;
  239. #if DBG
  240. IF_DEBUG(NETBIOS) {
  241. DBGPRINT("Netbios32Post: NCB @ %04x:%04x Command=%02x ANR=%08x. pncbw @ %08x\n",
  242. pncbw->ncb_es,
  243. pncbw->ncb_bx,
  244. pncbw->ncb_command,
  245. READ_DWORD(&pdosNcb->ncb_post),
  246. pncbw
  247. );
  248. }
  249. #endif
  250. if ( READ_DWORD(&pdosNcb->ncb_post) ) {
  251. //
  252. // Pretend we have a network card on IRQL NETWORK_LINE. Queue the NCB
  253. // completion to the NETWORK_LINE interrupt handler so that it will
  254. // call the 16 bit post routine.
  255. //
  256. EnterCriticalSection( &PostCrit );
  257. InsertTailList( &PostWorkQueue, &pncbw->u.ncb_next );
  258. LeaveCriticalSection( &PostCrit );
  259. VrQueueCompletionHandler(VrNetbios5cInterrupt);
  260. VrRaiseInterrupt();
  261. } else {
  262. //
  263. // Copy back the fields that might have changed during the call.
  264. //
  265. STOREWORD(pdosNcb->ncb_length, pncbw->ncb_length);
  266. if ((( pncbw->ncb_command & ~ASYNCH ) == NCBLISTEN ) ||
  267. (( pncbw->ncb_command & ~ASYNCH ) == NCBDGRECV ) ||
  268. (( pncbw->ncb_command & ~ASYNCH ) == NCBDGRECVBC )) {
  269. RtlCopyMemory( pdosNcb->ncb_callname, pncbw->cu.ncb_callname, NCBNAMSZ );
  270. }
  271. pdosNcb->ncb_retcode = pncbw->ncb_retcode;
  272. pdosNcb->ncb_lsn = pncbw->ncb_lsn;
  273. pdosNcb->ncb_num = pncbw->ncb_num;
  274. pdosNcb->ncb_cmd_cplt = pncbw->ncb_cmd_cplt;
  275. RtlFreeHeap( RtlProcessHeap(), 0, pncbw );
  276. }
  277. }
  278. VOID
  279. VrNetbios5cInterrupt(
  280. VOID
  281. )
  282. /*++
  283. Routine Description:
  284. If there is a completed asynchronous DLC CCB then complete it else
  285. Retrieves an NCB from the PostWorkQueue and returns it to the 16 bit code
  286. to call the post routine specified by the application.
  287. Arguments:
  288. None.
  289. Return Value:
  290. None. Returns values in VDM Ax, Es and Bx registers.
  291. --*/
  292. {
  293. #if DBG
  294. IF_DEBUG(NETBIOS) {
  295. DBGPRINT("Netbios5cInterrupt\n");
  296. }
  297. #endif
  298. EnterCriticalSection( &PostCrit );
  299. if (!IsListEmpty(&PostWorkQueue)) {
  300. PLIST_ENTRY entry;
  301. PNCBW pncbw;
  302. PNCB pncb;
  303. entry = RemoveHeadList(&PostWorkQueue);
  304. LeaveCriticalSection( &PostCrit );
  305. pncbw = CONTAINING_RECORD( entry, NCBW, u.ncb_next );
  306. pncb = pncbw->ncb_original_ncb;
  307. #if DBG
  308. IF_DEBUG(NETBIOS) {
  309. DBGPRINT("Netbios5cInterrupt returning pncbw: %lx, 16-bit NCB: %04x:%04x Command=%02x\n",
  310. pncbw,
  311. pncbw->ncb_es,
  312. pncbw->ncb_bx,
  313. pncbw->ncb_command
  314. );
  315. }
  316. #endif
  317. // Copy back the fields that might have changed during the call.
  318. STOREWORD(pncb->ncb_length, pncbw->ncb_length);
  319. if ((( pncbw->ncb_command & ~ASYNCH ) == NCBLISTEN ) ||
  320. (( pncbw->ncb_command & ~ASYNCH ) == NCBDGRECV ) ||
  321. (( pncbw->ncb_command & ~ASYNCH ) == NCBDGRECVBC )) {
  322. RtlCopyMemory( pncb->ncb_callname, pncbw->cu.ncb_callname, NCBNAMSZ );
  323. }
  324. pncb->ncb_retcode = pncbw->ncb_retcode;
  325. pncb->ncb_lsn = pncbw->ncb_lsn;
  326. pncb->ncb_num = pncbw->ncb_num;
  327. pncb->ncb_cmd_cplt = pncbw->ncb_cmd_cplt;
  328. setES( pncbw->ncb_es );
  329. setBX( pncbw->ncb_bx );
  330. setAL(pncbw->ncb_retcode);
  331. //
  332. // use flags to indicate to hardware interrupt routine that there is
  333. // NetBios post processing to do
  334. //
  335. SET_CALLBACK_NETBIOS();
  336. RtlFreeHeap( RtlProcessHeap(), 0, pncbw );
  337. } else {
  338. LeaveCriticalSection( &PostCrit );
  339. //
  340. // use flags to indicate there is no post processing to do
  341. //
  342. SET_CALLBACK_NOTHING();
  343. }
  344. }
  345. UCHAR
  346. ResetLana(
  347. UCHAR Adapter
  348. )
  349. /*++
  350. Routine Description:
  351. Reset the adapter on the applications behalf.
  352. Arguments:
  353. UCHAR Adapter - Supplies the lana number to reset.
  354. Return Value:
  355. Result of the reset.
  356. --*/
  357. {
  358. NCB ResetNcb;
  359. RtlZeroMemory( &ResetNcb, sizeof(NCB) );
  360. ResetNcb.ncb_command = NCBRESET;
  361. ResetNcb.ncb_lana_num = Adapter;
  362. ResetNcb.ncb_callname[0] = 64;
  363. ResetNcb.ncb_callname[1] = 128;
  364. ResetNcb.ncb_callname[2] = 16;
  365. ResetNcb.ncb_callname[3] = 1;
  366. Netbios( &ResetNcb );
  367. return ResetNcb.ncb_retcode;
  368. }
  369. VOID
  370. VrNetbios5cInitialize(
  371. VOID
  372. )
  373. /*++
  374. Routine Description:
  375. Initialize the global structures used to return post routine calls back to the application.
  376. Arguments:
  377. None.
  378. Return Value:
  379. None.
  380. --*/
  381. {
  382. int index;
  383. InitializeCriticalSection( &PostCrit );
  384. InitializeListHead( &PostWorkQueue );
  385. for ( index = 0; index <= MAX_LANA ; index++ ) {
  386. LanaReset[index] = FALSE;
  387. }
  388. }
  389. BOOLEAN
  390. IsPmNcbAtQueueHead(
  391. VOID
  392. )
  393. /*++
  394. Routine Description:
  395. Returns TRUE if the NCBW at the head of the PostWorkQueue originated in
  396. protect mode, else FALSE
  397. Arguments:
  398. None.
  399. Return Value:
  400. BOOLEAN
  401. TRUE - head of queue represents protect mode NCB
  402. FALSE - head of queue is real-mode NCB
  403. --*/
  404. {
  405. return (BOOLEAN)((CONTAINING_RECORD(PostWorkQueue.Flink, NCBW, u.ncb_next))->ProtectModeNcb);
  406. }