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.

1114 lines
27 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. atalkio.c
  5. Abstract:
  6. This module contains the interfaces to the appletalk stack and the
  7. completion routines for the IO requests to the stack via the TDI.
  8. All the routines in this module can be called at DPC level.
  9. Author:
  10. Jameel Hyder (microsoft!jameelh)
  11. Revision History:
  12. 18 Jun 1992 Initial Version
  13. Notes: Tab stop: 4
  14. --*/
  15. #define FILENUM FILE_ATALKIO
  16. #include <afp.h>
  17. #include <scavengr.h>
  18. #include <forkio.h>
  19. #ifdef ALLOC_PRAGMA
  20. #pragma alloc_text( PAGE, AfpSpOpenAddress)
  21. #pragma alloc_text( PAGE, AfpSpCloseAddress)
  22. #pragma alloc_text( PAGE, AfpSpRegisterName)
  23. #endif
  24. /*** AfpTdiPnpHandler
  25. *
  26. * Call the routine (AfpSpOpenAddress) to bind to Asp. This used to be done earlier
  27. * in the DriverEntry code. With plug-n-play, we do it after TDI calls
  28. * us to notify us of an available binding
  29. */
  30. VOID
  31. AfpTdiPnpHandler(
  32. IN TDI_PNP_OPCODE PnPOpcode,
  33. IN PUNICODE_STRING pBindDeviceName,
  34. IN PWSTR BindingList
  35. )
  36. {
  37. NTSTATUS Status;
  38. UNICODE_STRING OurDeviceName;
  39. WORKER ReCfgRoutine;
  40. WORK_ITEM ReCfgWorkItem;
  41. KEVENT ReCfgEvent;
  42. //
  43. // now see what pnp event has occured and do the needful
  44. //
  45. RtlInitUnicodeString(&OurDeviceName, ATALKASPS_DEVICENAME);
  46. if ((AfpServerState == AFP_STATE_STOP_PENDING) ||
  47. (AfpServerState == AFP_STATE_STOPPED))
  48. {
  49. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  50. ("AfpTdiPnpHandler: server stopped or stopping (%d), ignoring PnP event %d\n",
  51. AfpServerState,PnPOpcode));
  52. return;
  53. }
  54. switch (PnPOpcode)
  55. {
  56. case TDI_PNP_OP_ADD:
  57. if (AfpServerBoundToAsp)
  58. {
  59. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  60. ("AfpTdi..: We are already bound!! ignoring!\n"));
  61. return;
  62. }
  63. // it had better be our device!
  64. if (!RtlEqualUnicodeString(pBindDeviceName, &OurDeviceName, TRUE))
  65. {
  66. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  67. ("AfpTdiPnpHandler: not our tranport: on %ws ignored\n",
  68. pBindDeviceName->Buffer));
  69. ASSERT(0);
  70. return;
  71. }
  72. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_INFO,
  73. ("AfpTdi..: Found our binding: %ws\n",pBindDeviceName->Buffer));
  74. ReCfgRoutine = (WORKER)AfpPnPReconfigEnable;
  75. break;
  76. case TDI_PNP_OP_DEL:
  77. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  78. ("AfpTdiPnpHandler: got TDI_PNP_OP_DEL, default adapter going away!\n"));
  79. if (!AfpServerBoundToAsp)
  80. {
  81. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  82. ("AfpTdiPnpHandler: We are not bound!! ignoring!\n"));
  83. return;
  84. }
  85. // it had better be our device!
  86. if (!RtlEqualUnicodeString(pBindDeviceName, &OurDeviceName, TRUE))
  87. {
  88. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  89. ("AfpTdiPnpHandler: not our tranport: on %ws ignored\n",
  90. pBindDeviceName->Buffer));
  91. ASSERT(0);
  92. return;
  93. }
  94. ReCfgRoutine = (WORKER)AfpPnPReconfigDisable;
  95. break;
  96. default:
  97. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  98. ("AfpTdiPnpHandler: ignoring PnPOpcode %d on %ws\n",
  99. PnPOpcode,(pBindDeviceName)?pBindDeviceName->Buffer:L"Null Ptr"));
  100. return;
  101. }
  102. KeInitializeEvent(&ReCfgEvent,NotificationEvent, False);
  103. // file handle operation needs system context: use worker thread
  104. AfpInitializeWorkItem(&ReCfgWorkItem,
  105. ReCfgRoutine,
  106. &ReCfgEvent);
  107. AfpQueueWorkItem(&ReCfgWorkItem);
  108. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_INFO,
  109. ("AfpTdiPnpHandler: put request on Queue, waiting for ReConfigure to complete\n"));
  110. KeWaitForSingleObject(&ReCfgEvent,
  111. UserRequest,
  112. KernelMode,
  113. False,
  114. NULL);
  115. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_INFO,
  116. ("AfpTdiPnpHandler: Reconfigure completed, returning....\n"));
  117. }
  118. /*** AfpPnPReconfigDisable
  119. *
  120. * When the stack gets a PnPReconfigure event, we get notified too. We first
  121. * get the TDI_PNP_OP_DEL msg. What we need to do here is close all the
  122. * sessions and close the handle.
  123. */
  124. VOID FASTCALL
  125. AfpPnPReconfigDisable(
  126. IN PVOID Context
  127. )
  128. {
  129. PKEVENT pReCfgEvent;
  130. pReCfgEvent = (PKEVENT)Context;
  131. // Deregister our name from the network
  132. // Since the stack is going away, explicitly set the flag to FALSE
  133. // There may be timing issues here, where stack may go away
  134. // before SpRegisterName is issued.
  135. // Flagging explicitly avoids re-registration problems during PnPEnable
  136. AfpSpRegisterName(&AfpServerName, False);
  137. afpSpNameRegistered = FALSE;
  138. // Disable listens on ASP
  139. AfpSpDisableListensOnAsp();
  140. // now go and kill all the appletalk sessions
  141. AfpKillSessionsOverProtocol(TRUE);
  142. AfpSpCloseAddress();
  143. // wake up the blocked pnp thread
  144. KeSetEvent(pReCfgEvent, IO_NETWORK_INCREMENT, False);
  145. }
  146. /*** AfpPnPReconfigEnable
  147. *
  148. * When the stack gets a PnPReconfigure event, we get notified too. We
  149. * get the TDI_PNP_OP_ADD msg. What we need to do here is open our handle to
  150. * the stack, register names etc.
  151. */
  152. VOID FASTCALL
  153. AfpPnPReconfigEnable(
  154. IN PVOID Context
  155. )
  156. {
  157. NTSTATUS Status=STATUS_SUCCESS;
  158. PKEVENT pReCfgEvent;
  159. ULONG OldServerState;
  160. pReCfgEvent = (PKEVENT)Context;
  161. if (afpSpAddressHandle == NULL)
  162. {
  163. Status = AfpSpOpenAddress();
  164. if (!NT_SUCCESS(Status))
  165. {
  166. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  167. ("AfpTdi..: AfpSpOpenAddress failed with status=%lx\n",Status));
  168. goto AfpPnPReconfigEnable_Exit;
  169. }
  170. }
  171. else
  172. {
  173. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  174. ("AfpPnPReconfigEnable: afp handle is already open!\n"));
  175. ASSERT(0);
  176. goto AfpPnPReconfigEnable_Exit;
  177. }
  178. if ((AfpServerState == AFP_STATE_START_PENDING) ||
  179. (AfpServerState == AFP_STATE_RUNNING))
  180. {
  181. // Det the server status block
  182. Status = AfpSetServerStatus();
  183. if (!NT_SUCCESS(Status))
  184. {
  185. AFPLOG_ERROR(AFPSRVMSG_SET_STATUS, Status, NULL, 0, NULL);
  186. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  187. ("AfpTdi..: AfpSetServerStatus failed with %lx\n",Status));
  188. goto AfpPnPReconfigEnable_Exit;
  189. }
  190. // Register our name on this address
  191. Status = AfpSpRegisterName(&AfpServerName, True);
  192. if (!NT_SUCCESS(Status))
  193. {
  194. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  195. ("AfpTdi...: AfpSpRegisterName failed with %lx\n",Status));
  196. goto AfpPnPReconfigEnable_Exit;
  197. }
  198. // Enable listens now that we are ready for it.
  199. AfpSpEnableListens();
  200. }
  201. AfpPnPReconfigEnable_Exit:
  202. if (!NT_SUCCESS(Status))
  203. {
  204. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  205. ("AfpTdi...: Closing Asp because of failure %lx\n",Status));
  206. AfpSpCloseAddress();
  207. }
  208. else
  209. {
  210. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  211. ("AFP/Appletalk bound and ready\n"));
  212. }
  213. // wake up the blocked pnp thread
  214. KeSetEvent(pReCfgEvent, IO_NETWORK_INCREMENT, False);
  215. }
  216. /*** AfpTdiRegister
  217. *
  218. * Register our handler with tdi
  219. */
  220. NTSTATUS
  221. AfpTdiRegister(
  222. IN VOID
  223. )
  224. {
  225. NTSTATUS Status;
  226. UNICODE_STRING ClientName;
  227. TDI_CLIENT_INTERFACE_INFO ClientInterfaceInfo;
  228. RtlInitUnicodeString(&ClientName,L"MacSrv");
  229. ClientInterfaceInfo.MajorTdiVersion = 2;
  230. ClientInterfaceInfo.MinorTdiVersion = 0;
  231. ClientInterfaceInfo.Unused = 0;
  232. ClientInterfaceInfo.ClientName = &ClientName;
  233. ClientInterfaceInfo.BindingHandler = AfpTdiPnpHandler;
  234. ClientInterfaceInfo.AddAddressHandlerV2 = DsiIpAddressCameIn;
  235. ClientInterfaceInfo.DelAddressHandlerV2 = DsiIpAddressWentAway;
  236. ClientInterfaceInfo.PnPPowerHandler = NULL;
  237. Status = TdiRegisterPnPHandlers (
  238. &ClientInterfaceInfo,
  239. sizeof(ClientInterfaceInfo),
  240. &AfpTdiNotificationHandle );
  241. if (!NT_SUCCESS(Status))
  242. {
  243. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  244. ("AfpTdiRegister: TdiRegisterPnPHandlers failed (%lx)\n",Status));
  245. }
  246. return(Status);
  247. }
  248. /*** AfpSpOpenAddress
  249. *
  250. * Create an address for the stack. This is called only once at initialization.
  251. * Create a handle to the address and map it to the associated file object.
  252. *
  253. * At this time, we do not know our server name. This is known only when the
  254. * service calls us.
  255. */
  256. AFPSTATUS
  257. AfpSpOpenAddress(
  258. VOID
  259. )
  260. {
  261. NTSTATUS Status;
  262. NTSTATUS Status2;
  263. BYTE EaBuffer[sizeof(FILE_FULL_EA_INFORMATION) +
  264. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  265. sizeof(TA_APPLETALK_ADDRESS)];
  266. PFILE_FULL_EA_INFORMATION pEaBuf = (PFILE_FULL_EA_INFORMATION)EaBuffer;
  267. TA_APPLETALK_ADDRESS Ta;
  268. OBJECT_ATTRIBUTES ObjAttr;
  269. UNICODE_STRING DeviceName;
  270. IO_STATUS_BLOCK IoStsBlk;
  271. PASP_BIND_ACTION pBind = NULL;
  272. KEVENT Event;
  273. PIRP pIrp = NULL;
  274. PMDL pMdl = NULL;
  275. PAGED_CODE( );
  276. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_INFO,
  277. ("AfpSpOpenAddress: Creating an address object\n"));
  278. RtlInitUnicodeString(&DeviceName, ATALKASPS_DEVICENAME);
  279. InitializeObjectAttributes(&ObjAttr, &DeviceName, 0, NULL, NULL);
  280. // Initialize the EA Buffer
  281. pEaBuf->NextEntryOffset = 0;
  282. pEaBuf->Flags = 0;
  283. pEaBuf->EaValueLength = sizeof(TA_APPLETALK_ADDRESS);
  284. pEaBuf->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  285. RtlCopyMemory(pEaBuf->EaName, TdiTransportAddress,
  286. TDI_TRANSPORT_ADDRESS_LENGTH + 1);
  287. Ta.TAAddressCount = 1;
  288. Ta.Address[0].AddressType = TDI_ADDRESS_TYPE_APPLETALK;
  289. Ta.Address[0].AddressLength = sizeof(TDI_ADDRESS_APPLETALK);
  290. Ta.Address[0].Address[0].Socket = 0;
  291. // Ta.Address[0].Address[0].Network = 0;
  292. // Ta.Address[0].Address[0].Node = 0;
  293. RtlCopyMemory(&pEaBuf->EaName[TDI_TRANSPORT_ADDRESS_LENGTH + 1], &Ta, sizeof(Ta));
  294. do
  295. {
  296. // Create the address object.
  297. Status = NtCreateFile(
  298. &afpSpAddressHandle,
  299. 0, // Don't Care
  300. &ObjAttr,
  301. &IoStsBlk,
  302. NULL, // Don't Care
  303. 0, // Don't Care
  304. 0, // Don't Care
  305. 0, // Don't Care
  306. FILE_GENERIC_READ + FILE_GENERIC_WRITE,
  307. &EaBuffer,
  308. sizeof(EaBuffer));
  309. if (!NT_SUCCESS(Status))
  310. {
  311. AFPLOG_DDERROR(AFPSRVMSG_CREATE_ATKADDR, Status, NULL, 0, NULL);
  312. break;
  313. }
  314. // Get the file object corres. to the address object.
  315. Status = ObReferenceObjectByHandle(
  316. afpSpAddressHandle,
  317. 0,
  318. NULL,
  319. KernelMode,
  320. (PVOID *)&afpSpAddressObject,
  321. NULL);
  322. ASSERT (NT_SUCCESS(Status));
  323. if (!NT_SUCCESS(Status))
  324. {
  325. if (afpSpAddressHandle != NULL)
  326. {
  327. ASSERT(VALID_FSH((PFILESYSHANDLE)&afpSpAddressHandle)) ;
  328. Status2 = NtClose(afpSpAddressHandle);
  329. afpSpAddressHandle = NULL;
  330. ASSERT(NT_SUCCESS(Status2));
  331. }
  332. AFPLOG_DDERROR(AFPSRVMSG_CREATE_ATKADDR, Status, NULL, 0, NULL);
  333. break;
  334. }
  335. // Now get the device object to the appletalk stack
  336. afpSpAppleTalkDeviceObject = IoGetRelatedDeviceObject(afpSpAddressObject);
  337. ASSERT (afpSpAppleTalkDeviceObject != NULL);
  338. // Now 'bind' to the ASP layer of the stack. Basically exchange the entry points
  339. // Allocate an Irp and an Mdl to describe the bind request
  340. KeInitializeEvent(&Event, NotificationEvent, False);
  341. if (((pBind = (PASP_BIND_ACTION)AfpAllocNonPagedMemory(
  342. sizeof(ASP_BIND_ACTION))) == NULL) ||
  343. ((pIrp = AfpAllocIrp(1)) == NULL) ||
  344. ((pMdl = AfpAllocMdl(pBind, sizeof(ASP_BIND_ACTION), pIrp)) == NULL))
  345. {
  346. Status = STATUS_INSUFFICIENT_RESOURCES;
  347. break;
  348. }
  349. afpInitializeActionHdr(pBind, ACTION_ASP_BIND);
  350. // Initialize the client part of the bind request
  351. pBind->Params.ClientEntries.clt_SessionNotify = AfpSdaCreateNewSession;
  352. pBind->Params.ClientEntries.clt_RequestNotify = afpSpHandleRequest;
  353. pBind->Params.ClientEntries.clt_GetWriteBuffer = AfpGetWriteBuffer;
  354. pBind->Params.ClientEntries.clt_ReplyCompletion = afpSpReplyComplete;
  355. pBind->Params.ClientEntries.clt_AttnCompletion = afpSpAttentionComplete;
  356. pBind->Params.ClientEntries.clt_CloseCompletion = afpSpCloseComplete;
  357. pBind->Params.pXportEntries = &AfpAspEntries;
  358. TdiBuildAction( pIrp,
  359. AfpDeviceObject,
  360. afpSpAddressObject,
  361. (PIO_COMPLETION_ROUTINE)afpSpGenericComplete,
  362. &Event,
  363. pMdl);
  364. IoCallDriver(afpSpAppleTalkDeviceObject, pIrp);
  365. // Assert this. We cannot block at DISPATCH_LEVEL
  366. ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
  367. AfpIoWait(&Event, NULL);
  368. } while (False);
  369. // Free the allocated resources
  370. if (pIrp != NULL)
  371. AfpFreeIrp(pIrp);
  372. if (pMdl != NULL)
  373. AfpFreeMdl(pMdl);
  374. if (pBind != NULL)
  375. AfpFreeMemory(pBind);
  376. if (NT_SUCCESS(Status))
  377. {
  378. AfpServerBoundToAsp = TRUE;
  379. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  380. ("AfpSpOpenAddress: net addr (net.node.socket) on def adapter = %x.%x.%x\n",
  381. AfpAspEntries.asp_AtalkAddr.Network,AfpAspEntries.asp_AtalkAddr.Node,AfpAspEntries.asp_AtalkAddr.Socket));
  382. }
  383. return Status;
  384. }
  385. /*** AfpSpCloseAddress
  386. *
  387. * Close the socket address. This is called only once at driver unload.
  388. */
  389. VOID
  390. AfpSpCloseAddress(
  391. VOID
  392. )
  393. {
  394. NTSTATUS Status;
  395. PAGED_CODE( );
  396. if (afpSpAddressHandle != NULL)
  397. {
  398. ObDereferenceObject(afpSpAddressObject);
  399. Status = NtClose(afpSpAddressHandle);
  400. afpSpAddressHandle = NULL;
  401. ASSERT(NT_SUCCESS(Status));
  402. }
  403. AfpServerBoundToAsp = FALSE;
  404. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  405. ("AfpSpCloseAddress: closed Afp handle (%lx)\n",Status));
  406. }
  407. /*** AfpSpRegisterName
  408. *
  409. * Call Nbp[De]Register to (de)register our name on the address that we
  410. * already opened. This is called at server start/pause/continue. The server
  411. * name is already validated and known to not contain any invalid characters.
  412. * This call is synchronous to the caller, i.e. we wait for operation to
  413. * complete and return an appropriate error.
  414. */
  415. AFPSTATUS
  416. AfpSpRegisterName(
  417. IN PANSI_STRING ServerName,
  418. IN BOOLEAN Register
  419. )
  420. {
  421. KEVENT Event;
  422. PNBP_REGDEREG_ACTION pNbp = NULL;
  423. PIRP pIrp = NULL;
  424. PMDL pMdl = NULL;
  425. AFPSTATUS Status = AFP_ERR_NONE;
  426. USHORT ActionCode;
  427. PAGED_CODE( );
  428. ASSERT(afpSpAddressHandle != NULL && afpSpAddressObject != NULL);
  429. if (Register ^ afpSpNameRegistered)
  430. {
  431. ASSERT(ServerName->Buffer != NULL);
  432. do
  433. {
  434. if (((pNbp = (PNBP_REGDEREG_ACTION)
  435. AfpAllocNonPagedMemory(sizeof(NBP_REGDEREG_ACTION))) == NULL) ||
  436. ((pIrp = AfpAllocIrp(1)) == NULL) ||
  437. ((pMdl = AfpAllocMdl(pNbp, sizeof(NBP_REGDEREG_ACTION), pIrp)) == NULL))
  438. {
  439. Status = STATUS_INSUFFICIENT_RESOURCES;
  440. break;
  441. }
  442. // Initialize the Action header and NBP Name. Note that the ServerName
  443. // is also NULL terminated apart from being a counted string.
  444. ActionCode = Register ?
  445. COMMON_ACTION_NBPREGISTER : COMMON_ACTION_NBPREMOVE;
  446. afpInitializeActionHdr(pNbp, ActionCode);
  447. pNbp->Params.RegisterTuple.NbpName.ObjectNameLen =
  448. (BYTE)(ServerName->Length);
  449. RtlCopyMemory(
  450. pNbp->Params.RegisterTuple.NbpName.ObjectName,
  451. ServerName->Buffer,
  452. ServerName->Length);
  453. pNbp->Params.RegisterTuple.NbpName.TypeNameLen =
  454. sizeof(AFP_SERVER_TYPE)-1;
  455. RtlCopyMemory(
  456. pNbp->Params.RegisterTuple.NbpName.TypeName,
  457. AFP_SERVER_TYPE,
  458. sizeof(AFP_SERVER_TYPE));
  459. pNbp->Params.RegisterTuple.NbpName.ZoneNameLen =
  460. sizeof(AFP_SERVER_ZONE)-1;
  461. RtlCopyMemory(
  462. pNbp->Params.RegisterTuple.NbpName.ZoneName,
  463. AFP_SERVER_ZONE,
  464. sizeof(AFP_SERVER_ZONE));
  465. KeInitializeEvent(&Event, NotificationEvent, False);
  466. // Build the Irp
  467. TdiBuildAction( pIrp,
  468. AfpDeviceObject,
  469. afpSpAddressObject,
  470. (PIO_COMPLETION_ROUTINE)afpSpGenericComplete,
  471. &Event,
  472. pMdl);
  473. IoCallDriver(afpSpAppleTalkDeviceObject, pIrp);
  474. // Assert this. We cannot block at DISPATCH_LEVEL
  475. ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
  476. // Wait for completion.
  477. AfpIoWait(&Event, NULL);
  478. Status = pIrp->IoStatus.Status;
  479. } while (False);
  480. if (NT_SUCCESS(Status))
  481. {
  482. afpSpNameRegistered = Register;
  483. }
  484. else
  485. {
  486. AFPLOG_ERROR(AFPSRVMSG_REGISTER_NAME, Status, NULL, 0, NULL);
  487. }
  488. if (pNbp != NULL)
  489. AfpFreeMemory(pNbp);
  490. if (pIrp != NULL)
  491. AfpFreeIrp(pIrp);
  492. if (pMdl != NULL)
  493. AfpFreeMdl(pMdl);
  494. }
  495. return Status;
  496. }
  497. /*** AfpSpReplyClient
  498. *
  499. * This is a wrapper over AspReply.
  500. * The SDA is set up to accept another request when the reply completes.
  501. * The sda_ReplyBuf is also freed up then.
  502. */
  503. VOID FASTCALL
  504. AfpSpReplyClient(
  505. IN PREQUEST pRequest,
  506. IN LONG ReplyCode,
  507. IN PASP_XPORT_ENTRIES XportTable
  508. )
  509. {
  510. LONG Response;
  511. // Update count of outstanding replies
  512. INTERLOCKED_INCREMENT_LONG((PLONG)&afpSpNumOutstandingReplies);
  513. // Convert reply code to on-the-wire format
  514. PUTDWORD2DWORD(&Response, ReplyCode);
  515. (*(XportTable->asp_Reply))(pRequest,(PUCHAR)&Response);
  516. }
  517. /*** AfpSpSendAttention
  518. *
  519. * Send a server attention to the client
  520. */
  521. VOID FASTCALL
  522. AfpSpSendAttention(
  523. IN PSDA pSda,
  524. IN USHORT AttnCode,
  525. IN BOOLEAN Synchronous
  526. )
  527. {
  528. KEVENT Event;
  529. NTSTATUS Status;
  530. if (Synchronous)
  531. {
  532. ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
  533. KeInitializeEvent(&Event, NotificationEvent, False);
  534. }
  535. Status = (*(pSda->sda_XportTable->asp_SendAttention))((pSda)->sda_SessHandle,
  536. AttnCode,
  537. Synchronous ? &Event : NULL);
  538. if (NT_SUCCESS(Status) && Synchronous)
  539. {
  540. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  541. AfpIoWait(&Event, NULL);
  542. }
  543. }
  544. /*** AfpAllocReplyBuf
  545. *
  546. * Allocate a reply buffer from non-paged memory. Initialize sda_ReplyBuf
  547. * with the pointer. If the reply buffer is small enough, use it out of the
  548. * sda itself.
  549. */
  550. AFPSTATUS FASTCALL
  551. AfpAllocReplyBuf(
  552. IN PSDA pSda
  553. )
  554. {
  555. KIRQL OldIrql;
  556. PBYTE pStartOfBuffer;
  557. DWORD Offset;
  558. USHORT ReplySize;
  559. ASSERT ((SHORT)(pSda->sda_ReplySize) >= 0);
  560. ACQUIRE_SPIN_LOCK(&pSda->sda_Lock, &OldIrql);
  561. ReplySize = pSda->sda_ReplySize;
  562. Offset = 0;
  563. //
  564. // for a TCP connection, alloc space for the DSI header
  565. //
  566. if (pSda->sda_Flags & SDA_SESSION_OVER_TCP)
  567. {
  568. ReplySize += DSI_HEADER_SIZE;
  569. Offset = DSI_HEADER_SIZE;
  570. }
  571. if (((pSda->sda_Flags & SDA_NAMEXSPACE_IN_USE) == 0) &&
  572. (ReplySize <= pSda->sda_SizeNameXSpace))
  573. {
  574. pStartOfBuffer = pSda->sda_NameXSpace;
  575. pSda->sda_Flags |= SDA_NAMEXSPACE_IN_USE;
  576. }
  577. else
  578. {
  579. pStartOfBuffer = AfpAllocNonPagedMemory(ReplySize);
  580. }
  581. if (pStartOfBuffer != NULL)
  582. {
  583. pSda->sda_ReplyBuf = (pStartOfBuffer + Offset);
  584. }
  585. else
  586. {
  587. pSda->sda_ReplySize = 0;
  588. pSda->sda_ReplyBuf = NULL;
  589. }
  590. #if DBG
  591. if (pStartOfBuffer != NULL)
  592. {
  593. *(DWORD *)pStartOfBuffer = 0x081294;
  594. }
  595. #endif
  596. RELEASE_SPIN_LOCK(&pSda->sda_Lock, OldIrql);
  597. return ((pSda->sda_ReplyBuf == NULL) ? AFP_ERR_MISC : AFP_ERR_NONE);
  598. }
  599. /*** AfpSpCloseSession
  600. *
  601. * Shutdown an existing session
  602. */
  603. NTSTATUS FASTCALL
  604. AfpSpCloseSession(
  605. IN PSDA pSda
  606. )
  607. {
  608. PASP_XPORT_ENTRIES XportTable;
  609. XportTable = pSda->sda_XportTable;
  610. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_INFO,
  611. ("AfpSpCloseSession: Closing session %lx\n", pSda->sda_SessHandle));
  612. (*(XportTable->asp_CloseConn))(pSda->sda_SessHandle);
  613. return STATUS_PENDING;
  614. }
  615. /*** afpSpHandleRequest
  616. *
  617. * Handle an incoming request.
  618. *
  619. * LOCKS: afpSpDeferralQLock (SPIN)
  620. */
  621. NTSTATUS FASTCALL
  622. afpSpHandleRequest(
  623. IN NTSTATUS Status,
  624. IN PSDA pSda,
  625. IN PREQUEST pRequest
  626. )
  627. {
  628. NTSTATUS RetStatus=STATUS_SUCCESS;
  629. PBYTE pWriteBuf;
  630. PDELAYEDALLOC pDelAlloc;
  631. ASSERT(VALID_SDA(pSda));
  632. // Get the status code and determine what happened.
  633. if (NT_SUCCESS(Status))
  634. {
  635. ASSERT(VALID_SDA(pSda));
  636. ASSERT(pSda->sda_RefCount != 0);
  637. ASSERT(pSda->sda_SessionId != 0);
  638. ACQUIRE_SPIN_LOCK_AT_DPC(&pSda->sda_Lock);
  639. if (pSda->sda_Flags & (SDA_CLOSING | SDA_SESSION_CLOSED | SDA_CLIENT_CLOSE))
  640. {
  641. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  642. ("afpSpHandleRequest: got request on a closing connection!\n"));
  643. RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock);
  644. // If this was a write request and we have allocated a write Mdl, free that
  645. if (pRequest->rq_WriteMdl != NULL)
  646. {
  647. //
  648. // did we get this Mdl from cache mgr? if so, treat it separately
  649. //
  650. if ((pDelAlloc = pRequest->rq_CacheMgrContext) != NULL)
  651. {
  652. pDelAlloc->Flags |= AFP_CACHEMDL_DEADSESSION;
  653. ASSERT(pRequest->rq_WriteMdl == pDelAlloc->pMdl);
  654. ASSERT(!(pDelAlloc->Flags & AFP_CACHEMDL_ALLOC_ERROR));
  655. pRequest->rq_CacheMgrContext = NULL;
  656. AfpReturnWriteMdlToCM(pDelAlloc);
  657. }
  658. else
  659. {
  660. pWriteBuf = MmGetSystemAddressForMdlSafe(
  661. pRequest->rq_WriteMdl,
  662. NormalPagePriority);
  663. if (pWriteBuf != NULL)
  664. {
  665. AfpIOFreeBuffer(pWriteBuf);
  666. }
  667. AfpFreeMdl(pRequest->rq_WriteMdl);
  668. }
  669. pRequest->rq_WriteMdl = NULL;
  670. }
  671. return(STATUS_LOCAL_DISCONNECT);
  672. }
  673. pSda->sda_RefCount ++;
  674. //
  675. // should we queue this request up?
  676. //
  677. if ((pSda->sda_Flags & SDA_REQUEST_IN_PROCESS) ||
  678. (!IsListEmpty(&pSda->sda_DeferredQueue)))
  679. {
  680. afpQueueDeferredRequest(pSda, pRequest);
  681. RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock);
  682. }
  683. //
  684. // nope, let's do it now!
  685. //
  686. else
  687. {
  688. pSda->sda_Request = pRequest;
  689. pSda->sda_Flags |= SDA_REQUEST_IN_PROCESS;
  690. ASSERT ((pSda->sda_ReplyBuf == NULL) &&
  691. (pSda->sda_ReplySize == 0));
  692. RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock);
  693. // Call AfpUnmarshallReq now. It will do the needful.
  694. AfpUnmarshallReq(pSda);
  695. }
  696. }
  697. else
  698. {
  699. KIRQL OldIrql;
  700. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  701. ("afpSpHandleRequest: Error %lx\n", Status));
  702. // if we nuked this session from the session maintenance timer the
  703. // status will be STATUS_LOCAL_DISCONNECT else STATUS_REMOTE_DISCONNECT
  704. // in the former case, log an error.
  705. if (Status == STATUS_LOCAL_DISCONNECT)
  706. {
  707. // The appletalk address of the client is encoded in the length
  708. if (pSda->sda_ClientType == SDA_CLIENT_GUEST)
  709. {
  710. if (pSda->sda_Flags & SDA_SESSION_OVER_TCP) {
  711. AFPLOG_DDERROR(AFPSRVMSG_DISCONNECT_GUEST_TCPIP,
  712. Status,
  713. &pRequest->rq_RequestSize,
  714. sizeof(LONG),
  715. NULL);
  716. } else {
  717. AFPLOG_DDERROR(AFPSRVMSG_DISCONNECT_GUEST,
  718. Status,
  719. &pRequest->rq_RequestSize,
  720. sizeof(LONG),
  721. NULL);
  722. }
  723. }
  724. else
  725. {
  726. if (pSda->sda_Flags & SDA_SESSION_OVER_TCP) {
  727. AFPLOG_DDERROR(AFPSRVMSG_DISCONNECT_TCPIP,
  728. Status,
  729. &pRequest->rq_RequestSize,
  730. sizeof(LONG),
  731. &pSda->sda_UserName);
  732. } else {
  733. AFPLOG_DDERROR(AFPSRVMSG_DISCONNECT,
  734. Status,
  735. &pRequest->rq_RequestSize,
  736. sizeof(LONG),
  737. &pSda->sda_UserName);
  738. }
  739. }
  740. }
  741. // Close down this session, but only if it isn't already closing
  742. // Its important to do this ahead of posting any new sessions since
  743. // we must take into account the ACTUAL number of sessions there are
  744. ACQUIRE_SPIN_LOCK(&pSda->sda_Lock, &OldIrql);
  745. pSda->sda_Flags |= SDA_CLIENT_CLOSE;
  746. if ((pSda->sda_Flags & SDA_SESSION_CLOSED) == 0)
  747. {
  748. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_INFO,
  749. ("afpSpHandleRequest: Closing session handle\n"));
  750. pSda->sda_Flags |= SDA_SESSION_CLOSED;
  751. RELEASE_SPIN_LOCK(&pSda->sda_Lock, OldIrql);
  752. AfpSpCloseSession(pSda);
  753. }
  754. else
  755. {
  756. RELEASE_SPIN_LOCK(&pSda->sda_Lock, OldIrql);
  757. }
  758. // If this was a write request and we have allocated a write Mdl, free that
  759. if (pRequest->rq_WriteMdl != NULL)
  760. {
  761. //
  762. // did we get this Mdl from cache mgr? if so, treat it separately
  763. //
  764. if ((pDelAlloc = pRequest->rq_CacheMgrContext) != NULL)
  765. {
  766. pDelAlloc->Flags |= AFP_CACHEMDL_DEADSESSION;
  767. ASSERT(pRequest->rq_WriteMdl == pDelAlloc->pMdl);
  768. ASSERT(!(pDelAlloc->Flags & AFP_CACHEMDL_ALLOC_ERROR));
  769. pRequest->rq_CacheMgrContext = NULL;
  770. AfpReturnWriteMdlToCM(pDelAlloc);
  771. }
  772. else
  773. {
  774. pWriteBuf = MmGetSystemAddressForMdlSafe(
  775. pRequest->rq_WriteMdl,
  776. NormalPagePriority);
  777. if (pWriteBuf != NULL)
  778. {
  779. AfpIOFreeBuffer(pWriteBuf);
  780. }
  781. AfpFreeMdl(pRequest->rq_WriteMdl);
  782. }
  783. pRequest->rq_WriteMdl = NULL;
  784. }
  785. }
  786. return(RetStatus);
  787. }
  788. /*** afpSpGenericComplete
  789. *
  790. * Generic completion for an asynchronous request to the appletalk stack.
  791. * Just clear the event and we are done.
  792. */
  793. LOCAL NTSTATUS
  794. afpSpGenericComplete(
  795. IN PDEVICE_OBJECT pDeviceObject,
  796. IN PIRP pIrp,
  797. IN PKEVENT pCmplEvent
  798. )
  799. {
  800. KeSetEvent(pCmplEvent, IO_NETWORK_INCREMENT, False);
  801. // Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
  802. // will stop working on the IRP.
  803. return STATUS_MORE_PROCESSING_REQUIRED;
  804. }
  805. /*** afpSpReplyComplete
  806. *
  807. * This is the completion routine for AfpSpReplyClient(). The reply buffer is freed
  808. * up and the Sda dereferenced.
  809. */
  810. VOID FASTCALL
  811. afpSpReplyComplete(
  812. IN NTSTATUS Status,
  813. IN PSDA pSda,
  814. IN PREQUEST pRequest
  815. )
  816. {
  817. KIRQL OldIrql;
  818. DWORD Flags = SDA_REPLY_IN_PROCESS;
  819. PMDL pMdl;
  820. PDELAYEDALLOC pDelAlloc;
  821. ASSERT(VALID_SDA(pSda));
  822. // Update the afpSpNumOutstandingReplies
  823. ASSERT (afpSpNumOutstandingReplies != 0);
  824. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_INFO,
  825. ("afpSpReplyComplete: %ld\n", Status));
  826. INTERLOCKED_DECREMENT_LONG((PLONG)&afpSpNumOutstandingReplies);
  827. pMdl = pRequest->rq_ReplyMdl;
  828. if ((pDelAlloc = pRequest->rq_CacheMgrContext) != NULL)
  829. {
  830. pRequest->rq_CacheMgrContext = NULL;
  831. ASSERT((pMdl != NULL) && (pMdl == pDelAlloc->pMdl));
  832. AfpReturnReadMdlToCM(pDelAlloc);
  833. }
  834. else
  835. {
  836. if (pMdl != NULL)
  837. {
  838. PBYTE pReplyBuf;
  839. pReplyBuf = MmGetSystemAddressForMdlSafe(
  840. pMdl,
  841. NormalPagePriority);
  842. ASSERT (pReplyBuf != NULL);
  843. if ((pReplyBuf != pSda->sda_NameXSpace) &&
  844. (pReplyBuf != NULL))
  845. {
  846. AfpFreeMemory(pReplyBuf);
  847. }
  848. else
  849. {
  850. Flags |= SDA_NAMEXSPACE_IN_USE;
  851. }
  852. AfpFreeMdl(pMdl);
  853. }
  854. }
  855. ACQUIRE_SPIN_LOCK(&pSda->sda_Lock, &OldIrql);
  856. pSda->sda_Flags &= ~Flags;
  857. RELEASE_SPIN_LOCK(&pSda->sda_Lock, OldIrql);
  858. AfpSdaDereferenceSession(pSda);
  859. }
  860. /*** afpSpAttentionComplete
  861. *
  862. * Completion routine for AfpSpSendAttention. Just signal the event and unblock caller.
  863. */
  864. VOID FASTCALL
  865. afpSpAttentionComplete(
  866. IN PVOID pEvent
  867. )
  868. {
  869. if (pEvent != NULL)
  870. KeSetEvent((PKEVENT)pEvent, IO_NETWORK_INCREMENT, False);
  871. }
  872. /*** afpSpCloseComplete
  873. *
  874. * Completion routine for AfpSpCloseSession. Remove the creation reference
  875. * from the sda.
  876. */
  877. VOID FASTCALL
  878. afpSpCloseComplete(
  879. IN NTSTATUS Status,
  880. IN PSDA pSda
  881. )
  882. {
  883. AfpInterlockedSetDword(&pSda->sda_Flags,
  884. SDA_SESSION_CLOSE_COMP,
  885. &pSda->sda_Lock);
  886. AfpScavengerScheduleEvent(AfpSdaCloseSession,
  887. pSda,
  888. 0,
  889. True);
  890. }