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.

2131 lines
60 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. servencb.c
  5. Abstract:
  6. Routines to service completed NCB's. This file contains the following
  7. functions:
  8. MsgCallNetBios
  9. MsgDeleteName
  10. MsgGetMachineName
  11. MsgHangupService
  12. MsgListenService
  13. Msgmblockbeg
  14. Msgmblockend
  15. Msgmblocktxt
  16. MsgNetBiosError
  17. MsgRecBcastService
  18. MsgReceiveService
  19. MsgRestart
  20. Msgsblockmes
  21. MsgSendAck
  22. MsgSendService
  23. MsgServeNCBs
  24. MsgSesFullService
  25. MsgStartListen
  26. MsgStartRecBcast
  27. MsgVerifySmb
  28. Author:
  29. Dan Lafferty (danl) 15-Jul-1991
  30. Environment:
  31. User Mode -Win32
  32. Revision History:
  33. 19-Aug-1997 wlees
  34. Add PNP support for lana's
  35. 27-Jul-1994 danl
  36. MsgServeNCBs: This function now returns FALSE when the service
  37. is to shut down.
  38. 29-May-1992 danl
  39. MsgListenService: reset the NRC_NORES error count when a good
  40. return code accompanies the Listen completion.
  41. 18-Feb-1992 ritaw
  42. Convert to Win32 service control APIs.
  43. 15-Jul-1991 danl
  44. Ported from LM2.0
  45. --*/
  46. //
  47. // SMB translation
  48. //
  49. //
  50. // OLD NEW
  51. // SMB SMB_HEADER or PSMB_HEADER
  52. // -------- -------------------------
  53. // smb_idf Protocol
  54. // smb_com Command
  55. // smb_rcls ErrorClass
  56. // smb_reh Reserved
  57. // smb_err Error
  58. // smb_flg Flags
  59. // smb_flag2 Flags2
  60. // smb_res Reserved2
  61. // smb_gid Tid
  62. // smb_tid Pid
  63. // smb_pid Uid
  64. // smb_uid Mid
  65. // smb_mid Kludge
  66. //
  67. // Includes
  68. //
  69. #include "msrv.h"
  70. #include <tstring.h> // Unicode string macros
  71. #include <string.h> // memcpy
  72. #include <netdebug.h> // NetpAssert
  73. #include <lmerrlog.h> // NELOG_ messages
  74. #include <netlib.h> // UNUSED macro
  75. #include <smbtypes.h> // needed for smb.h
  76. #include <smb.h> // Server Message Block definitions
  77. #include <smbgtpt.h> // SMB field manipulation macros
  78. //#include <msgrutil.h> // NetpNetBiosReset
  79. #include <nb30.h> // NRC_GOODRET, ASYNC
  80. #include "msgdbg.h" // MSG_LOG
  81. #include "heap.h"
  82. #include "msgdata.h"
  83. #include "apiutil.h" // MsgMapNetError
  84. #define MAX_RETRIES 10
  85. //
  86. // Local Functions
  87. //
  88. STATIC NET_API_STATUS
  89. MsgCallNetBios(
  90. DWORD net,
  91. PNCB ncb,
  92. DWORD ncbi
  93. );
  94. STATIC VOID
  95. MsgDeleteName(
  96. DWORD net,
  97. DWORD ncbi
  98. );
  99. STATIC VOID
  100. MsgGetMachineName(
  101. DWORD net,
  102. DWORD ncbi
  103. );
  104. STATIC VOID
  105. MsgHangupService(
  106. DWORD net,
  107. DWORD ncbi,
  108. CHAR retval
  109. );
  110. STATIC VOID
  111. MsgListenService(
  112. DWORD net,
  113. DWORD ncbi,
  114. CHAR retval
  115. );
  116. STATIC VOID
  117. Msgmblockbeg(
  118. DWORD net,
  119. DWORD ncbi
  120. );
  121. STATIC VOID
  122. Msgmblockend(
  123. DWORD net,
  124. DWORD ncbi
  125. );
  126. STATIC VOID
  127. Msgmblocktxt(
  128. DWORD net,
  129. DWORD ncbi
  130. );
  131. STATIC DWORD
  132. MsgNetBiosError(
  133. DWORD net,
  134. PNCB ncb,
  135. char retval,
  136. DWORD ncbi
  137. );
  138. STATIC VOID
  139. MsgReceiveService(
  140. DWORD net,
  141. DWORD ncbi,
  142. char retval
  143. );
  144. STATIC VOID
  145. MsgRestart(
  146. DWORD net,
  147. DWORD ncbi
  148. );
  149. STATIC VOID
  150. Msgsblockmes(
  151. DWORD net,
  152. DWORD ncbi
  153. );
  154. STATIC VOID
  155. MsgSendAck(
  156. DWORD net,
  157. DWORD ncbi,
  158. UCHAR smbrclass,
  159. USHORT smbrcode
  160. );
  161. STATIC VOID
  162. MsgSendService(
  163. DWORD net,
  164. DWORD ncbi,
  165. CHAR retval
  166. );
  167. STATIC VOID
  168. MsgSesFullService(
  169. DWORD net,
  170. DWORD ncbi,
  171. char retval
  172. );
  173. STATIC int
  174. MsgVerifySmb(
  175. DWORD net,
  176. DWORD ncbi,
  177. UCHAR func,
  178. int parms,
  179. char *buffers
  180. );
  181. #if DBG
  182. VOID
  183. MsgDumpNcb(
  184. IN PNCB pNcb
  185. );
  186. #endif //DBG
  187. /*
  188. * MsgCallNetBios - issue a net bios call
  189. *
  190. * This function issues a net bios call and calls the
  191. * error handler if that call results in an error.
  192. *
  193. * MsgCallNetBios (net, ncb, ncbi)
  194. *
  195. * ENTRY
  196. * net - network index
  197. * ncb - pointer to a Network Control Block
  198. * ncbi - index of ncb in ncb array
  199. *
  200. * RETURN
  201. * state of the Messenger: Either RUNNING or STOPPING.
  202. *
  203. * SIDE EFFECTS
  204. *
  205. * Calls NetBios() to actually issue the net bios call.
  206. * Calls MsgNetBiosError() if there is an error.
  207. */
  208. STATIC NET_API_STATUS
  209. MsgCallNetBios(
  210. DWORD net, // Which network?
  211. PNCB ncb, // Pointer to Network Control Block
  212. DWORD ncbi
  213. )
  214. {
  215. int retval;
  216. PNCB_DATA pNcbData;
  217. retval = Msgsendncb(ncb, net);
  218. pNcbData = GETNCBDATA(net,ncbi);
  219. if (retval == NRC_GOODRET) {
  220. //
  221. // Clear err on success
  222. //
  223. pNcbData->Status.last_immediate = 0;
  224. pNcbData->Status.this_immediate = 0;
  225. }
  226. else {
  227. //
  228. // NEW (11-4-91):
  229. // --------------
  230. // It is ok to get a Session Closed error if the state is STOP.
  231. //
  232. if ( (pNcbData->State == MESSTOP) &&
  233. (retval == NRC_SCLOSED) ) {
  234. MSG_LOG(TRACE,"CallNetBios: At end of msg, Session is closed for NET %d\n",
  235. net);
  236. pNcbData->Status.last_immediate = 0;
  237. pNcbData->Status.this_immediate = 0;
  238. }
  239. else {
  240. //
  241. // Else mark error
  242. //
  243. pNcbData->Status.this_immediate = retval;
  244. //
  245. // Call the error handler if err
  246. //
  247. MSG_LOG(TRACE,"CallNetBios: net bios call failed 0x%x\n",retval);
  248. MsgNetBiosError(net,ncb,(char)retval,ncbi);
  249. return(MsgMapNetError((UCHAR)retval));
  250. }
  251. //
  252. // Make sure the event for this thread is in the signaled state
  253. // so that we can wake up and properly handle the error.
  254. //
  255. if (SetEvent(ncb->ncb_event) != TRUE) {
  256. MSG_LOG(ERROR,"CallNetBios: SetEvent Failed\n",0);
  257. }
  258. }
  259. return(NERR_Success);
  260. }
  261. /*
  262. * MsgDeleteName - Delete a name from the Message Server's name table
  263. *
  264. * This function is called when a LISTEN, a RECEIVE BROADCAST DATAGRAM,
  265. * or a RECEIVE ANY completes with the error code specifying that the
  266. * name in question has been deleted. This function marks the appropriate
  267. * entry in the flag table in the shared data area and sets the NCB_CPLT
  268. * field of the appropriate NCB to 0xFF (so that FindCompletedNCB() will
  269. * never find it).
  270. *
  271. * MsgDeleteName (net, ncbi)
  272. *
  273. * ENTRY
  274. * net - network index
  275. * ncbi - Network Control Block index
  276. *
  277. * RETURN
  278. * nothing
  279. *
  280. * SIDE EFFECTS
  281. *
  282. * Modifies an NCB and the shared data area.
  283. */
  284. STATIC VOID
  285. MsgDeleteName(
  286. DWORD net, // Which network?
  287. DWORD ncbi // Network Control Block index
  288. )
  289. {
  290. NCB ncb;
  291. PNCB pNcb;
  292. NET_API_STATUS status;
  293. MSG_LOG(TRACE,"In MsgDeleteName %d\n",net);
  294. if( SD_NAMEFLAGS(net,ncbi) & NFMACHNAME) {
  295. //
  296. // Name is the machine name. It may have been removed from the
  297. // card by a board reset, so try to re-add it.
  298. //
  299. // NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW
  300. //
  301. // First reset the adapter
  302. //
  303. MSG_LOG1(TRACE,"Calling NetBiosReset for lana #%d\n",GETNETLANANUM(net));
  304. status = MsgsvcGlobalData->NetBiosReset(GETNETLANANUM(net));
  305. if (status != NERR_Success) {
  306. MSG_LOG(ERROR,"MsgDeleteName: NetBiosReset failed %d\n",
  307. status);
  308. MSG_LOG(ERROR,"MsgDeleteName: AdapterNum %d\n",net);
  309. //
  310. // I'm not sure what to do if this fails.
  311. //
  312. }
  313. //
  314. //
  315. // NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW
  316. memcpy((char far *) ncb.ncb_name, SD_NAMES(net,ncbi),NCBNAMSZ);
  317. ncb.ncb_command = NCBADDNAME; // Add name (wait)
  318. ncb.ncb_lana_num = GETNETLANANUM(net); // Use the LANMAN adapter
  319. Msgsendncb( &ncb, net);
  320. MsgStartListen(net,ncbi);
  321. }
  322. else {
  323. MsgDatabaseLock(MSG_GET_EXCLUSIVE,"MsgDeleteName"); // Wait for write access
  324. SD_NAMEFLAGS(net,ncbi) = NFDEL; // Name is deleted
  325. MsgDatabaseLock(MSG_RELEASE,"MsgDeleteName"); // Free lock on share table
  326. pNcb = GETNCB(net,ncbi);
  327. pNcb->ncb_cmd_cplt = 0xff; // Simulate command in progress
  328. }
  329. }
  330. /*
  331. * MsgGetMachineName - process a Get Machine Name Server Message Block
  332. *
  333. * This function sends to the caller the local machine name in
  334. * response to a Get Machine Name Server Message Block.
  335. *
  336. * MsgGetMachineName (net, ncbi)
  337. *
  338. * ENTRY
  339. * net - Network index
  340. * ncbi - Network Control Block index
  341. *
  342. * Globals used as input:
  343. *
  344. * machineName - Unicode version of the machine name.
  345. *
  346. * machineNameLen - The number of unicode characters in the machine
  347. * name.
  348. *
  349. * RETURN
  350. * nothing
  351. *
  352. * MsgGetMachineName() is called by MsgReceiveService (RecAnyService()).
  353. * After verifying that the request is valid, this function builds
  354. * an SMB containing the local machine name and sends it back to the
  355. * caller.
  356. *
  357. * SIDE EFFECTS
  358. *
  359. * Calls MsgVerifySmb() and MsgCallNetBios(). Sets MsgSendService() to be the
  360. * next service routine to be executed for the ncbi'th NCB.
  361. */
  362. STATIC VOID
  363. MsgGetMachineName(
  364. DWORD net, // Which network?
  365. DWORD ncbi // Index to NCB
  366. )
  367. {
  368. PNCB ncb; // Pointer to NCB
  369. PNCB_DATA pNcbData; // Pointer to NCB Data
  370. LPBYTE buffer; // Pointer to SMB buffer
  371. LPBYTE cp; // Save pointer
  372. PSHORT bufLen; // Pointer to buffer length field in SMB;
  373. NTSTATUS ntStatus;
  374. OEM_STRING ansiString;
  375. UNICODE_STRING unicodeString;
  376. MSG_LOG(TRACE,"In MsgGetMachineName %d\n",net);
  377. pNcbData = GETNCBDATA(net,ncbi);
  378. ncb = &pNcbData->Ncb; // Get pointer to NCB
  379. if(pNcbData->State != MESSTART) {
  380. //
  381. // If wrong time for this block
  382. //
  383. // Hang up and start a new listen,
  384. // log an error if mpncbistate[net][ncbi] == MESCONT;
  385. // otherwise, do not log the error.
  386. //
  387. if(pNcbData->State == MESCONT) {
  388. //
  389. // Log error if message in progress
  390. //
  391. Msglogmbe(MESERR,net,ncbi);
  392. }
  393. //
  394. // HANGUP and LISTEN again
  395. //
  396. MsgRestart(net,ncbi);
  397. return;
  398. }
  399. pNcbData->State = MESSTOP; // End of message state
  400. //
  401. // Check if SMB is malformed
  402. //
  403. if(MsgVerifySmb(net,ncbi,SMB_COM_GET_MACHINE_NAME,0,"") != 0) {
  404. return;
  405. }
  406. buffer = ncb->ncb_buffer; // Get pointer to buffer
  407. cp = &buffer[sizeof(SMB_HEADER)]; // Skip to end of header
  408. *cp++ = '\0'; // Return no parameters
  409. //
  410. // Length of name plus two
  411. //
  412. bufLen = (PSHORT)&cp[0];
  413. *bufLen = MachineNameLen + (SHORT)2;
  414. cp += sizeof(MachineNameLen); // Skip over buffer length field
  415. *cp++ = '\004'; // Null-terminated string next
  416. #ifdef UNICODE
  417. //
  418. // Translate the machineName from Unicode to Ansi and place it into
  419. // the buffer at the temp pointer location.
  420. //
  421. unicodeString.Length = (USHORT)(STRLEN(machineName)*sizeof(WCHAR));
  422. unicodeString.MaximumLength = (USHORT)((STRLEN(machineName)+1) * sizeof(WCHAR));
  423. unicodeString.Buffer = machineName;
  424. ansiString.Length = MachineNameLen;
  425. ansiString.MaximumLength = *bufLen;
  426. ansiString.Buffer = cp;
  427. ntStatus = RtlUnicodeStringToOemString(
  428. &ansiString,
  429. &unicodeString,
  430. FALSE); // Don't Allocate the ansiString Buffer
  431. if (!NT_SUCCESS(ntStatus)) {
  432. MSG_LOG(ERROR,
  433. "MsgGetMachineName:RtlUnicodeStringToOemString Failed rc=%X\n",
  434. ntStatus);
  435. return; // They return for other errors, so I will here too.
  436. }
  437. *(cp + ansiString.Length) = '\0';
  438. #else
  439. UNUSED(unicodeString);
  440. UNUSED(ansiString);
  441. UNUSED(ntStatus);
  442. strcpy( cp, (LPSTR)machineName); // Copy machine name
  443. #endif
  444. cp += MachineNameLen + 1; // Skip over machine name
  445. //
  446. // Set length of buffer
  447. //
  448. ncb->ncb_length = (USHORT)(cp - buffer);
  449. ncb->ncb_command = NCBSEND | ASYNCH; // Send (no wait)
  450. pNcbData->IFunc = (LPNCBIFCN)MsgSendService; // Set function pointer
  451. MsgCallNetBios(net,ncb,ncbi); // Issue the net bios call
  452. }
  453. /*
  454. * MsgHangupService - Service completed HANGUP net bios calls
  455. *
  456. * This function is invoked by NCBService() to process completed
  457. * HANGUP net bios calls. In response to a completed HANGUP,
  458. * this function issues a new LISTEN net bios call.
  459. *
  460. * MsgHangupService (net, ncbi, retval)
  461. *
  462. * ENTRY
  463. * net - network index
  464. * ncbi - Network Control Block index
  465. * retval - value returned from net bios call
  466. *
  467. * RETURN
  468. * nothing
  469. *
  470. * SIDE EFFECTS
  471. *
  472. * Calls MsgStartListen() to issue a new LISTEN net bios call. Calls
  473. * MsgNetBiosError() on errors it does not know how to deal with.
  474. */
  475. STATIC VOID
  476. MsgHangupService(
  477. DWORD net, // Which network
  478. DWORD ncbi, // Index of completed NCB
  479. CHAR retval // HANGUP return value
  480. )
  481. {
  482. PNCB pNcb;
  483. MSG_LOG(TRACE,"In MsgHangupService %d\n",net);
  484. switch(retval) { // Switch on return value
  485. case NRC_GOODRET: // Success
  486. case NRC_CMDTMO: // Command timed out
  487. case NRC_SCLOSED: // Session closed
  488. case NRC_SABORT: // Session ended abnormally
  489. //
  490. // BBSP - check if the name for this NCB ends in 0x3. If so,
  491. // add the 0x5 version and don't reissue the listen on the 0x03.
  492. // No need to worry about doing it on all nets, since on a machine
  493. // with more than one the 0x05 name will never leave home, and
  494. // the 0x03 version will never get a message.
  495. //
  496. MSG_LOG(TRACE," MsgHangupService: Issue a new LISTEN\n",0);
  497. MsgStartListen(net,ncbi); // Issue a new LISTEN net bios call
  498. break;
  499. default:
  500. //
  501. // Invoke error handler
  502. //
  503. MSG_LOG(TRACE," MsgHangupService: Unknown return value %x\n",retval);
  504. pNcb = GETNCB(net,ncbi);
  505. MsgNetBiosError(net,pNcb,retval,ncbi);
  506. //
  507. // BBSP - check if the name for this NCB ends in 0x3. If so,
  508. // add the 0x5 version and don't reissue the listen on the 0x03.
  509. // See note above.
  510. //
  511. MSG_LOG(TRACE," MsgHangupService: Issue a new LISTEN\n",0);
  512. MsgStartListen(net,ncbi); // Issue a new LISTEN net bios call
  513. break;
  514. }
  515. }
  516. /*
  517. * MsgListenService - service completed LISTEN net bios calls
  518. *
  519. * This function is called when a LISTEN net bios call completes
  520. * either due to an error or due to the establishment of a
  521. * session. In the latter case, it initiates message reception.
  522. *
  523. * MsgListenService (net, ncbi, retval)
  524. *
  525. * ENTRY
  526. * net - network index
  527. * ncbi - Network Control Block index
  528. * retval - value returned from NCB call
  529. *
  530. * RETURN
  531. * nothing
  532. *
  533. * If a session is established, this function issues a RECEIVE ANY
  534. * net bios call to initiate reception of a message. If the function
  535. * is invoked because the net bios call has failed due to the deletion
  536. * of a name from the local network adapter's name table, then this
  537. * function calls the routine responsible for deleting names from the
  538. * Message Server's data area. This is the mechanism by which the
  539. * NETNAME command notofies the Message Server of a deletion.
  540. *
  541. * SIDE EFFECTS
  542. *
  543. * Calls MsgCallNetBios() to issue a RECEIVE ANY net bios call. Calls
  544. * MsgDeleteName() if it is informed of the deletion of a name. Calls
  545. * MsgNetBiosError() on errors it does not know how to deal with. Sets
  546. * mpncbifun[ncbi] according to the net bios call it issues.
  547. */
  548. STATIC VOID
  549. MsgListenService(
  550. DWORD net, // Which network?
  551. DWORD ncbi, // Index of completed NCB
  552. CHAR retval // LISTEN return value
  553. )
  554. {
  555. PNCB ncb; // Pointer to completed NCB
  556. PNCB_DATA pNcbData; // Corresponding NCB data
  557. static DWORD SaveCount = 0;
  558. MSG_LOG(TRACE,"In MsgListenService %d\n",net);
  559. pNcbData = GETNCBDATA(net,ncbi);
  560. ncb = &pNcbData->Ncb; // Get pointer to completed NCB
  561. switch(retval) {
  562. case NRC_GOODRET:
  563. //
  564. // Success
  565. //
  566. //
  567. // Reset the No Resources error count if a good return code comes
  568. // in for this name.
  569. //
  570. SaveCount = 0;
  571. pNcbData->State = MESSTART; // Message start state
  572. pNcbData->IFunc = (LPNCBIFCN)MsgReceiveService;
  573. //
  574. // Set function pointer
  575. //
  576. ncb->ncb_command = NCBRECV | ASYNCH;
  577. //
  578. // Receive any (no wait)
  579. //
  580. ncb->ncb_length = BUFLEN; // Reset length of buffer
  581. MsgCallNetBios(net,ncb,ncbi); // Issue the net bios call
  582. break;
  583. case NRC_LOCTFUL:
  584. //
  585. // Session Table Full
  586. // Log error in system error log file
  587. //
  588. MSG_LOG(TRACE,"[%d]MsgListenService: Session Table is full\n",net);
  589. pNcbData->IFunc = (LPNCBIFCN)MsgSesFullService; // Set function pointer
  590. ncb->ncb_command = NCBDELNAME | ASYNCH; // Delete name (no wait)
  591. MsgCallNetBios(net,ncb,ncbi); // Issue the net bios call
  592. break;
  593. case NRC_NOWILD: // Name not found
  594. // Name not found
  595. // Name deleted between end of one session and start of next
  596. case NRC_NAMERR:
  597. //
  598. // Name was deleted
  599. //
  600. MSG_LOG(TRACE,"[%d]MsgListenService: Name was deleted for some reason\n",net);
  601. MsgDeleteName(net,ncbi); // Handle the deletion
  602. break;
  603. case NRC_NORES:
  604. //
  605. // We need to cover the case where we are adding a new name and
  606. // starting a new listen. In this case, the thread that is adding
  607. // the names will hangup and delete the name.
  608. //
  609. // So here we will sleep for a moment and then check to see if the
  610. // name is still there. If not we just return without setting
  611. // up to handle the NCB anymore. If the name is still there, then
  612. // we travel down the default path and try again.
  613. //
  614. MSG_LOG(TRACE,"[%d]No Net Resources. SLEEP FOR A WHILE\n",net);
  615. Sleep(1000);
  616. MSG_LOG(TRACE,"[%d]No Net Resources. WAKEUP\n",net);
  617. if (pNcbData->NameFlags == NFDEL)
  618. {
  619. MSG_LOG(TRACE,"[%d]MsgListenService: No Net Resources & Name Deleted\n",net);
  620. ncb->ncb_cmd_cplt = 0xff;
  621. }
  622. else
  623. {
  624. //
  625. // If a session goes away and we can't gain the resources for
  626. // it again, then we will attempt to re-connect MAX_RETRIES
  627. // times. If we still cannot connect, then the name will be
  628. // deleted.
  629. //
  630. // Don't deal with retries per net/ncbi -- if we've had
  631. // "out of resources" failures MAX_RETRIES times, odds are
  632. // the situation's not getting better even if we sleep/retry
  633. // for each individual net/ncbi combo.
  634. //
  635. if (SaveCount >= MAX_RETRIES)
  636. {
  637. //
  638. // Delete the Name
  639. //
  640. MSG_LOG(ERROR,
  641. "Out of Resources, Deleting %s\n",
  642. SD_NAMES(net,ncbi));
  643. MsgDeleteName(net,ncbi);
  644. //
  645. // Mark this as 0xff now to avoid another callback call the
  646. // next time this net/ncbi combo is hit in the loop (since that
  647. // call will simply set this value.
  648. //
  649. ncb->ncb_cmd_cplt = 0xff;
  650. //
  651. // Don't roll SaveCount back to zero until we have an NCB
  652. // completed with NRC_GOODRET in the future. This lets us
  653. // avoid rewaiting MAX_RETRIES times for every net/ncbi
  654. // combo as long as we keep getting NRC_NORES.
  655. //
  656. }
  657. else
  658. {
  659. SaveCount++;
  660. MSG_LOG(TRACE,
  661. "MsgListenService: new SaveCount = %d\n",
  662. SaveCount);
  663. }
  664. }
  665. break;
  666. case NRC_BRIDGE:
  667. //
  668. // Lana number no longer valid (network interface went away)
  669. //
  670. MSG_LOG(TRACE,"[%d] lana has become invalid\n", net);
  671. MsgNetBiosError(net, ncb, retval, ncbi);
  672. //
  673. // Indicate lana is now invalid
  674. //
  675. GETNETLANANUM(net) = 0xff;
  676. //
  677. // Mark current operation as deleted
  678. //
  679. ncb->ncb_cmd_cplt = 0xff;
  680. ncb->ncb_retcode = 0;
  681. break;
  682. default:
  683. //
  684. // Other failure
  685. //
  686. MSG_LOG(TRACE,"MsgListenService: Unrecognized retval %x\n",retval);
  687. MsgNetBiosError(net,ncb,retval,ncbi);
  688. // The listen error has been logged. Now as much as possible to
  689. // get another listen staterd. This involves performing
  690. // a HangUp for this name (which should fail but might help
  691. // to clear out the err) and then re-issuing the listen. If the
  692. // same error occurs SHUTDOWN_THRESHOLD consecutive times then
  693. // MsgNetBiosError will shut down the message server.
  694. //
  695. MsgRestart(net,ncbi); // Attempt to restart the Listen
  696. break;
  697. }
  698. }
  699. /*
  700. * Msgmblockbeg - process the header of a multi-block message
  701. *
  702. * This function acknowledges receipt of the header of a multi-block
  703. * message and initiates logging of that message.
  704. *
  705. * Msgmblockbeg (net, ncbi)
  706. *
  707. * ENTRY
  708. * net - network index
  709. * ncbi - Network Control Block index
  710. *
  711. * RETURN
  712. * nothing
  713. *
  714. * This function is called from ReceivePost() (RecAnyPost()).
  715. * It first check to see if it is appropriate for the ncbi'th
  716. * name to have received a begin-multi-block-message SMB at the
  717. * current time. It verifies the correctness of the SMB in the
  718. * ncbi'th buffer. It initiates logging of the multi-block message,
  719. * and it sends an acknowledgement to the sender of the message.
  720. *
  721. * SIDE EFFECTS
  722. *
  723. * Calls MsgRestart() to terminate the session if the SMB has arrived
  724. * at a bad time. Calls MsgVerifySmb() to check the SMB for correctness.
  725. * Calls logmbb() to begin logging. Calls MsgSendAck() to send an
  726. * acknowledgement to the sender of the message.
  727. */
  728. STATIC VOID
  729. Msgmblockbeg(
  730. DWORD net, // Which network?
  731. DWORD ncbi // Index to NCB
  732. )
  733. {
  734. PNCB ncb; // Pointer to NCB
  735. PNCB_DATA pNcbData; // Pointer to NCB Data
  736. LPBYTE buffer; // Pointer to SMB buffer
  737. LPSTR cp; // Save pointer
  738. LPSTR from; // From-name
  739. LPSTR to; // To-name
  740. MSG_LOG(TRACE,"In Msgmblockbeg %d\n",net);
  741. pNcbData = GETNCBDATA(net,ncbi);
  742. ncb = &pNcbData->Ncb; // Get pointer to NCB
  743. if(pNcbData->State != MESSTART) { // If wrong time for this block
  744. //
  745. // Hang up and start a new listen,
  746. // log an error if mpncbistate[net][ncbi] == MESCONT;
  747. // otherwise, do not log the error.
  748. //
  749. if(pNcbData->State == MESCONT) {
  750. //
  751. // Log error if message in progress
  752. //
  753. Msglogmbe(MESERR,net,ncbi);
  754. }
  755. //
  756. // HANGUP and LISTEN again
  757. //
  758. MsgRestart(net,ncbi);
  759. return;
  760. }
  761. pNcbData->State = MESCONT; // Processing multi-block message
  762. if(MsgVerifySmb(net,ncbi,SMB_COM_SEND_START_MB_MESSAGE,0,"ss") != 0) {
  763. //
  764. // Check for malformed SMB
  765. //
  766. return;
  767. }
  768. buffer = ncb->ncb_buffer; // Get pointer to buffer
  769. from = &buffer[sizeof(SMB_HEADER) + 4]; // Save pointer to from-name
  770. to = &from[strlen(from) + 2]; // Save pointer to to-name
  771. if(Msglogmbb(from,to,net,ncbi)) { // If attempt to log header fails
  772. pNcbData->State = MESERR; // Enter error state
  773. //
  774. // Send negative acknowledgement
  775. //
  776. MsgSendAck(net,ncbi,'\002',SMB_ERR_NO_ROOM);
  777. return;
  778. }
  779. //
  780. // Indicate message received
  781. //
  782. SmbPutUshort(&(((PSMB_HEADER)buffer)->Error), (USHORT)SMB_ERR_SUCCESS);
  783. // ((PSMB_HEADER)buffer)->Error = (USHORT)SMB_ERR_SUCCESS;
  784. cp = &buffer[sizeof(SMB_HEADER)]; // Point just past header
  785. *cp++ = '\001'; // One parameter
  786. ((short UNALIGNED far *) cp)[0] = ++mgid; // Message group ID
  787. pNcbData->mgid = mgid; // Save message group i.d.
  788. ((short UNALIGNED far *) cp)[1] = 0; // No buffer
  789. ncb->ncb_length = sizeof(SMB_HEADER) + 5; // Set length of buffer
  790. ncb->ncb_command = NCBSEND | ASYNCH; // Send(no wait)
  791. //
  792. // Set function pointer & issue the net bios call
  793. //
  794. pNcbData->IFunc = (LPNCBIFCN)MsgSendService;
  795. MsgCallNetBios(net,ncb,ncbi);
  796. }
  797. /*
  798. * Msgmblockend - process end of a multi-block message
  799. *
  800. * This function acknowledges receipt of the end of a
  801. * multi-block message and terminates logging of the message.
  802. *
  803. * Msgmblockend (net, ncbi)
  804. *
  805. * ENTRY
  806. * net - network index
  807. * ncbi - Network Control Block index
  808. *
  809. * RETURN
  810. * nothing
  811. *
  812. * This function is called from ReceivePost() (RecAnyPost()).
  813. * It first check to see if it is appropriate for the ncbi'th
  814. * name to have received an end-multi-block-message SMB at the
  815. * current time. It verifies the correctness of the SMB in the
  816. * ncbi'th buffer. It terminates logging, and it sends an
  817. * acknowledgement to the sender of the message.
  818. *
  819. * SIDE EFFECTS
  820. *
  821. * Calls MsgRestart() to terminate the session if the SMB has arrived
  822. * at a bad time. Calls MsgVerifySmb() to check the SMB for correctness.
  823. * Calls logmbe() to terminate logging. Calls MsgSendAck() to send an
  824. * acknowledgement to the sender of the message.
  825. */
  826. STATIC VOID
  827. Msgmblockend(
  828. DWORD net, // Which network?
  829. DWORD ncbi // Index to NCB
  830. )
  831. {
  832. PNCB ncb; // Pointer to NCB
  833. PNCB_DATA pNcbData; // Pointer to NCB Data
  834. LPBYTE buffer; // Pointer to SMB buffer
  835. int error; // Error flag
  836. char smbrclass; // SMB return class
  837. unsigned short smbrcode; // SMB return code
  838. MSG_LOG(TRACE,"In Msgmblockend %d\n",net);
  839. pNcbData = GETNCBDATA(net,ncbi);
  840. ncb = &pNcbData->Ncb; // Get pointer to NCB
  841. if(pNcbData->State != MESCONT) { // If wrong time for this block
  842. //
  843. // Hang up and start a new listen,
  844. // no error to log since no message in progress.
  845. // HANGUP and LISTEN again
  846. //
  847. MsgRestart(net,ncbi);
  848. return;
  849. }
  850. pNcbData->State = MESSTOP; // End of message state
  851. if(MsgVerifySmb(net,ncbi,SMB_COM_SEND_END_MB_MESSAGE,1,"") != 0) {
  852. //
  853. // If SMB is malformed, log error and return
  854. //
  855. Msglogmbe(MESERR,net,ncbi);
  856. return;
  857. }
  858. buffer = ncb->ncb_buffer; // Get pointer to buffer
  859. if(*((short UNALIGNED far *) &buffer[sizeof(SMB_HEADER) + 1]) != pNcbData->mgid) {
  860. //
  861. // If i.d. does not match
  862. //
  863. error = 1; // Error found
  864. smbrclass = '\002'; // Error return
  865. smbrcode = SMB_ERR_ERROR; // Non-specific error
  866. }
  867. else {
  868. //
  869. // Else if message group i.d. okay
  870. //
  871. error = 0; // No error found
  872. smbrclass = '\0'; // Good return
  873. smbrcode = (USHORT)SMB_ERR_SUCCESS; // Message received
  874. }
  875. MsgSendAck(net,ncbi,smbrclass,smbrcode); // Send acknowledgement
  876. if(!error) Msglogmbe(MESSTOP,net,ncbi); // Log end of message
  877. }
  878. /*
  879. * Msgmblocktxt - process text of a multi-block message
  880. *
  881. * This function acknowledges receipt of a block of text of a
  882. * multi-block message and logs that block.
  883. *
  884. * Msgmblocktxt (net, ncbi)
  885. *
  886. * ENTRY
  887. * net - Network index
  888. * ncbi - Network Control Block index
  889. *
  890. * RETURN
  891. * nothing
  892. *
  893. * This function is called from ReceivePost() (RecAnyPost()).
  894. * It first check to see if it is appropriate for the ncbi'th
  895. * name to have received a multi-block-message-text SMB at the
  896. * current time. It verifies the correctness of the SMB in the
  897. * ncbi'th buffer. It logs the text block, and it sends an
  898. * acknowledgement to the sender of the message.
  899. *
  900. * SIDE EFFECTS
  901. *
  902. * Calls MsgRestart() to terminate the session if the SMB has arrived
  903. * at a bad time. Calls MsgVerifySmb() to check the SMB for correctness.
  904. * Calls logmbt() to log the text block. Calls MsgSendAck() to send an
  905. * acknowledgement to the sender of the message.
  906. */
  907. STATIC VOID
  908. Msgmblocktxt(
  909. DWORD net, // Which network?
  910. DWORD ncbi // Index to NCB
  911. )
  912. {
  913. PNCB ncb; // Pointer to NCB
  914. PNCB_DATA pNcbData; // Pointer to NCB Data
  915. LPBYTE buffer; // Pointer to SMB buffer
  916. LPSTR cp; // Save pointer
  917. char smbrclass; // SMB return class
  918. unsigned short smbrcode; // SMB return code
  919. MSG_LOG(TRACE,"In Msgmblocktxt %d\n",net);
  920. pNcbData = GETNCBDATA(net,ncbi);
  921. ncb = &pNcbData->Ncb; // Get pointer to NCB
  922. if(pNcbData->State != MESCONT) { // If wrong time for this block
  923. //
  924. // HANGUP and start a new LISTEN.
  925. // no error to log since no message in progress.
  926. //
  927. MsgRestart(net,ncbi);
  928. return;
  929. }
  930. if(MsgVerifySmb(net,ncbi,SMB_COM_SEND_TEXT_MB_MESSAGE,1,"b") != 0) {
  931. //
  932. // If SMB is malformed
  933. //
  934. Msglogmbe(MESERR,net,ncbi); // Log error
  935. return;
  936. }
  937. buffer = ncb->ncb_buffer; // Get pointer to buffer
  938. cp = &buffer[sizeof(SMB_HEADER) + 1]; // Skip to message group i.d.
  939. if(*((short UNALIGNED far *) cp) != pNcbData->mgid) {
  940. //
  941. // If i.d. does not match
  942. //
  943. smbrclass = '\002'; // Error return
  944. smbrcode = SMB_ERR_ERROR; // Non-specific error
  945. }
  946. else if(Msglogmbt(&buffer[sizeof(SMB_HEADER) + 6], net, ncbi)) {
  947. //
  948. // Else if text cannot be logged
  949. //
  950. pNcbData->State = MESERR; // Enter error state
  951. smbrclass = '\002'; // Error return
  952. smbrcode = SMB_ERR_NO_ROOM; // No room in buffer
  953. }
  954. else {
  955. //
  956. // Else if message logged okay
  957. //
  958. smbrclass = '\0'; // Good return
  959. smbrcode = (USHORT)SMB_ERR_SUCCESS; // Message received
  960. }
  961. MsgSendAck(net,ncbi,smbrclass,smbrcode); // Send acknowledgement
  962. }
  963. /*
  964. * MsgNetBiosError - process an error returned by a net bios call
  965. *
  966. * This function performs generic error handling for
  967. * failed net bios calls. If the error is a fatal one because the error
  968. * counted exceeded the SHUTDOWN_THRESHOLD, this routine begins a forced
  969. * shutdown of the messenger. This shutdown will not complete until all
  970. * threads have woken up and returned to the main loop where the
  971. * messenger status is examined.
  972. *
  973. * MsgNetBiosError (net, ncb, retval, ncbi)
  974. *
  975. * ENTRY
  976. * net - Network index
  977. * ncb - Network Control Block pointer
  978. * retval - value returned from the net bios call
  979. * ncbi - ncb array index of ncb which resulted in this error
  980. *
  981. * RETURN
  982. * state of the Messenger: Either RUNNING or STOPPING.
  983. *
  984. * Chcks in ncbStatus array that this is not a repeated error
  985. * that has already been entered in the error log, and logs
  986. * the error.
  987. *
  988. * SIDE EFFECTS
  989. *
  990. * Calls MsgErrorLogWrite() to log errors in the Network System Error Log.
  991. * If this is a new error, the error status in the ncbStatus array for this
  992. * ncb is updated so that the same error will not be reported if it is
  993. * repeated.
  994. */
  995. STATIC DWORD
  996. MsgNetBiosError(
  997. DWORD net, // Which network?
  998. PNCB ncb, // Pointer to NCB
  999. char retval, // Error code
  1000. DWORD ncbi // Index of array causing the error
  1001. )
  1002. {
  1003. PNCB_DATA pNcbData;
  1004. //
  1005. // First check the immediate status for this ncb. If it is in error
  1006. // then this must be the error, else it is a final error code.
  1007. //
  1008. pNcbData = GETNCBDATA(net,ncbi);
  1009. if (pNcbData->Status.this_immediate != 0) {
  1010. if(pNcbData->Status.this_immediate ==
  1011. pNcbData->Status.last_immediate) {
  1012. if (++(pNcbData->Status.rep_count) >= SHUTDOWN_THRESHOLD) {
  1013. //
  1014. // The same error has occured SHUTDOWN_THRESHOLD times in
  1015. // a row. Write to the event log and shutdown the messenger.
  1016. //
  1017. MsgErrorLogWrite(
  1018. NELOG_Msg_Shutdown,
  1019. SERVICE_MESSENGER,
  1020. (LPBYTE) ncb,
  1021. sizeof(NCB),
  1022. NULL,
  1023. 0);
  1024. MSG_LOG(ERROR,"MsgNetBiosError1:repeated MsgNetBiosError(ncb error) - shutting down\n",0);
  1025. return(MsgBeginForcedShutdown(
  1026. PENDING,
  1027. NERR_InternalError));
  1028. }
  1029. return(RUNNING); // Same as last error so don't report it
  1030. }
  1031. else {
  1032. //
  1033. // This error was not the same as the last error. So just
  1034. // update the last error place holder.
  1035. //
  1036. pNcbData->Status.last_immediate =
  1037. pNcbData->Status.this_immediate;
  1038. }
  1039. }
  1040. else {
  1041. //
  1042. // Must have been a final ret code (ncb completion code) that was
  1043. // in error.
  1044. //
  1045. if(pNcbData->Status.this_final == pNcbData->Status.last_final) {
  1046. if (++(pNcbData->Status.rep_count) >= SHUTDOWN_THRESHOLD) {
  1047. MsgErrorLogWrite(
  1048. NELOG_Msg_Shutdown,
  1049. SERVICE_MESSENGER,
  1050. (LPBYTE) ncb,
  1051. sizeof(NCB),
  1052. NULL,
  1053. 0);
  1054. MSG_LOG(ERROR,"MsgNetBiosError2:repeated MsgNetBiosError (final ret code) - shutting down\n",0);
  1055. return(MsgBeginForcedShutdown(
  1056. PENDING,
  1057. NERR_InternalError));
  1058. }
  1059. return(RUNNING); // Same as last error so don't report it
  1060. }
  1061. else {
  1062. pNcbData->Status.last_final = pNcbData->Status.this_final;
  1063. }
  1064. }
  1065. //
  1066. // Here if a new error has occured so log it in the error log.
  1067. //
  1068. MsgErrorLogWrite(
  1069. NELOG_Ncb_Error,
  1070. SERVICE_MESSENGER,
  1071. (LPBYTE) ncb,
  1072. sizeof(NCB),
  1073. NULL,
  1074. 0); // Enter error in system error log
  1075. MSG_LOG(ERROR,"MsgNetBiosError3:An unexpected NCB was received 0x%x\n",retval);
  1076. UNUSED(retval);
  1077. #if DBG
  1078. MsgDumpNcb(ncb);
  1079. #endif
  1080. return (RUNNING);
  1081. }
  1082. /*
  1083. * MsgReceiveService - service a completed RECEIVE net bios call
  1084. *
  1085. * This function is called to service a completed RECEIVE net
  1086. * bios call. For successful completions, it examines the data
  1087. * received to determine which of the SMB-processing functions
  1088. * should be called.
  1089. *
  1090. * MsgReceiveService (net, ncbi, retval)
  1091. *
  1092. * ENTRY
  1093. * net - network index
  1094. * ncbi - Network Control Block index
  1095. * retval - value returned by the net bios
  1096. *
  1097. * RETURN
  1098. * nothing
  1099. *
  1100. * This function dispatches SMB's received to the proper processing
  1101. * function. It also handles a number of error conditions (noted
  1102. * in the code below).
  1103. *
  1104. * SIDE EFFECTS
  1105. *
  1106. * See handling of error conditions.
  1107. */
  1108. STATIC VOID
  1109. MsgReceiveService(
  1110. DWORD net, // Which network?
  1111. DWORD ncbi, // Index to completed NCB
  1112. char retval // SEND return value
  1113. )
  1114. {
  1115. PNCB ncb; // Pointer to completed NCB
  1116. PNCB_DATA pNcbData; // Pointer to NCB Data
  1117. PSMB_HEADER smb; // Pointer to SMB header
  1118. MSG_LOG(TRACE,"In MsgReceiveService %d\n",net);
  1119. pNcbData = GETNCBDATA(net,ncbi);
  1120. ncb = &pNcbData->Ncb; // Get pointer to NCB
  1121. switch(retval) {
  1122. case NRC_GOODRET: // Success
  1123. if(ncb->ncb_length >= sizeof(SMB_HEADER)) {
  1124. //
  1125. // If we could have an SMB
  1126. //
  1127. smb = (PSMB_HEADER)ncb->ncb_buffer;
  1128. // Get pointer to buffer
  1129. switch(smb->Command) { // Switch on SMB function code
  1130. case SMB_COM_SEND_MESSAGE: // Single block message
  1131. Msgsblockmes(net,ncbi);
  1132. return;
  1133. case SMB_COM_SEND_START_MB_MESSAGE: // Beginning of multi-block message
  1134. Msgmblockbeg(net,ncbi);
  1135. return;
  1136. case SMB_COM_SEND_END_MB_MESSAGE: // End of multi-block message
  1137. Msgmblockend(net,ncbi);
  1138. return;
  1139. case SMB_COM_SEND_TEXT_MB_MESSAGE: // Text of multi-block message
  1140. Msgmblocktxt(net,ncbi);
  1141. return;
  1142. case SMB_COM_GET_MACHINE_NAME: // Get Machine Name
  1143. MsgGetMachineName(net,ncbi);
  1144. return;
  1145. case SMB_COM_FORWARD_USER_NAME: // Add forward-name
  1146. //
  1147. // Not supported in NT.
  1148. // for now fall through as if unrecognized SMB.
  1149. //
  1150. case SMB_COM_CANCEL_FORWARD: // Delete forward-name
  1151. //
  1152. // Not supported in NT.
  1153. // for now fall through as if unrecognized SMB.
  1154. //
  1155. default: // Unrecognized SMB
  1156. break;
  1157. }
  1158. }
  1159. if(pNcbData->State == MESCONT) {
  1160. //
  1161. // If middle of multi-block message, Log an error
  1162. //
  1163. Msglogmbe(MESERR,net,ncbi);
  1164. }
  1165. //
  1166. // Enter error in system error log
  1167. //
  1168. MsgErrorLogWrite(
  1169. NELOG_Msg_Unexpected_SMB_Type,
  1170. SERVICE_MESSENGER,
  1171. (LPBYTE)ncb->ncb_buffer,
  1172. ncb->ncb_length,
  1173. NULL,
  1174. 0);
  1175. MSG_LOG(ERROR,"MsgReceiveService:An illegal SMB was received\n",0);
  1176. //
  1177. // HANGUP and LISTEN again
  1178. //
  1179. MsgRestart(net,ncbi);
  1180. break;
  1181. case NRC_CMDTMO: // Command timed out
  1182. if(pNcbData->State == MESCONT) {
  1183. //
  1184. // If middle of multi-block message
  1185. //
  1186. Msglogmbe(MESERR,net,ncbi); // Log an error
  1187. }
  1188. //
  1189. // HANGUP and start new LISTEN
  1190. //
  1191. MsgRestart(net,ncbi);
  1192. break;
  1193. case NRC_SCLOSED: // Session closed
  1194. case NRC_SABORT: // Session ended abnormally
  1195. if(pNcbData->State == MESCONT) {
  1196. //
  1197. // If middle of multi-block message, Log an error
  1198. //
  1199. Msglogmbe(MESERR,net,ncbi);
  1200. }
  1201. //
  1202. // Start a new LISTEN
  1203. //
  1204. MsgStartListen(net,ncbi);
  1205. break;
  1206. default: // Other errors
  1207. MSG_LOG(TRACE,"MsgReceiveService: Unrecognized retval %x\n",retval);
  1208. MsgNetBiosError(net,ncb,retval,ncbi);
  1209. if(pNcbData->State == MESCONT) {
  1210. //
  1211. // If middle of multi-block message, Log an error
  1212. //
  1213. Msglogmbe(MESERR,net,ncbi);
  1214. }
  1215. MsgRestart(net,ncbi); // HANGUP and LISTEN again
  1216. break;
  1217. }
  1218. }
  1219. /*
  1220. * MsgRestart - issue a HANGUP net bios call
  1221. *
  1222. * This function is invoked to issue a HANGUP net bios call using
  1223. * a particular Network Control Block.
  1224. *
  1225. * MsgRestart (net, ncbi)
  1226. *
  1227. * ENTRY
  1228. * net - network index
  1229. * ncbi - Network Control Block index
  1230. *
  1231. * RETURN
  1232. * nothing
  1233. *
  1234. * This function assumes that the NCB_LSN, NCB_POST, and NCB_LANA
  1235. * fields of the Network Control Block are already properly set.
  1236. * It sets the NCB_CMD field.
  1237. *
  1238. * This function is named "MsgRestart" since the very next routine
  1239. * to process the NCB used to issue the HANGUP should be
  1240. * MsgHangupService() which always invokes MsgStartListen() (assuming
  1241. * the HANGUP completes properly). Thus, the net effect of
  1242. * calling MsgRestart() is to terminate the current session and
  1243. * issue a LISTEN to start a new one.
  1244. *
  1245. * SIDE EFFECTS
  1246. *
  1247. * Calls MsgCallNetBios() to issue the net bios call. Sets mpncbifun[ncbi]
  1248. * to the address of MsgHangupService().
  1249. */
  1250. STATIC VOID
  1251. MsgRestart(
  1252. DWORD net, // Which network?
  1253. DWORD ncbi // Index to NCB
  1254. )
  1255. {
  1256. PNCB ncb; // Pointer to Network Control Block
  1257. PNCB_DATA pNcbData; // Pointer to NCB Data
  1258. MSG_LOG(TRACE,"In MsgRestart %d\n",net);
  1259. pNcbData = GETNCBDATA(net,ncbi);
  1260. ncb = &pNcbData->Ncb;
  1261. pNcbData->IFunc = (LPNCBIFCN)MsgHangupService; // Set function pointer
  1262. ncb->ncb_command = NCBHANGUP | ASYNCH; // Hang up (no wait)
  1263. MsgCallNetBios(net,ncb,ncbi); // Issue the net bios call
  1264. }
  1265. /*
  1266. * Msgsblockmes - process a single block message
  1267. *
  1268. * This function logs and acknowledges a single block message.
  1269. *
  1270. * Msgsblockmes (net, ncbi)
  1271. *
  1272. * ENTRY
  1273. * net - network index
  1274. * ncbi - Network Control Block index
  1275. *
  1276. * RETURN
  1277. * nothing
  1278. *
  1279. * This function is called from ReceivePost() (RecAnyPost()).
  1280. * It first check to see if it is appropriate for the ncbi'th
  1281. * name to have received a single block message SMB at the current
  1282. * time. It verifies the correctness of the SMB in the ncbi'th
  1283. * buffer. It attempts to log the single block message, and it
  1284. * sends an acknowledgement to the sender of the message.
  1285. *
  1286. * SIDE EFFECTS
  1287. *
  1288. * Calls MsgRestart() to terminate the session if the SMB has arrived
  1289. * at a bad time. Calls MsgVerifySmb() to check the SMB for correctness.
  1290. * Calls logsbm() to log the message. Calls MsgSendAck() to send an
  1291. * acknowledgement to the sender of the message.
  1292. */
  1293. STATIC VOID
  1294. Msgsblockmes(
  1295. DWORD net, // Which network ?
  1296. DWORD ncbi // Index to NCB
  1297. )
  1298. {
  1299. PNCB ncb; // Pointer to NCB
  1300. PNCB_DATA pNcbData; // Pointer to NCB
  1301. LPBYTE buffer; // Pointer to SMB buffer
  1302. LPSTR cp; // Save pointer
  1303. LPSTR from; // From-name
  1304. LPSTR to; // To-name
  1305. // to browse the SessionId List :
  1306. PMSG_SESSION_ID_ITEM pItem; // item in the list
  1307. PLIST_ENTRY pHead; // head of the list
  1308. PLIST_ENTRY pList; // list pointer
  1309. DWORD bError = 0; // error flag
  1310. MSG_LOG(TRACE,"In Msgsblockmes %d\n",net);
  1311. pNcbData = GETNCBDATA(net,ncbi);
  1312. ncb = &pNcbData->Ncb; // Get pointer to NCB
  1313. if(pNcbData->State != MESSTART) {
  1314. //
  1315. // If wrong time for this block
  1316. // Hang up and start a new listen,
  1317. // log an error if mpncbistate[net][ncbi] == MESCONT;
  1318. // otherwise, do not log the error.
  1319. //
  1320. // Log error if message in progress
  1321. //
  1322. if(pNcbData->State == MESCONT) {
  1323. Msglogmbe(MESERR,net,ncbi);
  1324. }
  1325. //
  1326. // HANGUP and LISTEN again
  1327. //
  1328. MsgRestart(net,ncbi);
  1329. return;
  1330. }
  1331. pNcbData->State = MESSTOP; // End of message state
  1332. //
  1333. // Check for malformed SMB
  1334. //
  1335. if(MsgVerifySmb(net,ncbi,(unsigned char)SMB_COM_SEND_MESSAGE,0,"ssb") != 0) {
  1336. return;
  1337. }
  1338. buffer = ncb->ncb_buffer; // Get pointer to buffer
  1339. from = &buffer[sizeof(SMB_HEADER) + 4]; // Save pointer to from-name
  1340. to = &from[strlen(from) + 2]; // Save pointer to to-name
  1341. cp = &to[strlen(to) + 2]; // Skip over the name
  1342. if (g_IsTerminalServer)
  1343. {
  1344. MsgDatabaseLock(MSG_GET_EXCLUSIVE,"Msgsblockmes");
  1345. pHead = &(SD_SIDLIST(net,ncbi));
  1346. pList = pHead;
  1347. while (pList->Flink != pHead) // loop all over the list
  1348. {
  1349. pList = pList->Flink;
  1350. pItem = CONTAINING_RECORD(pList, MSG_SESSION_ID_ITEM, List);
  1351. bError = Msglogsbm(from,to,cp, pItem->SessionId);
  1352. if (bError)
  1353. {
  1354. break;
  1355. }
  1356. }
  1357. MsgDatabaseLock(MSG_RELEASE,"Msgsblockmes");
  1358. }
  1359. else //regular NT
  1360. {
  1361. bError = Msglogsbm(from,to,cp,0);
  1362. }
  1363. if (bError)
  1364. {
  1365. //
  1366. // If message cannot be logged, enter error state
  1367. // and send error acknowledgement.
  1368. //
  1369. pNcbData->State = MESERR;
  1370. MsgSendAck(net,ncbi,'\002',SMB_ERR_NO_ROOM);
  1371. }
  1372. else
  1373. {
  1374. //
  1375. // Otherwise acknowledge success
  1376. //
  1377. MsgSendAck(net, ncbi, SMB_ERR_SUCCESS, (USHORT)SMB_ERR_SUCCESS);
  1378. }
  1379. }
  1380. /*
  1381. * MsgSendAck - send an SMB to acknowledge a network transaction
  1382. *
  1383. * This function is used to send a Server Message Block to some
  1384. * machine with whom a session has been established acknowledging
  1385. * (positively or negatively) the occurrence of some event pertaining
  1386. * to the session.
  1387. *
  1388. * MsgSendAck (net, ncbi, smbrclass, smbrcode)
  1389. *
  1390. * ENTRY
  1391. * net - Network index
  1392. * ncbi - Network Control Block index
  1393. * smbrclass - SMB return class
  1394. * smbrcode - SMB return code
  1395. *
  1396. * RETURN
  1397. * nothing
  1398. *
  1399. * Using the NCB index to locate the buffer containing the last SMB
  1400. * received in the session, this function sets the return class and
  1401. * the return code in that SMB according to its arguments and sends
  1402. * the SMB to the other party in the session. This function will
  1403. * not return any parameters or buffers in that SMB.
  1404. *
  1405. * SIDE EFFECTS
  1406. *
  1407. * This function calls MsgCallNetBios() to send the SMB, and it sets
  1408. * the function vector so that control will pass to Send Service()
  1409. * when the NCB completes (assuming, of course, that it doesn't
  1410. * fail immediately).
  1411. */
  1412. STATIC VOID
  1413. MsgSendAck(
  1414. DWORD net, // Which network?
  1415. DWORD ncbi, // Network Control Block Index
  1416. UCHAR smbrclass, // SMB return class
  1417. USHORT smbrcode // SMB return code
  1418. )
  1419. {
  1420. PNCB ncb; // Pointer to NCB
  1421. PNCB_DATA pNcbData; // Pointer to NCB Data
  1422. LPBYTE buffer; // Pointer to buffer
  1423. MSG_LOG(TRACE,"In MsgSendAck %d\n",net);
  1424. pNcbData = GETNCBDATA(net,ncbi);
  1425. ncb = &pNcbData->Ncb; // Get pointer to NCB
  1426. buffer = ncb->ncb_buffer; // Get pointer to buffer
  1427. //
  1428. // No parameters, buffers
  1429. //
  1430. buffer[sizeof(SMB_HEADER)+2]=
  1431. buffer[sizeof(SMB_HEADER)+1]=
  1432. buffer[sizeof(SMB_HEADER)]= '\0';
  1433. //
  1434. // Set return information
  1435. //
  1436. ((PSMB_HEADER)buffer)->ErrorClass = smbrclass; // Set return class
  1437. SmbPutUshort( &(((PSMB_HEADER)buffer)->Error),smbrcode);// Set return code
  1438. // ((PSMB_HEADER)buffer)->Error = smbrcode; // Set return code
  1439. ncb->ncb_length = sizeof(SMB_HEADER) + 3; // Set length of buffer
  1440. ncb->ncb_command = NCBSEND | ASYNCH; // Send (no wait)
  1441. pNcbData->IFunc = (LPNCBIFCN)MsgSendService; // Set function pointer
  1442. MsgCallNetBios(net,ncb,ncbi); // Issue the net bios call
  1443. }
  1444. /*
  1445. * MsgSendService - service a completed SEND net bios call
  1446. *
  1447. * This function is called to service a completed SEND net bios
  1448. * call. The usual course of action is to issue a RECEIVE (ANY)
  1449. * net bios call.
  1450. *
  1451. * MsgSendService (net, ncbi, retval)
  1452. *
  1453. * ENTRY
  1454. * net - network index
  1455. * ncbi - Network Control Block index
  1456. * retval - value returned by net bios
  1457. *
  1458. * RETURN
  1459. * nothing
  1460. *
  1461. * If a SEND net bios call has completed successfully, this function
  1462. * will issue a RECEIVE (ANY) net bios call in all cases. The com-
  1463. * pleted SEND represents one of the following cases:
  1464. *
  1465. * - Acknowledgement of a Single Block Message
  1466. * The message originator will HANG UP, completing the RECEIVE (ANY) call.
  1467. * - Acknowledgement of the start of a Multi-block Message
  1468. * The message originator will SEND a text block, completing the RECEIVE
  1469. * (ANY) call.
  1470. * - Acknowledgement of text of a Multi-block Message
  1471. * The message originator will SEND more text or the end of the message,
  1472. * completing the RECEIVE (ANY) call.
  1473. * - Acknowledgement of the end of a Multi-block Message
  1474. * The message originator will HANG UP, completing the RECEIVE (ANY) call.
  1475. * - Response to a Get Machine Name request
  1476. * The message originator will HANG UP, completing the RECEIVE (ANY) call.
  1477. * - Acknowledgement of a Forward Name request
  1478. * The message originator will HANG UP, completing the RECEIVE (ANY) call.
  1479. * - Acknowledgement of a Cancel Forward request
  1480. * The message originator will HANG UP, completing the RECEIVE (ANY) call.
  1481. * - An error response
  1482. * The message originator will HANG UP, completing the RECEIVE (ANY) call.
  1483. *
  1484. * In all cases, it is clear to the RECEIVE (ANY) service function what its
  1485. * course of action is.
  1486. *
  1487. * SIDE EFFECTS
  1488. *
  1489. * If a SEND has completed normally, this function issues a RECEIVE (ANY)
  1490. * net bios call. In some abnormal cases, this function calls MsgStartListen()
  1491. * to initiate a new session. In all other abnormal cases, it calls
  1492. * MsgNetBiosError().
  1493. */
  1494. STATIC VOID
  1495. MsgSendService(
  1496. DWORD net, // Which network?
  1497. DWORD ncbi, // Index of completed NCB
  1498. char retval // SEND return value
  1499. )
  1500. {
  1501. PNCB ncb; // Pointer to completed NCB
  1502. PNCB_DATA pNcbData; // Pointer to NCB Data
  1503. PSMB_HEADER smb; // Pointer to SMB header
  1504. MSG_LOG(TRACE,"In MsgSendService %d\n",net);
  1505. pNcbData = GETNCBDATA(net,ncbi);
  1506. ncb = &pNcbData->Ncb; // Get pointer to completed NCB
  1507. switch(retval) {
  1508. case NRC_GOODRET: // Success
  1509. pNcbData->IFunc = (LPNCBIFCN)MsgReceiveService;
  1510. //
  1511. // Set function pointer
  1512. //
  1513. ncb->ncb_command = NCBRECV | ASYNCH; // Receive (no wait)
  1514. ncb->ncb_length = BUFLEN; // Set length of buffer
  1515. MsgCallNetBios(net,ncb,ncbi); // Issue the net bios call
  1516. break;
  1517. case NRC_CMDTMO: // Timeout
  1518. case NRC_SCLOSED: // Session closed
  1519. case NRC_SABORT: // Session ended abnormally
  1520. smb = (PSMB_HEADER)ncb->ncb_buffer; // Get pointer to SMB
  1521. if(smb->Command == SMB_COM_SEND_START_MB_MESSAGE || smb->Command == SMB_COM_SEND_TEXT_MB_MESSAGE) {
  1522. //
  1523. // Message ended abnormally
  1524. //
  1525. Msglogmbe(MESERR,net,ncbi);
  1526. }
  1527. //
  1528. // Issue a new LISTEN
  1529. //
  1530. MsgStartListen(net,ncbi);
  1531. break;
  1532. default: // Other failure
  1533. MSG_LOG(TRACE,"MsgSendService: Unrecognized retval %x\n",retval);
  1534. MsgNetBiosError(net,ncb,retval,ncbi);
  1535. //
  1536. // HANGUP and LISTEN again
  1537. //
  1538. MsgRestart(net,ncbi);
  1539. break;
  1540. }
  1541. }
  1542. /*
  1543. * MsgServeNCBs - service completed Network Control Blocks
  1544. *
  1545. * This function scans the array of NCB's looking for NCB's in
  1546. * need of service.
  1547. *
  1548. * MsgServeNCBs (net)
  1549. *
  1550. * ENTRY
  1551. * net - network to service NCBs on
  1552. *
  1553. * RETURN
  1554. * TRUE - If this function actually services a completed NCB.
  1555. * FALSE - If this function didn't find any completed NCB's, or if
  1556. * the service is supposed to stop.
  1557. *
  1558. * This function scans the array of NCB's until a completed NCB cannot be
  1559. * found. Each time a completed NCB is found, the service function specified
  1560. * in the service function vector (mpncbifun[]) is called to service that
  1561. * NCB.
  1562. *
  1563. * SIDE EFFECTS
  1564. *
  1565. * Maintains a private static index of the last NCB examined.
  1566. * Starts each search at first NCB after the last one serviced.
  1567. */
  1568. BOOL
  1569. MsgServeNCBs(
  1570. DWORD net // Which network am I serving?
  1571. )
  1572. {
  1573. PNCB pNcb;
  1574. PNCB_DATA pNcbData;
  1575. int counter; // A counter
  1576. BOOL found = FALSE; // Indicates if a completed NCB was found.
  1577. // Bugfix: each net has its own index, addressing
  1578. // its part NCB array. All index values are initiliazed to zero
  1579. // when the messenger starts. This solves the muti thread
  1580. // problem.
  1581. static int ncbIndexArray[MSNGR_MAX_NETS] = {0};
  1582. // NCB index array
  1583. DWORD ncbi; // NCB index for this net
  1584. //
  1585. // get NCB index for this net
  1586. //
  1587. ncbi = ncbIndexArray[net];
  1588. //
  1589. // Loop until none completed found
  1590. //
  1591. do {
  1592. //
  1593. // Loop to search NCB array
  1594. //
  1595. for(counter = NCBMAX(net); counter != 0; --counter, ++ncbi) {
  1596. if(ncbi >= NCBMAX(net)) {
  1597. ncbi = 0;// Wrap around
  1598. }
  1599. pNcbData = GETNCBDATA(net,ncbi);
  1600. pNcb = &pNcbData->Ncb;
  1601. if(pNcb->ncb_cmd_cplt != (unsigned char) 0xff) {
  1602. found=TRUE;
  1603. //
  1604. // If completed NCB found
  1605. //
  1606. if(pNcb->ncb_cmd_cplt == 0) {
  1607. //
  1608. // Clear err on success and error count
  1609. //
  1610. pNcbData->Status.last_final = 0;
  1611. pNcbData->Status.rep_count = 0;
  1612. }
  1613. else {
  1614. //
  1615. // Else mark error
  1616. //
  1617. pNcbData->Status.this_final = pNcb->ncb_cmd_cplt;
  1618. //
  1619. // If NetBios is failing with every call, we never
  1620. // return from this routine be cause there is always
  1621. // another NCB to service. Therefore, in error
  1622. // conditions it is necessary to check to see if a
  1623. // shutdown is in progress. If so, we want to return
  1624. // so that the adapter loop can handle the shutdown
  1625. // properly.
  1626. //
  1627. if (GetMsgrState() == STOPPING) {
  1628. ncbIndexArray[net] = ncbi;
  1629. return(FALSE);
  1630. }
  1631. }
  1632. //
  1633. // Call the service function
  1634. //
  1635. (*pNcbData->IFunc)(net,ncbi,pNcb->ncb_cmd_cplt);
  1636. ++ncbi; // Start next search after this NCB
  1637. break; // Exit loop
  1638. }
  1639. }
  1640. }
  1641. while(counter != 0); // Loop until counter zero
  1642. // update NCB index
  1643. ncbIndexArray[net] = ncbi;
  1644. return(found);
  1645. }
  1646. /*
  1647. * MsgSesFullService - complete deletion of a name after a system error
  1648. *
  1649. * MsgSesFullService() completes the process of deleting a name from
  1650. * the message system when the message server is unable to establish
  1651. * a session for that name.
  1652. *
  1653. * MsgSesFullService (net, ncbi, retval)
  1654. *
  1655. * ENTRY
  1656. * net - Network index
  1657. * ncbi - Network Control Block index
  1658. * retval - value returned by net bios
  1659. *
  1660. * RETURN
  1661. * nothing
  1662. *
  1663. * MsgSesFullService() is called to finish the job of cleaning up when
  1664. * a LISTEN fails because the local network adapter's session table
  1665. * is full. Specifically, this function is called when the DELETE
  1666. * NAME net bios call completes.
  1667. *
  1668. * SIDE EFFECTS
  1669. *
  1670. * Calls MsgDeleteName() to release the deleted name's entry in the
  1671. * shared data area. Calls MsgNetBiosError() if the DELETE NAME net
  1672. * bios call produced unexpected results.
  1673. */
  1674. STATIC VOID
  1675. MsgSesFullService(
  1676. DWORD net, // Which network ?
  1677. DWORD ncbi, // Index of completed NCB
  1678. char retval // SEND return value
  1679. )
  1680. {
  1681. PNCB pNcb;
  1682. MSG_LOG(TRACE,"In MsgSesFullService %d\n",net);
  1683. switch(retval) {
  1684. case NRC_GOODRET: // Success
  1685. case NRC_ACTSES: // Name deregistered
  1686. //
  1687. // Log deletion in system error log file
  1688. //
  1689. MsgDeleteName(net,ncbi); // Delete name from database
  1690. break;
  1691. default: // Failure
  1692. MSG_LOG(TRACE,"MsgSesFullService: Unrecognized retval %x\n",retval);
  1693. pNcb = GETNCB(net,ncbi);
  1694. MsgNetBiosError(net, pNcb, retval, ncbi);
  1695. break;
  1696. }
  1697. }
  1698. /*
  1699. * MsgStartListen - issue a LISTEN net bios call
  1700. *
  1701. * This function is invoked to issue a LISTEN net bios call using
  1702. * a particular Network Control Block. This function does not
  1703. * examine or change any of the shareable data corresponding to
  1704. * the NCB in question.
  1705. *
  1706. * MsgStartListen (net, ncbi)
  1707. *
  1708. * ENTRY
  1709. * net - network index
  1710. * ncbi - Network Control Block index
  1711. *
  1712. * RETURN
  1713. * DWORD status from the netbios call.
  1714. *
  1715. * This function assumes that the NCB_NAME, NCB_POST, and NCB_LANA
  1716. * fields of the Network Control Block are already set to the
  1717. * proper values. It sets the NCB_CNAME, NCB_RTO, NCB_STO, and
  1718. * NCB_CMD fields.
  1719. *
  1720. * SIDE EFFECTS
  1721. *
  1722. * Calls MsgCallNetBios() to issue the net bios call. Calls FmtNcbName()
  1723. * to set the NCB_CNAME field of the NCB. Sets mpncbifun[ncbi] to
  1724. * the address of MsgListenService().
  1725. */
  1726. NET_API_STATUS
  1727. MsgStartListen(
  1728. DWORD net, // Which network?
  1729. DWORD ncbi // Network Control Block index
  1730. )
  1731. {
  1732. PNCB ncb; // Pointer to NCB
  1733. PNCB_DATA pNcbData; // Pointer to NCB Data
  1734. NET_API_STATUS status;
  1735. TCHAR name[2] = TEXT("*");
  1736. MSG_LOG(TRACE,"In MsgStartListen %d\n",net);
  1737. pNcbData = GETNCBDATA(net,ncbi);
  1738. ncb = &pNcbData->Ncb;
  1739. pNcbData->IFunc = (LPNCBIFCN)MsgListenService; // Set function pointer
  1740. //
  1741. // Set call name to a"anyone"
  1742. //
  1743. status = MsgFmtNcbName(ncb->ncb_callname,name,' ');
  1744. if (status != NERR_Success) {
  1745. //
  1746. // This is a bug if this can't be done.
  1747. //
  1748. MSG_LOG(ERROR,"MsgStartListen: NASTY BUG! Cannot format \"*\" name! %X\n",
  1749. status);
  1750. NetpAssert(0);
  1751. }
  1752. ncb->ncb_rto = 60; // Receives time out in 30 sec
  1753. ncb->ncb_sto = 40; // Sends time out in 20 sec
  1754. ncb->ncb_command = NCBLISTEN | ASYNCH; // Listen (no wait)
  1755. return(MsgCallNetBios(net,ncb,ncbi)); // Issue the net bios call
  1756. }
  1757. /*
  1758. * MsgVerifySmb - Verify the correctness of a Server Message Block
  1759. *
  1760. * This function verifies that a Server Message Block is properly
  1761. * formed. If it detects a malformed SMB, it terminates the session
  1762. * and returns a non-zero value.
  1763. *
  1764. * MsgVerifySmb (net, ncbi, func, parms, buffers)
  1765. *
  1766. * ENTRY
  1767. * net - network index
  1768. * ncbi - index to a Network Control Block
  1769. * func - SMB function code
  1770. * parms - number of parameters in SMB
  1771. * buffers - dope vector describing buffers in the SMB
  1772. *
  1773. * RETURN
  1774. * int - error code (zero means no error)
  1775. *
  1776. * SIDE EFFECTS
  1777. *
  1778. * Calls smbcheck() to check the SMB. Calls MsgRestart() if
  1779. * smbcheck() reports an error.
  1780. */
  1781. STATIC int
  1782. MsgVerifySmb(
  1783. DWORD net, // Which network?
  1784. DWORD ncbi, // Index to Network Control Block
  1785. UCHAR func, // SMB function code
  1786. int parms, // Count of parameters in SMB
  1787. LPSTR buffers // Dope vector of SMB buffers
  1788. )
  1789. {
  1790. PNCB ncb; // Pointer to Network Control Block
  1791. int i; // Return code
  1792. ncb = GETNCB(net,ncbi); // Get pointer to NCB
  1793. i = Msgsmbcheck(
  1794. (ncb->ncb_buffer),
  1795. ncb->ncb_length,
  1796. func,
  1797. (char)parms,
  1798. buffers);
  1799. if (i != 0 ) {
  1800. //
  1801. // if SMB malformed, Enter error in system error log
  1802. //
  1803. MsgErrorLogWrite(
  1804. NELOG_SMB_Illegal,
  1805. SERVICE_MESSENGER,
  1806. (LPBYTE)ncb->ncb_buffer,
  1807. ncb->ncb_length,
  1808. NULL,
  1809. 0);
  1810. MSG_LOG(ERROR,"MsgVerifySmb:An illegal SMB was received\n",0);
  1811. //
  1812. // HANGUP
  1813. //
  1814. MsgRestart(net,ncbi);
  1815. }
  1816. return(i); // Return error code
  1817. }
  1818. #if DBG
  1819. VOID
  1820. MsgDumpNcb(
  1821. IN PNCB pNcb
  1822. )
  1823. /*++
  1824. Routine Description:
  1825. Displays the NCB on a debug terminal.
  1826. Arguments:
  1827. Return Value:
  1828. --*/
  1829. {
  1830. DbgPrint("NCBADDR: 0x%x\n"
  1831. "Command: 0x%x\n"
  1832. "RetCode: 0x%x\n"
  1833. "LanaNum: 0x%x\n"
  1834. "CmdCplt: 0x%x\n"
  1835. "Name : %s\n"
  1836. "callNam: %s\n",
  1837. pNcb, pNcb->ncb_command, pNcb->ncb_retcode, pNcb->ncb_lana_num,
  1838. pNcb->ncb_cmd_cplt, pNcb->ncb_name, pNcb->ncb_callname);
  1839. }
  1840. #endif // DBG