Leaked source code of windows server 2003
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.

686 lines
18 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. spxbind.c
  5. Abstract:
  6. This module contains the code to bind to the IPX transport, as well as the
  7. indication routines for the IPX transport not including the send/recv ones.
  8. Author:
  9. Stefan Solomon (stefans) Original Version
  10. Nikhil Kamkolkar (nikhilk) 11-November-1993
  11. Environment:
  12. Kernel mode
  13. Revision History:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. // Define module number for event logging entries
  18. #define FILENUM SPXBIND
  19. extern IPX_INTERNAL_PNP_COMPLETE IpxPnPComplete;
  20. VOID
  21. SpxStatus (
  22. IN USHORT NicId,
  23. IN NDIS_STATUS GeneralStatus,
  24. IN PVOID StatusBuffer,
  25. IN UINT StatusBufferLength);
  26. VOID
  27. SpxFindRouteComplete (
  28. IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
  29. IN BOOLEAN FoundRoute);
  30. VOID
  31. SpxScheduleRoute (
  32. IN PIPX_ROUTE_ENTRY RouteEntry);
  33. VOID
  34. SpxLineDown (
  35. IN USHORT NicId,
  36. IN ULONG_PTR FwdAdapterContext);
  37. VOID
  38. SpxLineUp (
  39. IN USHORT NicId,
  40. IN PIPX_LINE_INFO LineInfo,
  41. IN NDIS_MEDIUM DeviceType,
  42. IN PVOID ConfigurationData);
  43. VOID
  44. SpxFindRouteComplete (
  45. IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
  46. IN BOOLEAN FoundRoute);
  47. #if defined(_PNP_POWER)
  48. NTSTATUS
  49. SpxPnPNotification(
  50. IN IPX_PNP_OPCODE OpCode,
  51. IN PVOID PnPData
  52. );
  53. #endif _PNP_POWER
  54. VOID
  55. SpxPnPCompletionHandler(
  56. PNET_PNP_EVENT netevent,
  57. NTSTATUS status
  58. );
  59. #if defined(_PNP_POWER)
  60. //
  61. // globals and externs
  62. //
  63. extern CTELock spxTimerLock;
  64. extern LARGE_INTEGER spxTimerTick;
  65. extern KTIMER spxTimer;
  66. extern KDPC spxTimerDpc;
  67. extern BOOLEAN spxTimerStopped;
  68. #endif _PNP_POWER
  69. NTSTATUS
  70. SpxInitBindToIpx(
  71. VOID
  72. )
  73. {
  74. NTSTATUS status;
  75. IO_STATUS_BLOCK ioStatusBlock;
  76. OBJECT_ATTRIBUTES objectAttr;
  77. PIPX_INTERNAL_BIND_INPUT pBindInput;
  78. PIPX_INTERNAL_BIND_OUTPUT pBindOutput;
  79. InitializeObjectAttributes(
  80. &objectAttr,
  81. &IpxDeviceName,
  82. OBJ_CASE_INSENSITIVE,
  83. NULL,
  84. NULL);
  85. status = NtCreateFile(
  86. &IpxHandle,
  87. SYNCHRONIZE | GENERIC_READ,
  88. &objectAttr,
  89. &ioStatusBlock,
  90. NULL,
  91. FILE_ATTRIBUTE_NORMAL,
  92. FILE_SHARE_READ | FILE_SHARE_WRITE,
  93. FILE_OPEN,
  94. FILE_SYNCHRONOUS_IO_NONALERT,
  95. NULL,
  96. 0L);
  97. if (!NT_SUCCESS(status)) {
  98. return status;
  99. }
  100. if ((pBindInput = CTEAllocMem(sizeof(IPX_INTERNAL_BIND_INPUT))) == NULL) {
  101. NtClose(IpxHandle);
  102. return(STATUS_INSUFFICIENT_RESOURCES);
  103. }
  104. // Fill in our bind data
  105. #if defined(_PNP_POWER)
  106. pBindInput->Version = ISN_VERSION;
  107. #else
  108. pBindInput->Version = 1;
  109. #endif _PNP_POWER
  110. pBindInput->Identifier = IDENTIFIER_SPX;
  111. pBindInput->BroadcastEnable = FALSE;
  112. pBindInput->LookaheadRequired = IPX_HDRSIZE;
  113. pBindInput->ProtocolOptions = 0;
  114. pBindInput->ReceiveHandler = SpxReceive;
  115. pBindInput->ReceiveCompleteHandler = SpxReceiveComplete;
  116. pBindInput->StatusHandler = SpxStatus;
  117. pBindInput->SendCompleteHandler = SpxSendComplete;
  118. pBindInput->TransferDataCompleteHandler = SpxTransferDataComplete;
  119. pBindInput->FindRouteCompleteHandler = SpxFindRouteComplete;
  120. pBindInput->LineUpHandler = SpxLineUp;
  121. pBindInput->LineDownHandler = SpxLineDown;
  122. pBindInput->ScheduleRouteHandler = SpxScheduleRoute;
  123. #if defined(_PNP_POWER)
  124. pBindInput->PnPHandler = SpxPnPNotification;
  125. #endif _PNP_POWER
  126. // First get the length for the output buffer.
  127. status = NtDeviceIoControlFile(
  128. IpxHandle, // HANDLE to File
  129. NULL, // HANDLE to Event
  130. NULL, // ApcRoutine
  131. NULL, // ApcContext
  132. &ioStatusBlock, // IO_STATUS_BLOCK
  133. IOCTL_IPX_INTERNAL_BIND, // IoControlCode
  134. pBindInput, // Input Buffer
  135. sizeof(IPX_INTERNAL_BIND_INPUT), // Input Buffer Length
  136. NULL, // Output Buffer
  137. 0);
  138. if (status == STATUS_PENDING) {
  139. status = NtWaitForSingleObject(
  140. IpxHandle,
  141. (BOOLEAN)FALSE,
  142. NULL);
  143. }
  144. if (status != STATUS_BUFFER_TOO_SMALL) {
  145. CTEFreeMem(pBindInput);
  146. NtClose(IpxHandle);
  147. return(STATUS_INVALID_PARAMETER);
  148. }
  149. if ((pBindOutput = CTEAllocMem(ioStatusBlock.Information)) == NULL) {
  150. CTEFreeMem(pBindInput);
  151. NtClose(IpxHandle);
  152. return(STATUS_INSUFFICIENT_RESOURCES);
  153. }
  154. // ioStatusBlock.Information is of type ULONG_PTR and is used as
  155. // OutputBufferLength in NtDeviceIoControlFile.
  156. // The length should not exceed ulong or we have to wait until
  157. // NtDeviceIoControlFile changes to get rid of warning.
  158. status = NtDeviceIoControlFile(
  159. IpxHandle, // HANDLE to File
  160. NULL, // HANDLE to Event
  161. NULL, // ApcRoutine
  162. NULL, // ApcContext
  163. &ioStatusBlock, // IO_STATUS_BLOCK
  164. IOCTL_IPX_INTERNAL_BIND, // IoControlCode
  165. pBindInput, // Input Buffer
  166. sizeof(IPX_INTERNAL_BIND_INPUT), // Input Buffer Length
  167. pBindOutput, // Output Buffer
  168. (ULONG)(ioStatusBlock.Information));
  169. if (status == STATUS_PENDING) {
  170. status = NtWaitForSingleObject(
  171. IpxHandle,
  172. (BOOLEAN)FALSE,
  173. NULL);
  174. }
  175. if (status == STATUS_SUCCESS) {
  176. // Get all the info from the bind output buffer and save in
  177. // appropriate places.
  178. IpxLineInfo = pBindOutput->LineInfo;
  179. IpxMacHdrNeeded = pBindOutput->MacHeaderNeeded;
  180. IpxInclHdrOffset = pBindOutput->IncludedHeaderOffset;
  181. IpxSendPacket = pBindOutput->SendHandler;
  182. IpxFindRoute = pBindOutput->FindRouteHandler;
  183. IpxQuery = pBindOutput->QueryHandler;
  184. IpxTransferData = pBindOutput->TransferDataHandler;
  185. IpxPnPComplete = pBindOutput->PnPCompleteHandler;
  186. #if !defined(_PNP_POWER)
  187. // Copy over the network node info.
  188. RtlCopyMemory(
  189. SpxDevice->dev_Network,
  190. pBindOutput->Network,
  191. IPX_NET_LEN);
  192. RtlCopyMemory(
  193. SpxDevice->dev_Node,
  194. pBindOutput->Node,
  195. IPX_NODE_LEN);
  196. DBGPRINT(TDI, INFO,
  197. ("SpxInitBindToIpx: Ipx Net %lx\n",
  198. *(UNALIGNED ULONG *)SpxDevice->dev_Network));
  199. //
  200. // Find out how many adapters IPX has, if this fails
  201. // just assume one.
  202. //
  203. if ((*IpxQuery)(
  204. IPX_QUERY_MAXIMUM_NIC_ID,
  205. 0,
  206. &SpxDevice->dev_Adapters,
  207. sizeof(USHORT),
  208. NULL) != STATUS_SUCCESS) {
  209. SpxDevice->dev_Adapters = 1;
  210. }
  211. #endif !_PNP_POWER
  212. } else {
  213. NtClose(IpxHandle);
  214. status = STATUS_INVALID_PARAMETER;
  215. }
  216. CTEFreeMem(pBindInput);
  217. CTEFreeMem(pBindOutput);
  218. return status;
  219. }
  220. VOID
  221. SpxUnbindFromIpx(
  222. VOID
  223. )
  224. {
  225. NtClose(IpxHandle);
  226. return;
  227. }
  228. VOID
  229. SpxStatus(
  230. IN USHORT NicId,
  231. IN NDIS_STATUS GeneralStatus,
  232. IN PVOID StatusBuffer,
  233. IN UINT StatusBufferLength
  234. )
  235. {
  236. DBGPRINT(RECEIVE, ERR,
  237. ("SpxStatus: CALLED WITH %lx\n",
  238. GeneralStatus));
  239. return;
  240. }
  241. VOID
  242. SpxFindRouteComplete (
  243. IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
  244. IN BOOLEAN FoundRoute
  245. )
  246. {
  247. CTELockHandle lockHandle;
  248. PSPX_FIND_ROUTE_REQUEST pSpxFrReq = (PSPX_FIND_ROUTE_REQUEST)FindRouteRequest;
  249. PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)pSpxFrReq->fr_Ctx;
  250. // This will be on a connection. Grab the lock, check the state and go from
  251. // there.
  252. if (pSpxConnFile == NULL)
  253. {
  254. // Should this ever happen?
  255. KeBugCheck(0);
  256. return;
  257. }
  258. // Check the state. The called routines release the lock, remove the reference.
  259. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  260. if (SPX_CONN_CONNECTING(pSpxConnFile))
  261. {
  262. // We are doing an active connect!
  263. SpxConnConnectFindRouteComplete(
  264. pSpxConnFile,
  265. pSpxFrReq,
  266. FoundRoute,
  267. lockHandle);
  268. }
  269. else // For all others call active
  270. {
  271. SpxConnActiveFindRouteComplete(
  272. pSpxConnFile,
  273. pSpxFrReq,
  274. FoundRoute,
  275. lockHandle);
  276. }
  277. // Free the find route request.
  278. SpxFreeMemory(pSpxFrReq);
  279. return;
  280. }
  281. VOID
  282. SpxLineUp (
  283. IN USHORT NicId,
  284. IN PIPX_LINE_INFO LineInfo,
  285. IN NDIS_MEDIUM DeviceType,
  286. IN PVOID ConfigurationData
  287. )
  288. {
  289. // With PnP, our local address is changed when we get PnP
  290. // notification.
  291. #if !defined(_PNP_POWER)
  292. //
  293. // If we get a line up for NicId 0, it means our local
  294. // network number has changed, re-query from IPX.
  295. //
  296. if (NicId == 0) {
  297. TDI_ADDRESS_IPX IpxAddress;
  298. if ((*IpxQuery)(
  299. IPX_QUERY_IPX_ADDRESS,
  300. 0,
  301. &IpxAddress,
  302. sizeof(TDI_ADDRESS_IPX),
  303. NULL) == STATUS_SUCCESS) {
  304. RtlCopyMemory(
  305. SpxDevice->dev_Network,
  306. &IpxAddress.NetworkAddress,
  307. IPX_NET_LEN);
  308. DBGPRINT(TDI, INFO,
  309. ("SpxLineUp: Ipx Net %lx\n",
  310. *(UNALIGNED ULONG *)SpxDevice->dev_Network));
  311. //
  312. // The node shouldn't change!
  313. //
  314. if (!RtlEqualMemory(
  315. SpxDevice->dev_Node,
  316. IpxAddress.NodeAddress,
  317. IPX_NODE_LEN)) {
  318. DBGPRINT(TDI, ERR,
  319. ("SpxLineUp: Node address has changed\n"));
  320. }
  321. }
  322. } else {
  323. DBGPRINT(RECEIVE, ERR,
  324. ("SpxLineUp: CALLED WITH %lx\n",
  325. NicId));
  326. }
  327. return;
  328. #endif !_PNP_POWER
  329. }
  330. VOID
  331. SpxLineDown (
  332. IN USHORT NicId,
  333. IN ULONG_PTR FwdAdapterContext
  334. )
  335. {
  336. DBGPRINT(RECEIVE, ERR,
  337. ("SpxLineDown: CALLED WITH %lx\n",
  338. NicId));
  339. return;
  340. }
  341. VOID
  342. SpxScheduleRoute (
  343. IN PIPX_ROUTE_ENTRY RouteEntry
  344. )
  345. {
  346. DBGPRINT(RECEIVE, ERR,
  347. ("SpxScheduleRoute: CALLED WITH %lx\n",
  348. RouteEntry));
  349. return;
  350. }
  351. #if defined(_PNP_POWER)
  352. NTSTATUS
  353. SpxPnPNotification(
  354. IN IPX_PNP_OPCODE OpCode,
  355. IN PVOID PnPData
  356. )
  357. /*++
  358. Routine Description:
  359. This function receives the notification about PnP events from IPX
  360. Arguments:
  361. OpCode - Type of the PnP event
  362. PnPData - Data associated with this event.
  363. Return Value:
  364. None.
  365. --*/
  366. {
  367. USHORT MaximumNicId = 0;
  368. CTELockHandle LockHandle;
  369. PDEVICE Device = SpxDevice;
  370. UNICODE_STRING UnicodeDeviceName;
  371. NTSTATUS Status = STATUS_SUCCESS;
  372. #ifdef _PNP_POWER_
  373. PNET_PNP_EVENT NetPnpEvent;
  374. #endif // _PNP_POWER_
  375. DBGPRINT(DEVICE, DBG,("Received a pnp notification, opcode %d\n",OpCode));
  376. switch( OpCode ) {
  377. case IPX_PNP_ADD_DEVICE : {
  378. CTELockHandle TimerLockHandle;
  379. IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
  380. CTEGetLock (&Device->dev_Lock, &LockHandle);
  381. if ( PnPInfo->FirstORLastDevice ) {
  382. CTEAssert( PnPInfo->NewReservedAddress );
  383. //CTEAssert( Device->dev_State != DEVICE_STATE_OPEN );
  384. *(UNALIGNED ULONG *)Device->dev_Network = PnPInfo->NetworkAddress;
  385. RtlCopyMemory( Device->dev_Node, PnPInfo->NodeAddress, 6);
  386. //
  387. // Start the timer. It is possible that the timer
  388. // was still running or we are still in the timer dpc
  389. // from the previous ADD_DEVICE - DELETE_DEVICE execution
  390. // cycle. But it is ok simply restart this, because
  391. // KeSetTimer implicitly cancels the previous Dpc.
  392. //
  393. CTEGetLock(&spxTimerLock, &TimerLockHandle);
  394. spxTimerStopped = FALSE;
  395. CTEFreeLock(&spxTimerLock, TimerLockHandle);
  396. KeSetTimer(&spxTimer,
  397. spxTimerTick,
  398. &spxTimerDpc);
  399. Device->dev_State = DEVICE_STATE_OPEN;
  400. //CTEAssert( !Device->dev_Adapters );
  401. IpxLineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
  402. IpxLineInfo.MaximumPacketSize = PnPInfo->LineInfo.MaximumPacketSize;
  403. // set the provider info
  404. SpxDevice->dev_ProviderInfo.MaximumLookaheadData = IpxLineInfo.MaximumPacketSize;
  405. // Set the window size in statistics
  406. SpxDevice->dev_Stat.MaximumSendWindow =
  407. SpxDevice->dev_Stat.AverageSendWindow = PARAM(CONFIG_WINDOW_SIZE) *
  408. IpxLineInfo.MaximumSendSize;
  409. }else {
  410. IpxLineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
  411. // Set the window size in statistics
  412. SpxDevice->dev_Stat.MaximumSendWindow =
  413. SpxDevice->dev_Stat.AverageSendWindow = PARAM(CONFIG_WINDOW_SIZE) *
  414. IpxLineInfo.MaximumSendSize;
  415. }
  416. Device->dev_Adapters++;
  417. CTEFreeLock ( &Device->dev_Lock, LockHandle );
  418. //
  419. // Notify the TDI clients about the device creation
  420. //
  421. if ( PnPInfo->FirstORLastDevice ) {
  422. UnicodeDeviceName.Buffer = Device->dev_DeviceName;
  423. UnicodeDeviceName.MaximumLength = Device->dev_DeviceNameLen;
  424. UnicodeDeviceName.Length = Device->dev_DeviceNameLen - sizeof(WCHAR);
  425. if ( !NT_SUCCESS( TdiRegisterDeviceObject(
  426. &UnicodeDeviceName,
  427. &Device->dev_TdiRegistrationHandle ) )) {
  428. DBGPRINT(TDI,ERR, ("Failed to register Spx Device with TDI\n"));
  429. }
  430. }
  431. break;
  432. }
  433. case IPX_PNP_DELETE_DEVICE : {
  434. IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
  435. CTEGetLock (&Device->dev_Lock, &LockHandle);
  436. CTEAssert( Device->dev_Adapters );
  437. Device->dev_Adapters--;
  438. if ( PnPInfo->FirstORLastDevice ) {
  439. Device->dev_State = DEVICE_STATE_LOADED;
  440. Device->dev_Adapters = 0;
  441. }
  442. IpxLineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
  443. CTEFreeLock ( &Device->dev_Lock, LockHandle );
  444. if ( PnPInfo->FirstORLastDevice ) {
  445. SpxTimerFlushAndStop();
  446. //
  447. // inform tdi clients about the device deletion
  448. //
  449. if ( !NT_SUCCESS( TdiDeregisterDeviceObject(
  450. Device->dev_TdiRegistrationHandle ) )) {
  451. DBGPRINT(TDI,ERR, ("Failed to Deregister Spx Device with TDI\n"));
  452. }
  453. }
  454. //
  455. // TBD: call ExNotifyCallback
  456. //
  457. break;
  458. }
  459. case IPX_PNP_ADDRESS_CHANGE: {
  460. IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
  461. CTEGetLock (&Device->dev_Lock, &LockHandle);
  462. CTEAssert( PnPInfo->NewReservedAddress );
  463. *(UNALIGNED ULONG *)Device->dev_Network = PnPInfo->NetworkAddress;
  464. RtlCopyMemory( Device->dev_Node, PnPInfo->NodeAddress, 6);
  465. CTEFreeLock ( &Device->dev_Lock, LockHandle );
  466. break;
  467. }
  468. case IPX_PNP_TRANSLATE_DEVICE:
  469. break;
  470. case IPX_PNP_TRANSLATE_ADDRESS:
  471. break;
  472. #ifdef _PNP_POWER_
  473. case IPX_PNP_QUERY_POWER:
  474. case IPX_PNP_QUERY_REMOVE:
  475. //
  476. // IPX wants to know if we can power off or remove an apapter.
  477. // We also look if there are any open connections before deciding.
  478. // See if we support the NDIS_DEVICE_POWER_STATE
  479. //
  480. NetPnpEvent = (PNET_PNP_EVENT) PnPData;
  481. UnicodeDeviceName.Buffer = Device->dev_DeviceName;
  482. UnicodeDeviceName.MaximumLength = Device->dev_DeviceNameLen;
  483. UnicodeDeviceName.Length = Device->dev_DeviceNameLen - sizeof(WCHAR);
  484. // First, Via TDI to our Clients.
  485. Status = TdiPnPPowerRequest(
  486. &UnicodeDeviceName,
  487. NetPnpEvent,
  488. NULL,
  489. NULL,
  490. IpxPnPComplete
  491. );
  492. #if 0
  493. if (STATUS_SUCCESS == Status) {
  494. // now if we do not have any open connections,
  495. // we are all set.
  496. Status = STATUS_DEVICE_BUSY;
  497. }
  498. #endif
  499. break;
  500. case IPX_PNP_SET_POWER:
  501. case IPX_PNP_CANCEL_REMOVE:
  502. NetPnpEvent = (PNET_PNP_EVENT) PnPData;
  503. UnicodeDeviceName.Buffer = Device->dev_DeviceName;
  504. UnicodeDeviceName.MaximumLength = Device->dev_DeviceNameLen;
  505. UnicodeDeviceName.Length = Device->dev_DeviceNameLen - sizeof(WCHAR);
  506. //
  507. // Just call TDI here.
  508. //
  509. Status = TdiPnPPowerRequest(
  510. &UnicodeDeviceName,
  511. NetPnpEvent,
  512. NULL,
  513. NULL,
  514. IpxPnPComplete
  515. );
  516. break;
  517. #endif // _PNP_POWER_
  518. default:
  519. CTEAssert( FALSE );
  520. }
  521. return Status;
  522. } /* SpxPnPNotification */
  523. #endif _PNP_POWER