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.

2323 lines
58 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. netbios.c
  5. Abstract:
  6. This is the component of netbios that runs in the user process
  7. passing requests to \Device\Netbios.
  8. Author:
  9. Colin Watson (ColinW) 15-Mar-91
  10. Revision History:
  11. Ram Cherala (RamC) 31-Aug-95 Added a try/except around the code which
  12. calls the post routine in SendAddNcbToDriver
  13. function. Currently if there is an exception
  14. in the post routine this thread will die
  15. before it has a chance to call the
  16. "AddNameThreadExit" function to decrement
  17. the trhead count. This will result in not
  18. being able to shut down the machine without
  19. hitting the reset switch.
  20. --*/
  21. /*
  22. Notes:
  23. +-----------+ +------------+ +------------+
  24. | | | | | |
  25. | User | | User | | Worker |
  26. | Thread 1 | | Thread 2 | | thread in |
  27. | | | | | a Post Rtn.|
  28. +-----+-----+ +-----+------+ +------+-----+
  29. |Netbios(pncb);|Netbios(pncb); |
  30. v v |
  31. +-----+--------------+-----------------+------+
  32. | -----> Worker | NETAPI.DLL
  33. | WorkQueue thread |
  34. | -----> |
  35. +--------------------+------------------------+
  36. |
  37. +---------+---------+
  38. | |
  39. | \Device\Netbios |
  40. | |
  41. +-------------------+
  42. The netbios Worker thread is created automatically by the Netbios call
  43. when it determines that the user threads are calling Netbios() with
  44. calls that use a callback routine (called a Post routine in the NetBIOS
  45. specification).
  46. When a worker thread has been created, all requests will be sent via
  47. the WorkQueue to the worker thread for submission to \Device\Netbios.
  48. This ensures that send requests go on the wire in the same
  49. order as the send ncb's are presented. Because the IO system cancels all
  50. a threads requests when it terminates, the use of the worker thread allows
  51. such a request inside \Device\Netbios to complete normally.
  52. All Post routines are executed by the Worker thread. This allows any Win32
  53. synchronization mechanisms to be used between the Post routine and the
  54. applications normal code.
  55. The Worker thread terminates when the process exits or when it gets
  56. an exception such as an access violation.
  57. In addition. If the worker thread gets an addname it will create an
  58. extra thread which will process the addname and then die. This solves
  59. the problem that the netbios driver will block the users thread during an
  60. addname (by calling NtCreateFile) even if the caller specified ASYNCH. The
  61. same code is also used for ASTAT which also creates handles and can take a
  62. long time now that we support remote adapter status.
  63. */
  64. #include <netb.h>
  65. #include <lmcons.h>
  66. #include <netlib.h>
  67. #if defined(UNICODE)
  68. #define NETBIOS_SERVICE_NAME L"netbios"
  69. #else
  70. #define NETBIOS_SERVICE_NAME "netbios"
  71. #endif
  72. BOOL Initialized;
  73. CRITICAL_SECTION Crit; // protects WorkQueue & initialization.
  74. LIST_ENTRY WorkQueue; // queue to worker thread.
  75. HANDLE Event; // doorbell used when WorkQueue added too.
  76. HANDLE WorkerHandle; // Return value when worker thread created.
  77. HANDLE WaiterHandle; // Return value when waiter thread created.
  78. HANDLE NB; // This processes handle to \Device\Netbios.
  79. HANDLE ReservedEvent; // Used for synchronous calls
  80. LONG EventUse; // Prevents simultaneous use of ReservedEvent
  81. HANDLE AddNameEvent; // Doorbell used when an AddName worker thread
  82. // exits.
  83. volatile LONG AddNameThreadCount;
  84. //
  85. // Event used to wait for STOP notification from the Kernel mode NETBIOS.SYS
  86. //
  87. HANDLE StopEvent;
  88. IO_STATUS_BLOCK StopStatusBlock;
  89. #if AUTO_RESET
  90. //
  91. // Event used to wait for RESET notification from the Kernel mode NETBIOS.SYS
  92. // Adapters
  93. //
  94. CRITICAL_SECTION ResetCS; // protects access to LanaResetList
  95. LIST_ENTRY LanaResetList;
  96. NCB OutputNCB;
  97. HANDLE LanaResetEvent; // Event signalled when a new adapter is
  98. // bound to netbios and it needs to be reset
  99. IO_STATUS_BLOCK ResetStatusBlock;
  100. #endif
  101. HMODULE g_hModule;
  102. //
  103. // netbios command history
  104. //
  105. NCB_INFO g_QueuedHistory[16];
  106. DWORD g_dwNextQHEntry = 0;
  107. NCB_INFO g_DeQueuedHistory[16];
  108. DWORD g_dwNextDQHEntry = 0;
  109. NCB_INFO g_SyncCmdsHistory[16];
  110. DWORD g_dwNextSCEntry = 0;
  111. VOID
  112. SpinUpAddnameThread(
  113. IN PNCBI pncb
  114. );
  115. VOID
  116. AddNameThreadExit(
  117. VOID
  118. );
  119. DWORD
  120. SendAddNcbToDriver(
  121. IN PVOID Context
  122. );
  123. DWORD
  124. StartNetBIOSDriver(
  125. VOID
  126. );
  127. #if AUTO_RESET
  128. VOID
  129. ResetLanaAndPostListen(
  130. );
  131. #endif
  132. NTSTATUS
  133. StartNB(
  134. OUT OBJECT_ATTRIBUTES *pobjattr,
  135. IN UNICODE_STRING *punicode,
  136. OUT IO_STATUS_BLOCK *piosb
  137. )
  138. /*++
  139. Routine Description:
  140. This routine is a worker function of Netbios. It will try to start NB
  141. service.
  142. Arguments:
  143. OUT pobjattr - object attribute
  144. IN punicode - netbios file name
  145. OUT piosb - ioblock
  146. Return Value:
  147. The function value is the status of the operation.
  148. --*/
  149. {
  150. //
  151. // Open a handle to \\Device\Netbios
  152. //
  153. InitializeObjectAttributes(
  154. pobjattr, // obj attr to initialize
  155. punicode, // string to use
  156. OBJ_CASE_INSENSITIVE, // Attributes
  157. NULL, // Root directory
  158. NULL); // Security Descriptor
  159. return NtCreateFile(
  160. &NB, // ptr to handle
  161. GENERIC_READ // desired...
  162. | GENERIC_WRITE, // ...access
  163. pobjattr, // name & attributes
  164. piosb, // I/O status block.
  165. NULL, // alloc size.
  166. FILE_ATTRIBUTE_NORMAL,
  167. FILE_SHARE_DELETE // share...
  168. | FILE_SHARE_READ
  169. | FILE_SHARE_WRITE, // ...access
  170. FILE_OPEN_IF, // create disposition
  171. 0, // ...options
  172. NULL, // EA buffer
  173. 0L ); // Ea buffer len
  174. }
  175. unsigned char APIENTRY
  176. Netbios(
  177. IN PNCB pncb
  178. )
  179. /*++
  180. Routine Description:
  181. This routine is the applications entry point into netapi.dll to support
  182. netbios 3.0 conformant applications.
  183. Arguments:
  184. IN PNCB pncb- Supplies the NCB to be processed. Contents of the NCB and
  185. buffers pointed to by the NCB will be modified in conformance with
  186. the netbios 3.0 specification.
  187. Return Value:
  188. The function value is the status of the operation.
  189. Notes:
  190. The reserved field is used to hold the IO_STATUS_BLOCK.
  191. Even if the application specifies ASYNCH, the thread may get blocked
  192. for a period of time while we open transports, create worker threads
  193. etc.
  194. --*/
  195. {
  196. //
  197. // pncbi saves doing lots of type casting. The internal form includes
  198. // the use of the reserved fields.
  199. //
  200. PNCBI pncbi = (PNCBI) pncb;
  201. NTSTATUS ntStatus;
  202. BOOL bPending = FALSE;
  203. if ( ((ULONG_PTR)pncbi & 3) != 0)
  204. {
  205. //
  206. // NCB must be 32 bit aligned
  207. //
  208. pncbi->ncb_retcode = pncbi->ncb_cmd_cplt = NRC_BADDR;
  209. return NRC_BADDR;
  210. }
  211. //
  212. // using this field to fix bug # 293765
  213. //
  214. pncbi-> ncb_reserved = 0;
  215. //
  216. // Conform to Netbios 3.0 specification by flagging request in progress
  217. //
  218. pncbi->ncb_retcode = pncbi->ncb_cmd_cplt = NRC_PENDING;
  219. DisplayNcb( pncbi );
  220. if ( !Initialized )
  221. {
  222. EnterCriticalSection( &Crit );
  223. //
  224. // Check again to see if another thread got into the critical section
  225. // and initialized the worker thread.
  226. //
  227. if ( !Initialized )
  228. {
  229. IO_STATUS_BLOCK iosb;
  230. OBJECT_ATTRIBUTES objattr;
  231. UNICODE_STRING unicode;
  232. HANDLE Threadid;
  233. BOOL Flag;
  234. //
  235. // 1. start netbios driver
  236. //
  237. //
  238. // Open handle to \\Device\Netbios
  239. //
  240. RtlInitUnicodeString( &unicode, NB_DEVICE_NAME);
  241. ntStatus = StartNB( &objattr, &unicode, &iosb );
  242. if ( !NT_SUCCESS( ntStatus ) )
  243. {
  244. //
  245. // Load the driver
  246. //
  247. DWORD err = 0;
  248. err = StartNetBIOSDriver();
  249. if ( err )
  250. {
  251. pncbi->ncb_retcode = NRC_OPENERR;
  252. pncbi->ncb_cmd_cplt = NRC_OPENERR;
  253. NbPrintf( ( "[NETAPI32] Failed to load driver : %lx\n",
  254. err ));
  255. LeaveCriticalSection( &Crit );
  256. return pncbi->ncb_cmd_cplt;
  257. }
  258. else
  259. {
  260. //
  261. // Driver loaded.
  262. // Open handle to \\Device\Netbios
  263. //
  264. ntStatus = StartNB( &objattr, &unicode, &iosb );
  265. if ( !NT_SUCCESS( ntStatus ) )
  266. {
  267. pncbi->ncb_retcode = NRC_OPENERR;
  268. pncbi->ncb_cmd_cplt = NRC_OPENERR;
  269. NbPrintf( ( "[NETAPI32] Failed to open handle : %X\n",
  270. ntStatus ));
  271. LeaveCriticalSection( &Crit );
  272. return pncbi->ncb_cmd_cplt;
  273. }
  274. }
  275. }
  276. //
  277. // 2. create a reserved (reusable) event for internal use
  278. //
  279. ntStatus = NtCreateEvent(
  280. &ReservedEvent, EVENT_ALL_ACCESS,
  281. NULL, SynchronizationEvent, FALSE
  282. );
  283. if ( !NT_SUCCESS( ntStatus) )
  284. {
  285. pncbi->ncb_retcode = NRC_SYSTEM;
  286. pncbi->ncb_cmd_cplt = NRC_SYSTEM;
  287. NbPrintf( ( "[NETAPI32] Failed to create Reserved Event : %X\n",
  288. ntStatus ) );
  289. LeaveCriticalSection( &Crit );
  290. NtClose( NB );
  291. NB = NULL;
  292. return pncbi->ncb_cmd_cplt;
  293. }
  294. EventUse = 1;
  295. //
  296. // Initialize shared datastructures
  297. //
  298. //
  299. // create a queue for work items to be queued to the Worker thread
  300. //
  301. InitializeListHead( &WorkQueue );
  302. //
  303. // 4. create an event to communicate with the Worker thread
  304. //
  305. ntStatus = NtCreateEvent(
  306. &Event, EVENT_ALL_ACCESS,
  307. NULL, SynchronizationEvent, FALSE
  308. );
  309. if ( !NT_SUCCESS( ntStatus ) )
  310. {
  311. pncbi->ncb_retcode = NRC_SYSTEM;
  312. pncbi->ncb_cmd_cplt = NRC_SYSTEM;
  313. NbPrintf( ( "[NETAPI32] Failed to create Event : %X\n",
  314. ntStatus ) );
  315. LeaveCriticalSection( &Crit );
  316. NtClose( ReservedEvent );
  317. NtClose( NB );
  318. NB = NULL;
  319. return pncbi->ncb_cmd_cplt;
  320. }
  321. //
  322. // 5.
  323. // create an event to synchronize ADD name operations with
  324. // Lana Reset operations. Both these are performed in separate
  325. // threads and RESET operations are gated by the ADD names
  326. //
  327. ntStatus = NtCreateEvent(
  328. &AddNameEvent, EVENT_ALL_ACCESS,
  329. NULL, NotificationEvent, FALSE
  330. );
  331. if ( !NT_SUCCESS( ntStatus ) )
  332. {
  333. pncbi->ncb_retcode = NRC_SYSTEM;
  334. pncbi->ncb_cmd_cplt = NRC_SYSTEM;
  335. NbPrintf( ( "[NETAPI32] Failed to create AddName Event : %X\n",
  336. ntStatus ) );
  337. LeaveCriticalSection( &Crit );
  338. NtClose( Event );
  339. NtClose( ReservedEvent );
  340. NtClose( NB );
  341. NB = NULL;
  342. return pncbi->ncb_cmd_cplt;
  343. }
  344. //
  345. // 6. Create an event to register for stop notification.
  346. //
  347. ntStatus = NtCreateEvent(
  348. &StopEvent,
  349. EVENT_ALL_ACCESS,
  350. NULL,
  351. SynchronizationEvent,
  352. FALSE
  353. );
  354. if ( !NT_SUCCESS( ntStatus ) )
  355. {
  356. pncbi->ncb_retcode = NRC_SYSTEM;
  357. pncbi->ncb_cmd_cplt = NRC_SYSTEM;
  358. NbPrintf( ( "[NETAPI32] Failed to create StopEvent Event : %X\n",
  359. ntStatus ) );
  360. LeaveCriticalSection( &Crit );
  361. NtClose( AddNameEvent );
  362. NtClose( Event );
  363. NtClose( ReservedEvent );
  364. NtClose( NB );
  365. NB = NULL;
  366. return pncbi->ncb_cmd_cplt;
  367. }
  368. #if AUTO_RESET
  369. //
  370. // 7. Create an event to register for reset notification.
  371. //
  372. ntStatus = NtCreateEvent(
  373. &LanaResetEvent,
  374. EVENT_ALL_ACCESS,
  375. NULL,
  376. SynchronizationEvent,
  377. FALSE
  378. );
  379. if ( !NT_SUCCESS( ntStatus ) )
  380. {
  381. pncbi->ncb_retcode = NRC_SYSTEM;
  382. pncbi->ncb_cmd_cplt = NRC_SYSTEM;
  383. NbPrintf( ( "[NETAPI32] Failed to create StopEvent Event : %X\n",
  384. ntStatus ) );
  385. LeaveCriticalSection( &Crit );
  386. NtClose( StopEvent );
  387. NtClose( AddNameEvent );
  388. NtClose( Event );
  389. NtClose( ReservedEvent );
  390. NtClose( NB );
  391. NB = NULL;
  392. return pncbi->ncb_cmd_cplt;
  393. }
  394. #endif
  395. //
  396. // 8. create a worker thread to handle async. Netbios requests
  397. //
  398. {
  399. TCHAR szFileName[MAX_PATH + 1];
  400. GetModuleFileName(g_hModule, szFileName,
  401. sizeof(szFileName) / sizeof(TCHAR));
  402. LoadLibrary(szFileName);
  403. }
  404. WaiterHandle = CreateThread(
  405. NULL, // Standard thread attributes
  406. 0, // Use same size stack as users
  407. // application
  408. NetbiosWaiter,
  409. // Routine to start in new thread
  410. 0, // Parameter to thread
  411. 0, // No special CreateFlags
  412. (LPDWORD)&Threadid
  413. );
  414. if ( WaiterHandle == NULL )
  415. {
  416. pncbi->ncb_retcode = NRC_SYSTEM;
  417. pncbi->ncb_cmd_cplt = NRC_SYSTEM;
  418. NbPrintf( ( "[NETAPI32] Failed to create Waiter thread" ) );
  419. LeaveCriticalSection( &Crit );
  420. NtClose( StopEvent );
  421. NtClose( AddNameEvent );
  422. NtClose( Event );
  423. NtClose( ReservedEvent );
  424. NtClose( NB );
  425. NB = NULL;
  426. return pncbi->ncb_cmd_cplt;
  427. }
  428. NbPrintf( ( "Waiter handle: %lx, threadid %lx\n", WaiterHandle, Threadid ) );
  429. }
  430. Initialized = TRUE;
  431. LeaveCriticalSection( &Crit );
  432. }
  433. //
  434. // Verify that handle to \\Device\Netbios is still open.
  435. //
  436. if ( NB == NULL )
  437. {
  438. pncbi->ncb_retcode = NRC_OPENERR;
  439. pncbi->ncb_cmd_cplt = NRC_OPENERR;
  440. NbPrintf( ("[NETAPI32] Netbios service has been stopped\n") );
  441. return pncbi->ncb_cmd_cplt;
  442. }
  443. //
  444. // Disallow simultaneous use of both event and callback routine.
  445. // This will cut down the test cases by disallowing a weird feature.
  446. //
  447. if ( ( ( pncbi->ncb_command & ASYNCH) != 0) &&
  448. ( pncbi->ncb_event) &&
  449. ( pncbi->ncb_post ) )
  450. {
  451. pncbi->ncb_retcode = NRC_ILLCMD;
  452. pncbi->ncb_cmd_cplt = NRC_ILLCMD;
  453. NbPrintf( ( "[NETAPI32] Event and Post Routine specified\n" ) );
  454. return pncbi->ncb_cmd_cplt;
  455. }
  456. //
  457. // if synchronous command
  458. //
  459. if ( (pncb->ncb_command & ASYNCH) == 0 )
  460. {
  461. NTSTATUS Status;
  462. LONG EventOwned;
  463. // NbPrint( ("[NETAPI32] Synchronpus netbios call\n") );
  464. //
  465. // Caller wants a synchronous call so ignore ncb_post and ncb_event.
  466. //
  467. // We need an event so that we can pause if STATUS_PENDING is returned.
  468. //
  469. EventOwned = InterlockedDecrement( &EventUse );
  470. //
  471. // If EventUse went from 1 to 0 then we obtained ReservedEvent
  472. //
  473. if ( EventOwned == 0)
  474. {
  475. pncbi->ncb_event = ReservedEvent;
  476. }
  477. else
  478. {
  479. InterlockedIncrement( &EventUse );
  480. Status = NtCreateEvent(
  481. &pncbi->ncb_event, EVENT_ALL_ACCESS,
  482. NULL, SynchronizationEvent,
  483. FALSE
  484. );
  485. if ( !NT_SUCCESS( Status ) )
  486. {
  487. //
  488. // Failed to create event
  489. //
  490. pncbi->ncb_retcode = NRC_SYSTEM;
  491. pncbi->ncb_cmd_cplt = NRC_SYSTEM;
  492. NbPrintf( ( "[NETAPI32] Failed to create event : %X\n", Status ) );
  493. return pncbi->ncb_cmd_cplt;
  494. }
  495. }
  496. pncbi-> ncb_post = NULL;
  497. //
  498. // Check if the worker thread has been created. If it has queue workitem
  499. // to it. Else use the caller's thread to execute synchronous NCB command
  500. //
  501. if ( WorkerHandle == NULL )
  502. {
  503. ADD_SYNCCMD_ENTRY(pncbi);
  504. //
  505. // Worker thread has not been created. Execute in the context of
  506. // invoker's thread.
  507. //
  508. SendNcbToDriver( pncbi );
  509. }
  510. else
  511. {
  512. //
  513. // Queue Netbios command to worker thread and wait for APC to fire
  514. //
  515. QueueToWorker( pncbi );
  516. }
  517. do
  518. {
  519. ntStatus = NtWaitForSingleObject(
  520. pncbi->ncb_event, TRUE, NULL
  521. );
  522. } while ( ( ntStatus == STATUS_USER_APC ) ||
  523. ( ntStatus == STATUS_ALERTED) );
  524. ASSERT( ntStatus == STATUS_SUCCESS );
  525. if ( !NT_SUCCESS(ntStatus) )
  526. {
  527. NbPrintf(( "[NETAPI32] NtWaitForSingleObject failed: %X\n", ntStatus ) );
  528. pncbi->ncb_retcode = NRC_SYSTEM;
  529. pncbi->ncb_cmd_cplt = NRC_SYSTEM;
  530. }
  531. //
  532. // release the local event used to wait for
  533. // completion of netbios command
  534. //
  535. if ( EventOwned == 0)
  536. {
  537. InterlockedIncrement( &EventUse );
  538. }
  539. else
  540. {
  541. NtClose( pncbi->ncb_event );
  542. }
  543. pncbi-> ncb_event = NULL;
  544. }
  545. else
  546. {
  547. //
  548. // Async netbios command. Queue to worker thread
  549. //
  550. //
  551. // Check if worker exists.
  552. //
  553. if ( WorkerHandle == NULL )
  554. {
  555. EnterCriticalSection( &Crit );
  556. //
  557. // verify that worker thread has not been created by
  558. // while this thread was waiting in EnterCriticalSection
  559. //
  560. if ( WorkerHandle == NULL )
  561. {
  562. HANDLE Threadid;
  563. BOOL Flag;
  564. //
  565. // create a worker thread to handle async. Netbios requests
  566. //
  567. WorkerHandle = CreateThread(
  568. NULL, // Standard thread attributes
  569. 0, // Use same size stack as users
  570. // application
  571. NetbiosWorker,
  572. // Routine to start in new thread
  573. 0, // Parameter to thread
  574. 0, // No special CreateFlags
  575. (LPDWORD)&Threadid
  576. );
  577. if ( WorkerHandle == NULL )
  578. {
  579. pncbi->ncb_retcode = NRC_SYSTEM;
  580. pncbi->ncb_cmd_cplt = NRC_SYSTEM;
  581. NbPrintf( ( "[NETAPI32] Failed to create Worker thread" ) );
  582. LeaveCriticalSection( &Crit );
  583. return pncbi->ncb_cmd_cplt;
  584. }
  585. Flag = SetThreadPriority(
  586. WorkerHandle,
  587. THREAD_PRIORITY_ABOVE_NORMAL
  588. );
  589. ASSERT( Flag == TRUE );
  590. if ( Flag != TRUE )
  591. {
  592. NbPrintf(
  593. ("[NETAPI32] Worker SetThreadPriority: %lx\n", GetLastError() )
  594. );
  595. }
  596. AddNameThreadCount = 0;
  597. NbPrintf( ( "Worker handle: %lx, threadid %lx\n", WorkerHandle, Threadid ) );
  598. }
  599. LeaveCriticalSection( &Crit );
  600. }
  601. // NbPrint( ("[NETAPI32] Asynchronpus netbios call\n") );
  602. bPending = TRUE;
  603. QueueToWorker( pncbi );
  604. }
  605. switch ( pncb->ncb_command & ~ASYNCH )
  606. {
  607. case NCBRECV:
  608. case NCBRECVANY:
  609. case NCBDGRECV:
  610. case NCBDGSENDBC:
  611. case NCBDGRECVBC:
  612. case NCBENUM:
  613. case NCBASTAT:
  614. case NCBSSTAT:
  615. case NCBCANCEL:
  616. case NCBCALL:
  617. DisplayNcb( pncbi );
  618. }
  619. if ( bPending )
  620. {
  621. return NRC_GOODRET;
  622. }
  623. else
  624. {
  625. return pncbi->ncb_cmd_cplt;
  626. }
  627. } // NetBios
  628. DWORD
  629. StartNetBIOSDriver(
  630. VOID
  631. )
  632. /*++
  633. Routine Description:
  634. Starts the netbios.sys driver using the service controller
  635. Arguments:
  636. none
  637. Returns:
  638. Error return from service controller.
  639. ++*/
  640. {
  641. DWORD err = NO_ERROR;
  642. SC_HANDLE hSC;
  643. SC_HANDLE hSCService;
  644. hSC = OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT );
  645. if (hSC == NULL)
  646. {
  647. return(GetLastError());
  648. }
  649. hSCService = OpenService( hSC, NETBIOS_SERVICE_NAME, SERVICE_START );
  650. if (hSCService == NULL)
  651. {
  652. CloseServiceHandle(hSC);
  653. return(GetLastError());
  654. }
  655. if ( !StartService( hSCService, 0, NULL ) )
  656. {
  657. err = GetLastError();
  658. }
  659. CloseServiceHandle(hSCService);
  660. CloseServiceHandle(hSC);
  661. if ( err )
  662. {
  663. NbPrintf( ("[NETAPI32] LEAVING StartNetBIOSDriver, Error : %d\n", err) );
  664. }
  665. return(err);
  666. }
  667. VOID
  668. QueueToWorker(
  669. IN PNCBI pncb
  670. )
  671. /*++
  672. Routine Description:
  673. This routine queues an ncb to the worker thread.
  674. Arguments:
  675. IN PNCBI pncb - Supplies the NCB to be processed. Contents of the NCB and
  676. buffers pointed to by the NCB will be modified in conformance with
  677. the netbios 3.0 specification.
  678. Return Value:
  679. The function value is the status of the operation.
  680. --*/
  681. {
  682. if ( pncb->ncb_event != NULL ) {
  683. NtResetEvent( pncb->ncb_event, NULL );
  684. }
  685. EnterCriticalSection( &Crit );
  686. if ( pncb-> ncb_reserved == 0 ) {
  687. InsertTailList( &WorkQueue, &pncb->u.ncb_next );
  688. pncb-> ncb_reserved = 1;
  689. //
  690. // Note queued distory
  691. //
  692. ADD_QUEUE_ENTRY(pncb);
  693. }
  694. LeaveCriticalSection( &Crit );
  695. // Make sure the worker is awake to perform the request
  696. NtSetEvent(Event, NULL);
  697. }
  698. #if _MSC_FULL_VER >= 13008827
  699. #pragma warning(push)
  700. #pragma warning(disable:4715) // Not all control paths return (due to infinite loop)
  701. #endif
  702. DWORD
  703. NetbiosWorker(
  704. IN LPVOID Parameter
  705. )
  706. /*++
  707. Routine Description:
  708. This routine processes ASYNC requests made with the callback interface.
  709. The reasons for using a seperate thread are:
  710. 1) If a thread makes an async request and exits while the request
  711. is outstanding then the request will be cancelled by the IO system.
  712. 2) A seperate thread must be used so that the users POST routine
  713. can use normal synchronization APIs to access shared data structures.
  714. If the users thread is used then deadlock can and will happen.
  715. The POST routine operates in the context of the worker thread. There are
  716. no restrictions on what the POST routine can do. For example it can
  717. submit another ASYNCH request if desired. It will add it to the queue
  718. of work and set the event as normal.
  719. The worker thread will die when the process terminates.
  720. Arguments:
  721. IN PULONG Parameter - supplies an unused parameter.
  722. Return Value:
  723. none.
  724. --*/
  725. {
  726. NTSTATUS Status;
  727. while ( TRUE)
  728. {
  729. //
  730. // Wait for a request to be placed onto the work queue.
  731. //
  732. //
  733. // Must wait alertable so that the Apc (post) routine is called.
  734. //
  735. Status = NtWaitForSingleObject( Event, TRUE, NULL );
  736. if ( ( Status == STATUS_SUCCESS ) && ( NB != NULL ) )
  737. {
  738. EnterCriticalSection( &Crit );
  739. //
  740. // remove each Netbios request and forward it to the NETBIOS driver
  741. //
  742. while ( !IsListEmpty( &WorkQueue ) )
  743. {
  744. PLIST_ENTRY entry;
  745. PNCBI pncb;
  746. entry = RemoveHeadList(&WorkQueue);
  747. //
  748. // Zero out reserved field again
  749. //
  750. entry->Flink = entry->Blink = 0;
  751. pncb = CONTAINING_RECORD( entry, NCBI, u.ncb_next );
  752. ADD_DEQUEUE_ENTRY(pncb);
  753. LeaveCriticalSection( &Crit );
  754. // Give ncb to the driver specifying the callers APC routine
  755. if ( (pncb->ncb_command & ~ASYNCH) == NCBRESET )
  756. {
  757. //
  758. // We may have threads adding names. Wait until
  759. // they are complete before submitting the reset.
  760. // Addnames and resets are rare so this should rarely
  761. // affect an application.
  762. //
  763. EnterCriticalSection( &Crit );
  764. NtResetEvent( AddNameEvent, NULL );
  765. while ( AddNameThreadCount != 0 )
  766. {
  767. LeaveCriticalSection( &Crit );
  768. NtWaitForSingleObject( AddNameEvent, TRUE, NULL );
  769. EnterCriticalSection( &Crit );
  770. NtResetEvent( AddNameEvent, NULL );
  771. }
  772. LeaveCriticalSection( &Crit );
  773. }
  774. //
  775. // SendNcbToDriver must not be in a critical section since the
  776. // request may block if its a non ASYNCH request.
  777. //
  778. if (( (pncb->ncb_command & ~ASYNCH) != NCBADDNAME ) &&
  779. ( (pncb->ncb_command & ~ASYNCH) != NCBADDGRNAME ) &&
  780. ( (pncb->ncb_command & ~ASYNCH) != NCBASTAT ))
  781. {
  782. SendNcbToDriver( pncb );
  783. }
  784. else
  785. {
  786. SpinUpAddnameThread( pncb );
  787. }
  788. EnterCriticalSection( &Crit );
  789. }
  790. LeaveCriticalSection( &Crit );
  791. }
  792. else
  793. if ( NB == NULL )
  794. {
  795. }
  796. }
  797. return 0;
  798. UNREFERENCED_PARAMETER( Parameter );
  799. }
  800. DWORD
  801. NetbiosWaiter(
  802. IN LPVOID Parameter
  803. )
  804. /*++
  805. Routine Description:
  806. This routine pends IOCTLs with the kernel mde component of Netbios and
  807. wait for them to complete. The reason for a separate thread is that
  808. these IOCTLs cannot be pended in the context of the user threads as
  809. exiting the user thread will cause the IOCTL to get cancelled.
  810. In addition this thread is created at Netbios initialization (refer
  811. Netbios function) which could (and is) called from the DLL main of
  812. applications. So the initialization code cannot wait for this thread
  813. to be created and initialized due to NT serialization of library
  814. loads and thread creation.
  815. To merge this thread with the Worker thread was deemed risky. To do
  816. this the worker thread would execute all ASYNC requests and SYNC
  817. requests would be executed in the context of the user's thread. This
  818. was a break from the the previous model where the once the Worker
  819. thread was created all requests (ASYNC and SYNC) would be executed
  820. in the context of the worker thread. To preserve the previous mode
  821. of operation a separate wait thread was created. **** There may be
  822. a better way to do this **** with only one thread but I am not sure.
  823. Arguments:
  824. IN PULONG Parameter - supplies an unused parameter.
  825. Return Value:
  826. none.
  827. --*/
  828. {
  829. #if AUTO_RESET
  830. #define POS_STOP 0
  831. #define POS_RESET 1
  832. #endif
  833. NTSTATUS Status;
  834. //
  835. // Send an IOCTL down to the kernel mode Netbios driver, to register
  836. // for stop notification. This call should return STATUS_PENDING.
  837. // The event specified "StopEvent" will be signalled when the netbios
  838. // driver is being unloaded.
  839. //
  840. Status = NtDeviceIoControlFile(
  841. NB,
  842. StopEvent,
  843. NULL, NULL,
  844. &StopStatusBlock,
  845. IOCTL_NB_REGISTER_STOP,
  846. NULL, 0,
  847. NULL, 0
  848. );
  849. if ( ( Status != STATUS_PENDING ) &&
  850. ( Status != STATUS_SUCCESS ) )
  851. {
  852. NbPrintf(
  853. ("[NETAPI32] : Netbios IOCTL for STOP failed with status %lx\n", Status)
  854. );
  855. }
  856. #if AUTO_RESET
  857. Status = NtDeviceIoControlFile(
  858. NB,
  859. LanaResetEvent,
  860. NULL, NULL,
  861. &ResetStatusBlock,
  862. IOCTL_NB_REGISTER_RESET,
  863. NULL, 0,
  864. (PVOID) &OutputNCB, sizeof( NCB )
  865. );
  866. if ( ( Status != STATUS_PENDING ) &&
  867. ( Status != STATUS_SUCCESS ) )
  868. {
  869. //
  870. // Failed to register reset notification.
  871. //
  872. NbPrintf(
  873. ("[NETAPI32] : Netbios : Failed to register Reset event\n" )
  874. );
  875. }
  876. #endif
  877. while ( TRUE )
  878. {
  879. #if AUTO_RESET
  880. HANDLE Events[] = { StopEvent, LanaResetEvent };
  881. Status = NtWaitForMultipleObjects( 2, Events, WaitAny, TRUE, NULL );
  882. if ( Status == POS_STOP )
  883. {
  884. Status = NtClose( NB );
  885. InterlockedExchangePointer( (PVOID *) &NB, NULL );
  886. NbPrintf( ("[NETAPI32] Stop event signaled, Status : %lx\n", Status) );
  887. }
  888. else
  889. if ( ( Status == POS_RESET ) && (NB != NULL ) )
  890. {
  891. NbPrintf( ("[NETAPI32] Reset event signaled\n") );
  892. ResetLanaAndPostListen();
  893. }
  894. #else
  895. Status = NtWaitForSingleObject( StopEvent, TRUE, NULL );
  896. if ( Status == STATUS_SUCCESS )
  897. {
  898. NbPrintf( ("[NETAPI32] Stop event signaled\n") );
  899. NtClose( NB );
  900. InterlockedExchangePointer( (PVOID *) &NB, NULL );
  901. }
  902. #endif
  903. }
  904. return 0;
  905. }
  906. #if _MSC_FULL_VER >= 13008827
  907. #pragma warning(pop)
  908. #endif
  909. VOID
  910. SendNcbToDriver(
  911. IN PNCBI pncb
  912. )
  913. /*++
  914. Routine Description:
  915. This routine determines the Device Ioctl code to be used to send the
  916. ncb to \Device\Netbios and then does the call to send the request
  917. to the driver.
  918. Arguments:
  919. IN PNCBI pncb - supplies the NCB to be sent to the driver.
  920. Return Value:
  921. None.
  922. --*/
  923. {
  924. NTSTATUS ntstatus;
  925. char * buffer;
  926. unsigned short length;
  927. // Use NULL for the buffer if only the NCB is to be passed.
  928. switch ( pncb->ncb_command & ~ASYNCH ) {
  929. case NCBSEND:
  930. case NCBSENDNA:
  931. case NCBRECV:
  932. case NCBRECVANY:
  933. case NCBDGSEND:
  934. case NCBDGRECV:
  935. case NCBDGSENDBC:
  936. case NCBDGRECVBC:
  937. case NCBASTAT:
  938. case NCBFINDNAME:
  939. case NCBSSTAT:
  940. case NCBENUM:
  941. case NCBACTION:
  942. buffer = pncb->ncb_buffer;
  943. length = pncb->ncb_length;
  944. break;
  945. case NCBCANCEL:
  946. // The second buffer points to the NCB to be cancelled.
  947. buffer = pncb->ncb_buffer;
  948. length = sizeof(NCB);
  949. NbPrintf(( "[NETAPI32] Attempting to cancel PNCB: %lx\n", buffer ));
  950. DisplayNcb( (PNCBI)buffer );
  951. break;
  952. case NCBCHAINSEND:
  953. case NCBCHAINSENDNA:
  954. {
  955. PUCHAR BigBuffer; // Points to the start of BigBuffer, not
  956. // the start of user data.
  957. PUCHAR FirstBuffer;
  958. //
  959. // There is nowhere in the NCB to save the address of BigBuffer.
  960. // The address is needed to free BigBuffer when the transfer is
  961. // complete. At the start of BigBuffer, 4 bytes are used to store
  962. // the user supplied ncb_buffer value which is restored later.
  963. //
  964. BigBuffer = RtlAllocateHeap(
  965. RtlProcessHeap(), 0,
  966. sizeof(pncb->ncb_buffer) +
  967. pncb->ncb_length +
  968. pncb->cu.ncb_chain.ncb_length2);
  969. if ( BigBuffer == NULL ) {
  970. NbPrintf(( "[NETAPI32] The Netbios BigBuffer Allocation failed: %lx\n",
  971. pncb->ncb_length + pncb->cu.ncb_chain.ncb_length2));
  972. pncb->ncb_retcode = NRC_NORES;
  973. pncb->ncb_cmd_cplt = NRC_NORES;
  974. pncb->u.ncb_iosb.Status = STATUS_SUCCESS;
  975. PostRoutineCaller( pncb, &pncb->u.ncb_iosb, 0);
  976. return;
  977. }
  978. NbPrintf(( "[NETAPI32] BigBuffer Allocation: %lx\n", BigBuffer));
  979. // Save users buffer address.
  980. RtlMoveMemory(
  981. BigBuffer,
  982. &pncb->ncb_buffer,
  983. sizeof(pncb->ncb_buffer));
  984. FirstBuffer = pncb->ncb_buffer;
  985. pncb->ncb_buffer = BigBuffer;
  986. // Copy the user data.
  987. try {
  988. RtlMoveMemory(
  989. sizeof(pncb->ncb_buffer) + BigBuffer,
  990. &FirstBuffer[0],
  991. pncb->ncb_length);
  992. RtlMoveMemory(
  993. sizeof(pncb->ncb_buffer) + BigBuffer + pncb->ncb_length,
  994. &pncb->cu.ncb_chain.ncb_buffer2[0],
  995. pncb->cu.ncb_chain.ncb_length2);
  996. } except (EXCEPTION_EXECUTE_HANDLER) {
  997. pncb->ncb_retcode = NRC_BUFLEN;
  998. pncb->ncb_cmd_cplt = NRC_BUFLEN;
  999. pncb->u.ncb_iosb.Status = STATUS_SUCCESS;
  1000. ChainSendPostRoutine( pncb, &pncb->u.ncb_iosb, 0);
  1001. return;
  1002. }
  1003. NbPrintf(( "[NETAPI32] Submit chain send pncb: %lx, event: %lx, post: %lx. \n",
  1004. pncb,
  1005. pncb->ncb_event,
  1006. pncb->ncb_post));
  1007. ntstatus = NtDeviceIoControlFile(
  1008. NB,
  1009. NULL,
  1010. ChainSendPostRoutine, // APC Routine
  1011. pncb, // APC Context
  1012. &pncb->u.ncb_iosb, // IO Status block
  1013. IOCTL_NB_NCB,
  1014. pncb, // InputBuffer
  1015. sizeof(NCB),
  1016. sizeof(pncb->ncb_buffer) + BigBuffer, // Outputbuffer
  1017. pncb->ncb_length + pncb->cu.ncb_chain.ncb_length2);
  1018. if ((ntstatus != STATUS_SUCCESS) &&
  1019. (ntstatus != STATUS_PENDING) &&
  1020. (ntstatus != STATUS_HANGUP_REQUIRED)) {
  1021. NbPrintf(( "[NETAPI32] The Netbios Chain Send failed: %X\n", ntstatus ));
  1022. if ( ntstatus == STATUS_ACCESS_VIOLATION ) {
  1023. pncb->ncb_retcode = NRC_BUFLEN;
  1024. } else {
  1025. pncb->ncb_retcode = NRC_SYSTEM;
  1026. }
  1027. ChainSendPostRoutine( pncb, &pncb->u.ncb_iosb, 0);
  1028. }
  1029. NbPrintf(( "[NETAPI32] PNCB: %lx completed, status:%lx, ncb_retcode: %#04x\n",
  1030. pncb,
  1031. ntstatus,
  1032. pncb->ncb_retcode ));
  1033. return;
  1034. }
  1035. #if AUTO_RESET
  1036. //
  1037. // added to fix bug : 170107
  1038. //
  1039. //
  1040. // Remember the parameters used in reseting a LANA. LANAs need to
  1041. // be automatically re-reset when they get unbound and bound back to
  1042. // netbios.sys. This happens in the case of TCPIP devices that renew
  1043. // their IP addresses.
  1044. //
  1045. case NCBRESET :
  1046. {
  1047. PRESET_LANA_NCB prlnTmp;
  1048. PLIST_ENTRY ple, pleHead;
  1049. buffer = NULL;
  1050. length = 0;
  1051. NbPrintf( (
  1052. "[NETAPI32] : Netbios : reseting adapter %d\n",
  1053. pncb-> ncb_lana_num
  1054. ) );
  1055. //
  1056. // Add Reset NCB to global list
  1057. //
  1058. EnterCriticalSection( &ResetCS );
  1059. //
  1060. // check if already present
  1061. //
  1062. pleHead = &LanaResetList;
  1063. for ( ple = pleHead-> Flink; ple != pleHead; ple = ple-> Flink )
  1064. {
  1065. prlnTmp = CONTAINING_RECORD( ple, RESET_LANA_NCB, leList );
  1066. if ( prlnTmp-> ResetNCB.ncb_lana_num == pncb-> ncb_lana_num )
  1067. {
  1068. break;
  1069. }
  1070. }
  1071. if ( ple == pleHead )
  1072. {
  1073. //
  1074. // NO reset was performed before for this LANA
  1075. //
  1076. //
  1077. // allocate a NCB entry and copy the NCB used
  1078. //
  1079. prlnTmp = HeapAlloc(
  1080. GetProcessHeap(), 0, sizeof( RESET_LANA_NCB )
  1081. );
  1082. if ( prlnTmp == NULL )
  1083. {
  1084. NbPrintf( (
  1085. "[NETAPI32] : Netbios : Failed to allocate RESET_LANA_NCB"
  1086. ) );
  1087. LeaveCriticalSection( &ResetCS );
  1088. break;
  1089. }
  1090. ZeroMemory( prlnTmp, sizeof( RESET_LANA_NCB ) );
  1091. InitializeListHead( &prlnTmp-> leList );
  1092. CopyMemory( &prlnTmp-> ResetNCB, pncb, FIELD_OFFSET( NCB, ncb_cmd_cplt ) );
  1093. InsertTailList( &LanaResetList, &prlnTmp-> leList );
  1094. }
  1095. else
  1096. {
  1097. //
  1098. // Lana was previously reset. Overwrite old parameters.
  1099. //
  1100. CopyMemory( &prlnTmp-> ResetNCB, pncb, FIELD_OFFSET( NCB, ncb_cmd_cplt ) );
  1101. }
  1102. //
  1103. // clear out event/post completion routine when saving the ResetNCB.
  1104. // When this NCB is used to re-issue the reset command, there is no
  1105. // post completion processing to be done.
  1106. //
  1107. prlnTmp-> ResetNCB.ncb_event = NULL;
  1108. prlnTmp-> ResetNCB.ncb_post = NULL;
  1109. //
  1110. // when a reset is re-issued it will always a ASYNC command.
  1111. //
  1112. prlnTmp-> ResetNCB.ncb_command = pncb-> ncb_command | ASYNCH;
  1113. LeaveCriticalSection( &ResetCS );
  1114. break;
  1115. }
  1116. #endif
  1117. default:
  1118. buffer = NULL;
  1119. length = 0;
  1120. break;
  1121. }
  1122. // NbPrintf(( "[NETAPI32] Submit pncb: %lx, event: %lx, post: %lx. \n",
  1123. // pncb,
  1124. // pncb->ncb_event,
  1125. // pncb->ncb_post));
  1126. ntstatus = NtDeviceIoControlFile(
  1127. NB,
  1128. NULL,
  1129. PostRoutineCaller, // APC Routine
  1130. pncb, // APC Context
  1131. &pncb->u.ncb_iosb, // IO Status block
  1132. IOCTL_NB_NCB,
  1133. pncb, // InputBuffer
  1134. sizeof(NCB),
  1135. buffer, // Outputbuffer
  1136. length );
  1137. if ((ntstatus != STATUS_SUCCESS) &&
  1138. (ntstatus != STATUS_PENDING) &&
  1139. (ntstatus != STATUS_HANGUP_REQUIRED)) {
  1140. NbPrintf(( "[NETAPI32] The Netbios NtDeviceIoControlFile failed: %X\n", ntstatus ));
  1141. NbPrintf(( "[NETAPI32] PNCB: %lx completed, status:%lx, ncb_retcode: %#04x,"
  1142. "ncb_cmd_cmplt: %#04x\n", pncb, ntstatus, pncb->ncb_retcode,
  1143. pncb-> ncb_cmd_cplt ));
  1144. if ( ntstatus == STATUS_ACCESS_VIOLATION ) {
  1145. pncb->ncb_retcode = NRC_BUFLEN;
  1146. } else {
  1147. pncb->ncb_retcode = NRC_SYSTEM;
  1148. }
  1149. PostRoutineCaller( pncb, &pncb->u.ncb_iosb, 0);
  1150. }
  1151. return;
  1152. }
  1153. VOID
  1154. SpinUpAddnameThread(
  1155. IN PNCBI pncb
  1156. )
  1157. /*++
  1158. Routine Description:
  1159. Spin up an another thread so that the worker thread does not block while
  1160. the blocking fsctl is being processed.
  1161. Arguments:
  1162. IN PNCBI pncb - supplies the NCB to be sent to the driver.
  1163. Return Value:
  1164. None.
  1165. --*/
  1166. {
  1167. HANDLE Threadid;
  1168. HANDLE AddNameHandle;
  1169. EnterCriticalSection( &Crit );
  1170. AddNameThreadCount++;
  1171. NtResetEvent( AddNameEvent, NULL );
  1172. LeaveCriticalSection( &Crit );
  1173. AddNameHandle = CreateThread(
  1174. NULL, // Standard thread attributes
  1175. 0, // Use same size stack as users
  1176. // application
  1177. SendAddNcbToDriver,
  1178. // Routine to start in new thread
  1179. pncb, // Parameter to thread
  1180. 0, // No special CreateFlags
  1181. (LPDWORD)&Threadid);
  1182. if ( AddNameHandle == NULL ) {
  1183. //
  1184. // Wait a couple of seconds just in case this is a burst
  1185. // of addnames and we have run out of resources creating
  1186. // threads. In a couple of seconds one of the other
  1187. // addname threads should complete.
  1188. //
  1189. Sleep(2000);
  1190. AddNameHandle = CreateThread(
  1191. NULL, // Standard thread attributes
  1192. 0, // Use same size stack as users
  1193. // application
  1194. SendAddNcbToDriver,
  1195. // Routine to start in new thread
  1196. pncb, // Parameter to thread
  1197. 0, // No special CreateFlags
  1198. (LPDWORD)&Threadid);
  1199. if ( AddNameHandle == NULL ) {
  1200. //
  1201. // Retry failed. Lower the counts to their values prior to
  1202. // calling SpinUpAddNameThread
  1203. //
  1204. AddNameThreadExit();
  1205. pncb->ncb_retcode = NRC_NORES;
  1206. NbPrintf(( "[NETAPI32] Create Addname Worker Thread failed\n" ));
  1207. pncb->u.ncb_iosb.Status = STATUS_SUCCESS;
  1208. PostRoutineCaller( pncb, &pncb->u.ncb_iosb, 0);
  1209. } else {
  1210. CloseHandle( AddNameHandle );
  1211. }
  1212. } else {
  1213. CloseHandle( AddNameHandle );
  1214. }
  1215. }
  1216. VOID
  1217. AddNameThreadExit(
  1218. VOID
  1219. )
  1220. /*++
  1221. Routine Description:
  1222. Keep counts accurate so that any resets being processed by the main
  1223. worker thread block appropriately.
  1224. Arguments:
  1225. none.
  1226. Return Value:
  1227. none.
  1228. --*/
  1229. {
  1230. EnterCriticalSection( &Crit );
  1231. AddNameThreadCount--;
  1232. if (AddNameThreadCount == 0) {
  1233. NtSetEvent(AddNameEvent, NULL);
  1234. }
  1235. LeaveCriticalSection( &Crit );
  1236. }
  1237. DWORD
  1238. SendAddNcbToDriver(
  1239. IN PVOID Context
  1240. )
  1241. /*++
  1242. Routine Description:
  1243. This routine is used to post an addname or adapter status ensuring
  1244. that the worker thread does not block.
  1245. Arguments:
  1246. IN PVOID Context - supplies the NCB to be sent to the driver.
  1247. Return Value:
  1248. None.
  1249. --*/
  1250. {
  1251. PNCBI pncb = (PNCBI) Context;
  1252. void (CALLBACK *post)( struct _NCB * );
  1253. HANDLE event;
  1254. HANDLE LocalEvent;
  1255. UCHAR command;
  1256. NTSTATUS ntstatus;
  1257. char * buffer;
  1258. unsigned short length;
  1259. try {
  1260. command = pncb->ncb_command;
  1261. post = pncb->ncb_post;
  1262. event = pncb->ncb_event;
  1263. ntstatus = NtCreateEvent( &LocalEvent,
  1264. EVENT_ALL_ACCESS,
  1265. NULL,
  1266. SynchronizationEvent,
  1267. FALSE );
  1268. if ( !NT_SUCCESS(ntstatus) ) {
  1269. pncb->ncb_retcode = NRC_NORES;
  1270. NbPrintf(( "[NETAPI32] Could not create event\n" ));
  1271. pncb->u.ncb_iosb.Status = STATUS_SUCCESS;
  1272. PostRoutineCaller( pncb, &pncb->u.ncb_iosb, 0);
  1273. AddNameThreadExit();
  1274. return 0;
  1275. }
  1276. //
  1277. // While the NCB is submitted the driver can modify the contents
  1278. // of the NCB. We will ensure that this thread waits until the addname
  1279. // completes before it exits.
  1280. //
  1281. pncb->ncb_command = pncb->ncb_command & ~ASYNCH;
  1282. if ( pncb->ncb_command == NCBASTAT ) {
  1283. buffer = pncb->ncb_buffer;
  1284. length = pncb->ncb_length;
  1285. } else {
  1286. ASSERT( (pncb->ncb_command == NCBADDNAME) ||
  1287. (pncb->ncb_command == NCBADDGRNAME) ||
  1288. (pncb->ncb_command == NCBASTAT) );
  1289. buffer = NULL;
  1290. length = 0;
  1291. }
  1292. ntstatus = NtDeviceIoControlFile(
  1293. NB,
  1294. LocalEvent,
  1295. NULL, // APC Routine
  1296. NULL, // APC Context
  1297. &pncb->u.ncb_iosb, // IO Status block
  1298. IOCTL_NB_NCB,
  1299. pncb, // InputBuffer
  1300. sizeof(NCB),
  1301. buffer, // Outputbuffer
  1302. length );
  1303. if ((ntstatus != STATUS_SUCCESS) &&
  1304. (ntstatus != STATUS_PENDING) &&
  1305. (ntstatus != STATUS_HANGUP_REQUIRED)) {
  1306. NbPrintf(( "[NETAPI32] The Netbios NtDeviceIoControlFile failed: %X\n", ntstatus ));
  1307. if ( ntstatus == STATUS_ACCESS_VIOLATION ) {
  1308. pncb->ncb_retcode = NRC_BUFLEN;
  1309. } else {
  1310. pncb->ncb_retcode = NRC_SYSTEM;
  1311. }
  1312. } else {
  1313. do {
  1314. ntstatus = NtWaitForSingleObject(
  1315. LocalEvent,
  1316. TRUE,
  1317. NULL );
  1318. } while ( (ntstatus == STATUS_USER_APC) ||
  1319. (ntstatus == STATUS_ALERTED) );
  1320. ASSERT(ntstatus == STATUS_SUCCESS);
  1321. }
  1322. pncb->ncb_command = command;
  1323. // Set the flag that indicates that the NCB is now completed.
  1324. pncb->ncb_cmd_cplt = pncb->ncb_retcode;
  1325. // Allow application/worker thread to proceed.
  1326. if ( event != NULL ) {
  1327. NtSetEvent( event, NULL );
  1328. }
  1329. // If the user supplied a post routine then call it.
  1330. if (( post != NULL ) &&
  1331. ( (command & ASYNCH) != 0 )) {
  1332. (*(post))( (PNCB)pncb );
  1333. }
  1334. } except (EXCEPTION_EXECUTE_HANDLER) {
  1335. NbPrintf(( "[NETAPI32] Netbios: Access Violation post processing NCB %lx\n", pncb ));
  1336. NbPrintf(( "[NETAPI32] Netbios: Probable application error\n" ));
  1337. }
  1338. NtClose( LocalEvent );
  1339. AddNameThreadExit();
  1340. ExitThread(0);
  1341. return 0;
  1342. }
  1343. VOID
  1344. PostRoutineCaller(
  1345. PVOID Context,
  1346. PIO_STATUS_BLOCK Status,
  1347. ULONG Reserved
  1348. )
  1349. /*++
  1350. Routine Description:
  1351. This routine is supplied by SendNcbToDriver to the Io system when
  1352. a Post routine is to be called directly.
  1353. Arguments:
  1354. IN PVOID Context - supplies the NCB post routine to be called.
  1355. IN PIO_STATUS_BLOCK Status.
  1356. IN ULONG Reserved.
  1357. Return Value:
  1358. none.
  1359. --*/
  1360. {
  1361. PNCBI pncbi = (PNCBI) Context;
  1362. void (CALLBACK *post)( struct _NCB * );
  1363. HANDLE event;
  1364. UCHAR command;
  1365. try {
  1366. if ( Status->Status == STATUS_HANGUP_REQUIRED ) {
  1367. HangupConnection( pncbi );
  1368. }
  1369. //
  1370. // Save the command, post routine and the handle to the event so that if the other thread is
  1371. // polling the cmd_cplt flag or the event awaiting completion and immediately trashes
  1372. // the NCB, we behave appropriately.
  1373. //
  1374. post = pncbi->ncb_post;
  1375. event = pncbi->ncb_event;
  1376. command = pncbi->ncb_command;
  1377. // Set the flag that indicates that the NCB is now completed.
  1378. pncbi->ncb_cmd_cplt = pncbi->ncb_retcode;
  1379. //
  1380. // NCB may be queued again
  1381. //
  1382. EnterCriticalSection( &Crit );
  1383. pncbi->ncb_reserved = 0;
  1384. LeaveCriticalSection( &Crit );
  1385. // Allow application/worker thread to proceed.
  1386. if ( event != NULL ) {
  1387. NtSetEvent( event, NULL );
  1388. }
  1389. // If the user supplied a post routine then call it.
  1390. if (( post != NULL ) &&
  1391. ( (command & ASYNCH) != 0 )) {
  1392. (*(post))( (PNCB)pncbi );
  1393. }
  1394. } except (EXCEPTION_EXECUTE_HANDLER) {
  1395. NbPrintf(( "[NETAPI32] Netbios: Access Violation post processing NCB %lx\n", pncbi ));
  1396. NbPrintf(( "[NETAPI32] Netbios: Probable application error\n" ));
  1397. }
  1398. UNREFERENCED_PARAMETER( Reserved );
  1399. }
  1400. VOID
  1401. ChainSendPostRoutine(
  1402. PVOID Context,
  1403. PIO_STATUS_BLOCK Status,
  1404. ULONG Reserved
  1405. )
  1406. /*++
  1407. Routine Description:
  1408. This routine is supplied by SendNcbToDriver to the Io system when
  1409. a chain send ncb is being processed. When the send is complete,
  1410. this routine deletes the BigBuffer used to hold the two parts of
  1411. the chain send. It then calls a post routine if the user supplied one.
  1412. Arguments:
  1413. IN PVOID Context - supplies the NCB post routine to be called.
  1414. IN PIO_STATUS_BLOCK Status.
  1415. IN ULONG Reserved.
  1416. Return Value:
  1417. none.
  1418. --*/
  1419. {
  1420. PNCBI pncbi = (PNCBI) Context;
  1421. PUCHAR BigBuffer;
  1422. void (CALLBACK *post)( struct _NCB * );
  1423. HANDLE event;
  1424. UCHAR command;
  1425. BigBuffer = pncbi->ncb_buffer;
  1426. try {
  1427. // Restore the users NCB contents.
  1428. RtlMoveMemory(
  1429. &pncbi->ncb_buffer,
  1430. BigBuffer,
  1431. sizeof(pncbi->ncb_buffer));
  1432. NbPrintf(( "[NETAPI32] ChainSendPostRoutine PNCB: %lx, Status: %X\n", pncbi, Status->Status ));
  1433. DisplayNcb( pncbi );
  1434. if ( Status->Status == STATUS_HANGUP_REQUIRED ) {
  1435. HangupConnection( pncbi );
  1436. }
  1437. //
  1438. // Save the command, post routine and the handle to the event so that if the other thread is
  1439. // polling the cmd_cplt flag or the event awaiting completion and immediately trashes
  1440. // the NCB, we behave appropriately.
  1441. //
  1442. post = pncbi->ncb_post;
  1443. event = pncbi->ncb_event;
  1444. command = pncbi->ncb_command;
  1445. // Set the flag that indicates that the NCB is now completed.
  1446. pncbi->ncb_cmd_cplt = pncbi->ncb_retcode;
  1447. //
  1448. // NCB may be queued again
  1449. //
  1450. EnterCriticalSection( &Crit );
  1451. pncbi->ncb_reserved = 0;
  1452. LeaveCriticalSection( &Crit );
  1453. // Allow application/worker thread to proceed.
  1454. if ( event != NULL ) {
  1455. NtSetEvent(event, NULL);
  1456. }
  1457. // If the user supplied a post routine then call it.
  1458. if (( post != NULL ) &&
  1459. ( (command & ASYNCH) != 0 )) {
  1460. (*(post))( (PNCB)pncbi );
  1461. }
  1462. } except (EXCEPTION_EXECUTE_HANDLER) {
  1463. NbPrintf(( "[NETAPI32] Netbios: Access Violation post processing NCB %lx\n", pncbi ));
  1464. NbPrintf(( "[NETAPI32] Netbios: Probable application error\n" ));
  1465. }
  1466. RtlFreeHeap( RtlProcessHeap(), 0, BigBuffer);
  1467. UNREFERENCED_PARAMETER( Reserved );
  1468. }
  1469. VOID
  1470. HangupConnection(
  1471. PNCBI pUserNcb
  1472. )
  1473. /*++
  1474. Routine Description:
  1475. This routine generates a hangup for the connection. This allows orderly
  1476. cleanup of the connection block in the driver.
  1477. The return value from the hangup is not used. If the hangup overlaps with
  1478. a reset or a hangup then the hangup will have no effect.
  1479. The user application is unaware that this operation is being performed.
  1480. Arguments:
  1481. IN PNCBI pUserNcb - Identifies the connection to be hung up.
  1482. Return Value:
  1483. none.
  1484. --*/
  1485. {
  1486. NCBI ncbi;
  1487. NTSTATUS Status;
  1488. RtlZeroMemory( &ncbi, sizeof (NCB) );
  1489. ncbi.ncb_command = NCBHANGUP;
  1490. ncbi.ncb_lsn = pUserNcb->ncb_lsn;
  1491. ncbi.ncb_lana_num = pUserNcb->ncb_lana_num;
  1492. ncbi.ncb_retcode = ncbi.ncb_cmd_cplt = NRC_PENDING;
  1493. Status = NtCreateEvent( &ncbi.ncb_event,
  1494. EVENT_ALL_ACCESS,
  1495. NULL,
  1496. SynchronizationEvent,
  1497. FALSE );
  1498. if ( !NT_SUCCESS(Status) ) {
  1499. //
  1500. // Failed to create event. Cleanup of the Cb will have to wait until
  1501. // the user decides to do another request or exits.
  1502. //
  1503. NbPrintf(( "[NETAPI32] Hangup Session PNCBI: %lx failed to create event!\n" ));
  1504. return;
  1505. }
  1506. Status = NtDeviceIoControlFile(
  1507. NB,
  1508. ncbi.ncb_event,
  1509. NULL, // APC Routine
  1510. NULL, // APC Context
  1511. &ncbi.u.ncb_iosb, // IO Status block
  1512. IOCTL_NB_NCB,
  1513. &ncbi, // InputBuffer
  1514. sizeof(NCB),
  1515. NULL, // Outputbuffer
  1516. 0 );
  1517. //
  1518. // We must always wait to allow the Apc to fire
  1519. //
  1520. do {
  1521. Status = NtWaitForSingleObject(
  1522. ncbi.ncb_event,
  1523. TRUE,
  1524. NULL );
  1525. } while ( (Status == STATUS_USER_APC) ||
  1526. (Status == STATUS_ALERTED) );
  1527. ASSERT(Status == STATUS_SUCCESS);
  1528. if (! NT_SUCCESS(Status)) {
  1529. NbPrintf(( "[NETAPI32] The Netbios NtWaitForSingleObject failed: %X\n", Status ));
  1530. }
  1531. NtClose( ncbi.ncb_event );
  1532. }
  1533. VOID
  1534. NetbiosInitialize(
  1535. HMODULE hModule
  1536. )
  1537. /*++
  1538. Routine Description:
  1539. This routine is called each time a process that uses netapi.dll
  1540. starts up.
  1541. Arguments:
  1542. IN HMODULE hModule - Handle to module instance (netapi32.dll)
  1543. Return Value:
  1544. none.
  1545. --*/
  1546. {
  1547. Initialized = FALSE;
  1548. WorkerHandle = NULL;
  1549. InitializeCriticalSection( &Crit );
  1550. #if AUTO_RESET
  1551. InitializeCriticalSection( &ResetCS );
  1552. InitializeListHead( &LanaResetList );
  1553. RtlZeroMemory( &OutputNCB, sizeof( NCB ) );
  1554. #endif
  1555. g_hModule = hModule;
  1556. }
  1557. VOID
  1558. NetbiosDelete(
  1559. VOID
  1560. )
  1561. /*++
  1562. Routine Description:
  1563. This routine is called each time a process that uses netapi.dll
  1564. Exits. It resets all lana numbers that could have been used by this
  1565. process. This will cause all Irp's in the system to be completed
  1566. because all the Connection and Address handles will be closed tidily.
  1567. Arguments:
  1568. none.
  1569. Return Value:
  1570. none.
  1571. --*/
  1572. {
  1573. #if AUTO_RESET
  1574. PLIST_ENTRY ple;
  1575. PRESET_LANA_NCB prln;
  1576. while ( !IsListEmpty( &LanaResetList ) )
  1577. {
  1578. ple = RemoveHeadList( &LanaResetList );
  1579. prln = CONTAINING_RECORD( ple, RESET_LANA_NCB, leList );
  1580. HeapFree( GetProcessHeap(), 0, prln );
  1581. }
  1582. DeleteCriticalSection( &ResetCS );
  1583. #endif
  1584. DeleteCriticalSection( &Crit );
  1585. if ( Initialized == FALSE ) {
  1586. // This process did not use Netbios.
  1587. return;
  1588. }
  1589. NtClose(NB);
  1590. }
  1591. #if AUTO_RESET
  1592. VOID
  1593. ResetLanaAndPostListen(
  1594. )
  1595. /*++
  1596. Routine Description:
  1597. This routine is invoked in response to new LANA being indicated to
  1598. NETBIOS.SYS. When this occurs the IOCTL posted by this user-mode
  1599. component of netbios (to listen for new LANA indications) is completed.
  1600. In response the new LANA is reset if it had previously been reset.
  1601. In addition the routine re-posts the listen to the kernel mode
  1602. component of netbios (NETBIOS.SYS). An exception to this is if
  1603. the LANA number to be reset is 255 ( MAX_LANA + 1 ). This is a
  1604. special case that indicates the NETBIOS.SYS is stopping and listen
  1605. should not be reposted in this case.
  1606. Arguments:
  1607. none.
  1608. Return Value:
  1609. none.
  1610. --*/
  1611. {
  1612. NTSTATUS Status;
  1613. PRESET_LANA_NCB prln;
  1614. PLIST_ENTRY ple, pleHead;
  1615. NbPrintf( ("[NETAPI32] : Netbios : Entered ResetLanaAndPostListen \n") );
  1616. //
  1617. // Check if the LANA number is valid.
  1618. //
  1619. if ( OutputNCB.ncb_lana_num != ( MAX_LANA + 1 ) )
  1620. {
  1621. EnterCriticalSection( &ResetCS );
  1622. //
  1623. // find which lana needs a reset
  1624. //
  1625. NbPrintf( (
  1626. "[NETAPI32] : Netbios : Looking for Lana %d\n", OutputNCB.ncb_lana_num
  1627. ) );
  1628. pleHead = &LanaResetList;
  1629. for ( ple = pleHead-> Flink; ple != pleHead; ple = ple-> Flink )
  1630. {
  1631. prln = CONTAINING_RECORD( ple, RESET_LANA_NCB, leList );
  1632. if ( prln-> ResetNCB.ncb_lana_num == OutputNCB.ncb_lana_num )
  1633. {
  1634. //
  1635. // found Lana that needs reseting
  1636. //
  1637. break;
  1638. }
  1639. }
  1640. //
  1641. // if found send reset
  1642. //
  1643. if ( ple != pleHead )
  1644. {
  1645. //
  1646. // Send Reset to NETBIOS.SYS
  1647. //
  1648. QueueToWorker( (PNCBI) &prln-> ResetNCB );
  1649. }
  1650. else
  1651. {
  1652. NbPrintf( (
  1653. "[NETAPI32] : Netbios : Lana %d not found\n",
  1654. OutputNCB.ncb_lana_num
  1655. ) );
  1656. }
  1657. LeaveCriticalSection( &ResetCS );
  1658. OutputNCB.ncb_lana_num = 0;
  1659. //
  1660. // post listen again
  1661. //
  1662. Status = NtDeviceIoControlFile(
  1663. NB,
  1664. LanaResetEvent,
  1665. NULL, NULL,
  1666. &ResetStatusBlock,
  1667. IOCTL_NB_REGISTER_RESET,
  1668. NULL, 0,
  1669. (PVOID) &OutputNCB, sizeof( NCB )
  1670. );
  1671. if ( ( Status != STATUS_PENDING ) &&
  1672. ( Status != STATUS_SUCCESS ) )
  1673. {
  1674. //
  1675. // Failed to register reset notification.
  1676. //
  1677. NbPrintf(
  1678. ("[NETAPI32] : Netbios : Failed to register Reset event\n" )
  1679. );
  1680. }
  1681. }
  1682. else
  1683. {
  1684. NbPrintf( (
  1685. "[NETAPI32] : Netbios : LANA 255 indicated, no Listen posted\n"
  1686. ) )
  1687. }
  1688. NbPrintf( ("[NETAPI32] : Netbios : Leaving ResetLanaAndPostListen \n") );
  1689. }
  1690. #endif